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 // Unload unused data (delete from memory)
1835 m_env.getMap().unloadUnusedData(
1836 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);
1860 void Server::Receive()
1862 DSTACK(__FUNCTION_NAME);
1863 u32 data_maxsize = 10000;
1864 Buffer<u8> data(data_maxsize);
1869 JMutexAutoLock conlock(m_con_mutex);
1870 datasize = m_con.Receive(peer_id, *data, data_maxsize);
1873 // This has to be called so that the client list gets synced
1874 // with the peer list of the connection
1875 handlePeerChanges();
1877 ProcessData(*data, datasize, peer_id);
1879 catch(con::InvalidIncomingDataException &e)
1881 derr_server<<"Server::Receive(): "
1882 "InvalidIncomingDataException: what()="
1883 <<e.what()<<std::endl;
1885 catch(con::PeerNotFoundException &e)
1887 //NOTE: This is not needed anymore
1889 // The peer has been disconnected.
1890 // Find the associated player and remove it.
1892 /*JMutexAutoLock envlock(m_env_mutex);
1894 dout_server<<"ServerThread: peer_id="<<peer_id
1895 <<" has apparently closed connection. "
1896 <<"Removing player."<<std::endl;
1898 m_env.removePlayer(peer_id);*/
1902 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1904 DSTACK(__FUNCTION_NAME);
1905 // Environment is locked first.
1906 JMutexAutoLock envlock(m_env_mutex);
1907 JMutexAutoLock conlock(m_con_mutex);
1911 peer = m_con.GetPeer(peer_id);
1913 catch(con::PeerNotFoundException &e)
1915 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1916 <<peer_id<<" not found"<<std::endl;
1920 u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1928 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1930 if(command == TOSERVER_INIT)
1932 // [0] u16 TOSERVER_INIT
1933 // [2] u8 SER_FMT_VER_HIGHEST
1934 // [3] u8[20] player_name
1935 // [23] u8[28] password <--- can be sent without this, from old versions
1937 if(datasize < 2+1+PLAYERNAME_SIZE)
1940 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1941 <<peer->id<<std::endl;
1943 // First byte after command is maximum supported
1944 // serialization version
1945 u8 client_max = data[2];
1946 u8 our_max = SER_FMT_VER_HIGHEST;
1947 // Use the highest version supported by both
1948 u8 deployed = core::min_(client_max, our_max);
1949 // If it's lower than the lowest supported, give up.
1950 if(deployed < SER_FMT_VER_LOWEST)
1951 deployed = SER_FMT_VER_INVALID;
1953 //peer->serialization_version = deployed;
1954 getClient(peer->id)->pending_serialization_version = deployed;
1956 if(deployed == SER_FMT_VER_INVALID)
1958 derr_server<<DTIME<<"Server: Cannot negotiate "
1959 "serialization version with peer "
1960 <<peer_id<<std::endl;
1969 char playername[PLAYERNAME_SIZE];
1970 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1972 playername[i] = data[3+i];
1974 playername[PLAYERNAME_SIZE-1] = 0;
1976 if(playername[0]=='\0')
1978 derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
1979 SendAccessDenied(m_con, peer_id,
1984 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1986 derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
1987 SendAccessDenied(m_con, peer_id,
1988 L"Name contains unallowed characters");
1993 char password[PASSWORD_SIZE];
1994 if(datasize == 2+1+PLAYERNAME_SIZE)
1996 // old version - assume blank password
2001 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2003 password[i] = data[23+i];
2005 password[PASSWORD_SIZE-1] = 0;
2008 std::string checkpwd;
2009 if(m_authmanager.exists(playername))
2011 checkpwd = m_authmanager.getPassword(playername);
2015 checkpwd = g_settings.get("default_password");
2018 if(password != checkpwd && checkpwd != "")
2020 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2021 <<": supplied invalid password for "
2022 <<playername<<std::endl;
2023 SendAccessDenied(m_con, peer_id, L"Invalid password");
2027 // Add player to auth manager
2028 if(m_authmanager.exists(playername) == false)
2030 derr_server<<DTIME<<"Server: adding player "<<playername
2031 <<" to auth manager"<<std::endl;
2032 m_authmanager.add(playername);
2033 m_authmanager.setPassword(playername, checkpwd);
2034 m_authmanager.setPrivs(playername,
2035 stringToPrivs(g_settings.get("default_privs")));
2036 m_authmanager.save();
2040 Player *player = emergePlayer(playername, password, peer_id);
2044 // DEBUG: Test serialization
2045 std::ostringstream test_os;
2046 player->serialize(test_os);
2047 dstream<<"Player serialization test: \""<<test_os.str()
2049 std::istringstream test_is(test_os.str());
2050 player->deSerialize(test_is);
2053 // If failed, cancel
2056 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2057 <<": failed to emerge player"<<std::endl;
2062 // If a client is already connected to the player, cancel
2063 if(player->peer_id != 0)
2065 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2066 <<" tried to connect to "
2067 "an already connected player (peer_id="
2068 <<player->peer_id<<")"<<std::endl;
2071 // Set client of player
2072 player->peer_id = peer_id;
2075 // Check if player doesn't exist
2077 throw con::InvalidIncomingDataException
2078 ("Server::ProcessData(): INIT: Player doesn't exist");
2080 /*// update name if it was supplied
2081 if(datasize >= 20+3)
2084 player->updateName((const char*)&data[3]);
2088 Answer with a TOCLIENT_INIT
2091 SharedBuffer<u8> reply(2+1+6+8);
2092 writeU16(&reply[0], TOCLIENT_INIT);
2093 writeU8(&reply[2], deployed);
2094 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2095 writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2098 m_con.Send(peer_id, 0, reply, true);
2102 Send complete position information
2104 SendMovePlayer(player);
2109 if(command == TOSERVER_INIT2)
2111 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2112 <<peer->id<<std::endl;
2115 getClient(peer->id)->serialization_version
2116 = getClient(peer->id)->pending_serialization_version;
2119 Send some initialization data
2122 // Send player info to all players
2125 // Send inventory to player
2126 UpdateCrafting(peer->id);
2127 SendInventory(peer->id);
2131 Player *player = m_env.getPlayer(peer_id);
2132 SendPlayerHP(player);
2137 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2138 m_env.getTimeOfDay());
2139 m_con.Send(peer->id, 0, data, true);
2142 // Send information about server to player in chat
2143 SendChatMessage(peer_id, getStatusString());
2145 // Send information about joining in chat
2147 std::wstring name = L"unknown";
2148 Player *player = m_env.getPlayer(peer_id);
2150 name = narrow_to_wide(player->getName());
2152 std::wstring message;
2155 message += L" joined game";
2156 BroadcastChatMessage(message);
2162 if(peer_ser_ver == SER_FMT_VER_INVALID)
2164 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2165 " serialization format invalid or not initialized."
2166 " Skipping incoming command="<<command<<std::endl;
2170 Player *player = m_env.getPlayer(peer_id);
2173 derr_server<<"Server::ProcessData(): Cancelling: "
2174 "No player for peer_id="<<peer_id
2178 if(command == TOSERVER_PLAYERPOS)
2180 if(datasize < 2+12+12+4+4)
2184 v3s32 ps = readV3S32(&data[start+2]);
2185 v3s32 ss = readV3S32(&data[start+2+12]);
2186 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2187 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2188 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2189 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2190 pitch = wrapDegrees(pitch);
2191 yaw = wrapDegrees(yaw);
2192 player->setPosition(position);
2193 player->setSpeed(speed);
2194 player->setPitch(pitch);
2195 player->setYaw(yaw);
2197 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2198 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2199 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2201 else if(command == TOSERVER_GOTBLOCKS)
2214 u16 count = data[2];
2215 for(u16 i=0; i<count; i++)
2217 if((s16)datasize < 2+1+(i+1)*6)
2218 throw con::InvalidIncomingDataException
2219 ("GOTBLOCKS length is too short");
2220 v3s16 p = readV3S16(&data[2+1+i*6]);
2221 /*dstream<<"Server: GOTBLOCKS ("
2222 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2223 RemoteClient *client = getClient(peer_id);
2224 client->GotBlock(p);
2227 else if(command == TOSERVER_DELETEDBLOCKS)
2240 u16 count = data[2];
2241 for(u16 i=0; i<count; i++)
2243 if((s16)datasize < 2+1+(i+1)*6)
2244 throw con::InvalidIncomingDataException
2245 ("DELETEDBLOCKS length is too short");
2246 v3s16 p = readV3S16(&data[2+1+i*6]);
2247 /*dstream<<"Server: DELETEDBLOCKS ("
2248 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2249 RemoteClient *client = getClient(peer_id);
2250 client->SetBlockNotSent(p);
2253 else if(command == TOSERVER_CLICK_OBJECT)
2258 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2263 [2] u8 button (0=left, 1=right)
2268 u8 button = readU8(&data[2]);
2270 p.X = readS16(&data[3]);
2271 p.Y = readS16(&data[5]);
2272 p.Z = readS16(&data[7]);
2273 s16 id = readS16(&data[9]);
2274 //u16 item_i = readU16(&data[11]);
2276 MapBlock *block = NULL;
2279 block = m_env.getMap().getBlockNoCreate(p);
2281 catch(InvalidPositionException &e)
2283 derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2287 MapBlockObject *obj = block->getObject(id);
2291 derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2295 //TODO: Check that object is reasonably close
2300 InventoryList *ilist = player->inventory.getList("main");
2301 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2304 // Skip if inventory has no free space
2305 if(ilist->getUsedSlots() == ilist->getSize())
2307 dout_server<<"Player inventory has no free space"<<std::endl;
2312 Create the inventory item
2314 InventoryItem *item = NULL;
2315 // If it is an item-object, take the item from it
2316 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2318 item = ((ItemObject*)obj)->createInventoryItem();
2320 // Else create an item of the object
2323 item = new MapBlockObjectItem
2324 (obj->getInventoryString());
2327 // Add to inventory and send inventory
2328 ilist->addItem(item);
2329 UpdateCrafting(player->peer_id);
2330 SendInventory(player->peer_id);
2333 // Remove from block
2334 block->removeObject(id);
2337 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2342 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2348 [2] u8 button (0=left, 1=right)
2352 u8 button = readU8(&data[2]);
2353 u16 id = readS16(&data[3]);
2354 u16 item_i = readU16(&data[11]);
2356 ServerActiveObject *obj = m_env.getActiveObject(id);
2360 derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2365 //TODO: Check that object is reasonably close
2367 // Left click, pick object up (usually)
2370 InventoryList *ilist = player->inventory.getList("main");
2371 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2374 // Skip if inventory has no free space
2375 if(ilist->getUsedSlots() == ilist->getSize())
2377 dout_server<<"Player inventory has no free space"<<std::endl;
2381 // Skip if object has been removed
2386 Create the inventory item
2388 InventoryItem *item = obj->createPickedUpItem();
2392 // Add to inventory and send inventory
2393 ilist->addItem(item);
2394 UpdateCrafting(player->peer_id);
2395 SendInventory(player->peer_id);
2397 // Remove object from environment
2398 obj->m_removed = true;
2403 Item cannot be picked up. Punch it instead.
2406 ToolItem *titem = NULL;
2407 std::string toolname = "";
2409 InventoryList *mlist = player->inventory.getList("main");
2412 InventoryItem *item = mlist->getItem(item_i);
2413 if(item && (std::string)item->getName() == "ToolItem")
2415 titem = (ToolItem*)item;
2416 toolname = titem->getToolName();
2420 v3f playerpos = player->getPosition();
2421 v3f objpos = obj->getBasePosition();
2422 v3f dir = (objpos - playerpos).normalize();
2424 u16 wear = obj->punch(toolname, dir);
2428 bool weared_out = titem->addWear(wear);
2430 mlist->deleteItem(item_i);
2431 SendInventory(player->peer_id);
2437 else if(command == TOSERVER_GROUND_ACTION)
2445 [3] v3s16 nodepos_undersurface
2446 [9] v3s16 nodepos_abovesurface
2451 2: stop digging (all parameters ignored)
2452 3: digging completed
2454 u8 action = readU8(&data[2]);
2456 p_under.X = readS16(&data[3]);
2457 p_under.Y = readS16(&data[5]);
2458 p_under.Z = readS16(&data[7]);
2460 p_over.X = readS16(&data[9]);
2461 p_over.Y = readS16(&data[11]);
2462 p_over.Z = readS16(&data[13]);
2463 u16 item_i = readU16(&data[15]);
2465 //TODO: Check that target is reasonably close
2473 NOTE: This can be used in the future to check if
2474 somebody is cheating, by checking the timing.
2481 else if(action == 2)
2484 RemoteClient *client = getClient(peer->id);
2485 JMutexAutoLock digmutex(client->m_dig_mutex);
2486 client->m_dig_tool_item = -1;
2491 3: Digging completed
2493 else if(action == 3)
2495 // Mandatory parameter; actually used for nothing
2496 core::map<v3s16, MapBlock*> modified_blocks;
2498 u8 material = CONTENT_IGNORE;
2499 u8 mineral = MINERAL_NONE;
2501 bool cannot_remove_node = false;
2505 MapNode n = m_env.getMap().getNode(p_under);
2507 mineral = n.getMineral();
2508 // Get material at position
2510 // If not yet cancelled
2511 if(cannot_remove_node == false)
2513 // If it's not diggable, do nothing
2514 if(content_diggable(material) == false)
2516 derr_server<<"Server: Not finishing digging: "
2517 <<"Node not diggable"
2519 cannot_remove_node = true;
2522 // If not yet cancelled
2523 if(cannot_remove_node == false)
2525 // Get node metadata
2526 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2527 if(meta && meta->nodeRemovalDisabled() == true)
2529 derr_server<<"Server: Not finishing digging: "
2530 <<"Node metadata disables removal"
2532 cannot_remove_node = true;
2536 catch(InvalidPositionException &e)
2538 derr_server<<"Server: Not finishing digging: Node not found."
2539 <<" Adding block to emerge queue."
2541 m_emerge_queue.addBlock(peer_id,
2542 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2543 cannot_remove_node = true;
2546 // Make sure the player is allowed to do it
2547 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2549 dstream<<"Player "<<player->getName()<<" cannot remove node"
2550 <<" because privileges are "<<getPlayerPrivs(player)
2552 cannot_remove_node = true;
2556 If node can't be removed, set block to be re-sent to
2559 if(cannot_remove_node)
2561 derr_server<<"Server: Not finishing digging."<<std::endl;
2563 // Client probably has wrong data.
2564 // Set block not sent, so that client will get
2566 dstream<<"Client "<<peer_id<<" tried to dig "
2567 <<"node; but node cannot be removed."
2568 <<" setting MapBlock not sent."<<std::endl;
2569 RemoteClient *client = getClient(peer_id);
2570 v3s16 blockpos = getNodeBlockPos(p_under);
2571 client->SetBlockNotSent(blockpos);
2577 Send the removal to all close-by players.
2578 - If other player is close, send REMOVENODE
2579 - Otherwise set blocks not sent
2581 core::list<u16> far_players;
2582 sendRemoveNode(p_under, peer_id, &far_players, 30);
2585 Update and send inventory
2588 if(g_settings.getBool("creative_mode") == false)
2593 InventoryList *mlist = player->inventory.getList("main");
2596 InventoryItem *item = mlist->getItem(item_i);
2597 if(item && (std::string)item->getName() == "ToolItem")
2599 ToolItem *titem = (ToolItem*)item;
2600 std::string toolname = titem->getToolName();
2602 // Get digging properties for material and tool
2603 DiggingProperties prop =
2604 getDiggingProperties(material, toolname);
2606 if(prop.diggable == false)
2608 derr_server<<"Server: WARNING: Player digged"
2609 <<" with impossible material + tool"
2610 <<" combination"<<std::endl;
2613 bool weared_out = titem->addWear(prop.wear);
2617 mlist->deleteItem(item_i);
2623 Add dug item to inventory
2626 InventoryItem *item = NULL;
2628 if(mineral != MINERAL_NONE)
2629 item = getDiggedMineralItem(mineral);
2634 std::string &dug_s = content_features(material).dug_item;
2637 std::istringstream is(dug_s, std::ios::binary);
2638 item = InventoryItem::deSerialize(is);
2644 // Add a item to inventory
2645 player->inventory.addItem("main", item);
2648 UpdateCrafting(player->peer_id);
2649 SendInventory(player->peer_id);
2655 (this takes some time so it is done after the quick stuff)
2658 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2660 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2663 Set blocks not sent to far players
2665 for(core::list<u16>::Iterator
2666 i = far_players.begin();
2667 i != far_players.end(); i++)
2670 RemoteClient *client = getClient(peer_id);
2673 client->SetBlocksNotSent(modified_blocks);
2680 else if(action == 1)
2683 InventoryList *ilist = player->inventory.getList("main");
2688 InventoryItem *item = ilist->getItem(item_i);
2690 // If there is no item, it is not possible to add it anywhere
2695 Handle material items
2697 if(std::string("MaterialItem") == item->getName())
2700 // Don't add a node if this is not a free space
2701 MapNode n2 = m_env.getMap().getNode(p_over);
2702 bool no_enough_privs =
2703 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2705 dstream<<"Player "<<player->getName()<<" cannot add node"
2706 <<" because privileges are "<<getPlayerPrivs(player)
2709 if(content_buildable_to(n2.d) == false
2712 // Client probably has wrong data.
2713 // Set block not sent, so that client will get
2715 dstream<<"Client "<<peer_id<<" tried to place"
2716 <<" node in invalid position; setting"
2717 <<" MapBlock not sent."<<std::endl;
2718 RemoteClient *client = getClient(peer_id);
2719 v3s16 blockpos = getNodeBlockPos(p_over);
2720 client->SetBlockNotSent(blockpos);
2724 catch(InvalidPositionException &e)
2726 derr_server<<"Server: Ignoring ADDNODE: Node not found"
2727 <<" Adding block to emerge queue."
2729 m_emerge_queue.addBlock(peer_id,
2730 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2734 // Reset build time counter
2735 getClient(peer->id)->m_time_from_building = 0.0;
2738 MaterialItem *mitem = (MaterialItem*)item;
2740 n.d = mitem->getMaterial();
2742 // Calculate direction for wall mounted stuff
2743 if(content_features(n.d).wall_mounted)
2744 n.dir = packDir(p_under - p_over);
2746 // Calculate the direction for furnaces and chests and stuff
2747 if(content_features(n.d).param_type == CPT_FACEDIR_SIMPLE)
2749 v3f playerpos = player->getPosition();
2750 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2751 blockpos = blockpos.normalize();
2753 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2767 Send to all close-by players
2769 core::list<u16> far_players;
2770 sendAddNode(p_over, n, 0, &far_players, 30);
2775 InventoryList *ilist = player->inventory.getList("main");
2776 if(g_settings.getBool("creative_mode") == false && ilist)
2778 // Remove from inventory and send inventory
2779 if(mitem->getCount() == 1)
2780 ilist->deleteItem(item_i);
2784 UpdateCrafting(peer_id);
2785 SendInventory(peer_id);
2791 This takes some time so it is done after the quick stuff
2793 core::map<v3s16, MapBlock*> modified_blocks;
2795 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2797 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2800 Set blocks not sent to far players
2802 for(core::list<u16>::Iterator
2803 i = far_players.begin();
2804 i != far_players.end(); i++)
2807 RemoteClient *client = getClient(peer_id);
2810 client->SetBlocksNotSent(modified_blocks);
2814 Calculate special events
2817 /*if(n.d == CONTENT_MESE)
2820 for(s16 z=-1; z<=1; z++)
2821 for(s16 y=-1; y<=1; y++)
2822 for(s16 x=-1; x<=1; x++)
2829 Place other item (not a block)
2833 v3s16 blockpos = getNodeBlockPos(p_over);
2836 Check that the block is loaded so that the item
2837 can properly be added to the static list too
2839 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2842 derr_server<<"Error while placing object: "
2843 "block not found"<<std::endl;
2847 dout_server<<"Placing a miscellaneous item on map"
2850 // Calculate a position for it
2851 v3f pos = intToFloat(p_over, BS);
2853 pos.Y -= BS*0.25; // let it drop a bit
2855 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2856 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2861 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2865 derr_server<<"WARNING: item resulted in NULL object, "
2866 <<"not placing onto map"
2871 // Add the object to the environment
2872 m_env.addActiveObject(obj);
2874 dout_server<<"Placed object"<<std::endl;
2876 if(g_settings.getBool("creative_mode") == false)
2878 // Delete the right amount of items from the slot
2879 u16 dropcount = item->getDropCount();
2881 // Delete item if all gone
2882 if(item->getCount() <= dropcount)
2884 if(item->getCount() < dropcount)
2885 dstream<<"WARNING: Server: dropped more items"
2886 <<" than the slot contains"<<std::endl;
2888 InventoryList *ilist = player->inventory.getList("main");
2890 // Remove from inventory and send inventory
2891 ilist->deleteItem(item_i);
2893 // Else decrement it
2895 item->remove(dropcount);
2898 UpdateCrafting(peer_id);
2899 SendInventory(peer_id);
2907 Catch invalid actions
2911 derr_server<<"WARNING: Server: Invalid action "
2912 <<action<<std::endl;
2916 else if(command == TOSERVER_RELEASE)
2925 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2928 else if(command == TOSERVER_SIGNTEXT)
2930 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2939 std::string datastring((char*)&data[2], datasize-2);
2940 std::istringstream is(datastring, std::ios_base::binary);
2943 is.read((char*)buf, 6);
2944 v3s16 blockpos = readV3S16(buf);
2945 is.read((char*)buf, 2);
2946 s16 id = readS16(buf);
2947 is.read((char*)buf, 2);
2948 u16 textlen = readU16(buf);
2950 for(u16 i=0; i<textlen; i++)
2952 is.read((char*)buf, 1);
2953 text += (char)buf[0];
2956 MapBlock *block = NULL;
2959 block = m_env.getMap().getBlockNoCreate(blockpos);
2961 catch(InvalidPositionException &e)
2963 derr_server<<"Error while setting sign text: "
2964 "block not found"<<std::endl;
2968 MapBlockObject *obj = block->getObject(id);
2971 derr_server<<"Error while setting sign text: "
2972 "object not found"<<std::endl;
2976 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
2978 derr_server<<"Error while setting sign text: "
2979 "object is not a sign"<<std::endl;
2983 ((SignObject*)obj)->setText(text);
2985 obj->getBlock()->setChangedFlag();
2987 else if(command == TOSERVER_SIGNNODETEXT)
2989 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2997 std::string datastring((char*)&data[2], datasize-2);
2998 std::istringstream is(datastring, std::ios_base::binary);
3001 is.read((char*)buf, 6);
3002 v3s16 p = readV3S16(buf);
3003 is.read((char*)buf, 2);
3004 u16 textlen = readU16(buf);
3006 for(u16 i=0; i<textlen; i++)
3008 is.read((char*)buf, 1);
3009 text += (char)buf[0];
3012 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3015 if(meta->typeId() != CONTENT_SIGN_WALL)
3017 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3018 signmeta->setText(text);
3020 v3s16 blockpos = getNodeBlockPos(p);
3021 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
3024 block->setChangedFlag();
3027 for(core::map<u16, RemoteClient*>::Iterator
3028 i = m_clients.getIterator();
3029 i.atEnd()==false; i++)
3031 RemoteClient *client = i.getNode()->getValue();
3032 client->SetBlockNotSent(blockpos);
3035 else if(command == TOSERVER_INVENTORY_ACTION)
3037 /*// Ignore inventory changes if in creative mode
3038 if(g_settings.getBool("creative_mode") == true)
3040 dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3044 // Strip command and create a stream
3045 std::string datastring((char*)&data[2], datasize-2);
3046 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3047 std::istringstream is(datastring, std::ios_base::binary);
3049 InventoryAction *a = InventoryAction::deSerialize(is);
3054 c.current_player = player;
3057 Handle craftresult specially if not in creative mode
3059 bool disable_action = false;
3060 if(a->getType() == IACTION_MOVE
3061 && g_settings.getBool("creative_mode") == false)
3063 IMoveAction *ma = (IMoveAction*)a;
3064 if(ma->to_inv == "current_player" &&
3065 ma->from_inv == "current_player")
3067 InventoryList *rlist = player->inventory.getList("craftresult");
3069 InventoryList *clist = player->inventory.getList("craft");
3071 InventoryList *mlist = player->inventory.getList("main");
3074 Craftresult is no longer preview if something
3077 if(ma->to_list == "craftresult"
3078 && ma->from_list != "craftresult")
3080 // If it currently is a preview, remove
3082 if(player->craftresult_is_preview)
3084 rlist->deleteItem(0);
3086 player->craftresult_is_preview = false;
3089 Crafting takes place if this condition is true.
3091 if(player->craftresult_is_preview &&
3092 ma->from_list == "craftresult")
3094 player->craftresult_is_preview = false;
3095 clist->decrementMaterials(1);
3098 If the craftresult is placed on itself, move it to
3099 main inventory instead of doing the action
3101 if(ma->to_list == "craftresult"
3102 && ma->from_list == "craftresult")
3104 disable_action = true;
3106 InventoryItem *item1 = rlist->changeItem(0, NULL);
3107 mlist->addItem(item1);
3112 if(disable_action == false)
3114 // Feed action to player inventory
3122 UpdateCrafting(player->peer_id);
3123 SendInventory(player->peer_id);
3128 dstream<<"TOSERVER_INVENTORY_ACTION: "
3129 <<"InventoryAction::deSerialize() returned NULL"
3133 else if(command == TOSERVER_CHAT_MESSAGE)
3141 std::string datastring((char*)&data[2], datasize-2);
3142 std::istringstream is(datastring, std::ios_base::binary);
3145 is.read((char*)buf, 2);
3146 u16 len = readU16(buf);
3148 std::wstring message;
3149 for(u16 i=0; i<len; i++)
3151 is.read((char*)buf, 2);
3152 message += (wchar_t)readU16(buf);
3155 // Get player name of this client
3156 std::wstring name = narrow_to_wide(player->getName());
3158 // Line to send to players
3160 // Whether to send to the player that sent the line
3161 bool send_to_sender = false;
3162 // Whether to send to other players
3163 bool send_to_others = false;
3165 // Local player gets all privileges regardless of
3166 // what's set on their account.
3167 u64 privs = getPlayerPrivs(player);
3170 std::wstring commandprefix = L"/#";
3171 if(message.substr(0, commandprefix.size()) == commandprefix)
3173 line += L"Server: ";
3175 message = message.substr(commandprefix.size());
3177 ServerCommandContext *ctx = new ServerCommandContext(
3178 str_split(message, L' '),
3184 line += processServerCommand(ctx);
3185 send_to_sender = ctx->flags & 1;
3186 send_to_others = ctx->flags & 2;
3192 if(privs & PRIV_SHOUT)
3198 send_to_others = true;
3202 line += L"Server: You are not allowed to shout";
3203 send_to_sender = true;
3209 dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3212 Send the message to clients
3214 for(core::map<u16, RemoteClient*>::Iterator
3215 i = m_clients.getIterator();
3216 i.atEnd() == false; i++)
3218 // Get client and check that it is valid
3219 RemoteClient *client = i.getNode()->getValue();
3220 assert(client->peer_id == i.getNode()->getKey());
3221 if(client->serialization_version == SER_FMT_VER_INVALID)
3225 bool sender_selected = (peer_id == client->peer_id);
3226 if(sender_selected == true && send_to_sender == false)
3228 if(sender_selected == false && send_to_others == false)
3231 SendChatMessage(client->peer_id, line);
3235 else if(command == TOSERVER_DAMAGE)
3237 if(g_settings.getBool("enable_damage"))
3239 std::string datastring((char*)&data[2], datasize-2);
3240 std::istringstream is(datastring, std::ios_base::binary);
3241 u8 damage = readU8(is);
3242 if(player->hp > damage)
3244 player->hp -= damage;
3250 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3253 v3f pos = findSpawnPos(m_env.getServerMap());
3254 player->setPosition(pos);
3256 SendMovePlayer(player);
3257 SendPlayerHP(player);
3259 //TODO: Throw items around
3263 SendPlayerHP(player);
3265 else if(command == TOSERVER_PASSWORD)
3268 [0] u16 TOSERVER_PASSWORD
3269 [2] u8[28] old password
3270 [30] u8[28] new password
3273 if(datasize != 2+PASSWORD_SIZE*2)
3275 /*char password[PASSWORD_SIZE];
3276 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3277 password[i] = data[2+i];
3278 password[PASSWORD_SIZE-1] = 0;*/
3280 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3288 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3290 char c = data[2+PASSWORD_SIZE+i];
3296 std::string playername = player->getName();
3298 if(m_authmanager.exists(playername) == false)
3300 dstream<<"Server: playername not found in authmanager"<<std::endl;
3301 // Wrong old password supplied!!
3302 SendChatMessage(peer_id, L"playername not found in authmanager");
3306 std::string checkpwd = m_authmanager.getPassword(playername);
3308 if(oldpwd != checkpwd)
3310 dstream<<"Server: invalid old password"<<std::endl;
3311 // Wrong old password supplied!!
3312 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3316 m_authmanager.setPassword(playername, newpwd);
3318 dstream<<"Server: password change successful for "<<playername
3320 SendChatMessage(peer_id, L"Password change successful");
3324 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3325 "unknown command "<<command<<std::endl;
3329 catch(SendFailedException &e)
3331 derr_server<<"Server::ProcessData(): SendFailedException: "
3337 void Server::onMapEditEvent(MapEditEvent *event)
3339 dstream<<"Server::onMapEditEvent()"<<std::endl;
3340 if(m_ignore_map_edit_events)
3342 MapEditEvent *e = event->clone();
3343 m_unsent_map_edit_queue.push_back(e);
3346 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3348 if(id == "current_player")
3350 assert(c->current_player);
3351 return &(c->current_player->inventory);
3355 std::string id0 = fn.next(":");
3357 if(id0 == "nodemeta")
3360 p.X = stoi(fn.next(","));
3361 p.Y = stoi(fn.next(","));
3362 p.Z = stoi(fn.next(","));
3363 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3365 return meta->getInventory();
3366 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3367 <<"no metadata found"<<std::endl;
3371 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3374 void Server::inventoryModified(InventoryContext *c, std::string id)
3376 if(id == "current_player")
3378 assert(c->current_player);
3380 UpdateCrafting(c->current_player->peer_id);
3381 SendInventory(c->current_player->peer_id);
3386 std::string id0 = fn.next(":");
3388 if(id0 == "nodemeta")
3391 p.X = stoi(fn.next(","));
3392 p.Y = stoi(fn.next(","));
3393 p.Z = stoi(fn.next(","));
3394 v3s16 blockpos = getNodeBlockPos(p);
3396 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3398 meta->inventoryModified();
3400 for(core::map<u16, RemoteClient*>::Iterator
3401 i = m_clients.getIterator();
3402 i.atEnd()==false; i++)
3404 RemoteClient *client = i.getNode()->getValue();
3405 client->SetBlockNotSent(blockpos);
3411 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3414 core::list<PlayerInfo> Server::getPlayerInfo()
3416 DSTACK(__FUNCTION_NAME);
3417 JMutexAutoLock envlock(m_env_mutex);
3418 JMutexAutoLock conlock(m_con_mutex);
3420 core::list<PlayerInfo> list;
3422 core::list<Player*> players = m_env.getPlayers();
3424 core::list<Player*>::Iterator i;
3425 for(i = players.begin();
3426 i != players.end(); i++)
3430 Player *player = *i;
3433 con::Peer *peer = m_con.GetPeer(player->peer_id);
3434 // Copy info from peer to info struct
3436 info.address = peer->address;
3437 info.avg_rtt = peer->avg_rtt;
3439 catch(con::PeerNotFoundException &e)
3441 // Set dummy peer info
3443 info.address = Address(0,0,0,0,0);
3447 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3448 info.position = player->getPosition();
3450 list.push_back(info);
3457 void Server::peerAdded(con::Peer *peer)
3459 DSTACK(__FUNCTION_NAME);
3460 dout_server<<"Server::peerAdded(): peer->id="
3461 <<peer->id<<std::endl;
3464 c.type = PEER_ADDED;
3465 c.peer_id = peer->id;
3467 m_peer_change_queue.push_back(c);
3470 void Server::deletingPeer(con::Peer *peer, bool timeout)
3472 DSTACK(__FUNCTION_NAME);
3473 dout_server<<"Server::deletingPeer(): peer->id="
3474 <<peer->id<<", timeout="<<timeout<<std::endl;
3477 c.type = PEER_REMOVED;
3478 c.peer_id = peer->id;
3479 c.timeout = timeout;
3480 m_peer_change_queue.push_back(c);
3487 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3489 DSTACK(__FUNCTION_NAME);
3490 std::ostringstream os(std::ios_base::binary);
3492 writeU16(os, TOCLIENT_HP);
3496 std::string s = os.str();
3497 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3499 con.Send(peer_id, 0, data, true);
3502 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3503 const std::wstring &reason)
3505 DSTACK(__FUNCTION_NAME);
3506 std::ostringstream os(std::ios_base::binary);
3508 writeU16(os, TOCLIENT_ACCESS_DENIED);
3509 os<<serializeWideString(reason);
3512 std::string s = os.str();
3513 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3515 con.Send(peer_id, 0, data, true);
3519 Non-static send methods
3522 void Server::SendObjectData(float dtime)
3524 DSTACK(__FUNCTION_NAME);
3526 core::map<v3s16, bool> stepped_blocks;
3528 for(core::map<u16, RemoteClient*>::Iterator
3529 i = m_clients.getIterator();
3530 i.atEnd() == false; i++)
3532 u16 peer_id = i.getNode()->getKey();
3533 RemoteClient *client = i.getNode()->getValue();
3534 assert(client->peer_id == peer_id);
3536 if(client->serialization_version == SER_FMT_VER_INVALID)
3539 client->SendObjectData(this, dtime, stepped_blocks);
3543 void Server::SendPlayerInfos()
3545 DSTACK(__FUNCTION_NAME);
3547 //JMutexAutoLock envlock(m_env_mutex);
3549 // Get connected players
3550 core::list<Player*> players = m_env.getPlayers(true);
3552 u32 player_count = players.getSize();
3553 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3555 SharedBuffer<u8> data(datasize);
3556 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3559 core::list<Player*>::Iterator i;
3560 for(i = players.begin();
3561 i != players.end(); i++)
3563 Player *player = *i;
3565 /*dstream<<"Server sending player info for player with "
3566 "peer_id="<<player->peer_id<<std::endl;*/
3568 writeU16(&data[start], player->peer_id);
3569 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3570 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3571 start += 2+PLAYERNAME_SIZE;
3574 //JMutexAutoLock conlock(m_con_mutex);
3577 m_con.SendToAll(0, data, true);
3580 void Server::SendInventory(u16 peer_id)
3582 DSTACK(__FUNCTION_NAME);
3584 Player* player = m_env.getPlayer(peer_id);
3591 std::ostringstream os;
3592 //os.imbue(std::locale("C"));
3594 player->inventory.serialize(os);
3596 std::string s = os.str();
3598 SharedBuffer<u8> data(s.size()+2);
3599 writeU16(&data[0], TOCLIENT_INVENTORY);
3600 memcpy(&data[2], s.c_str(), s.size());
3603 m_con.Send(peer_id, 0, data, true);
3606 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3608 DSTACK(__FUNCTION_NAME);
3610 std::ostringstream os(std::ios_base::binary);
3614 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3615 os.write((char*)buf, 2);
3618 writeU16(buf, message.size());
3619 os.write((char*)buf, 2);
3622 for(u32 i=0; i<message.size(); i++)
3626 os.write((char*)buf, 2);
3630 std::string s = os.str();
3631 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3633 m_con.Send(peer_id, 0, data, true);
3636 void Server::BroadcastChatMessage(const std::wstring &message)
3638 for(core::map<u16, RemoteClient*>::Iterator
3639 i = m_clients.getIterator();
3640 i.atEnd() == false; i++)
3642 // Get client and check that it is valid
3643 RemoteClient *client = i.getNode()->getValue();
3644 assert(client->peer_id == i.getNode()->getKey());
3645 if(client->serialization_version == SER_FMT_VER_INVALID)
3648 SendChatMessage(client->peer_id, message);
3652 void Server::SendPlayerHP(Player *player)
3654 SendHP(m_con, player->peer_id, player->hp);
3657 void Server::SendMovePlayer(Player *player)
3659 DSTACK(__FUNCTION_NAME);
3660 std::ostringstream os(std::ios_base::binary);
3662 writeU16(os, TOCLIENT_MOVE_PLAYER);
3663 writeV3F1000(os, player->getPosition());
3664 writeF1000(os, player->getPitch());
3665 writeF1000(os, player->getYaw());
3668 v3f pos = player->getPosition();
3669 f32 pitch = player->getPitch();
3670 f32 yaw = player->getYaw();
3671 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3672 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3679 std::string s = os.str();
3680 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3682 m_con.Send(player->peer_id, 0, data, true);
3685 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3686 core::list<u16> *far_players, float far_d_nodes)
3688 float maxd = far_d_nodes*BS;
3689 v3f p_f = intToFloat(p, BS);
3693 SharedBuffer<u8> reply(replysize);
3694 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3695 writeS16(&reply[2], p.X);
3696 writeS16(&reply[4], p.Y);
3697 writeS16(&reply[6], p.Z);
3699 for(core::map<u16, RemoteClient*>::Iterator
3700 i = m_clients.getIterator();
3701 i.atEnd() == false; i++)
3703 // Get client and check that it is valid
3704 RemoteClient *client = i.getNode()->getValue();
3705 assert(client->peer_id == i.getNode()->getKey());
3706 if(client->serialization_version == SER_FMT_VER_INVALID)
3709 // Don't send if it's the same one
3710 if(client->peer_id == ignore_id)
3716 Player *player = m_env.getPlayer(client->peer_id);
3719 // If player is far away, only set modified blocks not sent
3720 v3f player_pos = player->getPosition();
3721 if(player_pos.getDistanceFrom(p_f) > maxd)
3723 far_players->push_back(client->peer_id);
3730 m_con.Send(client->peer_id, 0, reply, true);
3734 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3735 core::list<u16> *far_players, float far_d_nodes)
3737 float maxd = far_d_nodes*BS;
3738 v3f p_f = intToFloat(p, BS);
3740 for(core::map<u16, RemoteClient*>::Iterator
3741 i = m_clients.getIterator();
3742 i.atEnd() == false; i++)
3744 // Get client and check that it is valid
3745 RemoteClient *client = i.getNode()->getValue();
3746 assert(client->peer_id == i.getNode()->getKey());
3747 if(client->serialization_version == SER_FMT_VER_INVALID)
3750 // Don't send if it's the same one
3751 if(client->peer_id == ignore_id)
3757 Player *player = m_env.getPlayer(client->peer_id);
3760 // If player is far away, only set modified blocks not sent
3761 v3f player_pos = player->getPosition();
3762 if(player_pos.getDistanceFrom(p_f) > maxd)
3764 far_players->push_back(client->peer_id);
3771 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3772 SharedBuffer<u8> reply(replysize);
3773 writeU16(&reply[0], TOCLIENT_ADDNODE);
3774 writeS16(&reply[2], p.X);
3775 writeS16(&reply[4], p.Y);
3776 writeS16(&reply[6], p.Z);
3777 n.serialize(&reply[8], client->serialization_version);
3780 m_con.Send(client->peer_id, 0, reply, true);
3784 void Server::setBlockNotSent(v3s16 p)
3786 for(core::map<u16, RemoteClient*>::Iterator
3787 i = m_clients.getIterator();
3788 i.atEnd()==false; i++)
3790 RemoteClient *client = i.getNode()->getValue();
3791 client->SetBlockNotSent(p);
3795 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3797 DSTACK(__FUNCTION_NAME);
3799 v3s16 p = block->getPos();
3803 bool completely_air = true;
3804 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3805 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3806 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3808 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3810 completely_air = false;
3811 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3816 dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3818 dstream<<"[completely air] ";
3823 Create a packet with the block in the right format
3826 std::ostringstream os(std::ios_base::binary);
3827 block->serialize(os, ver);
3828 std::string s = os.str();
3829 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3831 u32 replysize = 8 + blockdata.getSize();
3832 SharedBuffer<u8> reply(replysize);
3833 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3834 writeS16(&reply[2], p.X);
3835 writeS16(&reply[4], p.Y);
3836 writeS16(&reply[6], p.Z);
3837 memcpy(&reply[8], *blockdata, blockdata.getSize());
3839 /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3840 <<": \tpacket size: "<<replysize<<std::endl;*/
3845 m_con.Send(peer_id, 1, reply, true);
3848 void Server::SendBlocks(float dtime)
3850 DSTACK(__FUNCTION_NAME);
3852 JMutexAutoLock envlock(m_env_mutex);
3853 JMutexAutoLock conlock(m_con_mutex);
3855 //TimeTaker timer("Server::SendBlocks");
3857 core::array<PrioritySortedBlockTransfer> queue;
3859 s32 total_sending = 0;
3862 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
3864 for(core::map<u16, RemoteClient*>::Iterator
3865 i = m_clients.getIterator();
3866 i.atEnd() == false; i++)
3868 RemoteClient *client = i.getNode()->getValue();
3869 assert(client->peer_id == i.getNode()->getKey());
3871 total_sending += client->SendingCount();
3873 if(client->serialization_version == SER_FMT_VER_INVALID)
3876 client->GetNextBlocks(this, dtime, queue);
3881 // Lowest priority number comes first.
3882 // Lowest is most important.
3885 for(u32 i=0; i<queue.size(); i++)
3887 //TODO: Calculate limit dynamically
3888 if(total_sending >= g_settings.getS32
3889 ("max_simultaneous_block_sends_server_total"))
3892 PrioritySortedBlockTransfer q = queue[i];
3894 MapBlock *block = NULL;
3897 block = m_env.getMap().getBlockNoCreate(q.pos);
3899 catch(InvalidPositionException &e)
3904 RemoteClient *client = getClient(q.peer_id);
3906 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3908 client->SentBlock(q.pos);
3918 void Server::UpdateCrafting(u16 peer_id)
3920 DSTACK(__FUNCTION_NAME);
3922 Player* player = m_env.getPlayer(peer_id);
3926 Calculate crafting stuff
3928 if(g_settings.getBool("creative_mode") == false)
3930 InventoryList *clist = player->inventory.getList("craft");
3931 InventoryList *rlist = player->inventory.getList("craftresult");
3933 if(rlist->getUsedSlots() == 0)
3934 player->craftresult_is_preview = true;
3936 if(rlist && player->craftresult_is_preview)
3938 rlist->clearItems();
3940 if(clist && rlist && player->craftresult_is_preview)
3942 InventoryItem *items[9];
3943 for(u16 i=0; i<9; i++)
3945 items[i] = clist->getItem(i);
3948 // Get result of crafting grid
3949 InventoryItem *result = craft_get_result(items);
3951 rlist->addItem(result);
3954 } // if creative_mode == false
3957 RemoteClient* Server::getClient(u16 peer_id)
3959 DSTACK(__FUNCTION_NAME);
3960 //JMutexAutoLock lock(m_con_mutex);
3961 core::map<u16, RemoteClient*>::Node *n;
3962 n = m_clients.find(peer_id);
3963 // A client should exist for all peers
3965 return n->getValue();
3968 std::wstring Server::getStatusString()
3970 std::wostringstream os(std::ios_base::binary);
3973 os<<L"version="<<narrow_to_wide(VERSION_STRING);
3975 os<<L", uptime="<<m_uptime.get();
3976 // Information about clients
3978 for(core::map<u16, RemoteClient*>::Iterator
3979 i = m_clients.getIterator();
3980 i.atEnd() == false; i++)
3982 // Get client and check that it is valid
3983 RemoteClient *client = i.getNode()->getValue();
3984 assert(client->peer_id == i.getNode()->getKey());
3985 if(client->serialization_version == SER_FMT_VER_INVALID)
3988 Player *player = m_env.getPlayer(client->peer_id);
3989 // Get name of player
3990 std::wstring name = L"unknown";
3992 name = narrow_to_wide(player->getName());
3993 // Add name to information string
3997 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
3998 os<<" WARNING: Map saving is disabled."<<std::endl;
4002 v3f findSpawnPos(ServerMap &map)
4004 //return v3f(50,50,50)*BS;
4007 s16 groundheight = 0;
4010 nodepos = v2s16(0,0);
4015 // Try to find a good place a few times
4016 for(s32 i=0; i<1000; i++)
4019 // We're going to try to throw the player to this position
4020 nodepos = v2s16(-range + (myrand()%(range*2)),
4021 -range + (myrand()%(range*2)));
4022 v2s16 sectorpos = getNodeSectorPos(nodepos);
4023 // Get sector (NOTE: Don't get because it's slow)
4024 //m_env.getMap().emergeSector(sectorpos);
4025 // Get ground height at point (fallbacks to heightmap function)
4026 groundheight = map.findGroundLevel(nodepos);
4027 // Don't go underwater
4028 if(groundheight < WATER_LEVEL)
4030 //dstream<<"-> Underwater"<<std::endl;
4033 // Don't go to high places
4034 if(groundheight > WATER_LEVEL + 4)
4036 //dstream<<"-> Underwater"<<std::endl;
4040 // Found a good place
4041 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4046 // If no suitable place was not found, go above water at least.
4047 if(groundheight < WATER_LEVEL)
4048 groundheight = WATER_LEVEL;
4050 return intToFloat(v3s16(
4057 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4060 Try to get an existing player
4062 Player *player = m_env.getPlayer(name);
4065 // If player is already connected, cancel
4066 if(player->peer_id != 0)
4068 dstream<<"emergePlayer(): Player already connected"<<std::endl;
4073 player->peer_id = peer_id;
4075 // Reset inventory to creative if in creative mode
4076 if(g_settings.getBool("creative_mode"))
4078 craft_set_creative_inventory(player);
4085 If player with the wanted peer_id already exists, cancel.
4087 if(m_env.getPlayer(peer_id) != NULL)
4089 dstream<<"emergePlayer(): Player with wrong name but same"
4090 " peer_id already exists"<<std::endl;
4098 player = new ServerRemotePlayer();
4099 //player->peer_id = c.peer_id;
4100 //player->peer_id = PEER_ID_INEXISTENT;
4101 player->peer_id = peer_id;
4102 player->updateName(name);
4103 m_authmanager.add(name);
4104 m_authmanager.setPassword(name, password);
4105 m_authmanager.setPrivs(name,
4106 stringToPrivs(g_settings.get("default_privs")));
4112 dstream<<"Server: Finding spawn place for player \""
4113 <<player->getName()<<"\""<<std::endl;
4115 v3f pos = findSpawnPos(m_env.getServerMap());
4117 player->setPosition(pos);
4120 Add player to environment
4123 m_env.addPlayer(player);
4126 Add stuff to inventory
4129 if(g_settings.getBool("creative_mode"))
4131 craft_set_creative_inventory(player);
4133 else if(g_settings.getBool("give_initial_stuff"))
4135 craft_give_initial_stuff(player);
4140 } // create new player
4143 void Server::handlePeerChange(PeerChange &c)
4145 JMutexAutoLock envlock(m_env_mutex);
4146 JMutexAutoLock conlock(m_con_mutex);
4148 if(c.type == PEER_ADDED)
4155 core::map<u16, RemoteClient*>::Node *n;
4156 n = m_clients.find(c.peer_id);
4157 // The client shouldn't already exist
4161 RemoteClient *client = new RemoteClient();
4162 client->peer_id = c.peer_id;
4163 m_clients.insert(client->peer_id, client);
4166 else if(c.type == PEER_REMOVED)
4173 core::map<u16, RemoteClient*>::Node *n;
4174 n = m_clients.find(c.peer_id);
4175 // The client should exist
4179 Mark objects to be not known by the client
4181 RemoteClient *client = n->getValue();
4183 for(core::map<u16, bool>::Iterator
4184 i = client->m_known_objects.getIterator();
4185 i.atEnd()==false; i++)
4188 u16 id = i.getNode()->getKey();
4189 ServerActiveObject* obj = m_env.getActiveObject(id);
4191 if(obj && obj->m_known_by_count > 0)
4192 obj->m_known_by_count--;
4195 // Collect information about leaving in chat
4196 std::wstring message;
4198 std::wstring name = L"unknown";
4199 Player *player = m_env.getPlayer(c.peer_id);
4201 name = narrow_to_wide(player->getName());
4205 message += L" left game";
4207 message += L" (timed out)";
4212 m_env.removePlayer(c.peer_id);
4215 // Set player client disconnected
4217 Player *player = m_env.getPlayer(c.peer_id);
4219 player->peer_id = 0;
4223 delete m_clients[c.peer_id];
4224 m_clients.remove(c.peer_id);
4226 // Send player info to all remaining clients
4229 // Send leave chat message to all remaining clients
4230 BroadcastChatMessage(message);
4239 void Server::handlePeerChanges()
4241 while(m_peer_change_queue.size() > 0)
4243 PeerChange c = m_peer_change_queue.pop_front();
4245 dout_server<<"Server: Handling peer change: "
4246 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4249 handlePeerChange(c);
4253 u64 Server::getPlayerPrivs(Player *player)
4257 std::string playername = player->getName();
4258 // Local player gets all privileges regardless of
4259 // what's set on their account.
4260 if(g_settings.get("name") == playername)
4266 return getPlayerAuthPrivs(playername);
4270 void dedicated_server_loop(Server &server, bool &kill)
4272 DSTACK(__FUNCTION_NAME);
4274 dstream<<DTIME<<std::endl;
4275 dstream<<"========================"<<std::endl;
4276 dstream<<"Running dedicated server"<<std::endl;
4277 dstream<<"========================"<<std::endl;
4280 IntervalLimiter m_profiler_interval;
4284 // This is kind of a hack but can be done like this
4285 // because server.step() is very light
4287 ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4292 if(server.getShutdownRequested() || kill)
4294 dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4301 float profiler_print_interval =
4302 g_settings.getFloat("profiler_print_interval");
4303 if(profiler_print_interval != 0)
4305 if(m_profiler_interval.step(0.030, profiler_print_interval))
4307 dstream<<"Profiler:"<<std::endl;
4308 g_profiler.print(dstream);
4316 static int counter = 0;
4322 core::list<PlayerInfo> list = server.getPlayerInfo();
4323 core::list<PlayerInfo>::Iterator i;
4324 static u32 sum_old = 0;
4325 u32 sum = PIChecksum(list);
4328 dstream<<DTIME<<"Player info:"<<std::endl;
4329 for(i=list.begin(); i!=list.end(); i++)
4331 i->PrintLine(&dstream);