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"
40 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
42 class MapEditEventIgnorer
45 MapEditEventIgnorer(bool *flag):
54 ~MapEditEventIgnorer()
67 void * ServerThread::Thread()
71 DSTACK(__FUNCTION_NAME);
73 BEGIN_DEBUG_EXCEPTION_HANDLER
78 //TimeTaker timer("AsyncRunStep() + Receive()");
81 //TimeTaker timer("AsyncRunStep()");
82 m_server->AsyncRunStep();
85 //dout_server<<"Running m_server->Receive()"<<std::endl;
88 catch(con::NoIncomingDataException &e)
91 catch(con::PeerNotFoundException &e)
93 dout_server<<"Server: PeerNotFoundException"<<std::endl;
97 END_DEBUG_EXCEPTION_HANDLER
102 void * EmergeThread::Thread()
106 DSTACK(__FUNCTION_NAME);
110 BEGIN_DEBUG_EXCEPTION_HANDLER
113 Get block info from queue, emerge them and send them
116 After queue is empty, exit.
120 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
124 SharedPtr<QueuedBlockEmerge> q(qptr);
130 Do not generate over-limit
132 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
133 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
134 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
135 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
136 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
137 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
140 //derr_server<<"EmergeThread::Thread(): running"<<std::endl;
142 //TimeTaker timer("block emerge");
145 Try to emerge it from somewhere.
147 If it is only wanted as optional, only loading from disk
152 Check if any peer wants it as non-optional. In that case it
155 Also decrement the emerge queue count in clients.
158 bool optional = true;
161 core::map<u16, u8>::Iterator i;
162 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
164 //u16 peer_id = i.getNode()->getKey();
167 u8 flags = i.getNode()->getValue();
168 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
174 /*dstream<<"EmergeThread: p="
175 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
176 <<"optional="<<optional<<std::endl;*/
178 ServerMap &map = ((ServerMap&)m_server->m_env.getMap());
180 //core::map<v3s16, MapBlock*> changed_blocks;
181 //core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
183 MapBlock *block = NULL;
184 bool got_block = true;
185 core::map<v3s16, MapBlock*> modified_blocks;
187 bool only_from_disk = false;
190 only_from_disk = true;
193 Fetch block from map or generate a single block
196 JMutexAutoLock envlock(m_server->m_env_mutex);
198 // Load sector if it isn't loaded
199 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
200 //map.loadSectorFull(p2d);
201 map.loadSectorMeta(p2d);
203 block = map.getBlockNoCreateNoEx(p);
204 if(!block || block->isDummy() || !block->isGenerated())
206 // Get, load or create sector
207 /*ServerMapSector *sector =
208 (ServerMapSector*)map.createSector(p2d);*/
210 // Load/generate block
212 /*block = map.emergeBlock(p, sector, changed_blocks,
213 lighting_invalidated_blocks);*/
215 block = map.loadBlock(p);
217 if(block == NULL && only_from_disk == false)
218 block = map.generateBlock(p, modified_blocks);
219 //block = map.generateBlock(p, changed_blocks);
220 /*block = map.generateBlock(p, block, sector, changed_blocks,
221 lighting_invalidated_blocks);*/
230 Ignore map edit events, they will not need to be
231 sent to anybody because the block hasn't been sent
234 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
236 // Activate objects and stuff
237 m_server->m_env.activateBlock(block, 3600);
242 /*if(block->getLightingExpired()){
243 lighting_invalidated_blocks[block->getPos()] = block;
247 // TODO: Some additional checking and lighting updating,
252 JMutexAutoLock envlock(m_server->m_env_mutex);
257 Collect a list of blocks that have been modified in
258 addition to the fetched one.
262 if(lighting_invalidated_blocks.size() > 0)
264 /*dstream<<"lighting "<<lighting_invalidated_blocks.size()
265 <<" blocks"<<std::endl;*/
267 // 50-100ms for single block generation
268 //TimeTaker timer("** EmergeThread updateLighting");
270 // Update lighting without locking the environment mutex,
271 // add modified blocks to changed blocks
272 map.updateLighting(lighting_invalidated_blocks, modified_blocks);
275 // Add all from changed_blocks to modified_blocks
276 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
277 i.atEnd() == false; i++)
279 MapBlock *block = i.getNode()->getValue();
280 modified_blocks.insert(block->getPos(), block);
284 // If we got no block, there should be no invalidated blocks
287 //assert(lighting_invalidated_blocks.size() == 0);
293 Set sent status of modified blocks on clients
296 // NOTE: Server's clients are also behind the connection mutex
297 JMutexAutoLock lock(m_server->m_con_mutex);
300 Add the originally fetched block to the modified list
304 modified_blocks.insert(p, block);
308 Set the modified blocks unsent for all the clients
311 for(core::map<u16, RemoteClient*>::Iterator
312 i = m_server->m_clients.getIterator();
313 i.atEnd() == false; i++)
315 RemoteClient *client = i.getNode()->getValue();
317 if(modified_blocks.size() > 0)
319 // Remove block from sent history
320 client->SetBlocksNotSent(modified_blocks);
326 END_DEBUG_EXCEPTION_HANDLER
331 void RemoteClient::GetNextBlocks(Server *server, float dtime,
332 core::array<PrioritySortedBlockTransfer> &dest)
334 DSTACK(__FUNCTION_NAME);
337 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
340 m_nothing_to_send_pause_timer -= dtime;
342 if(m_nothing_to_send_pause_timer >= 0)
345 m_nearest_unsent_reset_timer = 0;
349 // Won't send anything if already sending
350 if(m_blocks_sending.size() >= g_settings.getU16
351 ("max_simultaneous_block_sends_per_client"))
353 //dstream<<"Not sending any blocks, Queue full."<<std::endl;
357 //TimeTaker timer("RemoteClient::GetNextBlocks");
359 Player *player = server->m_env.getPlayer(peer_id);
361 assert(player != NULL);
363 v3f playerpos = player->getPosition();
364 v3f playerspeed = player->getSpeed();
365 v3f playerspeeddir(0,0,0);
366 if(playerspeed.getLength() > 1.0*BS)
367 playerspeeddir = playerspeed / playerspeed.getLength();
368 // Predict to next block
369 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
371 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
373 v3s16 center = getNodeBlockPos(center_nodepos);
375 // Camera position and direction
377 playerpos + v3f(0, BS+BS/2, 0);
378 v3f camera_dir = v3f(0,0,1);
379 camera_dir.rotateYZBy(player->getPitch());
380 camera_dir.rotateXZBy(player->getYaw());
382 /*dstream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
383 <<camera_dir.Z<<")"<<std::endl;*/
386 Get the starting value of the block finder radius.
389 if(m_last_center != center)
391 m_nearest_unsent_d = 0;
392 m_last_center = center;
395 /*dstream<<"m_nearest_unsent_reset_timer="
396 <<m_nearest_unsent_reset_timer<<std::endl;*/
398 // This has to be incremented only when the nothing to send pause
400 m_nearest_unsent_reset_timer += dtime;
402 // Reset periodically to avoid possible bugs or other mishaps
403 if(m_nearest_unsent_reset_timer > 10.0)
405 m_nearest_unsent_reset_timer = 0;
406 m_nearest_unsent_d = 0;
407 /*dstream<<"Resetting m_nearest_unsent_d for "
408 <<server->getPlayerName(peer_id)<<std::endl;*/
411 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
412 s16 d_start = m_nearest_unsent_d;
414 //dstream<<"d_start="<<d_start<<std::endl;
416 u16 max_simul_sends_setting = g_settings.getU16
417 ("max_simultaneous_block_sends_per_client");
418 u16 max_simul_sends_usually = max_simul_sends_setting;
421 Check the time from last addNode/removeNode.
423 Decrease send rate if player is building stuff.
425 m_time_from_building += dtime;
426 if(m_time_from_building < g_settings.getFloat(
427 "full_block_send_enable_min_time_from_building"))
429 max_simul_sends_usually
430 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
434 Number of blocks sending + number of blocks selected for sending
436 u32 num_blocks_selected = m_blocks_sending.size();
439 next time d will be continued from the d from which the nearest
440 unsent block was found this time.
442 This is because not necessarily any of the blocks found this
443 time are actually sent.
445 s32 new_nearest_unsent_d = -1;
447 s16 d_max = g_settings.getS16("max_block_send_distance");
448 s16 d_max_gen = g_settings.getS16("max_block_generate_distance");
450 // Don't loop very much at a time
451 if(d_max > d_start+1)
453 /*if(d_max_gen > d_start+2)
454 d_max_gen = d_start+2;*/
456 //dstream<<"Starting from "<<d_start<<std::endl;
458 bool sending_something = false;
460 bool no_blocks_found_for_sending = true;
462 bool queue_is_full = false;
465 for(d = d_start; d <= d_max; d++)
467 //dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
470 If m_nearest_unsent_d was changed by the EmergeThread
471 (it can change it to 0 through SetBlockNotSent),
473 Else update m_nearest_unsent_d
475 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
477 d = m_nearest_unsent_d;
478 last_nearest_unsent_d = m_nearest_unsent_d;
482 Get the border/face dot coordinates of a "d-radiused"
485 core::list<v3s16> list;
486 getFacePositions(list, d);
488 core::list<v3s16>::Iterator li;
489 for(li=list.begin(); li!=list.end(); li++)
491 v3s16 p = *li + center;
495 - Don't allow too many simultaneous transfers
496 - EXCEPT when the blocks are very close
498 Also, don't send blocks that are already flying.
501 // Start with the usual maximum
502 u16 max_simul_dynamic = max_simul_sends_usually;
504 // If block is very close, allow full maximum
505 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
506 max_simul_dynamic = max_simul_sends_setting;
508 // Don't select too many blocks for sending
509 if(num_blocks_selected >= max_simul_dynamic)
511 queue_is_full = true;
512 goto queue_full_break;
515 // Don't send blocks that are currently being transferred
516 if(m_blocks_sending.find(p) != NULL)
522 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
523 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
524 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
525 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
526 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
527 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
530 // If this is true, inexistent block will be made from scratch
531 bool generate = d <= d_max_gen;
534 /*// Limit the generating area vertically to 2/3
535 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
538 // Limit the send area vertically to 2/3
539 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
545 If block is far away, don't generate it unless it is
551 // Block center y in nodes
552 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
553 // Don't generate if it's very high or very low
554 if(y < -64 || y > 64)
558 v2s16 p2d_nodes_center(
562 // Get ground height in nodes
563 s16 gh = server->m_env.getServerMap().findGroundLevel(
566 // If differs a lot, don't generate
567 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
569 // Actually, don't even send it
575 //dstream<<"d="<<d<<std::endl;
578 Don't generate or send if not in sight
581 if(isBlockInSight(p, camera_pos, camera_dir, 10000*BS) == false)
587 Don't send already sent blocks
590 if(m_blocks_sent.find(p) != NULL)
597 Check if map has this block
599 MapBlock *block = server->m_env.getMap().getBlockNoCreateNoEx(p);
601 bool surely_not_found_on_disk = false;
602 bool block_is_invalid = false;
605 // Block is dummy if data doesn't exist.
606 // It means it has been not found from disk and not generated
609 surely_not_found_on_disk = true;
612 // Block is valid if lighting is up-to-date and data exists
613 if(block->isValid() == false)
615 block_is_invalid = true;
618 /*if(block->isFullyGenerated() == false)
620 block_is_invalid = true;
625 ServerMap *map = (ServerMap*)(&server->m_env.getMap());
626 v2s16 chunkpos = map->sector_to_chunk(p2d);
627 if(map->chunkNonVolatile(chunkpos) == false)
628 block_is_invalid = true;
630 if(block->isGenerated() == false)
631 block_is_invalid = true;
634 If block is not close, don't send it unless it is near
637 Block is near ground level if night-time mesh
638 differs from day-time mesh.
642 if(block->dayNightDiffed() == false)
649 If block has been marked to not exist on disk (dummy)
650 and generating new ones is not wanted, skip block.
652 if(generate == false && surely_not_found_on_disk == true)
659 Record the lowest d from which a block has been
660 found being not sent and possibly to exist
662 if(no_blocks_found_for_sending)
665 new_nearest_unsent_d = d;
668 no_blocks_found_for_sending = false;
671 Add inexistent block to emerge queue.
673 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
675 //TODO: Get value from somewhere
676 // Allow only one block in emerge queue
677 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
678 // Allow two blocks in queue per client
679 if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
681 //dstream<<"Adding block to emerge queue"<<std::endl;
683 // Add it to the emerge queue and trigger the thread
686 if(generate == false)
687 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
689 server->m_emerge_queue.addBlock(peer_id, p, flags);
690 server->m_emergethread.trigger();
698 Add block to send queue
701 PrioritySortedBlockTransfer q((float)d, p, peer_id);
705 num_blocks_selected += 1;
706 sending_something = true;
711 //dstream<<"Stopped at "<<d<<std::endl;
713 if(no_blocks_found_for_sending)
715 if(queue_is_full == false)
716 new_nearest_unsent_d = d;
719 if(new_nearest_unsent_d != -1)
720 m_nearest_unsent_d = new_nearest_unsent_d;
722 if(sending_something == false)
724 m_nothing_to_send_counter++;
725 if((s16)m_nothing_to_send_counter >=
726 g_settings.getS16("max_block_send_distance"))
728 // Pause time in seconds
729 m_nothing_to_send_pause_timer = 1.0;
730 /*dstream<<"nothing to send to "
731 <<server->getPlayerName(peer_id)
732 <<" (d="<<d<<")"<<std::endl;*/
737 m_nothing_to_send_counter = 0;
740 /*timer_result = timer.stop(true);
741 if(timer_result != 0)
742 dstream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
745 void RemoteClient::SendObjectData(
748 core::map<v3s16, bool> &stepped_blocks
751 DSTACK(__FUNCTION_NAME);
753 // Can't send anything without knowing version
754 if(serialization_version == SER_FMT_VER_INVALID)
756 dstream<<"RemoteClient::SendObjectData(): Not sending, no version."
762 Send a TOCLIENT_OBJECTDATA packet.
766 u16 number of player positions
777 std::ostringstream os(std::ios_base::binary);
781 writeU16(buf, TOCLIENT_OBJECTDATA);
782 os.write((char*)buf, 2);
785 Get and write player data
788 // Get connected players
789 core::list<Player*> players = server->m_env.getPlayers(true);
791 // Write player count
792 u16 playercount = players.size();
793 writeU16(buf, playercount);
794 os.write((char*)buf, 2);
796 core::list<Player*>::Iterator i;
797 for(i = players.begin();
798 i != players.end(); i++)
802 v3f pf = player->getPosition();
803 v3f sf = player->getSpeed();
805 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
806 v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
807 s32 pitch_i (player->getPitch() * 100);
808 s32 yaw_i (player->getYaw() * 100);
810 writeU16(buf, player->peer_id);
811 os.write((char*)buf, 2);
812 writeV3S32(buf, position_i);
813 os.write((char*)buf, 12);
814 writeV3S32(buf, speed_i);
815 os.write((char*)buf, 12);
816 writeS32(buf, pitch_i);
817 os.write((char*)buf, 4);
818 writeS32(buf, yaw_i);
819 os.write((char*)buf, 4);
823 Get and write object data
829 For making players to be able to build to their nearby
830 environment (building is not possible on blocks that are not
833 - Add blocks to emerge queue if they are not found
835 SUGGESTION: These could be ignored from the backside of the player
838 Player *player = server->m_env.getPlayer(peer_id);
842 v3f playerpos = player->getPosition();
843 v3f playerspeed = player->getSpeed();
845 v3s16 center_nodepos = floatToInt(playerpos, BS);
846 v3s16 center = getNodeBlockPos(center_nodepos);
848 s16 d_max = g_settings.getS16("active_object_range");
850 // Number of blocks whose objects were written to bos
853 std::ostringstream bos(std::ios_base::binary);
855 for(s16 d = 0; d <= d_max; d++)
857 core::list<v3s16> list;
858 getFacePositions(list, d);
860 core::list<v3s16>::Iterator li;
861 for(li=list.begin(); li!=list.end(); li++)
863 v3s16 p = *li + center;
866 Ignore blocks that haven't been sent to the client
869 if(m_blocks_sent.find(p) == NULL)
873 // Try stepping block and add it to a send queue
878 MapBlock *block = server->m_env.getMap().getBlockNoCreate(p);
881 Step block if not in stepped_blocks and add to stepped_blocks.
883 if(stepped_blocks.find(p) == NULL)
885 block->stepObjects(dtime, true, server->m_env.getDayNightRatio());
886 stepped_blocks.insert(p, true);
887 block->setChangedFlag();
890 // Skip block if there are no objects
891 if(block->getObjectCount() == 0)
900 bos.write((char*)buf, 6);
903 //block->serializeObjects(bos, serialization_version); // DEPRECATED
910 Stop collecting objects if data is already too big
912 // Sum of player and object data sizes
913 s32 sum = (s32)os.tellp() + 2 + (s32)bos.tellp();
914 // break out if data too big
915 if(sum > MAX_OBJECTDATA_SIZE)
917 goto skip_subsequent;
921 catch(InvalidPositionException &e)
924 // Add it to the emerge queue and trigger the thread.
925 // Fetch the block only if it is on disk.
927 // Grab and increment counter
928 /*SharedPtr<JMutexAutoLock> lock
929 (m_num_blocks_in_emerge_queue.getLock());
930 m_num_blocks_in_emerge_queue.m_value++;*/
932 // Add to queue as an anonymous fetch from disk
933 u8 flags = BLOCK_EMERGE_FLAG_FROMDISK;
934 server->m_emerge_queue.addBlock(0, p, flags);
935 server->m_emergethread.trigger();
943 writeU16(buf, blockcount);
944 os.write((char*)buf, 2);
946 // Write block objects
953 //dstream<<"Server: Sending object data to "<<peer_id<<std::endl;
956 std::string s = os.str();
957 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
958 // Send as unreliable
959 server->m_con.Send(peer_id, 0, data, false);
962 void RemoteClient::GotBlock(v3s16 p)
964 if(m_blocks_sending.find(p) != NULL)
965 m_blocks_sending.remove(p);
968 /*dstream<<"RemoteClient::GotBlock(): Didn't find in"
969 " m_blocks_sending"<<std::endl;*/
970 m_excess_gotblocks++;
972 m_blocks_sent.insert(p, true);
975 void RemoteClient::SentBlock(v3s16 p)
977 if(m_blocks_sending.find(p) == NULL)
978 m_blocks_sending.insert(p, 0.0);
980 dstream<<"RemoteClient::SentBlock(): Sent block"
981 " already in m_blocks_sending"<<std::endl;
984 void RemoteClient::SetBlockNotSent(v3s16 p)
986 m_nearest_unsent_d = 0;
988 if(m_blocks_sending.find(p) != NULL)
989 m_blocks_sending.remove(p);
990 if(m_blocks_sent.find(p) != NULL)
991 m_blocks_sent.remove(p);
994 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
996 m_nearest_unsent_d = 0;
998 for(core::map<v3s16, MapBlock*>::Iterator
999 i = blocks.getIterator();
1000 i.atEnd()==false; i++)
1002 v3s16 p = i.getNode()->getKey();
1004 if(m_blocks_sending.find(p) != NULL)
1005 m_blocks_sending.remove(p);
1006 if(m_blocks_sent.find(p) != NULL)
1007 m_blocks_sent.remove(p);
1015 PlayerInfo::PlayerInfo()
1021 void PlayerInfo::PrintLine(std::ostream *s)
1024 (*s)<<"\""<<name<<"\" ("
1025 <<(position.X/10)<<","<<(position.Y/10)
1026 <<","<<(position.Z/10)<<") ";
1028 (*s)<<" avg_rtt="<<avg_rtt;
1032 u32 PIChecksum(core::list<PlayerInfo> &l)
1034 core::list<PlayerInfo>::Iterator i;
1037 for(i=l.begin(); i!=l.end(); i++)
1039 checksum += a * (i->id+1);
1040 checksum ^= 0x435aafcd;
1051 std::string mapsavedir
1053 m_env(new ServerMap(mapsavedir), this),
1054 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
1055 m_authmanager(mapsavedir+"/auth.txt"),
1057 m_emergethread(this),
1059 m_time_of_day_send_timer(0),
1061 m_mapsavedir(mapsavedir),
1062 m_shutdown_requested(false),
1063 m_ignore_map_edit_events(false),
1064 m_ignore_map_edit_events_peer_id(0)
1066 m_liquid_transform_timer = 0.0;
1067 m_print_info_timer = 0.0;
1068 m_objectdata_timer = 0.0;
1069 m_emergethread_trigger_timer = 0.0;
1070 m_savemap_timer = 0.0;
1074 m_step_dtime_mutex.Init();
1077 // Register us to receive map edit events
1078 m_env.getMap().addEventReceiver(this);
1080 // If file exists, load environment metadata
1081 if(fs::PathExists(m_mapsavedir+"/env_meta.txt"))
1083 dstream<<"Server: Loading environment metadata"<<std::endl;
1084 m_env.loadMeta(m_mapsavedir);
1088 dstream<<"Server: Loading players"<<std::endl;
1089 m_env.deSerializePlayers(m_mapsavedir);
1094 dstream<<"Server::~Server()"<<std::endl;
1097 Send shutdown message
1100 JMutexAutoLock conlock(m_con_mutex);
1102 std::wstring line = L"*** Server shutting down";
1105 Send the message to clients
1107 for(core::map<u16, RemoteClient*>::Iterator
1108 i = m_clients.getIterator();
1109 i.atEnd() == false; i++)
1111 // Get client and check that it is valid
1112 RemoteClient *client = i.getNode()->getValue();
1113 assert(client->peer_id == i.getNode()->getKey());
1114 if(client->serialization_version == SER_FMT_VER_INVALID)
1118 SendChatMessage(client->peer_id, line);
1120 catch(con::PeerNotFoundException &e)
1128 dstream<<"Server: Saving players"<<std::endl;
1129 m_env.serializePlayers(m_mapsavedir);
1132 Save environment metadata
1134 dstream<<"Server: Saving environment metadata"<<std::endl;
1135 m_env.saveMeta(m_mapsavedir);
1146 JMutexAutoLock clientslock(m_con_mutex);
1148 for(core::map<u16, RemoteClient*>::Iterator
1149 i = m_clients.getIterator();
1150 i.atEnd() == false; i++)
1153 // NOTE: These are removed by env destructor
1155 u16 peer_id = i.getNode()->getKey();
1156 JMutexAutoLock envlock(m_env_mutex);
1157 m_env.removePlayer(peer_id);
1161 delete i.getNode()->getValue();
1166 void Server::start(unsigned short port)
1168 DSTACK(__FUNCTION_NAME);
1169 // Stop thread if already running
1172 // Initialize connection
1173 m_con.setTimeoutMs(30);
1177 m_thread.setRun(true);
1180 dout_server<<"Server: Started on port "<<port<<std::endl;
1185 DSTACK(__FUNCTION_NAME);
1187 // Stop threads (set run=false first so both start stopping)
1188 m_thread.setRun(false);
1189 m_emergethread.setRun(false);
1191 m_emergethread.stop();
1193 dout_server<<"Server: Threads stopped"<<std::endl;
1196 void Server::step(float dtime)
1198 DSTACK(__FUNCTION_NAME);
1203 JMutexAutoLock lock(m_step_dtime_mutex);
1204 m_step_dtime += dtime;
1208 void Server::AsyncRunStep()
1210 DSTACK(__FUNCTION_NAME);
1214 JMutexAutoLock lock1(m_step_dtime_mutex);
1215 dtime = m_step_dtime;
1219 ScopeProfiler sp(&g_profiler, "Server: selecting and sending "
1220 "blocks to clients");
1221 // Send blocks to clients
1228 //dstream<<"Server steps "<<dtime<<std::endl;
1229 //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1232 JMutexAutoLock lock1(m_step_dtime_mutex);
1233 m_step_dtime -= dtime;
1240 m_uptime.set(m_uptime.get() + dtime);
1244 Update m_time_of_day and overall game time
1247 JMutexAutoLock envlock(m_env_mutex);
1249 m_time_counter += dtime;
1250 f32 speed = g_settings.getFloat("time_speed") * 24000./(24.*3600);
1251 u32 units = (u32)(m_time_counter*speed);
1252 m_time_counter -= (f32)units / speed;
1254 m_env.setTimeOfDay((m_env.getTimeOfDay() + units) % 24000);
1256 //dstream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1259 Send to clients at constant intervals
1262 m_time_of_day_send_timer -= dtime;
1263 if(m_time_of_day_send_timer < 0.0)
1265 m_time_of_day_send_timer = g_settings.getFloat("time_send_interval");
1267 //JMutexAutoLock envlock(m_env_mutex);
1268 JMutexAutoLock conlock(m_con_mutex);
1270 for(core::map<u16, RemoteClient*>::Iterator
1271 i = m_clients.getIterator();
1272 i.atEnd() == false; i++)
1274 RemoteClient *client = i.getNode()->getValue();
1275 //Player *player = m_env.getPlayer(client->peer_id);
1277 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1278 m_env.getTimeOfDay());
1280 m_con.Send(client->peer_id, 0, data, true);
1286 // Process connection's timeouts
1287 JMutexAutoLock lock2(m_con_mutex);
1288 ScopeProfiler sp(&g_profiler, "Server: connection timeout processing");
1289 m_con.RunTimeouts(dtime);
1293 // This has to be called so that the client list gets synced
1294 // with the peer list of the connection
1295 ScopeProfiler sp(&g_profiler, "Server: peer change handling");
1296 handlePeerChanges();
1301 // This also runs Map's timers
1302 JMutexAutoLock lock(m_env_mutex);
1303 ScopeProfiler sp(&g_profiler, "Server: environment step");
1314 m_liquid_transform_timer += dtime;
1315 if(m_liquid_transform_timer >= 1.00)
1317 m_liquid_transform_timer -= 1.00;
1319 JMutexAutoLock lock(m_env_mutex);
1321 ScopeProfiler sp(&g_profiler, "Server: liquid transform");
1323 core::map<v3s16, MapBlock*> modified_blocks;
1324 m_env.getMap().transformLiquids(modified_blocks);
1329 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1330 ServerMap &map = ((ServerMap&)m_env.getMap());
1331 map.updateLighting(modified_blocks, lighting_modified_blocks);
1333 // Add blocks modified by lighting to modified_blocks
1334 for(core::map<v3s16, MapBlock*>::Iterator
1335 i = lighting_modified_blocks.getIterator();
1336 i.atEnd() == false; i++)
1338 MapBlock *block = i.getNode()->getValue();
1339 modified_blocks.insert(block->getPos(), block);
1343 Set the modified blocks unsent for all the clients
1346 JMutexAutoLock lock2(m_con_mutex);
1348 for(core::map<u16, RemoteClient*>::Iterator
1349 i = m_clients.getIterator();
1350 i.atEnd() == false; i++)
1352 RemoteClient *client = i.getNode()->getValue();
1354 if(modified_blocks.size() > 0)
1356 // Remove block from sent history
1357 client->SetBlocksNotSent(modified_blocks);
1362 // Periodically print some info
1364 float &counter = m_print_info_timer;
1370 JMutexAutoLock lock2(m_con_mutex);
1372 for(core::map<u16, RemoteClient*>::Iterator
1373 i = m_clients.getIterator();
1374 i.atEnd() == false; i++)
1376 //u16 peer_id = i.getNode()->getKey();
1377 RemoteClient *client = i.getNode()->getValue();
1378 Player *player = m_env.getPlayer(client->peer_id);
1381 std::cout<<player->getName()<<"\t";
1382 client->PrintInfo(std::cout);
1387 //if(g_settings.getBool("enable_experimental"))
1391 Check added and deleted active objects
1394 //dstream<<"Server: Checking added and deleted active objects"<<std::endl;
1395 JMutexAutoLock envlock(m_env_mutex);
1396 JMutexAutoLock conlock(m_con_mutex);
1398 ScopeProfiler sp(&g_profiler, "Server: checking added and deleted objects");
1400 // Radius inside which objects are active
1403 for(core::map<u16, RemoteClient*>::Iterator
1404 i = m_clients.getIterator();
1405 i.atEnd() == false; i++)
1407 RemoteClient *client = i.getNode()->getValue();
1408 Player *player = m_env.getPlayer(client->peer_id);
1411 // This can happen if the client timeouts somehow
1412 /*dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1414 <<" has no associated player"<<std::endl;*/
1417 v3s16 pos = floatToInt(player->getPosition(), BS);
1419 core::map<u16, bool> removed_objects;
1420 core::map<u16, bool> added_objects;
1421 m_env.getRemovedActiveObjects(pos, radius,
1422 client->m_known_objects, removed_objects);
1423 m_env.getAddedActiveObjects(pos, radius,
1424 client->m_known_objects, added_objects);
1426 // Ignore if nothing happened
1427 if(removed_objects.size() == 0 && added_objects.size() == 0)
1429 //dstream<<"INFO: active objects: none changed"<<std::endl;
1433 std::string data_buffer;
1437 // Handle removed objects
1438 writeU16((u8*)buf, removed_objects.size());
1439 data_buffer.append(buf, 2);
1440 for(core::map<u16, bool>::Iterator
1441 i = removed_objects.getIterator();
1442 i.atEnd()==false; i++)
1445 u16 id = i.getNode()->getKey();
1446 ServerActiveObject* obj = m_env.getActiveObject(id);
1448 // Add to data buffer for sending
1449 writeU16((u8*)buf, i.getNode()->getKey());
1450 data_buffer.append(buf, 2);
1452 // Remove from known objects
1453 client->m_known_objects.remove(i.getNode()->getKey());
1455 if(obj && obj->m_known_by_count > 0)
1456 obj->m_known_by_count--;
1459 // Handle added objects
1460 writeU16((u8*)buf, added_objects.size());
1461 data_buffer.append(buf, 2);
1462 for(core::map<u16, bool>::Iterator
1463 i = added_objects.getIterator();
1464 i.atEnd()==false; i++)
1467 u16 id = i.getNode()->getKey();
1468 ServerActiveObject* obj = m_env.getActiveObject(id);
1471 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1473 dstream<<"WARNING: "<<__FUNCTION_NAME
1474 <<": NULL object"<<std::endl;
1476 type = obj->getType();
1478 // Add to data buffer for sending
1479 writeU16((u8*)buf, id);
1480 data_buffer.append(buf, 2);
1481 writeU8((u8*)buf, type);
1482 data_buffer.append(buf, 1);
1485 data_buffer.append(serializeLongString(
1486 obj->getClientInitializationData()));
1488 data_buffer.append(serializeLongString(""));
1490 // Add to known objects
1491 client->m_known_objects.insert(i.getNode()->getKey(), false);
1494 obj->m_known_by_count++;
1498 SharedBuffer<u8> reply(2 + data_buffer.size());
1499 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1500 memcpy((char*)&reply[2], data_buffer.c_str(),
1501 data_buffer.size());
1503 m_con.Send(client->peer_id, 0, reply, true);
1505 dstream<<"INFO: Server: Sent object remove/add: "
1506 <<removed_objects.size()<<" removed, "
1507 <<added_objects.size()<<" added, "
1508 <<"packet size is "<<reply.getSize()<<std::endl;
1513 Collect a list of all the objects known by the clients
1514 and report it back to the environment.
1517 core::map<u16, bool> all_known_objects;
1519 for(core::map<u16, RemoteClient*>::Iterator
1520 i = m_clients.getIterator();
1521 i.atEnd() == false; i++)
1523 RemoteClient *client = i.getNode()->getValue();
1524 // Go through all known objects of client
1525 for(core::map<u16, bool>::Iterator
1526 i = client->m_known_objects.getIterator();
1527 i.atEnd()==false; i++)
1529 u16 id = i.getNode()->getKey();
1530 all_known_objects[id] = true;
1534 m_env.setKnownActiveObjects(whatever);
1540 Send object messages
1543 JMutexAutoLock envlock(m_env_mutex);
1544 JMutexAutoLock conlock(m_con_mutex);
1546 ScopeProfiler sp(&g_profiler, "Server: sending object messages");
1549 // Value = data sent by object
1550 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1552 // Get active object messages from environment
1555 ActiveObjectMessage aom = m_env.getActiveObjectMessage();
1559 core::list<ActiveObjectMessage>* message_list = NULL;
1560 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1561 n = buffered_messages.find(aom.id);
1564 message_list = new core::list<ActiveObjectMessage>;
1565 buffered_messages.insert(aom.id, message_list);
1569 message_list = n->getValue();
1571 message_list->push_back(aom);
1574 // Route data to every client
1575 for(core::map<u16, RemoteClient*>::Iterator
1576 i = m_clients.getIterator();
1577 i.atEnd()==false; i++)
1579 RemoteClient *client = i.getNode()->getValue();
1580 std::string reliable_data;
1581 std::string unreliable_data;
1582 // Go through all objects in message buffer
1583 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1584 j = buffered_messages.getIterator();
1585 j.atEnd()==false; j++)
1587 // If object is not known by client, skip it
1588 u16 id = j.getNode()->getKey();
1589 if(client->m_known_objects.find(id) == NULL)
1591 // Get message list of object
1592 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1593 // Go through every message
1594 for(core::list<ActiveObjectMessage>::Iterator
1595 k = list->begin(); k != list->end(); k++)
1597 // Compose the full new data with header
1598 ActiveObjectMessage aom = *k;
1599 std::string new_data;
1602 writeU16((u8*)&buf[0], aom.id);
1603 new_data.append(buf, 2);
1605 new_data += serializeString(aom.datastring);
1606 // Add data to buffer
1608 reliable_data += new_data;
1610 unreliable_data += new_data;
1614 reliable_data and unreliable_data are now ready.
1617 if(reliable_data.size() > 0)
1619 SharedBuffer<u8> reply(2 + reliable_data.size());
1620 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1621 memcpy((char*)&reply[2], reliable_data.c_str(),
1622 reliable_data.size());
1624 m_con.Send(client->peer_id, 0, reply, true);
1626 if(unreliable_data.size() > 0)
1628 SharedBuffer<u8> reply(2 + unreliable_data.size());
1629 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1630 memcpy((char*)&reply[2], unreliable_data.c_str(),
1631 unreliable_data.size());
1632 // Send as unreliable
1633 m_con.Send(client->peer_id, 0, reply, false);
1636 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1638 dstream<<"INFO: Server: Size of object message data: "
1639 <<"reliable: "<<reliable_data.size()
1640 <<", unreliable: "<<unreliable_data.size()
1645 // Clear buffered_messages
1646 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1647 i = buffered_messages.getIterator();
1648 i.atEnd()==false; i++)
1650 delete i.getNode()->getValue();
1654 } // enable_experimental
1657 Send queued-for-sending map edit events.
1660 // Don't send too many at a time
1663 // Single change sending is disabled if queue size is not small
1664 bool disable_single_change_sending = false;
1665 if(m_unsent_map_edit_queue.size() >= 4)
1666 disable_single_change_sending = true;
1668 while(m_unsent_map_edit_queue.size() != 0)
1670 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1672 // Players far away from the change are stored here.
1673 // Instead of sending the changes, MapBlocks are set not sent
1675 core::list<u16> far_players;
1677 if(event->type == MEET_ADDNODE)
1679 dstream<<"Server: MEET_ADDNODE"<<std::endl;
1680 if(disable_single_change_sending)
1681 sendAddNode(event->p, event->n, event->already_known_by_peer,
1684 sendAddNode(event->p, event->n, event->already_known_by_peer,
1687 else if(event->type == MEET_REMOVENODE)
1689 dstream<<"Server: MEET_REMOVENODE"<<std::endl;
1690 if(disable_single_change_sending)
1691 sendRemoveNode(event->p, event->already_known_by_peer,
1694 sendRemoveNode(event->p, event->already_known_by_peer,
1697 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1699 dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1700 setBlockNotSent(event->p);
1702 else if(event->type == MEET_OTHER)
1704 dstream<<"WARNING: Server: MEET_OTHER not implemented"
1709 dstream<<"WARNING: Server: Unknown MapEditEvent "
1710 <<((u32)event->type)<<std::endl;
1714 Set blocks not sent to far players
1716 if(far_players.size() > 0)
1718 core::map<v3s16, MapBlock*> modified_blocks2;
1719 for(core::map<v3s16, bool>::Iterator
1720 i = event->modified_blocks.getIterator();
1721 i.atEnd()==false; i++)
1723 v3s16 p = i.getNode()->getKey();
1724 modified_blocks2.insert(p,
1725 m_env.getMap().getBlockNoCreateNoEx(p));
1727 for(core::list<u16>::Iterator
1728 i = far_players.begin();
1729 i != far_players.end(); i++)
1732 RemoteClient *client = getClient(peer_id);
1735 client->SetBlocksNotSent(modified_blocks2);
1741 /*// Don't send too many at a time
1743 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1749 Send object positions
1750 TODO: Get rid of MapBlockObjects
1753 float &counter = m_objectdata_timer;
1755 if(counter >= g_settings.getFloat("objectdata_interval"))
1757 JMutexAutoLock lock1(m_env_mutex);
1758 JMutexAutoLock lock2(m_con_mutex);
1760 ScopeProfiler sp(&g_profiler, "Server: sending mbo positions");
1762 SendObjectData(counter);
1770 TODO: Move to ServerEnvironment and utilize active block stuff
1773 //TimeTaker timer("Step node metadata");
1775 JMutexAutoLock envlock(m_env_mutex);
1776 JMutexAutoLock conlock(m_con_mutex);
1778 ScopeProfiler sp(&g_profiler, "Server: stepping node metadata");
1780 core::map<v3s16, MapBlock*> changed_blocks;
1781 m_env.getMap().nodeMetadataStep(dtime, changed_blocks);
1783 // Use setBlockNotSent
1785 for(core::map<v3s16, MapBlock*>::Iterator
1786 i = changed_blocks.getIterator();
1787 i.atEnd() == false; i++)
1789 MapBlock *block = i.getNode()->getValue();
1791 for(core::map<u16, RemoteClient*>::Iterator
1792 i = m_clients.getIterator();
1793 i.atEnd()==false; i++)
1795 RemoteClient *client = i.getNode()->getValue();
1796 client->SetBlockNotSent(block->getPos());
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 JMutexAutoLock lock(m_env_mutex);
1832 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == true)
1834 // Save only changed parts
1835 m_env.getMap().save(true);
1837 // Delete unused sectors
1838 u32 deleted_count = m_env.getMap().unloadUnusedData(
1839 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1840 if(deleted_count > 0)
1842 dout_server<<"Server: Unloaded "<<deleted_count
1843 <<" sectors from memory"<<std::endl;
1847 m_env.serializePlayers(m_mapsavedir);
1849 // Save environment metadata
1850 m_env.saveMeta(m_mapsavedir);
1856 void Server::Receive()
1858 DSTACK(__FUNCTION_NAME);
1859 u32 data_maxsize = 10000;
1860 Buffer<u8> data(data_maxsize);
1865 JMutexAutoLock conlock(m_con_mutex);
1866 datasize = m_con.Receive(peer_id, *data, data_maxsize);
1869 // This has to be called so that the client list gets synced
1870 // with the peer list of the connection
1871 handlePeerChanges();
1873 ProcessData(*data, datasize, peer_id);
1875 catch(con::InvalidIncomingDataException &e)
1877 derr_server<<"Server::Receive(): "
1878 "InvalidIncomingDataException: what()="
1879 <<e.what()<<std::endl;
1881 catch(con::PeerNotFoundException &e)
1883 //NOTE: This is not needed anymore
1885 // The peer has been disconnected.
1886 // Find the associated player and remove it.
1888 /*JMutexAutoLock envlock(m_env_mutex);
1890 dout_server<<"ServerThread: peer_id="<<peer_id
1891 <<" has apparently closed connection. "
1892 <<"Removing player."<<std::endl;
1894 m_env.removePlayer(peer_id);*/
1898 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1900 DSTACK(__FUNCTION_NAME);
1901 // Environment is locked first.
1902 JMutexAutoLock envlock(m_env_mutex);
1903 JMutexAutoLock conlock(m_con_mutex);
1907 peer = m_con.GetPeer(peer_id);
1909 catch(con::PeerNotFoundException &e)
1911 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1912 <<peer_id<<" not found"<<std::endl;
1916 u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1924 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1926 if(command == TOSERVER_INIT)
1928 // [0] u16 TOSERVER_INIT
1929 // [2] u8 SER_FMT_VER_HIGHEST
1930 // [3] u8[20] player_name
1931 // [23] u8[28] password <--- can be sent without this, from old versions
1933 if(datasize < 2+1+PLAYERNAME_SIZE)
1936 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1937 <<peer->id<<std::endl;
1939 // First byte after command is maximum supported
1940 // serialization version
1941 u8 client_max = data[2];
1942 u8 our_max = SER_FMT_VER_HIGHEST;
1943 // Use the highest version supported by both
1944 u8 deployed = core::min_(client_max, our_max);
1945 // If it's lower than the lowest supported, give up.
1946 if(deployed < SER_FMT_VER_LOWEST)
1947 deployed = SER_FMT_VER_INVALID;
1949 //peer->serialization_version = deployed;
1950 getClient(peer->id)->pending_serialization_version = deployed;
1952 if(deployed == SER_FMT_VER_INVALID)
1954 derr_server<<DTIME<<"Server: Cannot negotiate "
1955 "serialization version with peer "
1956 <<peer_id<<std::endl;
1965 char playername[PLAYERNAME_SIZE];
1966 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1968 playername[i] = data[3+i];
1970 playername[PLAYERNAME_SIZE-1] = 0;
1972 if(playername[0]=='\0')
1974 derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
1975 SendAccessDenied(m_con, peer_id,
1980 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1982 derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
1983 SendAccessDenied(m_con, peer_id,
1984 L"Name contains unallowed characters");
1989 char password[PASSWORD_SIZE];
1990 if(datasize == 2+1+PLAYERNAME_SIZE)
1992 // old version - assume blank password
1997 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1999 password[i] = data[23+i];
2001 password[PASSWORD_SIZE-1] = 0;
2004 std::string checkpwd;
2005 if(m_authmanager.exists(playername))
2007 checkpwd = m_authmanager.getPassword(playername);
2011 checkpwd = g_settings.get("default_password");
2014 if(password != checkpwd && checkpwd != "")
2016 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2017 <<": supplied invalid password for "
2018 <<playername<<std::endl;
2019 SendAccessDenied(m_con, peer_id, L"Invalid password");
2023 // Add player to auth manager
2024 if(m_authmanager.exists(playername) == false)
2026 derr_server<<DTIME<<"Server: adding player "<<playername
2027 <<" to auth manager"<<std::endl;
2028 m_authmanager.add(playername);
2029 m_authmanager.setPassword(playername, checkpwd);
2030 m_authmanager.setPrivs(playername,
2031 stringToPrivs(g_settings.get("default_privs")));
2032 m_authmanager.save();
2036 Player *player = emergePlayer(playername, password, peer_id);
2040 // DEBUG: Test serialization
2041 std::ostringstream test_os;
2042 player->serialize(test_os);
2043 dstream<<"Player serialization test: \""<<test_os.str()
2045 std::istringstream test_is(test_os.str());
2046 player->deSerialize(test_is);
2049 // If failed, cancel
2052 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2053 <<": failed to emerge player"<<std::endl;
2058 // If a client is already connected to the player, cancel
2059 if(player->peer_id != 0)
2061 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2062 <<" tried to connect to "
2063 "an already connected player (peer_id="
2064 <<player->peer_id<<")"<<std::endl;
2067 // Set client of player
2068 player->peer_id = peer_id;
2071 // Check if player doesn't exist
2073 throw con::InvalidIncomingDataException
2074 ("Server::ProcessData(): INIT: Player doesn't exist");
2076 /*// update name if it was supplied
2077 if(datasize >= 20+3)
2080 player->updateName((const char*)&data[3]);
2084 Answer with a TOCLIENT_INIT
2087 SharedBuffer<u8> reply(2+1+6+8);
2088 writeU16(&reply[0], TOCLIENT_INIT);
2089 writeU8(&reply[2], deployed);
2090 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2091 writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2094 m_con.Send(peer_id, 0, reply, true);
2098 Send complete position information
2100 SendMovePlayer(player);
2105 if(command == TOSERVER_INIT2)
2107 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2108 <<peer->id<<std::endl;
2111 getClient(peer->id)->serialization_version
2112 = getClient(peer->id)->pending_serialization_version;
2115 Send some initialization data
2118 // Send player info to all players
2121 // Send inventory to player
2122 UpdateCrafting(peer->id);
2123 SendInventory(peer->id);
2127 Player *player = m_env.getPlayer(peer_id);
2128 SendPlayerHP(player);
2133 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2134 m_env.getTimeOfDay());
2135 m_con.Send(peer->id, 0, data, true);
2138 // Send information about server to player in chat
2139 SendChatMessage(peer_id, getStatusString());
2141 // Send information about joining in chat
2143 std::wstring name = L"unknown";
2144 Player *player = m_env.getPlayer(peer_id);
2146 name = narrow_to_wide(player->getName());
2148 std::wstring message;
2151 message += L" joined game";
2152 BroadcastChatMessage(message);
2158 if(peer_ser_ver == SER_FMT_VER_INVALID)
2160 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2161 " serialization format invalid or not initialized."
2162 " Skipping incoming command="<<command<<std::endl;
2166 Player *player = m_env.getPlayer(peer_id);
2169 derr_server<<"Server::ProcessData(): Cancelling: "
2170 "No player for peer_id="<<peer_id
2174 if(command == TOSERVER_PLAYERPOS)
2176 if(datasize < 2+12+12+4+4)
2180 v3s32 ps = readV3S32(&data[start+2]);
2181 v3s32 ss = readV3S32(&data[start+2+12]);
2182 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2183 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2184 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2185 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2186 pitch = wrapDegrees(pitch);
2187 yaw = wrapDegrees(yaw);
2188 player->setPosition(position);
2189 player->setSpeed(speed);
2190 player->setPitch(pitch);
2191 player->setYaw(yaw);
2193 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2194 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2195 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2197 else if(command == TOSERVER_GOTBLOCKS)
2210 u16 count = data[2];
2211 for(u16 i=0; i<count; i++)
2213 if((s16)datasize < 2+1+(i+1)*6)
2214 throw con::InvalidIncomingDataException
2215 ("GOTBLOCKS length is too short");
2216 v3s16 p = readV3S16(&data[2+1+i*6]);
2217 /*dstream<<"Server: GOTBLOCKS ("
2218 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2219 RemoteClient *client = getClient(peer_id);
2220 client->GotBlock(p);
2223 else if(command == TOSERVER_DELETEDBLOCKS)
2236 u16 count = data[2];
2237 for(u16 i=0; i<count; i++)
2239 if((s16)datasize < 2+1+(i+1)*6)
2240 throw con::InvalidIncomingDataException
2241 ("DELETEDBLOCKS length is too short");
2242 v3s16 p = readV3S16(&data[2+1+i*6]);
2243 /*dstream<<"Server: DELETEDBLOCKS ("
2244 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2245 RemoteClient *client = getClient(peer_id);
2246 client->SetBlockNotSent(p);
2249 else if(command == TOSERVER_CLICK_OBJECT)
2254 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2259 [2] u8 button (0=left, 1=right)
2264 u8 button = readU8(&data[2]);
2266 p.X = readS16(&data[3]);
2267 p.Y = readS16(&data[5]);
2268 p.Z = readS16(&data[7]);
2269 s16 id = readS16(&data[9]);
2270 //u16 item_i = readU16(&data[11]);
2272 MapBlock *block = NULL;
2275 block = m_env.getMap().getBlockNoCreate(p);
2277 catch(InvalidPositionException &e)
2279 derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2283 MapBlockObject *obj = block->getObject(id);
2287 derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2291 //TODO: Check that object is reasonably close
2296 InventoryList *ilist = player->inventory.getList("main");
2297 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2300 // Skip if inventory has no free space
2301 if(ilist->getUsedSlots() == ilist->getSize())
2303 dout_server<<"Player inventory has no free space"<<std::endl;
2308 Create the inventory item
2310 InventoryItem *item = NULL;
2311 // If it is an item-object, take the item from it
2312 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2314 item = ((ItemObject*)obj)->createInventoryItem();
2316 // Else create an item of the object
2319 item = new MapBlockObjectItem
2320 (obj->getInventoryString());
2323 // Add to inventory and send inventory
2324 ilist->addItem(item);
2325 UpdateCrafting(player->peer_id);
2326 SendInventory(player->peer_id);
2329 // Remove from block
2330 block->removeObject(id);
2333 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2338 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2344 [2] u8 button (0=left, 1=right)
2348 u8 button = readU8(&data[2]);
2349 u16 id = readS16(&data[3]);
2350 u16 item_i = readU16(&data[11]);
2352 ServerActiveObject *obj = m_env.getActiveObject(id);
2356 derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2361 //TODO: Check that object is reasonably close
2363 // Left click, pick object up (usually)
2366 InventoryList *ilist = player->inventory.getList("main");
2367 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2370 // Skip if inventory has no free space
2371 if(ilist->getUsedSlots() == ilist->getSize())
2373 dout_server<<"Player inventory has no free space"<<std::endl;
2377 // Skip if object has been removed
2382 Create the inventory item
2384 InventoryItem *item = obj->createPickedUpItem();
2388 // Add to inventory and send inventory
2389 ilist->addItem(item);
2390 UpdateCrafting(player->peer_id);
2391 SendInventory(player->peer_id);
2393 // Remove object from environment
2394 obj->m_removed = true;
2399 Item cannot be picked up. Punch it instead.
2402 ToolItem *titem = NULL;
2403 std::string toolname = "";
2405 InventoryList *mlist = player->inventory.getList("main");
2408 InventoryItem *item = mlist->getItem(item_i);
2409 if(item && (std::string)item->getName() == "ToolItem")
2411 titem = (ToolItem*)item;
2412 toolname = titem->getToolName();
2416 v3f playerpos = player->getPosition();
2417 v3f objpos = obj->getBasePosition();
2418 v3f dir = (objpos - playerpos).normalize();
2420 u16 wear = obj->punch(toolname, dir);
2424 bool weared_out = titem->addWear(wear);
2426 mlist->deleteItem(item_i);
2427 SendInventory(player->peer_id);
2433 else if(command == TOSERVER_GROUND_ACTION)
2441 [3] v3s16 nodepos_undersurface
2442 [9] v3s16 nodepos_abovesurface
2447 2: stop digging (all parameters ignored)
2448 3: digging completed
2450 u8 action = readU8(&data[2]);
2452 p_under.X = readS16(&data[3]);
2453 p_under.Y = readS16(&data[5]);
2454 p_under.Z = readS16(&data[7]);
2456 p_over.X = readS16(&data[9]);
2457 p_over.Y = readS16(&data[11]);
2458 p_over.Z = readS16(&data[13]);
2459 u16 item_i = readU16(&data[15]);
2461 //TODO: Check that target is reasonably close
2469 NOTE: This can be used in the future to check if
2470 somebody is cheating, by checking the timing.
2477 else if(action == 2)
2480 RemoteClient *client = getClient(peer->id);
2481 JMutexAutoLock digmutex(client->m_dig_mutex);
2482 client->m_dig_tool_item = -1;
2487 3: Digging completed
2489 else if(action == 3)
2491 // Mandatory parameter; actually used for nothing
2492 core::map<v3s16, MapBlock*> modified_blocks;
2494 u8 material = CONTENT_IGNORE;
2495 u8 mineral = MINERAL_NONE;
2497 bool cannot_remove_node = false;
2501 MapNode n = m_env.getMap().getNode(p_under);
2503 mineral = n.getMineral();
2504 // Get material at position
2506 // If not yet cancelled
2507 if(cannot_remove_node == false)
2509 // If it's not diggable, do nothing
2510 if(content_diggable(material) == false)
2512 derr_server<<"Server: Not finishing digging: "
2513 <<"Node not diggable"
2515 cannot_remove_node = true;
2518 // If not yet cancelled
2519 if(cannot_remove_node == false)
2521 // Get node metadata
2522 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2523 if(meta && meta->nodeRemovalDisabled() == true)
2525 derr_server<<"Server: Not finishing digging: "
2526 <<"Node metadata disables removal"
2528 cannot_remove_node = true;
2532 catch(InvalidPositionException &e)
2534 derr_server<<"Server: Not finishing digging: Node not found."
2535 <<" Adding block to emerge queue."
2537 m_emerge_queue.addBlock(peer_id,
2538 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2539 cannot_remove_node = true;
2542 // Make sure the player is allowed to do it
2543 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2545 dstream<<"Player "<<player->getName()<<" cannot remove node"
2546 <<" because privileges are "<<getPlayerPrivs(player)
2548 cannot_remove_node = true;
2552 If node can't be removed, set block to be re-sent to
2555 if(cannot_remove_node)
2557 derr_server<<"Server: Not finishing digging."<<std::endl;
2559 // Client probably has wrong data.
2560 // Set block not sent, so that client will get
2562 dstream<<"Client "<<peer_id<<" tried to dig "
2563 <<"node; but node cannot be removed."
2564 <<" setting MapBlock not sent."<<std::endl;
2565 RemoteClient *client = getClient(peer_id);
2566 v3s16 blockpos = getNodeBlockPos(p_under);
2567 client->SetBlockNotSent(blockpos);
2573 Send the removal to all close-by players.
2574 - If other player is close, send REMOVENODE
2575 - Otherwise set blocks not sent
2577 core::list<u16> far_players;
2578 sendRemoveNode(p_under, peer_id, &far_players, 30);
2581 Update and send inventory
2584 if(g_settings.getBool("creative_mode") == false)
2589 InventoryList *mlist = player->inventory.getList("main");
2592 InventoryItem *item = mlist->getItem(item_i);
2593 if(item && (std::string)item->getName() == "ToolItem")
2595 ToolItem *titem = (ToolItem*)item;
2596 std::string toolname = titem->getToolName();
2598 // Get digging properties for material and tool
2599 DiggingProperties prop =
2600 getDiggingProperties(material, toolname);
2602 if(prop.diggable == false)
2604 derr_server<<"Server: WARNING: Player digged"
2605 <<" with impossible material + tool"
2606 <<" combination"<<std::endl;
2609 bool weared_out = titem->addWear(prop.wear);
2613 mlist->deleteItem(item_i);
2619 Add dug item to inventory
2622 InventoryItem *item = NULL;
2624 if(mineral != MINERAL_NONE)
2625 item = getDiggedMineralItem(mineral);
2630 std::string &dug_s = content_features(material).dug_item;
2633 std::istringstream is(dug_s, std::ios::binary);
2634 item = InventoryItem::deSerialize(is);
2640 // Add a item to inventory
2641 player->inventory.addItem("main", item);
2644 UpdateCrafting(player->peer_id);
2645 SendInventory(player->peer_id);
2651 (this takes some time so it is done after the quick stuff)
2654 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2656 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2659 Set blocks not sent to far players
2661 for(core::list<u16>::Iterator
2662 i = far_players.begin();
2663 i != far_players.end(); i++)
2666 RemoteClient *client = getClient(peer_id);
2669 client->SetBlocksNotSent(modified_blocks);
2676 else if(action == 1)
2679 InventoryList *ilist = player->inventory.getList("main");
2684 InventoryItem *item = ilist->getItem(item_i);
2686 // If there is no item, it is not possible to add it anywhere
2691 Handle material items
2693 if(std::string("MaterialItem") == item->getName())
2696 // Don't add a node if this is not a free space
2697 MapNode n2 = m_env.getMap().getNode(p_over);
2698 bool no_enough_privs =
2699 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2701 dstream<<"Player "<<player->getName()<<" cannot add node"
2702 <<" because privileges are "<<getPlayerPrivs(player)
2705 if(content_buildable_to(n2.d) == false
2708 // Client probably has wrong data.
2709 // Set block not sent, so that client will get
2711 dstream<<"Client "<<peer_id<<" tried to place"
2712 <<" node in invalid position; setting"
2713 <<" MapBlock not sent."<<std::endl;
2714 RemoteClient *client = getClient(peer_id);
2715 v3s16 blockpos = getNodeBlockPos(p_over);
2716 client->SetBlockNotSent(blockpos);
2720 catch(InvalidPositionException &e)
2722 derr_server<<"Server: Ignoring ADDNODE: Node not found"
2723 <<" Adding block to emerge queue."
2725 m_emerge_queue.addBlock(peer_id,
2726 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2730 // Reset build time counter
2731 getClient(peer->id)->m_time_from_building = 0.0;
2734 MaterialItem *mitem = (MaterialItem*)item;
2736 n.d = mitem->getMaterial();
2737 if(content_features(n.d).wall_mounted)
2738 n.dir = packDir(p_under - p_over);
2741 Send to all close-by players
2743 core::list<u16> far_players;
2744 sendAddNode(p_over, n, 0, &far_players, 30);
2749 InventoryList *ilist = player->inventory.getList("main");
2750 if(g_settings.getBool("creative_mode") == false && ilist)
2752 // Remove from inventory and send inventory
2753 if(mitem->getCount() == 1)
2754 ilist->deleteItem(item_i);
2758 UpdateCrafting(peer_id);
2759 SendInventory(peer_id);
2765 This takes some time so it is done after the quick stuff
2767 core::map<v3s16, MapBlock*> modified_blocks;
2769 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2771 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2774 Set blocks not sent to far players
2776 for(core::list<u16>::Iterator
2777 i = far_players.begin();
2778 i != far_players.end(); i++)
2781 RemoteClient *client = getClient(peer_id);
2784 client->SetBlocksNotSent(modified_blocks);
2788 Calculate special events
2791 /*if(n.d == CONTENT_MESE)
2794 for(s16 z=-1; z<=1; z++)
2795 for(s16 y=-1; y<=1; y++)
2796 for(s16 x=-1; x<=1; x++)
2803 Place other item (not a block)
2807 v3s16 blockpos = getNodeBlockPos(p_over);
2810 Check that the block is loaded so that the item
2811 can properly be added to the static list too
2813 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2816 derr_server<<"Error while placing object: "
2817 "block not found"<<std::endl;
2821 dout_server<<"Placing a miscellaneous item on map"
2824 // Calculate a position for it
2825 v3f pos = intToFloat(p_over, BS);
2827 pos.Y -= BS*0.25; // let it drop a bit
2829 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2830 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2835 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2839 derr_server<<"WARNING: item resulted in NULL object, "
2840 <<"not placing onto map"
2845 // Add the object to the environment
2846 m_env.addActiveObject(obj);
2848 dout_server<<"Placed object"<<std::endl;
2850 if(g_settings.getBool("creative_mode") == false)
2852 // Delete the right amount of items from the slot
2853 u16 dropcount = item->getDropCount();
2855 // Delete item if all gone
2856 if(item->getCount() <= dropcount)
2858 if(item->getCount() < dropcount)
2859 dstream<<"WARNING: Server: dropped more items"
2860 <<" than the slot contains"<<std::endl;
2862 InventoryList *ilist = player->inventory.getList("main");
2864 // Remove from inventory and send inventory
2865 ilist->deleteItem(item_i);
2867 // Else decrement it
2869 item->remove(dropcount);
2872 UpdateCrafting(peer_id);
2873 SendInventory(peer_id);
2881 Catch invalid actions
2885 derr_server<<"WARNING: Server: Invalid action "
2886 <<action<<std::endl;
2890 else if(command == TOSERVER_RELEASE)
2899 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2902 else if(command == TOSERVER_SIGNTEXT)
2904 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2913 std::string datastring((char*)&data[2], datasize-2);
2914 std::istringstream is(datastring, std::ios_base::binary);
2917 is.read((char*)buf, 6);
2918 v3s16 blockpos = readV3S16(buf);
2919 is.read((char*)buf, 2);
2920 s16 id = readS16(buf);
2921 is.read((char*)buf, 2);
2922 u16 textlen = readU16(buf);
2924 for(u16 i=0; i<textlen; i++)
2926 is.read((char*)buf, 1);
2927 text += (char)buf[0];
2930 MapBlock *block = NULL;
2933 block = m_env.getMap().getBlockNoCreate(blockpos);
2935 catch(InvalidPositionException &e)
2937 derr_server<<"Error while setting sign text: "
2938 "block not found"<<std::endl;
2942 MapBlockObject *obj = block->getObject(id);
2945 derr_server<<"Error while setting sign text: "
2946 "object not found"<<std::endl;
2950 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
2952 derr_server<<"Error while setting sign text: "
2953 "object is not a sign"<<std::endl;
2957 ((SignObject*)obj)->setText(text);
2959 obj->getBlock()->setChangedFlag();
2961 else if(command == TOSERVER_SIGNNODETEXT)
2963 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2971 std::string datastring((char*)&data[2], datasize-2);
2972 std::istringstream is(datastring, std::ios_base::binary);
2975 is.read((char*)buf, 6);
2976 v3s16 p = readV3S16(buf);
2977 is.read((char*)buf, 2);
2978 u16 textlen = readU16(buf);
2980 for(u16 i=0; i<textlen; i++)
2982 is.read((char*)buf, 1);
2983 text += (char)buf[0];
2986 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2989 if(meta->typeId() != CONTENT_SIGN_WALL)
2991 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2992 signmeta->setText(text);
2994 v3s16 blockpos = getNodeBlockPos(p);
2995 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2998 block->setChangedFlag();
3001 for(core::map<u16, RemoteClient*>::Iterator
3002 i = m_clients.getIterator();
3003 i.atEnd()==false; i++)
3005 RemoteClient *client = i.getNode()->getValue();
3006 client->SetBlockNotSent(blockpos);
3009 else if(command == TOSERVER_INVENTORY_ACTION)
3011 /*// Ignore inventory changes if in creative mode
3012 if(g_settings.getBool("creative_mode") == true)
3014 dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3018 // Strip command and create a stream
3019 std::string datastring((char*)&data[2], datasize-2);
3020 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3021 std::istringstream is(datastring, std::ios_base::binary);
3023 InventoryAction *a = InventoryAction::deSerialize(is);
3028 c.current_player = player;
3031 Handle craftresult specially if not in creative mode
3033 bool disable_action = false;
3034 if(a->getType() == IACTION_MOVE
3035 && g_settings.getBool("creative_mode") == false)
3037 IMoveAction *ma = (IMoveAction*)a;
3038 if(ma->to_inv == "current_player" &&
3039 ma->from_inv == "current_player")
3041 InventoryList *rlist = player->inventory.getList("craftresult");
3043 InventoryList *clist = player->inventory.getList("craft");
3045 InventoryList *mlist = player->inventory.getList("main");
3048 Craftresult is no longer preview if something
3051 if(ma->to_list == "craftresult"
3052 && ma->from_list != "craftresult")
3054 // If it currently is a preview, remove
3056 if(player->craftresult_is_preview)
3058 rlist->deleteItem(0);
3060 player->craftresult_is_preview = false;
3063 Crafting takes place if this condition is true.
3065 if(player->craftresult_is_preview &&
3066 ma->from_list == "craftresult")
3068 player->craftresult_is_preview = false;
3069 clist->decrementMaterials(1);
3072 If the craftresult is placed on itself, move it to
3073 main inventory instead of doing the action
3075 if(ma->to_list == "craftresult"
3076 && ma->from_list == "craftresult")
3078 disable_action = true;
3080 InventoryItem *item1 = rlist->changeItem(0, NULL);
3081 mlist->addItem(item1);
3086 if(disable_action == false)
3088 // Feed action to player inventory
3096 UpdateCrafting(player->peer_id);
3097 SendInventory(player->peer_id);
3102 dstream<<"TOSERVER_INVENTORY_ACTION: "
3103 <<"InventoryAction::deSerialize() returned NULL"
3107 else if(command == TOSERVER_CHAT_MESSAGE)
3115 std::string datastring((char*)&data[2], datasize-2);
3116 std::istringstream is(datastring, std::ios_base::binary);
3119 is.read((char*)buf, 2);
3120 u16 len = readU16(buf);
3122 std::wstring message;
3123 for(u16 i=0; i<len; i++)
3125 is.read((char*)buf, 2);
3126 message += (wchar_t)readU16(buf);
3129 // Get player name of this client
3130 std::wstring name = narrow_to_wide(player->getName());
3132 // Line to send to players
3134 // Whether to send to the player that sent the line
3135 bool send_to_sender = false;
3136 // Whether to send to other players
3137 bool send_to_others = false;
3139 // Local player gets all privileges regardless of
3140 // what's set on their account.
3141 u64 privs = getPlayerPrivs(player);
3144 std::wstring commandprefix = L"/#";
3145 if(message.substr(0, commandprefix.size()) == commandprefix)
3147 line += L"Server: ";
3149 message = message.substr(commandprefix.size());
3151 ServerCommandContext *ctx = new ServerCommandContext(
3152 str_split(message, L' '),
3158 line += processServerCommand(ctx);
3159 send_to_sender = ctx->flags & 1;
3160 send_to_others = ctx->flags & 2;
3166 if(privs & PRIV_SHOUT)
3172 send_to_others = true;
3176 line += L"Server: You are not allowed to shout";
3177 send_to_sender = true;
3183 dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3186 Send the message to clients
3188 for(core::map<u16, RemoteClient*>::Iterator
3189 i = m_clients.getIterator();
3190 i.atEnd() == false; i++)
3192 // Get client and check that it is valid
3193 RemoteClient *client = i.getNode()->getValue();
3194 assert(client->peer_id == i.getNode()->getKey());
3195 if(client->serialization_version == SER_FMT_VER_INVALID)
3199 bool sender_selected = (peer_id == client->peer_id);
3200 if(sender_selected == true && send_to_sender == false)
3202 if(sender_selected == false && send_to_others == false)
3205 SendChatMessage(client->peer_id, line);
3209 else if(command == TOSERVER_DAMAGE)
3211 if(g_settings.getBool("enable_damage"))
3213 std::string datastring((char*)&data[2], datasize-2);
3214 std::istringstream is(datastring, std::ios_base::binary);
3215 u8 damage = readU8(is);
3216 if(player->hp > damage)
3218 player->hp -= damage;
3224 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3227 v3f pos = findSpawnPos(m_env.getServerMap());
3228 player->setPosition(pos);
3230 SendMovePlayer(player);
3231 SendPlayerHP(player);
3233 //TODO: Throw items around
3237 SendPlayerHP(player);
3239 else if(command == TOSERVER_PASSWORD)
3242 [0] u16 TOSERVER_PASSWORD
3243 [2] u8[28] old password
3244 [30] u8[28] new password
3247 if(datasize != 2+PASSWORD_SIZE*2)
3249 /*char password[PASSWORD_SIZE];
3250 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3251 password[i] = data[2+i];
3252 password[PASSWORD_SIZE-1] = 0;*/
3254 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3262 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3264 char c = data[2+PASSWORD_SIZE+i];
3270 std::string playername = player->getName();
3272 if(m_authmanager.exists(playername) == false)
3274 dstream<<"Server: playername not found in authmanager"<<std::endl;
3275 // Wrong old password supplied!!
3276 SendChatMessage(peer_id, L"playername not found in authmanager");
3280 std::string checkpwd = m_authmanager.getPassword(playername);
3282 if(oldpwd != checkpwd)
3284 dstream<<"Server: invalid old password"<<std::endl;
3285 // Wrong old password supplied!!
3286 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3290 m_authmanager.setPassword(playername, newpwd);
3292 dstream<<"Server: password change successful for "<<playername
3294 SendChatMessage(peer_id, L"Password change successful");
3298 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3299 "unknown command "<<command<<std::endl;
3303 catch(SendFailedException &e)
3305 derr_server<<"Server::ProcessData(): SendFailedException: "
3311 void Server::onMapEditEvent(MapEditEvent *event)
3313 dstream<<"Server::onMapEditEvent()"<<std::endl;
3314 if(m_ignore_map_edit_events)
3316 MapEditEvent *e = event->clone();
3317 m_unsent_map_edit_queue.push_back(e);
3320 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3322 if(id == "current_player")
3324 assert(c->current_player);
3325 return &(c->current_player->inventory);
3329 std::string id0 = fn.next(":");
3331 if(id0 == "nodemeta")
3334 p.X = stoi(fn.next(","));
3335 p.Y = stoi(fn.next(","));
3336 p.Z = stoi(fn.next(","));
3337 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3339 return meta->getInventory();
3340 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3341 <<"no metadata found"<<std::endl;
3345 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3348 void Server::inventoryModified(InventoryContext *c, std::string id)
3350 if(id == "current_player")
3352 assert(c->current_player);
3354 UpdateCrafting(c->current_player->peer_id);
3355 SendInventory(c->current_player->peer_id);
3360 std::string id0 = fn.next(":");
3362 if(id0 == "nodemeta")
3365 p.X = stoi(fn.next(","));
3366 p.Y = stoi(fn.next(","));
3367 p.Z = stoi(fn.next(","));
3368 v3s16 blockpos = getNodeBlockPos(p);
3370 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3372 meta->inventoryModified();
3374 for(core::map<u16, RemoteClient*>::Iterator
3375 i = m_clients.getIterator();
3376 i.atEnd()==false; i++)
3378 RemoteClient *client = i.getNode()->getValue();
3379 client->SetBlockNotSent(blockpos);
3385 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3388 core::list<PlayerInfo> Server::getPlayerInfo()
3390 DSTACK(__FUNCTION_NAME);
3391 JMutexAutoLock envlock(m_env_mutex);
3392 JMutexAutoLock conlock(m_con_mutex);
3394 core::list<PlayerInfo> list;
3396 core::list<Player*> players = m_env.getPlayers();
3398 core::list<Player*>::Iterator i;
3399 for(i = players.begin();
3400 i != players.end(); i++)
3404 Player *player = *i;
3407 con::Peer *peer = m_con.GetPeer(player->peer_id);
3408 // Copy info from peer to info struct
3410 info.address = peer->address;
3411 info.avg_rtt = peer->avg_rtt;
3413 catch(con::PeerNotFoundException &e)
3415 // Set dummy peer info
3417 info.address = Address(0,0,0,0,0);
3421 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3422 info.position = player->getPosition();
3424 list.push_back(info);
3431 void Server::peerAdded(con::Peer *peer)
3433 DSTACK(__FUNCTION_NAME);
3434 dout_server<<"Server::peerAdded(): peer->id="
3435 <<peer->id<<std::endl;
3438 c.type = PEER_ADDED;
3439 c.peer_id = peer->id;
3441 m_peer_change_queue.push_back(c);
3444 void Server::deletingPeer(con::Peer *peer, bool timeout)
3446 DSTACK(__FUNCTION_NAME);
3447 dout_server<<"Server::deletingPeer(): peer->id="
3448 <<peer->id<<", timeout="<<timeout<<std::endl;
3451 c.type = PEER_REMOVED;
3452 c.peer_id = peer->id;
3453 c.timeout = timeout;
3454 m_peer_change_queue.push_back(c);
3461 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3463 DSTACK(__FUNCTION_NAME);
3464 std::ostringstream os(std::ios_base::binary);
3466 writeU16(os, TOCLIENT_HP);
3470 std::string s = os.str();
3471 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3473 con.Send(peer_id, 0, data, true);
3476 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3477 const std::wstring &reason)
3479 DSTACK(__FUNCTION_NAME);
3480 std::ostringstream os(std::ios_base::binary);
3482 writeU16(os, TOCLIENT_ACCESS_DENIED);
3483 os<<serializeWideString(reason);
3486 std::string s = os.str();
3487 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3489 con.Send(peer_id, 0, data, true);
3493 Non-static send methods
3496 void Server::SendObjectData(float dtime)
3498 DSTACK(__FUNCTION_NAME);
3500 core::map<v3s16, bool> stepped_blocks;
3502 for(core::map<u16, RemoteClient*>::Iterator
3503 i = m_clients.getIterator();
3504 i.atEnd() == false; i++)
3506 u16 peer_id = i.getNode()->getKey();
3507 RemoteClient *client = i.getNode()->getValue();
3508 assert(client->peer_id == peer_id);
3510 if(client->serialization_version == SER_FMT_VER_INVALID)
3513 client->SendObjectData(this, dtime, stepped_blocks);
3517 void Server::SendPlayerInfos()
3519 DSTACK(__FUNCTION_NAME);
3521 //JMutexAutoLock envlock(m_env_mutex);
3523 // Get connected players
3524 core::list<Player*> players = m_env.getPlayers(true);
3526 u32 player_count = players.getSize();
3527 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3529 SharedBuffer<u8> data(datasize);
3530 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3533 core::list<Player*>::Iterator i;
3534 for(i = players.begin();
3535 i != players.end(); i++)
3537 Player *player = *i;
3539 /*dstream<<"Server sending player info for player with "
3540 "peer_id="<<player->peer_id<<std::endl;*/
3542 writeU16(&data[start], player->peer_id);
3543 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3544 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3545 start += 2+PLAYERNAME_SIZE;
3548 //JMutexAutoLock conlock(m_con_mutex);
3551 m_con.SendToAll(0, data, true);
3554 void Server::SendInventory(u16 peer_id)
3556 DSTACK(__FUNCTION_NAME);
3558 Player* player = m_env.getPlayer(peer_id);
3565 std::ostringstream os;
3566 //os.imbue(std::locale("C"));
3568 player->inventory.serialize(os);
3570 std::string s = os.str();
3572 SharedBuffer<u8> data(s.size()+2);
3573 writeU16(&data[0], TOCLIENT_INVENTORY);
3574 memcpy(&data[2], s.c_str(), s.size());
3577 m_con.Send(peer_id, 0, data, true);
3580 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3582 DSTACK(__FUNCTION_NAME);
3584 std::ostringstream os(std::ios_base::binary);
3588 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3589 os.write((char*)buf, 2);
3592 writeU16(buf, message.size());
3593 os.write((char*)buf, 2);
3596 for(u32 i=0; i<message.size(); i++)
3600 os.write((char*)buf, 2);
3604 std::string s = os.str();
3605 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3607 m_con.Send(peer_id, 0, data, true);
3610 void Server::BroadcastChatMessage(const std::wstring &message)
3612 for(core::map<u16, RemoteClient*>::Iterator
3613 i = m_clients.getIterator();
3614 i.atEnd() == false; i++)
3616 // Get client and check that it is valid
3617 RemoteClient *client = i.getNode()->getValue();
3618 assert(client->peer_id == i.getNode()->getKey());
3619 if(client->serialization_version == SER_FMT_VER_INVALID)
3622 SendChatMessage(client->peer_id, message);
3626 void Server::SendPlayerHP(Player *player)
3628 SendHP(m_con, player->peer_id, player->hp);
3631 void Server::SendMovePlayer(Player *player)
3633 DSTACK(__FUNCTION_NAME);
3634 std::ostringstream os(std::ios_base::binary);
3636 writeU16(os, TOCLIENT_MOVE_PLAYER);
3637 writeV3F1000(os, player->getPosition());
3638 writeF1000(os, player->getPitch());
3639 writeF1000(os, player->getYaw());
3642 v3f pos = player->getPosition();
3643 f32 pitch = player->getPitch();
3644 f32 yaw = player->getYaw();
3645 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3646 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3653 std::string s = os.str();
3654 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3656 m_con.Send(player->peer_id, 0, data, true);
3659 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3660 core::list<u16> *far_players, float far_d_nodes)
3662 float maxd = far_d_nodes*BS;
3663 v3f p_f = intToFloat(p, BS);
3667 SharedBuffer<u8> reply(replysize);
3668 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3669 writeS16(&reply[2], p.X);
3670 writeS16(&reply[4], p.Y);
3671 writeS16(&reply[6], p.Z);
3673 for(core::map<u16, RemoteClient*>::Iterator
3674 i = m_clients.getIterator();
3675 i.atEnd() == false; i++)
3677 // Get client and check that it is valid
3678 RemoteClient *client = i.getNode()->getValue();
3679 assert(client->peer_id == i.getNode()->getKey());
3680 if(client->serialization_version == SER_FMT_VER_INVALID)
3683 // Don't send if it's the same one
3684 if(client->peer_id == ignore_id)
3690 Player *player = m_env.getPlayer(client->peer_id);
3693 // If player is far away, only set modified blocks not sent
3694 v3f player_pos = player->getPosition();
3695 if(player_pos.getDistanceFrom(p_f) > maxd)
3697 far_players->push_back(client->peer_id);
3704 m_con.Send(client->peer_id, 0, reply, true);
3708 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3709 core::list<u16> *far_players, float far_d_nodes)
3711 float maxd = far_d_nodes*BS;
3712 v3f p_f = intToFloat(p, BS);
3714 for(core::map<u16, RemoteClient*>::Iterator
3715 i = m_clients.getIterator();
3716 i.atEnd() == false; i++)
3718 // Get client and check that it is valid
3719 RemoteClient *client = i.getNode()->getValue();
3720 assert(client->peer_id == i.getNode()->getKey());
3721 if(client->serialization_version == SER_FMT_VER_INVALID)
3724 // Don't send if it's the same one
3725 if(client->peer_id == ignore_id)
3731 Player *player = m_env.getPlayer(client->peer_id);
3734 // If player is far away, only set modified blocks not sent
3735 v3f player_pos = player->getPosition();
3736 if(player_pos.getDistanceFrom(p_f) > maxd)
3738 far_players->push_back(client->peer_id);
3745 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3746 SharedBuffer<u8> reply(replysize);
3747 writeU16(&reply[0], TOCLIENT_ADDNODE);
3748 writeS16(&reply[2], p.X);
3749 writeS16(&reply[4], p.Y);
3750 writeS16(&reply[6], p.Z);
3751 n.serialize(&reply[8], client->serialization_version);
3754 m_con.Send(client->peer_id, 0, reply, true);
3758 void Server::setBlockNotSent(v3s16 p)
3760 for(core::map<u16, RemoteClient*>::Iterator
3761 i = m_clients.getIterator();
3762 i.atEnd()==false; i++)
3764 RemoteClient *client = i.getNode()->getValue();
3765 client->SetBlockNotSent(p);
3769 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3771 DSTACK(__FUNCTION_NAME);
3773 v3s16 p = block->getPos();
3777 bool completely_air = true;
3778 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3779 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3780 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3782 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3784 completely_air = false;
3785 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3790 dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3792 dstream<<"[completely air] ";
3797 Create a packet with the block in the right format
3800 std::ostringstream os(std::ios_base::binary);
3801 block->serialize(os, ver);
3802 std::string s = os.str();
3803 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3805 u32 replysize = 8 + blockdata.getSize();
3806 SharedBuffer<u8> reply(replysize);
3807 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3808 writeS16(&reply[2], p.X);
3809 writeS16(&reply[4], p.Y);
3810 writeS16(&reply[6], p.Z);
3811 memcpy(&reply[8], *blockdata, blockdata.getSize());
3813 /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3814 <<": \tpacket size: "<<replysize<<std::endl;*/
3819 m_con.Send(peer_id, 1, reply, true);
3822 void Server::SendBlocks(float dtime)
3824 DSTACK(__FUNCTION_NAME);
3826 JMutexAutoLock envlock(m_env_mutex);
3827 JMutexAutoLock conlock(m_con_mutex);
3829 //TimeTaker timer("Server::SendBlocks");
3831 core::array<PrioritySortedBlockTransfer> queue;
3833 s32 total_sending = 0;
3836 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
3838 for(core::map<u16, RemoteClient*>::Iterator
3839 i = m_clients.getIterator();
3840 i.atEnd() == false; i++)
3842 RemoteClient *client = i.getNode()->getValue();
3843 assert(client->peer_id == i.getNode()->getKey());
3845 total_sending += client->SendingCount();
3847 if(client->serialization_version == SER_FMT_VER_INVALID)
3850 client->GetNextBlocks(this, dtime, queue);
3855 // Lowest priority number comes first.
3856 // Lowest is most important.
3859 for(u32 i=0; i<queue.size(); i++)
3861 //TODO: Calculate limit dynamically
3862 if(total_sending >= g_settings.getS32
3863 ("max_simultaneous_block_sends_server_total"))
3866 PrioritySortedBlockTransfer q = queue[i];
3868 MapBlock *block = NULL;
3871 block = m_env.getMap().getBlockNoCreate(q.pos);
3873 catch(InvalidPositionException &e)
3878 RemoteClient *client = getClient(q.peer_id);
3880 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3882 client->SentBlock(q.pos);
3892 void Server::UpdateCrafting(u16 peer_id)
3894 DSTACK(__FUNCTION_NAME);
3896 Player* player = m_env.getPlayer(peer_id);
3900 Calculate crafting stuff
3902 if(g_settings.getBool("creative_mode") == false)
3904 InventoryList *clist = player->inventory.getList("craft");
3905 InventoryList *rlist = player->inventory.getList("craftresult");
3907 if(rlist->getUsedSlots() == 0)
3908 player->craftresult_is_preview = true;
3910 if(rlist && player->craftresult_is_preview)
3912 rlist->clearItems();
3914 if(clist && rlist && player->craftresult_is_preview)
3916 InventoryItem *items[9];
3917 for(u16 i=0; i<9; i++)
3919 items[i] = clist->getItem(i);
3922 // Get result of crafting grid
3923 InventoryItem *result = craft_get_result(items);
3925 rlist->addItem(result);
3928 } // if creative_mode == false
3931 RemoteClient* Server::getClient(u16 peer_id)
3933 DSTACK(__FUNCTION_NAME);
3934 //JMutexAutoLock lock(m_con_mutex);
3935 core::map<u16, RemoteClient*>::Node *n;
3936 n = m_clients.find(peer_id);
3937 // A client should exist for all peers
3939 return n->getValue();
3942 std::wstring Server::getStatusString()
3944 std::wostringstream os(std::ios_base::binary);
3947 os<<L"version="<<narrow_to_wide(VERSION_STRING);
3949 os<<L", uptime="<<m_uptime.get();
3950 // Information about clients
3952 for(core::map<u16, RemoteClient*>::Iterator
3953 i = m_clients.getIterator();
3954 i.atEnd() == false; i++)
3956 // Get client and check that it is valid
3957 RemoteClient *client = i.getNode()->getValue();
3958 assert(client->peer_id == i.getNode()->getKey());
3959 if(client->serialization_version == SER_FMT_VER_INVALID)
3962 Player *player = m_env.getPlayer(client->peer_id);
3963 // Get name of player
3964 std::wstring name = L"unknown";
3966 name = narrow_to_wide(player->getName());
3967 // Add name to information string
3971 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
3972 os<<" WARNING: Map saving is disabled."<<std::endl;
3976 v3f findSpawnPos(ServerMap &map)
3978 //return v3f(50,50,50)*BS;
3981 s16 groundheight = 0;
3984 nodepos = v2s16(0,0);
3989 // Try to find a good place a few times
3990 for(s32 i=0; i<1000; i++)
3993 // We're going to try to throw the player to this position
3994 nodepos = v2s16(-range + (myrand()%(range*2)),
3995 -range + (myrand()%(range*2)));
3996 v2s16 sectorpos = getNodeSectorPos(nodepos);
3997 // Get sector (NOTE: Don't get because it's slow)
3998 //m_env.getMap().emergeSector(sectorpos);
3999 // Get ground height at point (fallbacks to heightmap function)
4000 groundheight = map.findGroundLevel(nodepos);
4001 // Don't go underwater
4002 if(groundheight < WATER_LEVEL)
4004 //dstream<<"-> Underwater"<<std::endl;
4007 // Don't go to high places
4008 if(groundheight > WATER_LEVEL + 4)
4010 //dstream<<"-> Underwater"<<std::endl;
4014 // Found a good place
4015 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4020 // If no suitable place was not found, go above water at least.
4021 if(groundheight < WATER_LEVEL)
4022 groundheight = WATER_LEVEL;
4024 return intToFloat(v3s16(
4031 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4034 Try to get an existing player
4036 Player *player = m_env.getPlayer(name);
4039 // If player is already connected, cancel
4040 if(player->peer_id != 0)
4042 dstream<<"emergePlayer(): Player already connected"<<std::endl;
4047 player->peer_id = peer_id;
4049 // Reset inventory to creative if in creative mode
4050 if(g_settings.getBool("creative_mode"))
4052 craft_set_creative_inventory(player);
4059 If player with the wanted peer_id already exists, cancel.
4061 if(m_env.getPlayer(peer_id) != NULL)
4063 dstream<<"emergePlayer(): Player with wrong name but same"
4064 " peer_id already exists"<<std::endl;
4072 player = new ServerRemotePlayer();
4073 //player->peer_id = c.peer_id;
4074 //player->peer_id = PEER_ID_INEXISTENT;
4075 player->peer_id = peer_id;
4076 player->updateName(name);
4077 m_authmanager.add(name);
4078 m_authmanager.setPassword(name, password);
4079 m_authmanager.setPrivs(name,
4080 stringToPrivs(g_settings.get("default_privs")));
4086 dstream<<"Server: Finding spawn place for player \""
4087 <<player->getName()<<"\""<<std::endl;
4089 v3f pos = findSpawnPos(m_env.getServerMap());
4091 player->setPosition(pos);
4094 Add player to environment
4097 m_env.addPlayer(player);
4100 Add stuff to inventory
4103 if(g_settings.getBool("creative_mode"))
4105 craft_set_creative_inventory(player);
4107 else if(g_settings.getBool("give_initial_stuff"))
4109 craft_give_initial_stuff(player);
4114 } // create new player
4117 void Server::handlePeerChange(PeerChange &c)
4119 JMutexAutoLock envlock(m_env_mutex);
4120 JMutexAutoLock conlock(m_con_mutex);
4122 if(c.type == PEER_ADDED)
4129 core::map<u16, RemoteClient*>::Node *n;
4130 n = m_clients.find(c.peer_id);
4131 // The client shouldn't already exist
4135 RemoteClient *client = new RemoteClient();
4136 client->peer_id = c.peer_id;
4137 m_clients.insert(client->peer_id, client);
4140 else if(c.type == PEER_REMOVED)
4147 core::map<u16, RemoteClient*>::Node *n;
4148 n = m_clients.find(c.peer_id);
4149 // The client should exist
4153 Mark objects to be not known by the client
4155 RemoteClient *client = n->getValue();
4157 for(core::map<u16, bool>::Iterator
4158 i = client->m_known_objects.getIterator();
4159 i.atEnd()==false; i++)
4162 u16 id = i.getNode()->getKey();
4163 ServerActiveObject* obj = m_env.getActiveObject(id);
4165 if(obj && obj->m_known_by_count > 0)
4166 obj->m_known_by_count--;
4169 // Collect information about leaving in chat
4170 std::wstring message;
4172 std::wstring name = L"unknown";
4173 Player *player = m_env.getPlayer(c.peer_id);
4175 name = narrow_to_wide(player->getName());
4179 message += L" left game";
4181 message += L" (timed out)";
4186 m_env.removePlayer(c.peer_id);
4189 // Set player client disconnected
4191 Player *player = m_env.getPlayer(c.peer_id);
4193 player->peer_id = 0;
4197 delete m_clients[c.peer_id];
4198 m_clients.remove(c.peer_id);
4200 // Send player info to all remaining clients
4203 // Send leave chat message to all remaining clients
4204 BroadcastChatMessage(message);
4213 void Server::handlePeerChanges()
4215 while(m_peer_change_queue.size() > 0)
4217 PeerChange c = m_peer_change_queue.pop_front();
4219 dout_server<<"Server: Handling peer change: "
4220 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4223 handlePeerChange(c);
4227 u64 Server::getPlayerPrivs(Player *player)
4231 std::string playername = player->getName();
4232 // Local player gets all privileges regardless of
4233 // what's set on their account.
4234 if(g_settings.get("name") == playername)
4240 return getPlayerAuthPrivs(playername);
4244 void dedicated_server_loop(Server &server, bool &kill)
4246 DSTACK(__FUNCTION_NAME);
4248 dstream<<DTIME<<std::endl;
4249 dstream<<"========================"<<std::endl;
4250 dstream<<"Running dedicated server"<<std::endl;
4251 dstream<<"========================"<<std::endl;
4254 IntervalLimiter m_profiler_interval;
4258 // This is kind of a hack but can be done like this
4259 // because server.step() is very light
4261 ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4266 if(server.getShutdownRequested() || kill)
4268 dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4275 float profiler_print_interval =
4276 g_settings.getFloat("profiler_print_interval");
4277 if(profiler_print_interval != 0)
4279 if(m_profiler_interval.step(0.030, profiler_print_interval))
4281 dstream<<"Profiler:"<<std::endl;
4282 g_profiler.print(dstream);
4290 static int counter = 0;
4296 core::list<PlayerInfo> list = server.getPlayerInfo();
4297 core::list<PlayerInfo>::Iterator i;
4298 static u32 sum_old = 0;
4299 u32 sum = PIChecksum(list);
4302 dstream<<DTIME<<"Player info:"<<std::endl;
4303 for(i=list.begin(); i!=list.end(); i++)
4305 i->PrintLine(&dstream);