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 // Reset usage timer, this block will be of use in the future.
606 block->resetUsageTimer();
608 // Block is dummy if data doesn't exist.
609 // It means it has been not found from disk and not generated
612 surely_not_found_on_disk = true;
615 // Block is valid if lighting is up-to-date and data exists
616 if(block->isValid() == false)
618 block_is_invalid = true;
621 /*if(block->isFullyGenerated() == false)
623 block_is_invalid = true;
628 ServerMap *map = (ServerMap*)(&server->m_env.getMap());
629 v2s16 chunkpos = map->sector_to_chunk(p2d);
630 if(map->chunkNonVolatile(chunkpos) == false)
631 block_is_invalid = true;
633 if(block->isGenerated() == false)
634 block_is_invalid = true;
637 If block is not close, don't send it unless it is near
640 Block is near ground level if night-time mesh
641 differs from day-time mesh.
645 if(block->dayNightDiffed() == false)
652 If block has been marked to not exist on disk (dummy)
653 and generating new ones is not wanted, skip block.
655 if(generate == false && surely_not_found_on_disk == true)
662 Record the lowest d from which a block has been
663 found being not sent and possibly to exist
665 if(no_blocks_found_for_sending)
668 new_nearest_unsent_d = d;
671 no_blocks_found_for_sending = false;
674 Add inexistent block to emerge queue.
676 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
678 //TODO: Get value from somewhere
679 // Allow only one block in emerge queue
680 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
681 // Allow two blocks in queue per client
682 if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
684 //dstream<<"Adding block to emerge queue"<<std::endl;
686 // Add it to the emerge queue and trigger the thread
689 if(generate == false)
690 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
692 server->m_emerge_queue.addBlock(peer_id, p, flags);
693 server->m_emergethread.trigger();
701 Add block to send queue
704 PrioritySortedBlockTransfer q((float)d, p, peer_id);
708 num_blocks_selected += 1;
709 sending_something = true;
714 //dstream<<"Stopped at "<<d<<std::endl;
716 if(no_blocks_found_for_sending)
718 if(queue_is_full == false)
719 new_nearest_unsent_d = d;
722 if(new_nearest_unsent_d != -1)
723 m_nearest_unsent_d = new_nearest_unsent_d;
725 if(sending_something == false)
727 m_nothing_to_send_counter++;
728 if((s16)m_nothing_to_send_counter >=
729 g_settings.getS16("max_block_send_distance"))
731 // Pause time in seconds
732 m_nothing_to_send_pause_timer = 1.0;
733 /*dstream<<"nothing to send to "
734 <<server->getPlayerName(peer_id)
735 <<" (d="<<d<<")"<<std::endl;*/
740 m_nothing_to_send_counter = 0;
743 /*timer_result = timer.stop(true);
744 if(timer_result != 0)
745 dstream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
748 void RemoteClient::SendObjectData(
751 core::map<v3s16, bool> &stepped_blocks
754 DSTACK(__FUNCTION_NAME);
756 // Can't send anything without knowing version
757 if(serialization_version == SER_FMT_VER_INVALID)
759 dstream<<"RemoteClient::SendObjectData(): Not sending, no version."
765 Send a TOCLIENT_OBJECTDATA packet.
769 u16 number of player positions
780 std::ostringstream os(std::ios_base::binary);
784 writeU16(buf, TOCLIENT_OBJECTDATA);
785 os.write((char*)buf, 2);
788 Get and write player data
791 // Get connected players
792 core::list<Player*> players = server->m_env.getPlayers(true);
794 // Write player count
795 u16 playercount = players.size();
796 writeU16(buf, playercount);
797 os.write((char*)buf, 2);
799 core::list<Player*>::Iterator i;
800 for(i = players.begin();
801 i != players.end(); i++)
805 v3f pf = player->getPosition();
806 v3f sf = player->getSpeed();
808 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
809 v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
810 s32 pitch_i (player->getPitch() * 100);
811 s32 yaw_i (player->getYaw() * 100);
813 writeU16(buf, player->peer_id);
814 os.write((char*)buf, 2);
815 writeV3S32(buf, position_i);
816 os.write((char*)buf, 12);
817 writeV3S32(buf, speed_i);
818 os.write((char*)buf, 12);
819 writeS32(buf, pitch_i);
820 os.write((char*)buf, 4);
821 writeS32(buf, yaw_i);
822 os.write((char*)buf, 4);
826 Get and write object data
832 For making players to be able to build to their nearby
833 environment (building is not possible on blocks that are not
836 - Add blocks to emerge queue if they are not found
838 SUGGESTION: These could be ignored from the backside of the player
841 Player *player = server->m_env.getPlayer(peer_id);
845 v3f playerpos = player->getPosition();
846 v3f playerspeed = player->getSpeed();
848 v3s16 center_nodepos = floatToInt(playerpos, BS);
849 v3s16 center = getNodeBlockPos(center_nodepos);
851 s16 d_max = g_settings.getS16("active_object_range");
853 // Number of blocks whose objects were written to bos
856 std::ostringstream bos(std::ios_base::binary);
858 for(s16 d = 0; d <= d_max; d++)
860 core::list<v3s16> list;
861 getFacePositions(list, d);
863 core::list<v3s16>::Iterator li;
864 for(li=list.begin(); li!=list.end(); li++)
866 v3s16 p = *li + center;
869 Ignore blocks that haven't been sent to the client
872 if(m_blocks_sent.find(p) == NULL)
876 // Try stepping block and add it to a send queue
881 MapBlock *block = server->m_env.getMap().getBlockNoCreate(p);
884 Step block if not in stepped_blocks and add to stepped_blocks.
886 if(stepped_blocks.find(p) == NULL)
888 block->stepObjects(dtime, true, server->m_env.getDayNightRatio());
889 stepped_blocks.insert(p, true);
890 block->setChangedFlag();
893 // Skip block if there are no objects
894 if(block->getObjectCount() == 0)
903 bos.write((char*)buf, 6);
906 //block->serializeObjects(bos, serialization_version); // DEPRECATED
913 Stop collecting objects if data is already too big
915 // Sum of player and object data sizes
916 s32 sum = (s32)os.tellp() + 2 + (s32)bos.tellp();
917 // break out if data too big
918 if(sum > MAX_OBJECTDATA_SIZE)
920 goto skip_subsequent;
924 catch(InvalidPositionException &e)
927 // Add it to the emerge queue and trigger the thread.
928 // Fetch the block only if it is on disk.
930 // Grab and increment counter
931 /*SharedPtr<JMutexAutoLock> lock
932 (m_num_blocks_in_emerge_queue.getLock());
933 m_num_blocks_in_emerge_queue.m_value++;*/
935 // Add to queue as an anonymous fetch from disk
936 u8 flags = BLOCK_EMERGE_FLAG_FROMDISK;
937 server->m_emerge_queue.addBlock(0, p, flags);
938 server->m_emergethread.trigger();
946 writeU16(buf, blockcount);
947 os.write((char*)buf, 2);
949 // Write block objects
956 //dstream<<"Server: Sending object data to "<<peer_id<<std::endl;
959 std::string s = os.str();
960 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
961 // Send as unreliable
962 server->m_con.Send(peer_id, 0, data, false);
965 void RemoteClient::GotBlock(v3s16 p)
967 if(m_blocks_sending.find(p) != NULL)
968 m_blocks_sending.remove(p);
971 /*dstream<<"RemoteClient::GotBlock(): Didn't find in"
972 " m_blocks_sending"<<std::endl;*/
973 m_excess_gotblocks++;
975 m_blocks_sent.insert(p, true);
978 void RemoteClient::SentBlock(v3s16 p)
980 if(m_blocks_sending.find(p) == NULL)
981 m_blocks_sending.insert(p, 0.0);
983 dstream<<"RemoteClient::SentBlock(): Sent block"
984 " already in m_blocks_sending"<<std::endl;
987 void RemoteClient::SetBlockNotSent(v3s16 p)
989 m_nearest_unsent_d = 0;
991 if(m_blocks_sending.find(p) != NULL)
992 m_blocks_sending.remove(p);
993 if(m_blocks_sent.find(p) != NULL)
994 m_blocks_sent.remove(p);
997 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
999 m_nearest_unsent_d = 0;
1001 for(core::map<v3s16, MapBlock*>::Iterator
1002 i = blocks.getIterator();
1003 i.atEnd()==false; i++)
1005 v3s16 p = i.getNode()->getKey();
1007 if(m_blocks_sending.find(p) != NULL)
1008 m_blocks_sending.remove(p);
1009 if(m_blocks_sent.find(p) != NULL)
1010 m_blocks_sent.remove(p);
1018 PlayerInfo::PlayerInfo()
1024 void PlayerInfo::PrintLine(std::ostream *s)
1027 (*s)<<"\""<<name<<"\" ("
1028 <<(position.X/10)<<","<<(position.Y/10)
1029 <<","<<(position.Z/10)<<") ";
1031 (*s)<<" avg_rtt="<<avg_rtt;
1035 u32 PIChecksum(core::list<PlayerInfo> &l)
1037 core::list<PlayerInfo>::Iterator i;
1040 for(i=l.begin(); i!=l.end(); i++)
1042 checksum += a * (i->id+1);
1043 checksum ^= 0x435aafcd;
1054 std::string mapsavedir
1056 m_env(new ServerMap(mapsavedir), this),
1057 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
1058 m_authmanager(mapsavedir+"/auth.txt"),
1060 m_emergethread(this),
1062 m_time_of_day_send_timer(0),
1064 m_mapsavedir(mapsavedir),
1065 m_shutdown_requested(false),
1066 m_ignore_map_edit_events(false),
1067 m_ignore_map_edit_events_peer_id(0)
1069 m_liquid_transform_timer = 0.0;
1070 m_print_info_timer = 0.0;
1071 m_objectdata_timer = 0.0;
1072 m_emergethread_trigger_timer = 0.0;
1073 m_savemap_timer = 0.0;
1077 m_step_dtime_mutex.Init();
1080 // Register us to receive map edit events
1081 m_env.getMap().addEventReceiver(this);
1083 // If file exists, load environment metadata
1084 if(fs::PathExists(m_mapsavedir+"/env_meta.txt"))
1086 dstream<<"Server: Loading environment metadata"<<std::endl;
1087 m_env.loadMeta(m_mapsavedir);
1091 dstream<<"Server: Loading players"<<std::endl;
1092 m_env.deSerializePlayers(m_mapsavedir);
1097 dstream<<"Server::~Server()"<<std::endl;
1100 Send shutdown message
1103 JMutexAutoLock conlock(m_con_mutex);
1105 std::wstring line = L"*** Server shutting down";
1108 Send the message to clients
1110 for(core::map<u16, RemoteClient*>::Iterator
1111 i = m_clients.getIterator();
1112 i.atEnd() == false; i++)
1114 // Get client and check that it is valid
1115 RemoteClient *client = i.getNode()->getValue();
1116 assert(client->peer_id == i.getNode()->getKey());
1117 if(client->serialization_version == SER_FMT_VER_INVALID)
1121 SendChatMessage(client->peer_id, line);
1123 catch(con::PeerNotFoundException &e)
1131 dstream<<"Server: Saving players"<<std::endl;
1132 m_env.serializePlayers(m_mapsavedir);
1135 Save environment metadata
1137 dstream<<"Server: Saving environment metadata"<<std::endl;
1138 m_env.saveMeta(m_mapsavedir);
1149 JMutexAutoLock clientslock(m_con_mutex);
1151 for(core::map<u16, RemoteClient*>::Iterator
1152 i = m_clients.getIterator();
1153 i.atEnd() == false; i++)
1156 // NOTE: These are removed by env destructor
1158 u16 peer_id = i.getNode()->getKey();
1159 JMutexAutoLock envlock(m_env_mutex);
1160 m_env.removePlayer(peer_id);
1164 delete i.getNode()->getValue();
1169 void Server::start(unsigned short port)
1171 DSTACK(__FUNCTION_NAME);
1172 // Stop thread if already running
1175 // Initialize connection
1176 m_con.setTimeoutMs(30);
1180 m_thread.setRun(true);
1183 dout_server<<"Server: Started on port "<<port<<std::endl;
1188 DSTACK(__FUNCTION_NAME);
1190 // Stop threads (set run=false first so both start stopping)
1191 m_thread.setRun(false);
1192 m_emergethread.setRun(false);
1194 m_emergethread.stop();
1196 dout_server<<"Server: Threads stopped"<<std::endl;
1199 void Server::step(float dtime)
1201 DSTACK(__FUNCTION_NAME);
1206 JMutexAutoLock lock(m_step_dtime_mutex);
1207 m_step_dtime += dtime;
1211 void Server::AsyncRunStep()
1213 DSTACK(__FUNCTION_NAME);
1217 JMutexAutoLock lock1(m_step_dtime_mutex);
1218 dtime = m_step_dtime;
1222 ScopeProfiler sp(&g_profiler, "Server: selecting and sending "
1223 "blocks to clients");
1224 // Send blocks to clients
1231 //dstream<<"Server steps "<<dtime<<std::endl;
1232 //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1235 JMutexAutoLock lock1(m_step_dtime_mutex);
1236 m_step_dtime -= dtime;
1243 m_uptime.set(m_uptime.get() + dtime);
1247 Update m_time_of_day and overall game time
1250 JMutexAutoLock envlock(m_env_mutex);
1252 m_time_counter += dtime;
1253 f32 speed = g_settings.getFloat("time_speed") * 24000./(24.*3600);
1254 u32 units = (u32)(m_time_counter*speed);
1255 m_time_counter -= (f32)units / speed;
1257 m_env.setTimeOfDay((m_env.getTimeOfDay() + units) % 24000);
1259 //dstream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1262 Send to clients at constant intervals
1265 m_time_of_day_send_timer -= dtime;
1266 if(m_time_of_day_send_timer < 0.0)
1268 m_time_of_day_send_timer = g_settings.getFloat("time_send_interval");
1270 //JMutexAutoLock envlock(m_env_mutex);
1271 JMutexAutoLock conlock(m_con_mutex);
1273 for(core::map<u16, RemoteClient*>::Iterator
1274 i = m_clients.getIterator();
1275 i.atEnd() == false; i++)
1277 RemoteClient *client = i.getNode()->getValue();
1278 //Player *player = m_env.getPlayer(client->peer_id);
1280 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1281 m_env.getTimeOfDay());
1283 m_con.Send(client->peer_id, 0, data, true);
1289 // Process connection's timeouts
1290 JMutexAutoLock lock2(m_con_mutex);
1291 ScopeProfiler sp(&g_profiler, "Server: connection timeout processing");
1292 m_con.RunTimeouts(dtime);
1296 // This has to be called so that the client list gets synced
1297 // with the peer list of the connection
1298 ScopeProfiler sp(&g_profiler, "Server: peer change handling");
1299 handlePeerChanges();
1303 JMutexAutoLock lock(m_env_mutex);
1305 ScopeProfiler sp(&g_profiler, "Server: environment step");
1309 const float map_timer_and_unload_dtime = 5.15;
1310 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1312 JMutexAutoLock lock(m_env_mutex);
1313 // Run Map's timers and unload unused data
1314 ScopeProfiler sp(&g_profiler, "Server: map timer and unload");
1315 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
1316 g_settings.getFloat("server_unload_unused_data_timeout"));
1326 m_liquid_transform_timer += dtime;
1327 if(m_liquid_transform_timer >= 1.00)
1329 m_liquid_transform_timer -= 1.00;
1331 JMutexAutoLock lock(m_env_mutex);
1333 ScopeProfiler sp(&g_profiler, "Server: liquid transform");
1335 core::map<v3s16, MapBlock*> modified_blocks;
1336 m_env.getMap().transformLiquids(modified_blocks);
1341 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1342 ServerMap &map = ((ServerMap&)m_env.getMap());
1343 map.updateLighting(modified_blocks, lighting_modified_blocks);
1345 // Add blocks modified by lighting to modified_blocks
1346 for(core::map<v3s16, MapBlock*>::Iterator
1347 i = lighting_modified_blocks.getIterator();
1348 i.atEnd() == false; i++)
1350 MapBlock *block = i.getNode()->getValue();
1351 modified_blocks.insert(block->getPos(), block);
1355 Set the modified blocks unsent for all the clients
1358 JMutexAutoLock lock2(m_con_mutex);
1360 for(core::map<u16, RemoteClient*>::Iterator
1361 i = m_clients.getIterator();
1362 i.atEnd() == false; i++)
1364 RemoteClient *client = i.getNode()->getValue();
1366 if(modified_blocks.size() > 0)
1368 // Remove block from sent history
1369 client->SetBlocksNotSent(modified_blocks);
1374 // Periodically print some info
1376 float &counter = m_print_info_timer;
1382 JMutexAutoLock lock2(m_con_mutex);
1384 for(core::map<u16, RemoteClient*>::Iterator
1385 i = m_clients.getIterator();
1386 i.atEnd() == false; i++)
1388 //u16 peer_id = i.getNode()->getKey();
1389 RemoteClient *client = i.getNode()->getValue();
1390 Player *player = m_env.getPlayer(client->peer_id);
1393 std::cout<<player->getName()<<"\t";
1394 client->PrintInfo(std::cout);
1399 //if(g_settings.getBool("enable_experimental"))
1403 Check added and deleted active objects
1406 //dstream<<"Server: Checking added and deleted active objects"<<std::endl;
1407 JMutexAutoLock envlock(m_env_mutex);
1408 JMutexAutoLock conlock(m_con_mutex);
1410 ScopeProfiler sp(&g_profiler, "Server: checking added and deleted objects");
1412 // Radius inside which objects are active
1415 for(core::map<u16, RemoteClient*>::Iterator
1416 i = m_clients.getIterator();
1417 i.atEnd() == false; i++)
1419 RemoteClient *client = i.getNode()->getValue();
1420 Player *player = m_env.getPlayer(client->peer_id);
1423 // This can happen if the client timeouts somehow
1424 /*dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1426 <<" has no associated player"<<std::endl;*/
1429 v3s16 pos = floatToInt(player->getPosition(), BS);
1431 core::map<u16, bool> removed_objects;
1432 core::map<u16, bool> added_objects;
1433 m_env.getRemovedActiveObjects(pos, radius,
1434 client->m_known_objects, removed_objects);
1435 m_env.getAddedActiveObjects(pos, radius,
1436 client->m_known_objects, added_objects);
1438 // Ignore if nothing happened
1439 if(removed_objects.size() == 0 && added_objects.size() == 0)
1441 //dstream<<"INFO: active objects: none changed"<<std::endl;
1445 std::string data_buffer;
1449 // Handle removed objects
1450 writeU16((u8*)buf, removed_objects.size());
1451 data_buffer.append(buf, 2);
1452 for(core::map<u16, bool>::Iterator
1453 i = removed_objects.getIterator();
1454 i.atEnd()==false; i++)
1457 u16 id = i.getNode()->getKey();
1458 ServerActiveObject* obj = m_env.getActiveObject(id);
1460 // Add to data buffer for sending
1461 writeU16((u8*)buf, i.getNode()->getKey());
1462 data_buffer.append(buf, 2);
1464 // Remove from known objects
1465 client->m_known_objects.remove(i.getNode()->getKey());
1467 if(obj && obj->m_known_by_count > 0)
1468 obj->m_known_by_count--;
1471 // Handle added objects
1472 writeU16((u8*)buf, added_objects.size());
1473 data_buffer.append(buf, 2);
1474 for(core::map<u16, bool>::Iterator
1475 i = added_objects.getIterator();
1476 i.atEnd()==false; i++)
1479 u16 id = i.getNode()->getKey();
1480 ServerActiveObject* obj = m_env.getActiveObject(id);
1483 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1485 dstream<<"WARNING: "<<__FUNCTION_NAME
1486 <<": NULL object"<<std::endl;
1488 type = obj->getType();
1490 // Add to data buffer for sending
1491 writeU16((u8*)buf, id);
1492 data_buffer.append(buf, 2);
1493 writeU8((u8*)buf, type);
1494 data_buffer.append(buf, 1);
1497 data_buffer.append(serializeLongString(
1498 obj->getClientInitializationData()));
1500 data_buffer.append(serializeLongString(""));
1502 // Add to known objects
1503 client->m_known_objects.insert(i.getNode()->getKey(), false);
1506 obj->m_known_by_count++;
1510 SharedBuffer<u8> reply(2 + data_buffer.size());
1511 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1512 memcpy((char*)&reply[2], data_buffer.c_str(),
1513 data_buffer.size());
1515 m_con.Send(client->peer_id, 0, reply, true);
1517 dstream<<"INFO: Server: Sent object remove/add: "
1518 <<removed_objects.size()<<" removed, "
1519 <<added_objects.size()<<" added, "
1520 <<"packet size is "<<reply.getSize()<<std::endl;
1525 Collect a list of all the objects known by the clients
1526 and report it back to the environment.
1529 core::map<u16, bool> all_known_objects;
1531 for(core::map<u16, RemoteClient*>::Iterator
1532 i = m_clients.getIterator();
1533 i.atEnd() == false; i++)
1535 RemoteClient *client = i.getNode()->getValue();
1536 // Go through all known objects of client
1537 for(core::map<u16, bool>::Iterator
1538 i = client->m_known_objects.getIterator();
1539 i.atEnd()==false; i++)
1541 u16 id = i.getNode()->getKey();
1542 all_known_objects[id] = true;
1546 m_env.setKnownActiveObjects(whatever);
1552 Send object messages
1555 JMutexAutoLock envlock(m_env_mutex);
1556 JMutexAutoLock conlock(m_con_mutex);
1558 ScopeProfiler sp(&g_profiler, "Server: sending object messages");
1561 // Value = data sent by object
1562 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1564 // Get active object messages from environment
1567 ActiveObjectMessage aom = m_env.getActiveObjectMessage();
1571 core::list<ActiveObjectMessage>* message_list = NULL;
1572 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1573 n = buffered_messages.find(aom.id);
1576 message_list = new core::list<ActiveObjectMessage>;
1577 buffered_messages.insert(aom.id, message_list);
1581 message_list = n->getValue();
1583 message_list->push_back(aom);
1586 // Route data to every client
1587 for(core::map<u16, RemoteClient*>::Iterator
1588 i = m_clients.getIterator();
1589 i.atEnd()==false; i++)
1591 RemoteClient *client = i.getNode()->getValue();
1592 std::string reliable_data;
1593 std::string unreliable_data;
1594 // Go through all objects in message buffer
1595 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1596 j = buffered_messages.getIterator();
1597 j.atEnd()==false; j++)
1599 // If object is not known by client, skip it
1600 u16 id = j.getNode()->getKey();
1601 if(client->m_known_objects.find(id) == NULL)
1603 // Get message list of object
1604 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1605 // Go through every message
1606 for(core::list<ActiveObjectMessage>::Iterator
1607 k = list->begin(); k != list->end(); k++)
1609 // Compose the full new data with header
1610 ActiveObjectMessage aom = *k;
1611 std::string new_data;
1614 writeU16((u8*)&buf[0], aom.id);
1615 new_data.append(buf, 2);
1617 new_data += serializeString(aom.datastring);
1618 // Add data to buffer
1620 reliable_data += new_data;
1622 unreliable_data += new_data;
1626 reliable_data and unreliable_data are now ready.
1629 if(reliable_data.size() > 0)
1631 SharedBuffer<u8> reply(2 + reliable_data.size());
1632 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1633 memcpy((char*)&reply[2], reliable_data.c_str(),
1634 reliable_data.size());
1636 m_con.Send(client->peer_id, 0, reply, true);
1638 if(unreliable_data.size() > 0)
1640 SharedBuffer<u8> reply(2 + unreliable_data.size());
1641 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1642 memcpy((char*)&reply[2], unreliable_data.c_str(),
1643 unreliable_data.size());
1644 // Send as unreliable
1645 m_con.Send(client->peer_id, 0, reply, false);
1648 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1650 dstream<<"INFO: Server: Size of object message data: "
1651 <<"reliable: "<<reliable_data.size()
1652 <<", unreliable: "<<unreliable_data.size()
1657 // Clear buffered_messages
1658 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1659 i = buffered_messages.getIterator();
1660 i.atEnd()==false; i++)
1662 delete i.getNode()->getValue();
1666 } // enable_experimental
1669 Send queued-for-sending map edit events.
1672 // Don't send too many at a time
1675 // Single change sending is disabled if queue size is not small
1676 bool disable_single_change_sending = false;
1677 if(m_unsent_map_edit_queue.size() >= 4)
1678 disable_single_change_sending = true;
1680 bool got_any_events = false;
1682 // We'll log the amount of each
1685 while(m_unsent_map_edit_queue.size() != 0)
1687 got_any_events = true;
1689 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1691 // Players far away from the change are stored here.
1692 // Instead of sending the changes, MapBlocks are set not sent
1694 core::list<u16> far_players;
1696 if(event->type == MEET_ADDNODE)
1698 //dstream<<"Server: MEET_ADDNODE"<<std::endl;
1699 prof.add("MEET_ADDNODE", 1);
1700 if(disable_single_change_sending)
1701 sendAddNode(event->p, event->n, event->already_known_by_peer,
1704 sendAddNode(event->p, event->n, event->already_known_by_peer,
1707 else if(event->type == MEET_REMOVENODE)
1709 //dstream<<"Server: MEET_REMOVENODE"<<std::endl;
1710 prof.add("MEET_REMOVENODE", 1);
1711 if(disable_single_change_sending)
1712 sendRemoveNode(event->p, event->already_known_by_peer,
1715 sendRemoveNode(event->p, event->already_known_by_peer,
1718 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1720 dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1721 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1722 setBlockNotSent(event->p);
1724 else if(event->type == MEET_OTHER)
1726 prof.add("MEET_OTHER", 1);
1727 dstream<<"WARNING: Server: MEET_OTHER not implemented"
1732 prof.add("unknown", 1);
1733 dstream<<"WARNING: Server: Unknown MapEditEvent "
1734 <<((u32)event->type)<<std::endl;
1738 Set blocks not sent to far players
1740 if(far_players.size() > 0)
1742 // Convert list format to that wanted by SetBlocksNotSent
1743 core::map<v3s16, MapBlock*> modified_blocks2;
1744 for(core::map<v3s16, bool>::Iterator
1745 i = event->modified_blocks.getIterator();
1746 i.atEnd()==false; i++)
1748 v3s16 p = i.getNode()->getKey();
1749 modified_blocks2.insert(p,
1750 m_env.getMap().getBlockNoCreateNoEx(p));
1752 // Set blocks not sent
1753 for(core::list<u16>::Iterator
1754 i = far_players.begin();
1755 i != far_players.end(); i++)
1758 RemoteClient *client = getClient(peer_id);
1761 client->SetBlocksNotSent(modified_blocks2);
1767 /*// Don't send too many at a time
1769 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1775 dstream<<"Server: MapEditEvents:"<<std::endl;
1776 prof.print(dstream);
1782 Send object positions
1783 TODO: Get rid of MapBlockObjects
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 mbo 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 JMutexAutoLock lock(m_env_mutex);
1833 /*// Unload unused data (delete from memory)
1834 m_env.getMap().unloadUnusedData(
1835 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1837 /*u32 deleted_count = m_env.getMap().unloadUnusedData(
1838 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1841 // Save only changed parts
1842 m_env.getMap().save(true);
1844 /*if(deleted_count > 0)
1846 dout_server<<"Server: Unloaded "<<deleted_count
1847 <<" blocks from memory"<<std::endl;
1851 m_env.serializePlayers(m_mapsavedir);
1853 // Save environment metadata
1854 m_env.saveMeta(m_mapsavedir);
1859 void Server::Receive()
1861 DSTACK(__FUNCTION_NAME);
1862 u32 data_maxsize = 10000;
1863 Buffer<u8> data(data_maxsize);
1868 JMutexAutoLock conlock(m_con_mutex);
1869 datasize = m_con.Receive(peer_id, *data, data_maxsize);
1872 // This has to be called so that the client list gets synced
1873 // with the peer list of the connection
1874 handlePeerChanges();
1876 ProcessData(*data, datasize, peer_id);
1878 catch(con::InvalidIncomingDataException &e)
1880 derr_server<<"Server::Receive(): "
1881 "InvalidIncomingDataException: what()="
1882 <<e.what()<<std::endl;
1884 catch(con::PeerNotFoundException &e)
1886 //NOTE: This is not needed anymore
1888 // The peer has been disconnected.
1889 // Find the associated player and remove it.
1891 /*JMutexAutoLock envlock(m_env_mutex);
1893 dout_server<<"ServerThread: peer_id="<<peer_id
1894 <<" has apparently closed connection. "
1895 <<"Removing player."<<std::endl;
1897 m_env.removePlayer(peer_id);*/
1901 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1903 DSTACK(__FUNCTION_NAME);
1904 // Environment is locked first.
1905 JMutexAutoLock envlock(m_env_mutex);
1906 JMutexAutoLock conlock(m_con_mutex);
1910 peer = m_con.GetPeer(peer_id);
1912 catch(con::PeerNotFoundException &e)
1914 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1915 <<peer_id<<" not found"<<std::endl;
1919 u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1927 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1929 if(command == TOSERVER_INIT)
1931 // [0] u16 TOSERVER_INIT
1932 // [2] u8 SER_FMT_VER_HIGHEST
1933 // [3] u8[20] player_name
1934 // [23] u8[28] password <--- can be sent without this, from old versions
1936 if(datasize < 2+1+PLAYERNAME_SIZE)
1939 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1940 <<peer->id<<std::endl;
1942 // First byte after command is maximum supported
1943 // serialization version
1944 u8 client_max = data[2];
1945 u8 our_max = SER_FMT_VER_HIGHEST;
1946 // Use the highest version supported by both
1947 u8 deployed = core::min_(client_max, our_max);
1948 // If it's lower than the lowest supported, give up.
1949 if(deployed < SER_FMT_VER_LOWEST)
1950 deployed = SER_FMT_VER_INVALID;
1952 //peer->serialization_version = deployed;
1953 getClient(peer->id)->pending_serialization_version = deployed;
1955 if(deployed == SER_FMT_VER_INVALID)
1957 derr_server<<DTIME<<"Server: Cannot negotiate "
1958 "serialization version with peer "
1959 <<peer_id<<std::endl;
1968 char playername[PLAYERNAME_SIZE];
1969 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1971 playername[i] = data[3+i];
1973 playername[PLAYERNAME_SIZE-1] = 0;
1975 if(playername[0]=='\0')
1977 derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
1978 SendAccessDenied(m_con, peer_id,
1983 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1985 derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
1986 SendAccessDenied(m_con, peer_id,
1987 L"Name contains unallowed characters");
1992 char password[PASSWORD_SIZE];
1993 if(datasize == 2+1+PLAYERNAME_SIZE)
1995 // old version - assume blank password
2000 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2002 password[i] = data[23+i];
2004 password[PASSWORD_SIZE-1] = 0;
2007 std::string checkpwd;
2008 if(m_authmanager.exists(playername))
2010 checkpwd = m_authmanager.getPassword(playername);
2014 checkpwd = g_settings.get("default_password");
2017 if(password != checkpwd && checkpwd != "")
2019 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2020 <<": supplied invalid password for "
2021 <<playername<<std::endl;
2022 SendAccessDenied(m_con, peer_id, L"Invalid password");
2026 // Add player to auth manager
2027 if(m_authmanager.exists(playername) == false)
2029 derr_server<<DTIME<<"Server: adding player "<<playername
2030 <<" to auth manager"<<std::endl;
2031 m_authmanager.add(playername);
2032 m_authmanager.setPassword(playername, checkpwd);
2033 m_authmanager.setPrivs(playername,
2034 stringToPrivs(g_settings.get("default_privs")));
2035 m_authmanager.save();
2039 Player *player = emergePlayer(playername, password, peer_id);
2043 // DEBUG: Test serialization
2044 std::ostringstream test_os;
2045 player->serialize(test_os);
2046 dstream<<"Player serialization test: \""<<test_os.str()
2048 std::istringstream test_is(test_os.str());
2049 player->deSerialize(test_is);
2052 // If failed, cancel
2055 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2056 <<": failed to emerge player"<<std::endl;
2061 // If a client is already connected to the player, cancel
2062 if(player->peer_id != 0)
2064 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2065 <<" tried to connect to "
2066 "an already connected player (peer_id="
2067 <<player->peer_id<<")"<<std::endl;
2070 // Set client of player
2071 player->peer_id = peer_id;
2074 // Check if player doesn't exist
2076 throw con::InvalidIncomingDataException
2077 ("Server::ProcessData(): INIT: Player doesn't exist");
2079 /*// update name if it was supplied
2080 if(datasize >= 20+3)
2083 player->updateName((const char*)&data[3]);
2087 Answer with a TOCLIENT_INIT
2090 SharedBuffer<u8> reply(2+1+6+8);
2091 writeU16(&reply[0], TOCLIENT_INIT);
2092 writeU8(&reply[2], deployed);
2093 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2094 writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2097 m_con.Send(peer_id, 0, reply, true);
2101 Send complete position information
2103 SendMovePlayer(player);
2108 if(command == TOSERVER_INIT2)
2110 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2111 <<peer->id<<std::endl;
2114 getClient(peer->id)->serialization_version
2115 = getClient(peer->id)->pending_serialization_version;
2118 Send some initialization data
2121 // Send player info to all players
2124 // Send inventory to player
2125 UpdateCrafting(peer->id);
2126 SendInventory(peer->id);
2130 Player *player = m_env.getPlayer(peer_id);
2131 SendPlayerHP(player);
2136 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2137 m_env.getTimeOfDay());
2138 m_con.Send(peer->id, 0, data, true);
2141 // Send information about server to player in chat
2142 SendChatMessage(peer_id, getStatusString());
2144 // Send information about joining in chat
2146 std::wstring name = L"unknown";
2147 Player *player = m_env.getPlayer(peer_id);
2149 name = narrow_to_wide(player->getName());
2151 std::wstring message;
2154 message += L" joined game";
2155 BroadcastChatMessage(message);
2161 if(peer_ser_ver == SER_FMT_VER_INVALID)
2163 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2164 " serialization format invalid or not initialized."
2165 " Skipping incoming command="<<command<<std::endl;
2169 Player *player = m_env.getPlayer(peer_id);
2172 derr_server<<"Server::ProcessData(): Cancelling: "
2173 "No player for peer_id="<<peer_id
2177 if(command == TOSERVER_PLAYERPOS)
2179 if(datasize < 2+12+12+4+4)
2183 v3s32 ps = readV3S32(&data[start+2]);
2184 v3s32 ss = readV3S32(&data[start+2+12]);
2185 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2186 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2187 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2188 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2189 pitch = wrapDegrees(pitch);
2190 yaw = wrapDegrees(yaw);
2191 player->setPosition(position);
2192 player->setSpeed(speed);
2193 player->setPitch(pitch);
2194 player->setYaw(yaw);
2196 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2197 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2198 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2200 else if(command == TOSERVER_GOTBLOCKS)
2213 u16 count = data[2];
2214 for(u16 i=0; i<count; i++)
2216 if((s16)datasize < 2+1+(i+1)*6)
2217 throw con::InvalidIncomingDataException
2218 ("GOTBLOCKS length is too short");
2219 v3s16 p = readV3S16(&data[2+1+i*6]);
2220 /*dstream<<"Server: GOTBLOCKS ("
2221 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2222 RemoteClient *client = getClient(peer_id);
2223 client->GotBlock(p);
2226 else if(command == TOSERVER_DELETEDBLOCKS)
2239 u16 count = data[2];
2240 for(u16 i=0; i<count; i++)
2242 if((s16)datasize < 2+1+(i+1)*6)
2243 throw con::InvalidIncomingDataException
2244 ("DELETEDBLOCKS length is too short");
2245 v3s16 p = readV3S16(&data[2+1+i*6]);
2246 /*dstream<<"Server: DELETEDBLOCKS ("
2247 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2248 RemoteClient *client = getClient(peer_id);
2249 client->SetBlockNotSent(p);
2252 else if(command == TOSERVER_CLICK_OBJECT)
2257 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2262 [2] u8 button (0=left, 1=right)
2267 u8 button = readU8(&data[2]);
2269 p.X = readS16(&data[3]);
2270 p.Y = readS16(&data[5]);
2271 p.Z = readS16(&data[7]);
2272 s16 id = readS16(&data[9]);
2273 //u16 item_i = readU16(&data[11]);
2275 MapBlock *block = NULL;
2278 block = m_env.getMap().getBlockNoCreate(p);
2280 catch(InvalidPositionException &e)
2282 derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2286 MapBlockObject *obj = block->getObject(id);
2290 derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2294 //TODO: Check that object is reasonably close
2299 InventoryList *ilist = player->inventory.getList("main");
2300 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2303 // Skip if inventory has no free space
2304 if(ilist->getUsedSlots() == ilist->getSize())
2306 dout_server<<"Player inventory has no free space"<<std::endl;
2311 Create the inventory item
2313 InventoryItem *item = NULL;
2314 // If it is an item-object, take the item from it
2315 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2317 item = ((ItemObject*)obj)->createInventoryItem();
2319 // Else create an item of the object
2322 item = new MapBlockObjectItem
2323 (obj->getInventoryString());
2326 // Add to inventory and send inventory
2327 ilist->addItem(item);
2328 UpdateCrafting(player->peer_id);
2329 SendInventory(player->peer_id);
2332 // Remove from block
2333 block->removeObject(id);
2336 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2341 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2347 [2] u8 button (0=left, 1=right)
2351 u8 button = readU8(&data[2]);
2352 u16 id = readS16(&data[3]);
2353 u16 item_i = readU16(&data[11]);
2355 ServerActiveObject *obj = m_env.getActiveObject(id);
2359 derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2364 //TODO: Check that object is reasonably close
2366 // Left click, pick object up (usually)
2369 InventoryList *ilist = player->inventory.getList("main");
2370 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2373 // Skip if inventory has no free space
2374 if(ilist->getUsedSlots() == ilist->getSize())
2376 dout_server<<"Player inventory has no free space"<<std::endl;
2380 // Skip if object has been removed
2385 Create the inventory item
2387 InventoryItem *item = obj->createPickedUpItem();
2391 // Add to inventory and send inventory
2392 ilist->addItem(item);
2393 UpdateCrafting(player->peer_id);
2394 SendInventory(player->peer_id);
2396 // Remove object from environment
2397 obj->m_removed = true;
2402 Item cannot be picked up. Punch it instead.
2405 ToolItem *titem = NULL;
2406 std::string toolname = "";
2408 InventoryList *mlist = player->inventory.getList("main");
2411 InventoryItem *item = mlist->getItem(item_i);
2412 if(item && (std::string)item->getName() == "ToolItem")
2414 titem = (ToolItem*)item;
2415 toolname = titem->getToolName();
2419 v3f playerpos = player->getPosition();
2420 v3f objpos = obj->getBasePosition();
2421 v3f dir = (objpos - playerpos).normalize();
2423 u16 wear = obj->punch(toolname, dir);
2427 bool weared_out = titem->addWear(wear);
2429 mlist->deleteItem(item_i);
2430 SendInventory(player->peer_id);
2436 else if(command == TOSERVER_GROUND_ACTION)
2444 [3] v3s16 nodepos_undersurface
2445 [9] v3s16 nodepos_abovesurface
2450 2: stop digging (all parameters ignored)
2451 3: digging completed
2453 u8 action = readU8(&data[2]);
2455 p_under.X = readS16(&data[3]);
2456 p_under.Y = readS16(&data[5]);
2457 p_under.Z = readS16(&data[7]);
2459 p_over.X = readS16(&data[9]);
2460 p_over.Y = readS16(&data[11]);
2461 p_over.Z = readS16(&data[13]);
2462 u16 item_i = readU16(&data[15]);
2464 //TODO: Check that target is reasonably close
2472 NOTE: This can be used in the future to check if
2473 somebody is cheating, by checking the timing.
2480 else if(action == 2)
2483 RemoteClient *client = getClient(peer->id);
2484 JMutexAutoLock digmutex(client->m_dig_mutex);
2485 client->m_dig_tool_item = -1;
2490 3: Digging completed
2492 else if(action == 3)
2494 // Mandatory parameter; actually used for nothing
2495 core::map<v3s16, MapBlock*> modified_blocks;
2497 u8 material = CONTENT_IGNORE;
2498 u8 mineral = MINERAL_NONE;
2500 bool cannot_remove_node = false;
2504 MapNode n = m_env.getMap().getNode(p_under);
2506 mineral = n.getMineral();
2507 // Get material at position
2509 // If not yet cancelled
2510 if(cannot_remove_node == false)
2512 // If it's not diggable, do nothing
2513 if(content_diggable(material) == false)
2515 derr_server<<"Server: Not finishing digging: "
2516 <<"Node not diggable"
2518 cannot_remove_node = true;
2521 // If not yet cancelled
2522 if(cannot_remove_node == false)
2524 // Get node metadata
2525 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2526 if(meta && meta->nodeRemovalDisabled() == true)
2528 derr_server<<"Server: Not finishing digging: "
2529 <<"Node metadata disables removal"
2531 cannot_remove_node = true;
2535 catch(InvalidPositionException &e)
2537 derr_server<<"Server: Not finishing digging: Node not found."
2538 <<" Adding block to emerge queue."
2540 m_emerge_queue.addBlock(peer_id,
2541 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2542 cannot_remove_node = true;
2545 // Make sure the player is allowed to do it
2546 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2548 dstream<<"Player "<<player->getName()<<" cannot remove node"
2549 <<" because privileges are "<<getPlayerPrivs(player)
2551 cannot_remove_node = true;
2555 If node can't be removed, set block to be re-sent to
2558 if(cannot_remove_node)
2560 derr_server<<"Server: Not finishing digging."<<std::endl;
2562 // Client probably has wrong data.
2563 // Set block not sent, so that client will get
2565 dstream<<"Client "<<peer_id<<" tried to dig "
2566 <<"node; but node cannot be removed."
2567 <<" setting MapBlock not sent."<<std::endl;
2568 RemoteClient *client = getClient(peer_id);
2569 v3s16 blockpos = getNodeBlockPos(p_under);
2570 client->SetBlockNotSent(blockpos);
2576 Send the removal to all close-by players.
2577 - If other player is close, send REMOVENODE
2578 - Otherwise set blocks not sent
2580 core::list<u16> far_players;
2581 sendRemoveNode(p_under, peer_id, &far_players, 30);
2584 Update and send inventory
2587 if(g_settings.getBool("creative_mode") == false)
2592 InventoryList *mlist = player->inventory.getList("main");
2595 InventoryItem *item = mlist->getItem(item_i);
2596 if(item && (std::string)item->getName() == "ToolItem")
2598 ToolItem *titem = (ToolItem*)item;
2599 std::string toolname = titem->getToolName();
2601 // Get digging properties for material and tool
2602 DiggingProperties prop =
2603 getDiggingProperties(material, toolname);
2605 if(prop.diggable == false)
2607 derr_server<<"Server: WARNING: Player digged"
2608 <<" with impossible material + tool"
2609 <<" combination"<<std::endl;
2612 bool weared_out = titem->addWear(prop.wear);
2616 mlist->deleteItem(item_i);
2622 Add dug item to inventory
2625 InventoryItem *item = NULL;
2627 if(mineral != MINERAL_NONE)
2628 item = getDiggedMineralItem(mineral);
2633 std::string &dug_s = content_features(material).dug_item;
2636 std::istringstream is(dug_s, std::ios::binary);
2637 item = InventoryItem::deSerialize(is);
2643 // Add a item to inventory
2644 player->inventory.addItem("main", item);
2647 UpdateCrafting(player->peer_id);
2648 SendInventory(player->peer_id);
2654 (this takes some time so it is done after the quick stuff)
2657 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2659 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2662 Set blocks not sent to far players
2664 for(core::list<u16>::Iterator
2665 i = far_players.begin();
2666 i != far_players.end(); i++)
2669 RemoteClient *client = getClient(peer_id);
2672 client->SetBlocksNotSent(modified_blocks);
2679 else if(action == 1)
2682 InventoryList *ilist = player->inventory.getList("main");
2687 InventoryItem *item = ilist->getItem(item_i);
2689 // If there is no item, it is not possible to add it anywhere
2694 Handle material items
2696 if(std::string("MaterialItem") == item->getName())
2699 // Don't add a node if this is not a free space
2700 MapNode n2 = m_env.getMap().getNode(p_over);
2701 bool no_enough_privs =
2702 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2704 dstream<<"Player "<<player->getName()<<" cannot add node"
2705 <<" because privileges are "<<getPlayerPrivs(player)
2708 if(content_buildable_to(n2.d) == false
2711 // Client probably has wrong data.
2712 // Set block not sent, so that client will get
2714 dstream<<"Client "<<peer_id<<" tried to place"
2715 <<" node in invalid position; setting"
2716 <<" MapBlock not sent."<<std::endl;
2717 RemoteClient *client = getClient(peer_id);
2718 v3s16 blockpos = getNodeBlockPos(p_over);
2719 client->SetBlockNotSent(blockpos);
2723 catch(InvalidPositionException &e)
2725 derr_server<<"Server: Ignoring ADDNODE: Node not found"
2726 <<" Adding block to emerge queue."
2728 m_emerge_queue.addBlock(peer_id,
2729 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2733 // Reset build time counter
2734 getClient(peer->id)->m_time_from_building = 0.0;
2737 MaterialItem *mitem = (MaterialItem*)item;
2739 n.d = mitem->getMaterial();
2741 // Calculate direction for wall mounted stuff
2742 if(content_features(n.d).wall_mounted)
2743 n.dir = packDir(p_under - p_over);
2745 // Calculate the direction for furnaces and chests and stuff
2746 if(content_features(n.d).param_type == CPT_FACEDIR_SIMPLE)
2748 v3f playerpos = player->getPosition();
2749 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2750 blockpos = blockpos.normalize();
2752 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2766 Send to all close-by players
2768 core::list<u16> far_players;
2769 sendAddNode(p_over, n, 0, &far_players, 30);
2774 InventoryList *ilist = player->inventory.getList("main");
2775 if(g_settings.getBool("creative_mode") == false && ilist)
2777 // Remove from inventory and send inventory
2778 if(mitem->getCount() == 1)
2779 ilist->deleteItem(item_i);
2783 UpdateCrafting(peer_id);
2784 SendInventory(peer_id);
2790 This takes some time so it is done after the quick stuff
2792 core::map<v3s16, MapBlock*> modified_blocks;
2794 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2796 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2799 Set blocks not sent to far players
2801 for(core::list<u16>::Iterator
2802 i = far_players.begin();
2803 i != far_players.end(); i++)
2806 RemoteClient *client = getClient(peer_id);
2809 client->SetBlocksNotSent(modified_blocks);
2813 Calculate special events
2816 /*if(n.d == CONTENT_MESE)
2819 for(s16 z=-1; z<=1; z++)
2820 for(s16 y=-1; y<=1; y++)
2821 for(s16 x=-1; x<=1; x++)
2828 Place other item (not a block)
2832 v3s16 blockpos = getNodeBlockPos(p_over);
2835 Check that the block is loaded so that the item
2836 can properly be added to the static list too
2838 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2841 derr_server<<"Error while placing object: "
2842 "block not found"<<std::endl;
2846 dout_server<<"Placing a miscellaneous item on map"
2849 // Calculate a position for it
2850 v3f pos = intToFloat(p_over, BS);
2852 pos.Y -= BS*0.25; // let it drop a bit
2854 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2855 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2860 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2864 derr_server<<"WARNING: item resulted in NULL object, "
2865 <<"not placing onto map"
2870 // Add the object to the environment
2871 m_env.addActiveObject(obj);
2873 dout_server<<"Placed object"<<std::endl;
2875 if(g_settings.getBool("creative_mode") == false)
2877 // Delete the right amount of items from the slot
2878 u16 dropcount = item->getDropCount();
2880 // Delete item if all gone
2881 if(item->getCount() <= dropcount)
2883 if(item->getCount() < dropcount)
2884 dstream<<"WARNING: Server: dropped more items"
2885 <<" than the slot contains"<<std::endl;
2887 InventoryList *ilist = player->inventory.getList("main");
2889 // Remove from inventory and send inventory
2890 ilist->deleteItem(item_i);
2892 // Else decrement it
2894 item->remove(dropcount);
2897 UpdateCrafting(peer_id);
2898 SendInventory(peer_id);
2906 Catch invalid actions
2910 derr_server<<"WARNING: Server: Invalid action "
2911 <<action<<std::endl;
2915 else if(command == TOSERVER_RELEASE)
2924 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2927 else if(command == TOSERVER_SIGNTEXT)
2929 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2938 std::string datastring((char*)&data[2], datasize-2);
2939 std::istringstream is(datastring, std::ios_base::binary);
2942 is.read((char*)buf, 6);
2943 v3s16 blockpos = readV3S16(buf);
2944 is.read((char*)buf, 2);
2945 s16 id = readS16(buf);
2946 is.read((char*)buf, 2);
2947 u16 textlen = readU16(buf);
2949 for(u16 i=0; i<textlen; i++)
2951 is.read((char*)buf, 1);
2952 text += (char)buf[0];
2955 MapBlock *block = NULL;
2958 block = m_env.getMap().getBlockNoCreate(blockpos);
2960 catch(InvalidPositionException &e)
2962 derr_server<<"Error while setting sign text: "
2963 "block not found"<<std::endl;
2967 MapBlockObject *obj = block->getObject(id);
2970 derr_server<<"Error while setting sign text: "
2971 "object not found"<<std::endl;
2975 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
2977 derr_server<<"Error while setting sign text: "
2978 "object is not a sign"<<std::endl;
2982 ((SignObject*)obj)->setText(text);
2984 obj->getBlock()->setChangedFlag();
2986 else if(command == TOSERVER_SIGNNODETEXT)
2988 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2996 std::string datastring((char*)&data[2], datasize-2);
2997 std::istringstream is(datastring, std::ios_base::binary);
3000 is.read((char*)buf, 6);
3001 v3s16 p = readV3S16(buf);
3002 is.read((char*)buf, 2);
3003 u16 textlen = readU16(buf);
3005 for(u16 i=0; i<textlen; i++)
3007 is.read((char*)buf, 1);
3008 text += (char)buf[0];
3011 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3014 if(meta->typeId() != CONTENT_SIGN_WALL)
3016 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3017 signmeta->setText(text);
3019 v3s16 blockpos = getNodeBlockPos(p);
3020 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
3023 block->setChangedFlag();
3026 for(core::map<u16, RemoteClient*>::Iterator
3027 i = m_clients.getIterator();
3028 i.atEnd()==false; i++)
3030 RemoteClient *client = i.getNode()->getValue();
3031 client->SetBlockNotSent(blockpos);
3034 else if(command == TOSERVER_INVENTORY_ACTION)
3036 /*// Ignore inventory changes if in creative mode
3037 if(g_settings.getBool("creative_mode") == true)
3039 dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3043 // Strip command and create a stream
3044 std::string datastring((char*)&data[2], datasize-2);
3045 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3046 std::istringstream is(datastring, std::ios_base::binary);
3048 InventoryAction *a = InventoryAction::deSerialize(is);
3053 c.current_player = player;
3056 Handle craftresult specially if not in creative mode
3058 bool disable_action = false;
3059 if(a->getType() == IACTION_MOVE
3060 && g_settings.getBool("creative_mode") == false)
3062 IMoveAction *ma = (IMoveAction*)a;
3063 if(ma->to_inv == "current_player" &&
3064 ma->from_inv == "current_player")
3066 InventoryList *rlist = player->inventory.getList("craftresult");
3068 InventoryList *clist = player->inventory.getList("craft");
3070 InventoryList *mlist = player->inventory.getList("main");
3073 Craftresult is no longer preview if something
3076 if(ma->to_list == "craftresult"
3077 && ma->from_list != "craftresult")
3079 // If it currently is a preview, remove
3081 if(player->craftresult_is_preview)
3083 rlist->deleteItem(0);
3085 player->craftresult_is_preview = false;
3088 Crafting takes place if this condition is true.
3090 if(player->craftresult_is_preview &&
3091 ma->from_list == "craftresult")
3093 player->craftresult_is_preview = false;
3094 clist->decrementMaterials(1);
3097 If the craftresult is placed on itself, move it to
3098 main inventory instead of doing the action
3100 if(ma->to_list == "craftresult"
3101 && ma->from_list == "craftresult")
3103 disable_action = true;
3105 InventoryItem *item1 = rlist->changeItem(0, NULL);
3106 mlist->addItem(item1);
3111 if(disable_action == false)
3113 // Feed action to player inventory
3121 UpdateCrafting(player->peer_id);
3122 SendInventory(player->peer_id);
3127 dstream<<"TOSERVER_INVENTORY_ACTION: "
3128 <<"InventoryAction::deSerialize() returned NULL"
3132 else if(command == TOSERVER_CHAT_MESSAGE)
3140 std::string datastring((char*)&data[2], datasize-2);
3141 std::istringstream is(datastring, std::ios_base::binary);
3144 is.read((char*)buf, 2);
3145 u16 len = readU16(buf);
3147 std::wstring message;
3148 for(u16 i=0; i<len; i++)
3150 is.read((char*)buf, 2);
3151 message += (wchar_t)readU16(buf);
3154 // Get player name of this client
3155 std::wstring name = narrow_to_wide(player->getName());
3157 // Line to send to players
3159 // Whether to send to the player that sent the line
3160 bool send_to_sender = false;
3161 // Whether to send to other players
3162 bool send_to_others = false;
3164 // Local player gets all privileges regardless of
3165 // what's set on their account.
3166 u64 privs = getPlayerPrivs(player);
3169 std::wstring commandprefix = L"/#";
3170 if(message.substr(0, commandprefix.size()) == commandprefix)
3172 line += L"Server: ";
3174 message = message.substr(commandprefix.size());
3176 ServerCommandContext *ctx = new ServerCommandContext(
3177 str_split(message, L' '),
3183 line += processServerCommand(ctx);
3184 send_to_sender = ctx->flags & 1;
3185 send_to_others = ctx->flags & 2;
3191 if(privs & PRIV_SHOUT)
3197 send_to_others = true;
3201 line += L"Server: You are not allowed to shout";
3202 send_to_sender = true;
3208 dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3211 Send the message to clients
3213 for(core::map<u16, RemoteClient*>::Iterator
3214 i = m_clients.getIterator();
3215 i.atEnd() == false; i++)
3217 // Get client and check that it is valid
3218 RemoteClient *client = i.getNode()->getValue();
3219 assert(client->peer_id == i.getNode()->getKey());
3220 if(client->serialization_version == SER_FMT_VER_INVALID)
3224 bool sender_selected = (peer_id == client->peer_id);
3225 if(sender_selected == true && send_to_sender == false)
3227 if(sender_selected == false && send_to_others == false)
3230 SendChatMessage(client->peer_id, line);
3234 else if(command == TOSERVER_DAMAGE)
3236 if(g_settings.getBool("enable_damage"))
3238 std::string datastring((char*)&data[2], datasize-2);
3239 std::istringstream is(datastring, std::ios_base::binary);
3240 u8 damage = readU8(is);
3241 if(player->hp > damage)
3243 player->hp -= damage;
3249 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3252 v3f pos = findSpawnPos(m_env.getServerMap());
3253 player->setPosition(pos);
3255 SendMovePlayer(player);
3256 SendPlayerHP(player);
3258 //TODO: Throw items around
3262 SendPlayerHP(player);
3264 else if(command == TOSERVER_PASSWORD)
3267 [0] u16 TOSERVER_PASSWORD
3268 [2] u8[28] old password
3269 [30] u8[28] new password
3272 if(datasize != 2+PASSWORD_SIZE*2)
3274 /*char password[PASSWORD_SIZE];
3275 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3276 password[i] = data[2+i];
3277 password[PASSWORD_SIZE-1] = 0;*/
3279 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3287 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3289 char c = data[2+PASSWORD_SIZE+i];
3295 std::string playername = player->getName();
3297 if(m_authmanager.exists(playername) == false)
3299 dstream<<"Server: playername not found in authmanager"<<std::endl;
3300 // Wrong old password supplied!!
3301 SendChatMessage(peer_id, L"playername not found in authmanager");
3305 std::string checkpwd = m_authmanager.getPassword(playername);
3307 if(oldpwd != checkpwd)
3309 dstream<<"Server: invalid old password"<<std::endl;
3310 // Wrong old password supplied!!
3311 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3315 m_authmanager.setPassword(playername, newpwd);
3317 dstream<<"Server: password change successful for "<<playername
3319 SendChatMessage(peer_id, L"Password change successful");
3323 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3324 "unknown command "<<command<<std::endl;
3328 catch(SendFailedException &e)
3330 derr_server<<"Server::ProcessData(): SendFailedException: "
3336 void Server::onMapEditEvent(MapEditEvent *event)
3338 //dstream<<"Server::onMapEditEvent()"<<std::endl;
3339 if(m_ignore_map_edit_events)
3341 MapEditEvent *e = event->clone();
3342 m_unsent_map_edit_queue.push_back(e);
3345 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3347 if(id == "current_player")
3349 assert(c->current_player);
3350 return &(c->current_player->inventory);
3354 std::string id0 = fn.next(":");
3356 if(id0 == "nodemeta")
3359 p.X = stoi(fn.next(","));
3360 p.Y = stoi(fn.next(","));
3361 p.Z = stoi(fn.next(","));
3362 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3364 return meta->getInventory();
3365 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3366 <<"no metadata found"<<std::endl;
3370 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3373 void Server::inventoryModified(InventoryContext *c, std::string id)
3375 if(id == "current_player")
3377 assert(c->current_player);
3379 UpdateCrafting(c->current_player->peer_id);
3380 SendInventory(c->current_player->peer_id);
3385 std::string id0 = fn.next(":");
3387 if(id0 == "nodemeta")
3390 p.X = stoi(fn.next(","));
3391 p.Y = stoi(fn.next(","));
3392 p.Z = stoi(fn.next(","));
3393 v3s16 blockpos = getNodeBlockPos(p);
3395 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3397 meta->inventoryModified();
3399 for(core::map<u16, RemoteClient*>::Iterator
3400 i = m_clients.getIterator();
3401 i.atEnd()==false; i++)
3403 RemoteClient *client = i.getNode()->getValue();
3404 client->SetBlockNotSent(blockpos);
3410 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3413 core::list<PlayerInfo> Server::getPlayerInfo()
3415 DSTACK(__FUNCTION_NAME);
3416 JMutexAutoLock envlock(m_env_mutex);
3417 JMutexAutoLock conlock(m_con_mutex);
3419 core::list<PlayerInfo> list;
3421 core::list<Player*> players = m_env.getPlayers();
3423 core::list<Player*>::Iterator i;
3424 for(i = players.begin();
3425 i != players.end(); i++)
3429 Player *player = *i;
3432 con::Peer *peer = m_con.GetPeer(player->peer_id);
3433 // Copy info from peer to info struct
3435 info.address = peer->address;
3436 info.avg_rtt = peer->avg_rtt;
3438 catch(con::PeerNotFoundException &e)
3440 // Set dummy peer info
3442 info.address = Address(0,0,0,0,0);
3446 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3447 info.position = player->getPosition();
3449 list.push_back(info);
3456 void Server::peerAdded(con::Peer *peer)
3458 DSTACK(__FUNCTION_NAME);
3459 dout_server<<"Server::peerAdded(): peer->id="
3460 <<peer->id<<std::endl;
3463 c.type = PEER_ADDED;
3464 c.peer_id = peer->id;
3466 m_peer_change_queue.push_back(c);
3469 void Server::deletingPeer(con::Peer *peer, bool timeout)
3471 DSTACK(__FUNCTION_NAME);
3472 dout_server<<"Server::deletingPeer(): peer->id="
3473 <<peer->id<<", timeout="<<timeout<<std::endl;
3476 c.type = PEER_REMOVED;
3477 c.peer_id = peer->id;
3478 c.timeout = timeout;
3479 m_peer_change_queue.push_back(c);
3486 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3488 DSTACK(__FUNCTION_NAME);
3489 std::ostringstream os(std::ios_base::binary);
3491 writeU16(os, TOCLIENT_HP);
3495 std::string s = os.str();
3496 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3498 con.Send(peer_id, 0, data, true);
3501 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3502 const std::wstring &reason)
3504 DSTACK(__FUNCTION_NAME);
3505 std::ostringstream os(std::ios_base::binary);
3507 writeU16(os, TOCLIENT_ACCESS_DENIED);
3508 os<<serializeWideString(reason);
3511 std::string s = os.str();
3512 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3514 con.Send(peer_id, 0, data, true);
3518 Non-static send methods
3521 void Server::SendObjectData(float dtime)
3523 DSTACK(__FUNCTION_NAME);
3525 core::map<v3s16, bool> stepped_blocks;
3527 for(core::map<u16, RemoteClient*>::Iterator
3528 i = m_clients.getIterator();
3529 i.atEnd() == false; i++)
3531 u16 peer_id = i.getNode()->getKey();
3532 RemoteClient *client = i.getNode()->getValue();
3533 assert(client->peer_id == peer_id);
3535 if(client->serialization_version == SER_FMT_VER_INVALID)
3538 client->SendObjectData(this, dtime, stepped_blocks);
3542 void Server::SendPlayerInfos()
3544 DSTACK(__FUNCTION_NAME);
3546 //JMutexAutoLock envlock(m_env_mutex);
3548 // Get connected players
3549 core::list<Player*> players = m_env.getPlayers(true);
3551 u32 player_count = players.getSize();
3552 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3554 SharedBuffer<u8> data(datasize);
3555 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3558 core::list<Player*>::Iterator i;
3559 for(i = players.begin();
3560 i != players.end(); i++)
3562 Player *player = *i;
3564 /*dstream<<"Server sending player info for player with "
3565 "peer_id="<<player->peer_id<<std::endl;*/
3567 writeU16(&data[start], player->peer_id);
3568 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3569 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3570 start += 2+PLAYERNAME_SIZE;
3573 //JMutexAutoLock conlock(m_con_mutex);
3576 m_con.SendToAll(0, data, true);
3579 void Server::SendInventory(u16 peer_id)
3581 DSTACK(__FUNCTION_NAME);
3583 Player* player = m_env.getPlayer(peer_id);
3590 std::ostringstream os;
3591 //os.imbue(std::locale("C"));
3593 player->inventory.serialize(os);
3595 std::string s = os.str();
3597 SharedBuffer<u8> data(s.size()+2);
3598 writeU16(&data[0], TOCLIENT_INVENTORY);
3599 memcpy(&data[2], s.c_str(), s.size());
3602 m_con.Send(peer_id, 0, data, true);
3605 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3607 DSTACK(__FUNCTION_NAME);
3609 std::ostringstream os(std::ios_base::binary);
3613 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3614 os.write((char*)buf, 2);
3617 writeU16(buf, message.size());
3618 os.write((char*)buf, 2);
3621 for(u32 i=0; i<message.size(); i++)
3625 os.write((char*)buf, 2);
3629 std::string s = os.str();
3630 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3632 m_con.Send(peer_id, 0, data, true);
3635 void Server::BroadcastChatMessage(const std::wstring &message)
3637 for(core::map<u16, RemoteClient*>::Iterator
3638 i = m_clients.getIterator();
3639 i.atEnd() == false; i++)
3641 // Get client and check that it is valid
3642 RemoteClient *client = i.getNode()->getValue();
3643 assert(client->peer_id == i.getNode()->getKey());
3644 if(client->serialization_version == SER_FMT_VER_INVALID)
3647 SendChatMessage(client->peer_id, message);
3651 void Server::SendPlayerHP(Player *player)
3653 SendHP(m_con, player->peer_id, player->hp);
3656 void Server::SendMovePlayer(Player *player)
3658 DSTACK(__FUNCTION_NAME);
3659 std::ostringstream os(std::ios_base::binary);
3661 writeU16(os, TOCLIENT_MOVE_PLAYER);
3662 writeV3F1000(os, player->getPosition());
3663 writeF1000(os, player->getPitch());
3664 writeF1000(os, player->getYaw());
3667 v3f pos = player->getPosition();
3668 f32 pitch = player->getPitch();
3669 f32 yaw = player->getYaw();
3670 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3671 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3678 std::string s = os.str();
3679 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3681 m_con.Send(player->peer_id, 0, data, true);
3684 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3685 core::list<u16> *far_players, float far_d_nodes)
3687 float maxd = far_d_nodes*BS;
3688 v3f p_f = intToFloat(p, BS);
3692 SharedBuffer<u8> reply(replysize);
3693 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3694 writeS16(&reply[2], p.X);
3695 writeS16(&reply[4], p.Y);
3696 writeS16(&reply[6], p.Z);
3698 for(core::map<u16, RemoteClient*>::Iterator
3699 i = m_clients.getIterator();
3700 i.atEnd() == false; i++)
3702 // Get client and check that it is valid
3703 RemoteClient *client = i.getNode()->getValue();
3704 assert(client->peer_id == i.getNode()->getKey());
3705 if(client->serialization_version == SER_FMT_VER_INVALID)
3708 // Don't send if it's the same one
3709 if(client->peer_id == ignore_id)
3715 Player *player = m_env.getPlayer(client->peer_id);
3718 // If player is far away, only set modified blocks not sent
3719 v3f player_pos = player->getPosition();
3720 if(player_pos.getDistanceFrom(p_f) > maxd)
3722 far_players->push_back(client->peer_id);
3729 m_con.Send(client->peer_id, 0, reply, true);
3733 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3734 core::list<u16> *far_players, float far_d_nodes)
3736 float maxd = far_d_nodes*BS;
3737 v3f p_f = intToFloat(p, BS);
3739 for(core::map<u16, RemoteClient*>::Iterator
3740 i = m_clients.getIterator();
3741 i.atEnd() == false; i++)
3743 // Get client and check that it is valid
3744 RemoteClient *client = i.getNode()->getValue();
3745 assert(client->peer_id == i.getNode()->getKey());
3746 if(client->serialization_version == SER_FMT_VER_INVALID)
3749 // Don't send if it's the same one
3750 if(client->peer_id == ignore_id)
3756 Player *player = m_env.getPlayer(client->peer_id);
3759 // If player is far away, only set modified blocks not sent
3760 v3f player_pos = player->getPosition();
3761 if(player_pos.getDistanceFrom(p_f) > maxd)
3763 far_players->push_back(client->peer_id);
3770 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3771 SharedBuffer<u8> reply(replysize);
3772 writeU16(&reply[0], TOCLIENT_ADDNODE);
3773 writeS16(&reply[2], p.X);
3774 writeS16(&reply[4], p.Y);
3775 writeS16(&reply[6], p.Z);
3776 n.serialize(&reply[8], client->serialization_version);
3779 m_con.Send(client->peer_id, 0, reply, true);
3783 void Server::setBlockNotSent(v3s16 p)
3785 for(core::map<u16, RemoteClient*>::Iterator
3786 i = m_clients.getIterator();
3787 i.atEnd()==false; i++)
3789 RemoteClient *client = i.getNode()->getValue();
3790 client->SetBlockNotSent(p);
3794 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3796 DSTACK(__FUNCTION_NAME);
3798 v3s16 p = block->getPos();
3802 bool completely_air = true;
3803 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3804 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3805 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3807 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3809 completely_air = false;
3810 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3815 dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3817 dstream<<"[completely air] ";
3822 Create a packet with the block in the right format
3825 std::ostringstream os(std::ios_base::binary);
3826 block->serialize(os, ver);
3827 std::string s = os.str();
3828 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3830 u32 replysize = 8 + blockdata.getSize();
3831 SharedBuffer<u8> reply(replysize);
3832 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3833 writeS16(&reply[2], p.X);
3834 writeS16(&reply[4], p.Y);
3835 writeS16(&reply[6], p.Z);
3836 memcpy(&reply[8], *blockdata, blockdata.getSize());
3838 /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3839 <<": \tpacket size: "<<replysize<<std::endl;*/
3844 m_con.Send(peer_id, 1, reply, true);
3847 void Server::SendBlocks(float dtime)
3849 DSTACK(__FUNCTION_NAME);
3851 JMutexAutoLock envlock(m_env_mutex);
3852 JMutexAutoLock conlock(m_con_mutex);
3854 //TimeTaker timer("Server::SendBlocks");
3856 core::array<PrioritySortedBlockTransfer> queue;
3858 s32 total_sending = 0;
3861 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
3863 for(core::map<u16, RemoteClient*>::Iterator
3864 i = m_clients.getIterator();
3865 i.atEnd() == false; i++)
3867 RemoteClient *client = i.getNode()->getValue();
3868 assert(client->peer_id == i.getNode()->getKey());
3870 total_sending += client->SendingCount();
3872 if(client->serialization_version == SER_FMT_VER_INVALID)
3875 client->GetNextBlocks(this, dtime, queue);
3880 // Lowest priority number comes first.
3881 // Lowest is most important.
3884 for(u32 i=0; i<queue.size(); i++)
3886 //TODO: Calculate limit dynamically
3887 if(total_sending >= g_settings.getS32
3888 ("max_simultaneous_block_sends_server_total"))
3891 PrioritySortedBlockTransfer q = queue[i];
3893 MapBlock *block = NULL;
3896 block = m_env.getMap().getBlockNoCreate(q.pos);
3898 catch(InvalidPositionException &e)
3903 RemoteClient *client = getClient(q.peer_id);
3905 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3907 client->SentBlock(q.pos);
3917 void Server::UpdateCrafting(u16 peer_id)
3919 DSTACK(__FUNCTION_NAME);
3921 Player* player = m_env.getPlayer(peer_id);
3925 Calculate crafting stuff
3927 if(g_settings.getBool("creative_mode") == false)
3929 InventoryList *clist = player->inventory.getList("craft");
3930 InventoryList *rlist = player->inventory.getList("craftresult");
3932 if(rlist->getUsedSlots() == 0)
3933 player->craftresult_is_preview = true;
3935 if(rlist && player->craftresult_is_preview)
3937 rlist->clearItems();
3939 if(clist && rlist && player->craftresult_is_preview)
3941 InventoryItem *items[9];
3942 for(u16 i=0; i<9; i++)
3944 items[i] = clist->getItem(i);
3947 // Get result of crafting grid
3948 InventoryItem *result = craft_get_result(items);
3950 rlist->addItem(result);
3953 } // if creative_mode == false
3956 RemoteClient* Server::getClient(u16 peer_id)
3958 DSTACK(__FUNCTION_NAME);
3959 //JMutexAutoLock lock(m_con_mutex);
3960 core::map<u16, RemoteClient*>::Node *n;
3961 n = m_clients.find(peer_id);
3962 // A client should exist for all peers
3964 return n->getValue();
3967 std::wstring Server::getStatusString()
3969 std::wostringstream os(std::ios_base::binary);
3972 os<<L"version="<<narrow_to_wide(VERSION_STRING);
3974 os<<L", uptime="<<m_uptime.get();
3975 // Information about clients
3977 for(core::map<u16, RemoteClient*>::Iterator
3978 i = m_clients.getIterator();
3979 i.atEnd() == false; i++)
3981 // Get client and check that it is valid
3982 RemoteClient *client = i.getNode()->getValue();
3983 assert(client->peer_id == i.getNode()->getKey());
3984 if(client->serialization_version == SER_FMT_VER_INVALID)
3987 Player *player = m_env.getPlayer(client->peer_id);
3988 // Get name of player
3989 std::wstring name = L"unknown";
3991 name = narrow_to_wide(player->getName());
3992 // Add name to information string
3996 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
3997 os<<" WARNING: Map saving is disabled."<<std::endl;
4001 v3f findSpawnPos(ServerMap &map)
4003 //return v3f(50,50,50)*BS;
4006 s16 groundheight = 0;
4009 nodepos = v2s16(0,0);
4014 // Try to find a good place a few times
4015 for(s32 i=0; i<1000; i++)
4018 // We're going to try to throw the player to this position
4019 nodepos = v2s16(-range + (myrand()%(range*2)),
4020 -range + (myrand()%(range*2)));
4021 v2s16 sectorpos = getNodeSectorPos(nodepos);
4022 // Get sector (NOTE: Don't get because it's slow)
4023 //m_env.getMap().emergeSector(sectorpos);
4024 // Get ground height at point (fallbacks to heightmap function)
4025 groundheight = map.findGroundLevel(nodepos);
4026 // Don't go underwater
4027 if(groundheight < WATER_LEVEL)
4029 //dstream<<"-> Underwater"<<std::endl;
4032 // Don't go to high places
4033 if(groundheight > WATER_LEVEL + 4)
4035 //dstream<<"-> Underwater"<<std::endl;
4039 // Found a good place
4040 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4045 // If no suitable place was not found, go above water at least.
4046 if(groundheight < WATER_LEVEL)
4047 groundheight = WATER_LEVEL;
4049 return intToFloat(v3s16(
4056 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4059 Try to get an existing player
4061 Player *player = m_env.getPlayer(name);
4064 // If player is already connected, cancel
4065 if(player->peer_id != 0)
4067 dstream<<"emergePlayer(): Player already connected"<<std::endl;
4072 player->peer_id = peer_id;
4074 // Reset inventory to creative if in creative mode
4075 if(g_settings.getBool("creative_mode"))
4077 craft_set_creative_inventory(player);
4084 If player with the wanted peer_id already exists, cancel.
4086 if(m_env.getPlayer(peer_id) != NULL)
4088 dstream<<"emergePlayer(): Player with wrong name but same"
4089 " peer_id already exists"<<std::endl;
4097 player = new ServerRemotePlayer();
4098 //player->peer_id = c.peer_id;
4099 //player->peer_id = PEER_ID_INEXISTENT;
4100 player->peer_id = peer_id;
4101 player->updateName(name);
4102 m_authmanager.add(name);
4103 m_authmanager.setPassword(name, password);
4104 m_authmanager.setPrivs(name,
4105 stringToPrivs(g_settings.get("default_privs")));
4111 dstream<<"Server: Finding spawn place for player \""
4112 <<player->getName()<<"\""<<std::endl;
4114 v3f pos = findSpawnPos(m_env.getServerMap());
4116 player->setPosition(pos);
4119 Add player to environment
4122 m_env.addPlayer(player);
4125 Add stuff to inventory
4128 if(g_settings.getBool("creative_mode"))
4130 craft_set_creative_inventory(player);
4132 else if(g_settings.getBool("give_initial_stuff"))
4134 craft_give_initial_stuff(player);
4139 } // create new player
4142 void Server::handlePeerChange(PeerChange &c)
4144 JMutexAutoLock envlock(m_env_mutex);
4145 JMutexAutoLock conlock(m_con_mutex);
4147 if(c.type == PEER_ADDED)
4154 core::map<u16, RemoteClient*>::Node *n;
4155 n = m_clients.find(c.peer_id);
4156 // The client shouldn't already exist
4160 RemoteClient *client = new RemoteClient();
4161 client->peer_id = c.peer_id;
4162 m_clients.insert(client->peer_id, client);
4165 else if(c.type == PEER_REMOVED)
4172 core::map<u16, RemoteClient*>::Node *n;
4173 n = m_clients.find(c.peer_id);
4174 // The client should exist
4178 Mark objects to be not known by the client
4180 RemoteClient *client = n->getValue();
4182 for(core::map<u16, bool>::Iterator
4183 i = client->m_known_objects.getIterator();
4184 i.atEnd()==false; i++)
4187 u16 id = i.getNode()->getKey();
4188 ServerActiveObject* obj = m_env.getActiveObject(id);
4190 if(obj && obj->m_known_by_count > 0)
4191 obj->m_known_by_count--;
4194 // Collect information about leaving in chat
4195 std::wstring message;
4197 std::wstring name = L"unknown";
4198 Player *player = m_env.getPlayer(c.peer_id);
4200 name = narrow_to_wide(player->getName());
4204 message += L" left game";
4206 message += L" (timed out)";
4211 m_env.removePlayer(c.peer_id);
4214 // Set player client disconnected
4216 Player *player = m_env.getPlayer(c.peer_id);
4218 player->peer_id = 0;
4222 delete m_clients[c.peer_id];
4223 m_clients.remove(c.peer_id);
4225 // Send player info to all remaining clients
4228 // Send leave chat message to all remaining clients
4229 BroadcastChatMessage(message);
4238 void Server::handlePeerChanges()
4240 while(m_peer_change_queue.size() > 0)
4242 PeerChange c = m_peer_change_queue.pop_front();
4244 dout_server<<"Server: Handling peer change: "
4245 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4248 handlePeerChange(c);
4252 u64 Server::getPlayerPrivs(Player *player)
4256 std::string playername = player->getName();
4257 // Local player gets all privileges regardless of
4258 // what's set on their account.
4259 if(g_settings.get("name") == playername)
4265 return getPlayerAuthPrivs(playername);
4269 void dedicated_server_loop(Server &server, bool &kill)
4271 DSTACK(__FUNCTION_NAME);
4273 dstream<<DTIME<<std::endl;
4274 dstream<<"========================"<<std::endl;
4275 dstream<<"Running dedicated server"<<std::endl;
4276 dstream<<"========================"<<std::endl;
4279 IntervalLimiter m_profiler_interval;
4283 // This is kind of a hack but can be done like this
4284 // because server.step() is very light
4286 ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4291 if(server.getShutdownRequested() || kill)
4293 dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4300 float profiler_print_interval =
4301 g_settings.getFloat("profiler_print_interval");
4302 if(profiler_print_interval != 0)
4304 if(m_profiler_interval.step(0.030, profiler_print_interval))
4306 dstream<<"Profiler:"<<std::endl;
4307 g_profiler.print(dstream);
4315 static int counter = 0;
4321 core::list<PlayerInfo> list = server.getPlayerInfo();
4322 core::list<PlayerInfo>::Iterator i;
4323 static u32 sum_old = 0;
4324 u32 sum = PIChecksum(list);
4327 dstream<<DTIME<<"Player info:"<<std::endl;
4328 for(i=list.begin(); i!=list.end(); i++)
4330 i->PrintLine(&dstream);