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 core::map<v3s16, MapBlock*> modified_blocks2;
1743 for(core::map<v3s16, bool>::Iterator
1744 i = event->modified_blocks.getIterator();
1745 i.atEnd()==false; i++)
1747 v3s16 p = i.getNode()->getKey();
1748 modified_blocks2.insert(p,
1749 m_env.getMap().getBlockNoCreateNoEx(p));
1751 for(core::list<u16>::Iterator
1752 i = far_players.begin();
1753 i != far_players.end(); i++)
1756 RemoteClient *client = getClient(peer_id);
1759 client->SetBlocksNotSent(modified_blocks2);
1765 /*// Don't send too many at a time
1767 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1773 dstream<<"Server: MapEditEvents:"<<std::endl;
1774 prof.print(dstream);
1780 Send object positions
1781 TODO: Get rid of MapBlockObjects
1784 float &counter = m_objectdata_timer;
1786 if(counter >= g_settings.getFloat("objectdata_interval"))
1788 JMutexAutoLock lock1(m_env_mutex);
1789 JMutexAutoLock lock2(m_con_mutex);
1791 ScopeProfiler sp(&g_profiler, "Server: sending mbo positions");
1793 SendObjectData(counter);
1800 Trigger emergethread (it somehow gets to a non-triggered but
1801 bysy state sometimes)
1804 float &counter = m_emergethread_trigger_timer;
1810 m_emergethread.trigger();
1814 // Save map, players and auth stuff
1816 float &counter = m_savemap_timer;
1818 if(counter >= g_settings.getFloat("server_map_save_interval"))
1822 ScopeProfiler sp(&g_profiler, "Server: saving stuff");
1825 if(m_authmanager.isModified())
1826 m_authmanager.save();
1829 JMutexAutoLock lock(m_env_mutex);
1831 /*// Unload unused data (delete from memory)
1832 m_env.getMap().unloadUnusedData(
1833 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1835 /*u32 deleted_count = m_env.getMap().unloadUnusedData(
1836 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1839 // Save only changed parts
1840 m_env.getMap().save(true);
1842 /*if(deleted_count > 0)
1844 dout_server<<"Server: Unloaded "<<deleted_count
1845 <<" blocks from memory"<<std::endl;
1849 m_env.serializePlayers(m_mapsavedir);
1851 // Save environment metadata
1852 m_env.saveMeta(m_mapsavedir);
1857 void Server::Receive()
1859 DSTACK(__FUNCTION_NAME);
1860 u32 data_maxsize = 10000;
1861 Buffer<u8> data(data_maxsize);
1866 JMutexAutoLock conlock(m_con_mutex);
1867 datasize = m_con.Receive(peer_id, *data, data_maxsize);
1870 // This has to be called so that the client list gets synced
1871 // with the peer list of the connection
1872 handlePeerChanges();
1874 ProcessData(*data, datasize, peer_id);
1876 catch(con::InvalidIncomingDataException &e)
1878 derr_server<<"Server::Receive(): "
1879 "InvalidIncomingDataException: what()="
1880 <<e.what()<<std::endl;
1882 catch(con::PeerNotFoundException &e)
1884 //NOTE: This is not needed anymore
1886 // The peer has been disconnected.
1887 // Find the associated player and remove it.
1889 /*JMutexAutoLock envlock(m_env_mutex);
1891 dout_server<<"ServerThread: peer_id="<<peer_id
1892 <<" has apparently closed connection. "
1893 <<"Removing player."<<std::endl;
1895 m_env.removePlayer(peer_id);*/
1899 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1901 DSTACK(__FUNCTION_NAME);
1902 // Environment is locked first.
1903 JMutexAutoLock envlock(m_env_mutex);
1904 JMutexAutoLock conlock(m_con_mutex);
1908 peer = m_con.GetPeer(peer_id);
1910 catch(con::PeerNotFoundException &e)
1912 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1913 <<peer_id<<" not found"<<std::endl;
1917 u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1925 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1927 if(command == TOSERVER_INIT)
1929 // [0] u16 TOSERVER_INIT
1930 // [2] u8 SER_FMT_VER_HIGHEST
1931 // [3] u8[20] player_name
1932 // [23] u8[28] password <--- can be sent without this, from old versions
1934 if(datasize < 2+1+PLAYERNAME_SIZE)
1937 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1938 <<peer->id<<std::endl;
1940 // First byte after command is maximum supported
1941 // serialization version
1942 u8 client_max = data[2];
1943 u8 our_max = SER_FMT_VER_HIGHEST;
1944 // Use the highest version supported by both
1945 u8 deployed = core::min_(client_max, our_max);
1946 // If it's lower than the lowest supported, give up.
1947 if(deployed < SER_FMT_VER_LOWEST)
1948 deployed = SER_FMT_VER_INVALID;
1950 //peer->serialization_version = deployed;
1951 getClient(peer->id)->pending_serialization_version = deployed;
1953 if(deployed == SER_FMT_VER_INVALID)
1955 derr_server<<DTIME<<"Server: Cannot negotiate "
1956 "serialization version with peer "
1957 <<peer_id<<std::endl;
1966 char playername[PLAYERNAME_SIZE];
1967 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1969 playername[i] = data[3+i];
1971 playername[PLAYERNAME_SIZE-1] = 0;
1973 if(playername[0]=='\0')
1975 derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
1976 SendAccessDenied(m_con, peer_id,
1981 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1983 derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
1984 SendAccessDenied(m_con, peer_id,
1985 L"Name contains unallowed characters");
1990 char password[PASSWORD_SIZE];
1991 if(datasize == 2+1+PLAYERNAME_SIZE)
1993 // old version - assume blank password
1998 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2000 password[i] = data[23+i];
2002 password[PASSWORD_SIZE-1] = 0;
2005 std::string checkpwd;
2006 if(m_authmanager.exists(playername))
2008 checkpwd = m_authmanager.getPassword(playername);
2012 checkpwd = g_settings.get("default_password");
2015 if(password != checkpwd && checkpwd != "")
2017 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2018 <<": supplied invalid password for "
2019 <<playername<<std::endl;
2020 SendAccessDenied(m_con, peer_id, L"Invalid password");
2024 // Add player to auth manager
2025 if(m_authmanager.exists(playername) == false)
2027 derr_server<<DTIME<<"Server: adding player "<<playername
2028 <<" to auth manager"<<std::endl;
2029 m_authmanager.add(playername);
2030 m_authmanager.setPassword(playername, checkpwd);
2031 m_authmanager.setPrivs(playername,
2032 stringToPrivs(g_settings.get("default_privs")));
2033 m_authmanager.save();
2037 Player *player = emergePlayer(playername, password, peer_id);
2041 // DEBUG: Test serialization
2042 std::ostringstream test_os;
2043 player->serialize(test_os);
2044 dstream<<"Player serialization test: \""<<test_os.str()
2046 std::istringstream test_is(test_os.str());
2047 player->deSerialize(test_is);
2050 // If failed, cancel
2053 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2054 <<": failed to emerge player"<<std::endl;
2059 // If a client is already connected to the player, cancel
2060 if(player->peer_id != 0)
2062 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2063 <<" tried to connect to "
2064 "an already connected player (peer_id="
2065 <<player->peer_id<<")"<<std::endl;
2068 // Set client of player
2069 player->peer_id = peer_id;
2072 // Check if player doesn't exist
2074 throw con::InvalidIncomingDataException
2075 ("Server::ProcessData(): INIT: Player doesn't exist");
2077 /*// update name if it was supplied
2078 if(datasize >= 20+3)
2081 player->updateName((const char*)&data[3]);
2085 Answer with a TOCLIENT_INIT
2088 SharedBuffer<u8> reply(2+1+6+8);
2089 writeU16(&reply[0], TOCLIENT_INIT);
2090 writeU8(&reply[2], deployed);
2091 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2092 writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2095 m_con.Send(peer_id, 0, reply, true);
2099 Send complete position information
2101 SendMovePlayer(player);
2106 if(command == TOSERVER_INIT2)
2108 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2109 <<peer->id<<std::endl;
2112 getClient(peer->id)->serialization_version
2113 = getClient(peer->id)->pending_serialization_version;
2116 Send some initialization data
2119 // Send player info to all players
2122 // Send inventory to player
2123 UpdateCrafting(peer->id);
2124 SendInventory(peer->id);
2128 Player *player = m_env.getPlayer(peer_id);
2129 SendPlayerHP(player);
2134 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2135 m_env.getTimeOfDay());
2136 m_con.Send(peer->id, 0, data, true);
2139 // Send information about server to player in chat
2140 SendChatMessage(peer_id, getStatusString());
2142 // Send information about joining in chat
2144 std::wstring name = L"unknown";
2145 Player *player = m_env.getPlayer(peer_id);
2147 name = narrow_to_wide(player->getName());
2149 std::wstring message;
2152 message += L" joined game";
2153 BroadcastChatMessage(message);
2159 if(peer_ser_ver == SER_FMT_VER_INVALID)
2161 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2162 " serialization format invalid or not initialized."
2163 " Skipping incoming command="<<command<<std::endl;
2167 Player *player = m_env.getPlayer(peer_id);
2170 derr_server<<"Server::ProcessData(): Cancelling: "
2171 "No player for peer_id="<<peer_id
2175 if(command == TOSERVER_PLAYERPOS)
2177 if(datasize < 2+12+12+4+4)
2181 v3s32 ps = readV3S32(&data[start+2]);
2182 v3s32 ss = readV3S32(&data[start+2+12]);
2183 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2184 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2185 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2186 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2187 pitch = wrapDegrees(pitch);
2188 yaw = wrapDegrees(yaw);
2189 player->setPosition(position);
2190 player->setSpeed(speed);
2191 player->setPitch(pitch);
2192 player->setYaw(yaw);
2194 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2195 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2196 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2198 else if(command == TOSERVER_GOTBLOCKS)
2211 u16 count = data[2];
2212 for(u16 i=0; i<count; i++)
2214 if((s16)datasize < 2+1+(i+1)*6)
2215 throw con::InvalidIncomingDataException
2216 ("GOTBLOCKS length is too short");
2217 v3s16 p = readV3S16(&data[2+1+i*6]);
2218 /*dstream<<"Server: GOTBLOCKS ("
2219 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2220 RemoteClient *client = getClient(peer_id);
2221 client->GotBlock(p);
2224 else if(command == TOSERVER_DELETEDBLOCKS)
2237 u16 count = data[2];
2238 for(u16 i=0; i<count; i++)
2240 if((s16)datasize < 2+1+(i+1)*6)
2241 throw con::InvalidIncomingDataException
2242 ("DELETEDBLOCKS length is too short");
2243 v3s16 p = readV3S16(&data[2+1+i*6]);
2244 /*dstream<<"Server: DELETEDBLOCKS ("
2245 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2246 RemoteClient *client = getClient(peer_id);
2247 client->SetBlockNotSent(p);
2250 else if(command == TOSERVER_CLICK_OBJECT)
2255 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2260 [2] u8 button (0=left, 1=right)
2265 u8 button = readU8(&data[2]);
2267 p.X = readS16(&data[3]);
2268 p.Y = readS16(&data[5]);
2269 p.Z = readS16(&data[7]);
2270 s16 id = readS16(&data[9]);
2271 //u16 item_i = readU16(&data[11]);
2273 MapBlock *block = NULL;
2276 block = m_env.getMap().getBlockNoCreate(p);
2278 catch(InvalidPositionException &e)
2280 derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2284 MapBlockObject *obj = block->getObject(id);
2288 derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2292 //TODO: Check that object is reasonably close
2297 InventoryList *ilist = player->inventory.getList("main");
2298 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2301 // Skip if inventory has no free space
2302 if(ilist->getUsedSlots() == ilist->getSize())
2304 dout_server<<"Player inventory has no free space"<<std::endl;
2309 Create the inventory item
2311 InventoryItem *item = NULL;
2312 // If it is an item-object, take the item from it
2313 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2315 item = ((ItemObject*)obj)->createInventoryItem();
2317 // Else create an item of the object
2320 item = new MapBlockObjectItem
2321 (obj->getInventoryString());
2324 // Add to inventory and send inventory
2325 ilist->addItem(item);
2326 UpdateCrafting(player->peer_id);
2327 SendInventory(player->peer_id);
2330 // Remove from block
2331 block->removeObject(id);
2334 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2339 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2345 [2] u8 button (0=left, 1=right)
2349 u8 button = readU8(&data[2]);
2350 u16 id = readS16(&data[3]);
2351 u16 item_i = readU16(&data[11]);
2353 ServerActiveObject *obj = m_env.getActiveObject(id);
2357 derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2362 //TODO: Check that object is reasonably close
2364 // Left click, pick object up (usually)
2367 InventoryList *ilist = player->inventory.getList("main");
2368 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2371 // Skip if inventory has no free space
2372 if(ilist->getUsedSlots() == ilist->getSize())
2374 dout_server<<"Player inventory has no free space"<<std::endl;
2378 // Skip if object has been removed
2383 Create the inventory item
2385 InventoryItem *item = obj->createPickedUpItem();
2389 // Add to inventory and send inventory
2390 ilist->addItem(item);
2391 UpdateCrafting(player->peer_id);
2392 SendInventory(player->peer_id);
2394 // Remove object from environment
2395 obj->m_removed = true;
2400 Item cannot be picked up. Punch it instead.
2403 ToolItem *titem = NULL;
2404 std::string toolname = "";
2406 InventoryList *mlist = player->inventory.getList("main");
2409 InventoryItem *item = mlist->getItem(item_i);
2410 if(item && (std::string)item->getName() == "ToolItem")
2412 titem = (ToolItem*)item;
2413 toolname = titem->getToolName();
2417 v3f playerpos = player->getPosition();
2418 v3f objpos = obj->getBasePosition();
2419 v3f dir = (objpos - playerpos).normalize();
2421 u16 wear = obj->punch(toolname, dir);
2425 bool weared_out = titem->addWear(wear);
2427 mlist->deleteItem(item_i);
2428 SendInventory(player->peer_id);
2434 else if(command == TOSERVER_GROUND_ACTION)
2442 [3] v3s16 nodepos_undersurface
2443 [9] v3s16 nodepos_abovesurface
2448 2: stop digging (all parameters ignored)
2449 3: digging completed
2451 u8 action = readU8(&data[2]);
2453 p_under.X = readS16(&data[3]);
2454 p_under.Y = readS16(&data[5]);
2455 p_under.Z = readS16(&data[7]);
2457 p_over.X = readS16(&data[9]);
2458 p_over.Y = readS16(&data[11]);
2459 p_over.Z = readS16(&data[13]);
2460 u16 item_i = readU16(&data[15]);
2462 //TODO: Check that target is reasonably close
2470 NOTE: This can be used in the future to check if
2471 somebody is cheating, by checking the timing.
2478 else if(action == 2)
2481 RemoteClient *client = getClient(peer->id);
2482 JMutexAutoLock digmutex(client->m_dig_mutex);
2483 client->m_dig_tool_item = -1;
2488 3: Digging completed
2490 else if(action == 3)
2492 // Mandatory parameter; actually used for nothing
2493 core::map<v3s16, MapBlock*> modified_blocks;
2495 u8 material = CONTENT_IGNORE;
2496 u8 mineral = MINERAL_NONE;
2498 bool cannot_remove_node = false;
2502 MapNode n = m_env.getMap().getNode(p_under);
2504 mineral = n.getMineral();
2505 // Get material at position
2507 // If not yet cancelled
2508 if(cannot_remove_node == false)
2510 // If it's not diggable, do nothing
2511 if(content_diggable(material) == false)
2513 derr_server<<"Server: Not finishing digging: "
2514 <<"Node not diggable"
2516 cannot_remove_node = true;
2519 // If not yet cancelled
2520 if(cannot_remove_node == false)
2522 // Get node metadata
2523 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2524 if(meta && meta->nodeRemovalDisabled() == true)
2526 derr_server<<"Server: Not finishing digging: "
2527 <<"Node metadata disables removal"
2529 cannot_remove_node = true;
2533 catch(InvalidPositionException &e)
2535 derr_server<<"Server: Not finishing digging: Node not found."
2536 <<" Adding block to emerge queue."
2538 m_emerge_queue.addBlock(peer_id,
2539 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2540 cannot_remove_node = true;
2543 // Make sure the player is allowed to do it
2544 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2546 dstream<<"Player "<<player->getName()<<" cannot remove node"
2547 <<" because privileges are "<<getPlayerPrivs(player)
2549 cannot_remove_node = true;
2553 If node can't be removed, set block to be re-sent to
2556 if(cannot_remove_node)
2558 derr_server<<"Server: Not finishing digging."<<std::endl;
2560 // Client probably has wrong data.
2561 // Set block not sent, so that client will get
2563 dstream<<"Client "<<peer_id<<" tried to dig "
2564 <<"node; but node cannot be removed."
2565 <<" setting MapBlock not sent."<<std::endl;
2566 RemoteClient *client = getClient(peer_id);
2567 v3s16 blockpos = getNodeBlockPos(p_under);
2568 client->SetBlockNotSent(blockpos);
2574 Send the removal to all close-by players.
2575 - If other player is close, send REMOVENODE
2576 - Otherwise set blocks not sent
2578 core::list<u16> far_players;
2579 sendRemoveNode(p_under, peer_id, &far_players, 30);
2582 Update and send inventory
2585 if(g_settings.getBool("creative_mode") == false)
2590 InventoryList *mlist = player->inventory.getList("main");
2593 InventoryItem *item = mlist->getItem(item_i);
2594 if(item && (std::string)item->getName() == "ToolItem")
2596 ToolItem *titem = (ToolItem*)item;
2597 std::string toolname = titem->getToolName();
2599 // Get digging properties for material and tool
2600 DiggingProperties prop =
2601 getDiggingProperties(material, toolname);
2603 if(prop.diggable == false)
2605 derr_server<<"Server: WARNING: Player digged"
2606 <<" with impossible material + tool"
2607 <<" combination"<<std::endl;
2610 bool weared_out = titem->addWear(prop.wear);
2614 mlist->deleteItem(item_i);
2620 Add dug item to inventory
2623 InventoryItem *item = NULL;
2625 if(mineral != MINERAL_NONE)
2626 item = getDiggedMineralItem(mineral);
2631 std::string &dug_s = content_features(material).dug_item;
2634 std::istringstream is(dug_s, std::ios::binary);
2635 item = InventoryItem::deSerialize(is);
2641 // Add a item to inventory
2642 player->inventory.addItem("main", item);
2645 UpdateCrafting(player->peer_id);
2646 SendInventory(player->peer_id);
2652 (this takes some time so it is done after the quick stuff)
2655 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2657 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2660 Set blocks not sent to far players
2662 for(core::list<u16>::Iterator
2663 i = far_players.begin();
2664 i != far_players.end(); i++)
2667 RemoteClient *client = getClient(peer_id);
2670 client->SetBlocksNotSent(modified_blocks);
2677 else if(action == 1)
2680 InventoryList *ilist = player->inventory.getList("main");
2685 InventoryItem *item = ilist->getItem(item_i);
2687 // If there is no item, it is not possible to add it anywhere
2692 Handle material items
2694 if(std::string("MaterialItem") == item->getName())
2697 // Don't add a node if this is not a free space
2698 MapNode n2 = m_env.getMap().getNode(p_over);
2699 bool no_enough_privs =
2700 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2702 dstream<<"Player "<<player->getName()<<" cannot add node"
2703 <<" because privileges are "<<getPlayerPrivs(player)
2706 if(content_buildable_to(n2.d) == false
2709 // Client probably has wrong data.
2710 // Set block not sent, so that client will get
2712 dstream<<"Client "<<peer_id<<" tried to place"
2713 <<" node in invalid position; setting"
2714 <<" MapBlock not sent."<<std::endl;
2715 RemoteClient *client = getClient(peer_id);
2716 v3s16 blockpos = getNodeBlockPos(p_over);
2717 client->SetBlockNotSent(blockpos);
2721 catch(InvalidPositionException &e)
2723 derr_server<<"Server: Ignoring ADDNODE: Node not found"
2724 <<" Adding block to emerge queue."
2726 m_emerge_queue.addBlock(peer_id,
2727 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2731 // Reset build time counter
2732 getClient(peer->id)->m_time_from_building = 0.0;
2735 MaterialItem *mitem = (MaterialItem*)item;
2737 n.d = mitem->getMaterial();
2739 // Calculate direction for wall mounted stuff
2740 if(content_features(n.d).wall_mounted)
2741 n.dir = packDir(p_under - p_over);
2743 // Calculate the direction for furnaces and chests and stuff
2744 if(content_features(n.d).param_type == CPT_FACEDIR_SIMPLE)
2746 v3f playerpos = player->getPosition();
2747 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2748 blockpos = blockpos.normalize();
2750 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2764 Send to all close-by players
2766 core::list<u16> far_players;
2767 sendAddNode(p_over, n, 0, &far_players, 30);
2772 InventoryList *ilist = player->inventory.getList("main");
2773 if(g_settings.getBool("creative_mode") == false && ilist)
2775 // Remove from inventory and send inventory
2776 if(mitem->getCount() == 1)
2777 ilist->deleteItem(item_i);
2781 UpdateCrafting(peer_id);
2782 SendInventory(peer_id);
2788 This takes some time so it is done after the quick stuff
2790 core::map<v3s16, MapBlock*> modified_blocks;
2792 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2794 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2797 Set blocks not sent to far players
2799 for(core::list<u16>::Iterator
2800 i = far_players.begin();
2801 i != far_players.end(); i++)
2804 RemoteClient *client = getClient(peer_id);
2807 client->SetBlocksNotSent(modified_blocks);
2811 Calculate special events
2814 /*if(n.d == CONTENT_MESE)
2817 for(s16 z=-1; z<=1; z++)
2818 for(s16 y=-1; y<=1; y++)
2819 for(s16 x=-1; x<=1; x++)
2826 Place other item (not a block)
2830 v3s16 blockpos = getNodeBlockPos(p_over);
2833 Check that the block is loaded so that the item
2834 can properly be added to the static list too
2836 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2839 derr_server<<"Error while placing object: "
2840 "block not found"<<std::endl;
2844 dout_server<<"Placing a miscellaneous item on map"
2847 // Calculate a position for it
2848 v3f pos = intToFloat(p_over, BS);
2850 pos.Y -= BS*0.25; // let it drop a bit
2852 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2853 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2858 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2862 derr_server<<"WARNING: item resulted in NULL object, "
2863 <<"not placing onto map"
2868 // Add the object to the environment
2869 m_env.addActiveObject(obj);
2871 dout_server<<"Placed object"<<std::endl;
2873 if(g_settings.getBool("creative_mode") == false)
2875 // Delete the right amount of items from the slot
2876 u16 dropcount = item->getDropCount();
2878 // Delete item if all gone
2879 if(item->getCount() <= dropcount)
2881 if(item->getCount() < dropcount)
2882 dstream<<"WARNING: Server: dropped more items"
2883 <<" than the slot contains"<<std::endl;
2885 InventoryList *ilist = player->inventory.getList("main");
2887 // Remove from inventory and send inventory
2888 ilist->deleteItem(item_i);
2890 // Else decrement it
2892 item->remove(dropcount);
2895 UpdateCrafting(peer_id);
2896 SendInventory(peer_id);
2904 Catch invalid actions
2908 derr_server<<"WARNING: Server: Invalid action "
2909 <<action<<std::endl;
2913 else if(command == TOSERVER_RELEASE)
2922 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2925 else if(command == TOSERVER_SIGNTEXT)
2927 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2936 std::string datastring((char*)&data[2], datasize-2);
2937 std::istringstream is(datastring, std::ios_base::binary);
2940 is.read((char*)buf, 6);
2941 v3s16 blockpos = readV3S16(buf);
2942 is.read((char*)buf, 2);
2943 s16 id = readS16(buf);
2944 is.read((char*)buf, 2);
2945 u16 textlen = readU16(buf);
2947 for(u16 i=0; i<textlen; i++)
2949 is.read((char*)buf, 1);
2950 text += (char)buf[0];
2953 MapBlock *block = NULL;
2956 block = m_env.getMap().getBlockNoCreate(blockpos);
2958 catch(InvalidPositionException &e)
2960 derr_server<<"Error while setting sign text: "
2961 "block not found"<<std::endl;
2965 MapBlockObject *obj = block->getObject(id);
2968 derr_server<<"Error while setting sign text: "
2969 "object not found"<<std::endl;
2973 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
2975 derr_server<<"Error while setting sign text: "
2976 "object is not a sign"<<std::endl;
2980 ((SignObject*)obj)->setText(text);
2982 obj->getBlock()->setChangedFlag();
2984 else if(command == TOSERVER_SIGNNODETEXT)
2986 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2994 std::string datastring((char*)&data[2], datasize-2);
2995 std::istringstream is(datastring, std::ios_base::binary);
2998 is.read((char*)buf, 6);
2999 v3s16 p = readV3S16(buf);
3000 is.read((char*)buf, 2);
3001 u16 textlen = readU16(buf);
3003 for(u16 i=0; i<textlen; i++)
3005 is.read((char*)buf, 1);
3006 text += (char)buf[0];
3009 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3012 if(meta->typeId() != CONTENT_SIGN_WALL)
3014 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3015 signmeta->setText(text);
3017 v3s16 blockpos = getNodeBlockPos(p);
3018 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
3021 block->setChangedFlag();
3024 for(core::map<u16, RemoteClient*>::Iterator
3025 i = m_clients.getIterator();
3026 i.atEnd()==false; i++)
3028 RemoteClient *client = i.getNode()->getValue();
3029 client->SetBlockNotSent(blockpos);
3032 else if(command == TOSERVER_INVENTORY_ACTION)
3034 /*// Ignore inventory changes if in creative mode
3035 if(g_settings.getBool("creative_mode") == true)
3037 dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3041 // Strip command and create a stream
3042 std::string datastring((char*)&data[2], datasize-2);
3043 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3044 std::istringstream is(datastring, std::ios_base::binary);
3046 InventoryAction *a = InventoryAction::deSerialize(is);
3051 c.current_player = player;
3054 Handle craftresult specially if not in creative mode
3056 bool disable_action = false;
3057 if(a->getType() == IACTION_MOVE
3058 && g_settings.getBool("creative_mode") == false)
3060 IMoveAction *ma = (IMoveAction*)a;
3061 if(ma->to_inv == "current_player" &&
3062 ma->from_inv == "current_player")
3064 InventoryList *rlist = player->inventory.getList("craftresult");
3066 InventoryList *clist = player->inventory.getList("craft");
3068 InventoryList *mlist = player->inventory.getList("main");
3071 Craftresult is no longer preview if something
3074 if(ma->to_list == "craftresult"
3075 && ma->from_list != "craftresult")
3077 // If it currently is a preview, remove
3079 if(player->craftresult_is_preview)
3081 rlist->deleteItem(0);
3083 player->craftresult_is_preview = false;
3086 Crafting takes place if this condition is true.
3088 if(player->craftresult_is_preview &&
3089 ma->from_list == "craftresult")
3091 player->craftresult_is_preview = false;
3092 clist->decrementMaterials(1);
3095 If the craftresult is placed on itself, move it to
3096 main inventory instead of doing the action
3098 if(ma->to_list == "craftresult"
3099 && ma->from_list == "craftresult")
3101 disable_action = true;
3103 InventoryItem *item1 = rlist->changeItem(0, NULL);
3104 mlist->addItem(item1);
3109 if(disable_action == false)
3111 // Feed action to player inventory
3119 UpdateCrafting(player->peer_id);
3120 SendInventory(player->peer_id);
3125 dstream<<"TOSERVER_INVENTORY_ACTION: "
3126 <<"InventoryAction::deSerialize() returned NULL"
3130 else if(command == TOSERVER_CHAT_MESSAGE)
3138 std::string datastring((char*)&data[2], datasize-2);
3139 std::istringstream is(datastring, std::ios_base::binary);
3142 is.read((char*)buf, 2);
3143 u16 len = readU16(buf);
3145 std::wstring message;
3146 for(u16 i=0; i<len; i++)
3148 is.read((char*)buf, 2);
3149 message += (wchar_t)readU16(buf);
3152 // Get player name of this client
3153 std::wstring name = narrow_to_wide(player->getName());
3155 // Line to send to players
3157 // Whether to send to the player that sent the line
3158 bool send_to_sender = false;
3159 // Whether to send to other players
3160 bool send_to_others = false;
3162 // Local player gets all privileges regardless of
3163 // what's set on their account.
3164 u64 privs = getPlayerPrivs(player);
3167 std::wstring commandprefix = L"/#";
3168 if(message.substr(0, commandprefix.size()) == commandprefix)
3170 line += L"Server: ";
3172 message = message.substr(commandprefix.size());
3174 ServerCommandContext *ctx = new ServerCommandContext(
3175 str_split(message, L' '),
3181 line += processServerCommand(ctx);
3182 send_to_sender = ctx->flags & 1;
3183 send_to_others = ctx->flags & 2;
3189 if(privs & PRIV_SHOUT)
3195 send_to_others = true;
3199 line += L"Server: You are not allowed to shout";
3200 send_to_sender = true;
3206 dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3209 Send the message to clients
3211 for(core::map<u16, RemoteClient*>::Iterator
3212 i = m_clients.getIterator();
3213 i.atEnd() == false; i++)
3215 // Get client and check that it is valid
3216 RemoteClient *client = i.getNode()->getValue();
3217 assert(client->peer_id == i.getNode()->getKey());
3218 if(client->serialization_version == SER_FMT_VER_INVALID)
3222 bool sender_selected = (peer_id == client->peer_id);
3223 if(sender_selected == true && send_to_sender == false)
3225 if(sender_selected == false && send_to_others == false)
3228 SendChatMessage(client->peer_id, line);
3232 else if(command == TOSERVER_DAMAGE)
3234 if(g_settings.getBool("enable_damage"))
3236 std::string datastring((char*)&data[2], datasize-2);
3237 std::istringstream is(datastring, std::ios_base::binary);
3238 u8 damage = readU8(is);
3239 if(player->hp > damage)
3241 player->hp -= damage;
3247 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3250 v3f pos = findSpawnPos(m_env.getServerMap());
3251 player->setPosition(pos);
3253 SendMovePlayer(player);
3254 SendPlayerHP(player);
3256 //TODO: Throw items around
3260 SendPlayerHP(player);
3262 else if(command == TOSERVER_PASSWORD)
3265 [0] u16 TOSERVER_PASSWORD
3266 [2] u8[28] old password
3267 [30] u8[28] new password
3270 if(datasize != 2+PASSWORD_SIZE*2)
3272 /*char password[PASSWORD_SIZE];
3273 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3274 password[i] = data[2+i];
3275 password[PASSWORD_SIZE-1] = 0;*/
3277 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3285 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3287 char c = data[2+PASSWORD_SIZE+i];
3293 std::string playername = player->getName();
3295 if(m_authmanager.exists(playername) == false)
3297 dstream<<"Server: playername not found in authmanager"<<std::endl;
3298 // Wrong old password supplied!!
3299 SendChatMessage(peer_id, L"playername not found in authmanager");
3303 std::string checkpwd = m_authmanager.getPassword(playername);
3305 if(oldpwd != checkpwd)
3307 dstream<<"Server: invalid old password"<<std::endl;
3308 // Wrong old password supplied!!
3309 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3313 m_authmanager.setPassword(playername, newpwd);
3315 dstream<<"Server: password change successful for "<<playername
3317 SendChatMessage(peer_id, L"Password change successful");
3321 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3322 "unknown command "<<command<<std::endl;
3326 catch(SendFailedException &e)
3328 derr_server<<"Server::ProcessData(): SendFailedException: "
3334 void Server::onMapEditEvent(MapEditEvent *event)
3336 //dstream<<"Server::onMapEditEvent()"<<std::endl;
3337 if(m_ignore_map_edit_events)
3339 MapEditEvent *e = event->clone();
3340 m_unsent_map_edit_queue.push_back(e);
3343 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3345 if(id == "current_player")
3347 assert(c->current_player);
3348 return &(c->current_player->inventory);
3352 std::string id0 = fn.next(":");
3354 if(id0 == "nodemeta")
3357 p.X = stoi(fn.next(","));
3358 p.Y = stoi(fn.next(","));
3359 p.Z = stoi(fn.next(","));
3360 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3362 return meta->getInventory();
3363 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3364 <<"no metadata found"<<std::endl;
3368 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3371 void Server::inventoryModified(InventoryContext *c, std::string id)
3373 if(id == "current_player")
3375 assert(c->current_player);
3377 UpdateCrafting(c->current_player->peer_id);
3378 SendInventory(c->current_player->peer_id);
3383 std::string id0 = fn.next(":");
3385 if(id0 == "nodemeta")
3388 p.X = stoi(fn.next(","));
3389 p.Y = stoi(fn.next(","));
3390 p.Z = stoi(fn.next(","));
3391 v3s16 blockpos = getNodeBlockPos(p);
3393 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3395 meta->inventoryModified();
3397 for(core::map<u16, RemoteClient*>::Iterator
3398 i = m_clients.getIterator();
3399 i.atEnd()==false; i++)
3401 RemoteClient *client = i.getNode()->getValue();
3402 client->SetBlockNotSent(blockpos);
3408 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3411 core::list<PlayerInfo> Server::getPlayerInfo()
3413 DSTACK(__FUNCTION_NAME);
3414 JMutexAutoLock envlock(m_env_mutex);
3415 JMutexAutoLock conlock(m_con_mutex);
3417 core::list<PlayerInfo> list;
3419 core::list<Player*> players = m_env.getPlayers();
3421 core::list<Player*>::Iterator i;
3422 for(i = players.begin();
3423 i != players.end(); i++)
3427 Player *player = *i;
3430 con::Peer *peer = m_con.GetPeer(player->peer_id);
3431 // Copy info from peer to info struct
3433 info.address = peer->address;
3434 info.avg_rtt = peer->avg_rtt;
3436 catch(con::PeerNotFoundException &e)
3438 // Set dummy peer info
3440 info.address = Address(0,0,0,0,0);
3444 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3445 info.position = player->getPosition();
3447 list.push_back(info);
3454 void Server::peerAdded(con::Peer *peer)
3456 DSTACK(__FUNCTION_NAME);
3457 dout_server<<"Server::peerAdded(): peer->id="
3458 <<peer->id<<std::endl;
3461 c.type = PEER_ADDED;
3462 c.peer_id = peer->id;
3464 m_peer_change_queue.push_back(c);
3467 void Server::deletingPeer(con::Peer *peer, bool timeout)
3469 DSTACK(__FUNCTION_NAME);
3470 dout_server<<"Server::deletingPeer(): peer->id="
3471 <<peer->id<<", timeout="<<timeout<<std::endl;
3474 c.type = PEER_REMOVED;
3475 c.peer_id = peer->id;
3476 c.timeout = timeout;
3477 m_peer_change_queue.push_back(c);
3484 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3486 DSTACK(__FUNCTION_NAME);
3487 std::ostringstream os(std::ios_base::binary);
3489 writeU16(os, TOCLIENT_HP);
3493 std::string s = os.str();
3494 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3496 con.Send(peer_id, 0, data, true);
3499 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3500 const std::wstring &reason)
3502 DSTACK(__FUNCTION_NAME);
3503 std::ostringstream os(std::ios_base::binary);
3505 writeU16(os, TOCLIENT_ACCESS_DENIED);
3506 os<<serializeWideString(reason);
3509 std::string s = os.str();
3510 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3512 con.Send(peer_id, 0, data, true);
3516 Non-static send methods
3519 void Server::SendObjectData(float dtime)
3521 DSTACK(__FUNCTION_NAME);
3523 core::map<v3s16, bool> stepped_blocks;
3525 for(core::map<u16, RemoteClient*>::Iterator
3526 i = m_clients.getIterator();
3527 i.atEnd() == false; i++)
3529 u16 peer_id = i.getNode()->getKey();
3530 RemoteClient *client = i.getNode()->getValue();
3531 assert(client->peer_id == peer_id);
3533 if(client->serialization_version == SER_FMT_VER_INVALID)
3536 client->SendObjectData(this, dtime, stepped_blocks);
3540 void Server::SendPlayerInfos()
3542 DSTACK(__FUNCTION_NAME);
3544 //JMutexAutoLock envlock(m_env_mutex);
3546 // Get connected players
3547 core::list<Player*> players = m_env.getPlayers(true);
3549 u32 player_count = players.getSize();
3550 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3552 SharedBuffer<u8> data(datasize);
3553 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3556 core::list<Player*>::Iterator i;
3557 for(i = players.begin();
3558 i != players.end(); i++)
3560 Player *player = *i;
3562 /*dstream<<"Server sending player info for player with "
3563 "peer_id="<<player->peer_id<<std::endl;*/
3565 writeU16(&data[start], player->peer_id);
3566 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3567 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3568 start += 2+PLAYERNAME_SIZE;
3571 //JMutexAutoLock conlock(m_con_mutex);
3574 m_con.SendToAll(0, data, true);
3577 void Server::SendInventory(u16 peer_id)
3579 DSTACK(__FUNCTION_NAME);
3581 Player* player = m_env.getPlayer(peer_id);
3588 std::ostringstream os;
3589 //os.imbue(std::locale("C"));
3591 player->inventory.serialize(os);
3593 std::string s = os.str();
3595 SharedBuffer<u8> data(s.size()+2);
3596 writeU16(&data[0], TOCLIENT_INVENTORY);
3597 memcpy(&data[2], s.c_str(), s.size());
3600 m_con.Send(peer_id, 0, data, true);
3603 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3605 DSTACK(__FUNCTION_NAME);
3607 std::ostringstream os(std::ios_base::binary);
3611 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3612 os.write((char*)buf, 2);
3615 writeU16(buf, message.size());
3616 os.write((char*)buf, 2);
3619 for(u32 i=0; i<message.size(); i++)
3623 os.write((char*)buf, 2);
3627 std::string s = os.str();
3628 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3630 m_con.Send(peer_id, 0, data, true);
3633 void Server::BroadcastChatMessage(const std::wstring &message)
3635 for(core::map<u16, RemoteClient*>::Iterator
3636 i = m_clients.getIterator();
3637 i.atEnd() == false; i++)
3639 // Get client and check that it is valid
3640 RemoteClient *client = i.getNode()->getValue();
3641 assert(client->peer_id == i.getNode()->getKey());
3642 if(client->serialization_version == SER_FMT_VER_INVALID)
3645 SendChatMessage(client->peer_id, message);
3649 void Server::SendPlayerHP(Player *player)
3651 SendHP(m_con, player->peer_id, player->hp);
3654 void Server::SendMovePlayer(Player *player)
3656 DSTACK(__FUNCTION_NAME);
3657 std::ostringstream os(std::ios_base::binary);
3659 writeU16(os, TOCLIENT_MOVE_PLAYER);
3660 writeV3F1000(os, player->getPosition());
3661 writeF1000(os, player->getPitch());
3662 writeF1000(os, player->getYaw());
3665 v3f pos = player->getPosition();
3666 f32 pitch = player->getPitch();
3667 f32 yaw = player->getYaw();
3668 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3669 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3676 std::string s = os.str();
3677 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3679 m_con.Send(player->peer_id, 0, data, true);
3682 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3683 core::list<u16> *far_players, float far_d_nodes)
3685 float maxd = far_d_nodes*BS;
3686 v3f p_f = intToFloat(p, BS);
3690 SharedBuffer<u8> reply(replysize);
3691 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3692 writeS16(&reply[2], p.X);
3693 writeS16(&reply[4], p.Y);
3694 writeS16(&reply[6], p.Z);
3696 for(core::map<u16, RemoteClient*>::Iterator
3697 i = m_clients.getIterator();
3698 i.atEnd() == false; i++)
3700 // Get client and check that it is valid
3701 RemoteClient *client = i.getNode()->getValue();
3702 assert(client->peer_id == i.getNode()->getKey());
3703 if(client->serialization_version == SER_FMT_VER_INVALID)
3706 // Don't send if it's the same one
3707 if(client->peer_id == ignore_id)
3713 Player *player = m_env.getPlayer(client->peer_id);
3716 // If player is far away, only set modified blocks not sent
3717 v3f player_pos = player->getPosition();
3718 if(player_pos.getDistanceFrom(p_f) > maxd)
3720 far_players->push_back(client->peer_id);
3727 m_con.Send(client->peer_id, 0, reply, true);
3731 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3732 core::list<u16> *far_players, float far_d_nodes)
3734 float maxd = far_d_nodes*BS;
3735 v3f p_f = intToFloat(p, BS);
3737 for(core::map<u16, RemoteClient*>::Iterator
3738 i = m_clients.getIterator();
3739 i.atEnd() == false; i++)
3741 // Get client and check that it is valid
3742 RemoteClient *client = i.getNode()->getValue();
3743 assert(client->peer_id == i.getNode()->getKey());
3744 if(client->serialization_version == SER_FMT_VER_INVALID)
3747 // Don't send if it's the same one
3748 if(client->peer_id == ignore_id)
3754 Player *player = m_env.getPlayer(client->peer_id);
3757 // If player is far away, only set modified blocks not sent
3758 v3f player_pos = player->getPosition();
3759 if(player_pos.getDistanceFrom(p_f) > maxd)
3761 far_players->push_back(client->peer_id);
3768 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3769 SharedBuffer<u8> reply(replysize);
3770 writeU16(&reply[0], TOCLIENT_ADDNODE);
3771 writeS16(&reply[2], p.X);
3772 writeS16(&reply[4], p.Y);
3773 writeS16(&reply[6], p.Z);
3774 n.serialize(&reply[8], client->serialization_version);
3777 m_con.Send(client->peer_id, 0, reply, true);
3781 void Server::setBlockNotSent(v3s16 p)
3783 for(core::map<u16, RemoteClient*>::Iterator
3784 i = m_clients.getIterator();
3785 i.atEnd()==false; i++)
3787 RemoteClient *client = i.getNode()->getValue();
3788 client->SetBlockNotSent(p);
3792 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3794 DSTACK(__FUNCTION_NAME);
3796 v3s16 p = block->getPos();
3800 bool completely_air = true;
3801 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3802 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3803 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3805 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3807 completely_air = false;
3808 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3813 dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3815 dstream<<"[completely air] ";
3820 Create a packet with the block in the right format
3823 std::ostringstream os(std::ios_base::binary);
3824 block->serialize(os, ver);
3825 std::string s = os.str();
3826 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3828 u32 replysize = 8 + blockdata.getSize();
3829 SharedBuffer<u8> reply(replysize);
3830 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3831 writeS16(&reply[2], p.X);
3832 writeS16(&reply[4], p.Y);
3833 writeS16(&reply[6], p.Z);
3834 memcpy(&reply[8], *blockdata, blockdata.getSize());
3836 /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3837 <<": \tpacket size: "<<replysize<<std::endl;*/
3842 m_con.Send(peer_id, 1, reply, true);
3845 void Server::SendBlocks(float dtime)
3847 DSTACK(__FUNCTION_NAME);
3849 JMutexAutoLock envlock(m_env_mutex);
3850 JMutexAutoLock conlock(m_con_mutex);
3852 //TimeTaker timer("Server::SendBlocks");
3854 core::array<PrioritySortedBlockTransfer> queue;
3856 s32 total_sending = 0;
3859 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
3861 for(core::map<u16, RemoteClient*>::Iterator
3862 i = m_clients.getIterator();
3863 i.atEnd() == false; i++)
3865 RemoteClient *client = i.getNode()->getValue();
3866 assert(client->peer_id == i.getNode()->getKey());
3868 total_sending += client->SendingCount();
3870 if(client->serialization_version == SER_FMT_VER_INVALID)
3873 client->GetNextBlocks(this, dtime, queue);
3878 // Lowest priority number comes first.
3879 // Lowest is most important.
3882 for(u32 i=0; i<queue.size(); i++)
3884 //TODO: Calculate limit dynamically
3885 if(total_sending >= g_settings.getS32
3886 ("max_simultaneous_block_sends_server_total"))
3889 PrioritySortedBlockTransfer q = queue[i];
3891 MapBlock *block = NULL;
3894 block = m_env.getMap().getBlockNoCreate(q.pos);
3896 catch(InvalidPositionException &e)
3901 RemoteClient *client = getClient(q.peer_id);
3903 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3905 client->SentBlock(q.pos);
3915 void Server::UpdateCrafting(u16 peer_id)
3917 DSTACK(__FUNCTION_NAME);
3919 Player* player = m_env.getPlayer(peer_id);
3923 Calculate crafting stuff
3925 if(g_settings.getBool("creative_mode") == false)
3927 InventoryList *clist = player->inventory.getList("craft");
3928 InventoryList *rlist = player->inventory.getList("craftresult");
3930 if(rlist->getUsedSlots() == 0)
3931 player->craftresult_is_preview = true;
3933 if(rlist && player->craftresult_is_preview)
3935 rlist->clearItems();
3937 if(clist && rlist && player->craftresult_is_preview)
3939 InventoryItem *items[9];
3940 for(u16 i=0; i<9; i++)
3942 items[i] = clist->getItem(i);
3945 // Get result of crafting grid
3946 InventoryItem *result = craft_get_result(items);
3948 rlist->addItem(result);
3951 } // if creative_mode == false
3954 RemoteClient* Server::getClient(u16 peer_id)
3956 DSTACK(__FUNCTION_NAME);
3957 //JMutexAutoLock lock(m_con_mutex);
3958 core::map<u16, RemoteClient*>::Node *n;
3959 n = m_clients.find(peer_id);
3960 // A client should exist for all peers
3962 return n->getValue();
3965 std::wstring Server::getStatusString()
3967 std::wostringstream os(std::ios_base::binary);
3970 os<<L"version="<<narrow_to_wide(VERSION_STRING);
3972 os<<L", uptime="<<m_uptime.get();
3973 // Information about clients
3975 for(core::map<u16, RemoteClient*>::Iterator
3976 i = m_clients.getIterator();
3977 i.atEnd() == false; i++)
3979 // Get client and check that it is valid
3980 RemoteClient *client = i.getNode()->getValue();
3981 assert(client->peer_id == i.getNode()->getKey());
3982 if(client->serialization_version == SER_FMT_VER_INVALID)
3985 Player *player = m_env.getPlayer(client->peer_id);
3986 // Get name of player
3987 std::wstring name = L"unknown";
3989 name = narrow_to_wide(player->getName());
3990 // Add name to information string
3994 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
3995 os<<" WARNING: Map saving is disabled."<<std::endl;
3999 v3f findSpawnPos(ServerMap &map)
4001 //return v3f(50,50,50)*BS;
4004 s16 groundheight = 0;
4007 nodepos = v2s16(0,0);
4012 // Try to find a good place a few times
4013 for(s32 i=0; i<1000; i++)
4016 // We're going to try to throw the player to this position
4017 nodepos = v2s16(-range + (myrand()%(range*2)),
4018 -range + (myrand()%(range*2)));
4019 v2s16 sectorpos = getNodeSectorPos(nodepos);
4020 // Get sector (NOTE: Don't get because it's slow)
4021 //m_env.getMap().emergeSector(sectorpos);
4022 // Get ground height at point (fallbacks to heightmap function)
4023 groundheight = map.findGroundLevel(nodepos);
4024 // Don't go underwater
4025 if(groundheight < WATER_LEVEL)
4027 //dstream<<"-> Underwater"<<std::endl;
4030 // Don't go to high places
4031 if(groundheight > WATER_LEVEL + 4)
4033 //dstream<<"-> Underwater"<<std::endl;
4037 // Found a good place
4038 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4043 // If no suitable place was not found, go above water at least.
4044 if(groundheight < WATER_LEVEL)
4045 groundheight = WATER_LEVEL;
4047 return intToFloat(v3s16(
4054 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4057 Try to get an existing player
4059 Player *player = m_env.getPlayer(name);
4062 // If player is already connected, cancel
4063 if(player->peer_id != 0)
4065 dstream<<"emergePlayer(): Player already connected"<<std::endl;
4070 player->peer_id = peer_id;
4072 // Reset inventory to creative if in creative mode
4073 if(g_settings.getBool("creative_mode"))
4075 craft_set_creative_inventory(player);
4082 If player with the wanted peer_id already exists, cancel.
4084 if(m_env.getPlayer(peer_id) != NULL)
4086 dstream<<"emergePlayer(): Player with wrong name but same"
4087 " peer_id already exists"<<std::endl;
4095 player = new ServerRemotePlayer();
4096 //player->peer_id = c.peer_id;
4097 //player->peer_id = PEER_ID_INEXISTENT;
4098 player->peer_id = peer_id;
4099 player->updateName(name);
4100 m_authmanager.add(name);
4101 m_authmanager.setPassword(name, password);
4102 m_authmanager.setPrivs(name,
4103 stringToPrivs(g_settings.get("default_privs")));
4109 dstream<<"Server: Finding spawn place for player \""
4110 <<player->getName()<<"\""<<std::endl;
4112 v3f pos = findSpawnPos(m_env.getServerMap());
4114 player->setPosition(pos);
4117 Add player to environment
4120 m_env.addPlayer(player);
4123 Add stuff to inventory
4126 if(g_settings.getBool("creative_mode"))
4128 craft_set_creative_inventory(player);
4130 else if(g_settings.getBool("give_initial_stuff"))
4132 craft_give_initial_stuff(player);
4137 } // create new player
4140 void Server::handlePeerChange(PeerChange &c)
4142 JMutexAutoLock envlock(m_env_mutex);
4143 JMutexAutoLock conlock(m_con_mutex);
4145 if(c.type == PEER_ADDED)
4152 core::map<u16, RemoteClient*>::Node *n;
4153 n = m_clients.find(c.peer_id);
4154 // The client shouldn't already exist
4158 RemoteClient *client = new RemoteClient();
4159 client->peer_id = c.peer_id;
4160 m_clients.insert(client->peer_id, client);
4163 else if(c.type == PEER_REMOVED)
4170 core::map<u16, RemoteClient*>::Node *n;
4171 n = m_clients.find(c.peer_id);
4172 // The client should exist
4176 Mark objects to be not known by the client
4178 RemoteClient *client = n->getValue();
4180 for(core::map<u16, bool>::Iterator
4181 i = client->m_known_objects.getIterator();
4182 i.atEnd()==false; i++)
4185 u16 id = i.getNode()->getKey();
4186 ServerActiveObject* obj = m_env.getActiveObject(id);
4188 if(obj && obj->m_known_by_count > 0)
4189 obj->m_known_by_count--;
4192 // Collect information about leaving in chat
4193 std::wstring message;
4195 std::wstring name = L"unknown";
4196 Player *player = m_env.getPlayer(c.peer_id);
4198 name = narrow_to_wide(player->getName());
4202 message += L" left game";
4204 message += L" (timed out)";
4209 m_env.removePlayer(c.peer_id);
4212 // Set player client disconnected
4214 Player *player = m_env.getPlayer(c.peer_id);
4216 player->peer_id = 0;
4220 delete m_clients[c.peer_id];
4221 m_clients.remove(c.peer_id);
4223 // Send player info to all remaining clients
4226 // Send leave chat message to all remaining clients
4227 BroadcastChatMessage(message);
4236 void Server::handlePeerChanges()
4238 while(m_peer_change_queue.size() > 0)
4240 PeerChange c = m_peer_change_queue.pop_front();
4242 dout_server<<"Server: Handling peer change: "
4243 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4246 handlePeerChange(c);
4250 u64 Server::getPlayerPrivs(Player *player)
4254 std::string playername = player->getName();
4255 // Local player gets all privileges regardless of
4256 // what's set on their account.
4257 if(g_settings.get("name") == playername)
4263 return getPlayerAuthPrivs(playername);
4267 void dedicated_server_loop(Server &server, bool &kill)
4269 DSTACK(__FUNCTION_NAME);
4271 dstream<<DTIME<<std::endl;
4272 dstream<<"========================"<<std::endl;
4273 dstream<<"Running dedicated server"<<std::endl;
4274 dstream<<"========================"<<std::endl;
4277 IntervalLimiter m_profiler_interval;
4281 // This is kind of a hack but can be done like this
4282 // because server.step() is very light
4284 ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4289 if(server.getShutdownRequested() || kill)
4291 dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4298 float profiler_print_interval =
4299 g_settings.getFloat("profiler_print_interval");
4300 if(profiler_print_interval != 0)
4302 if(m_profiler_interval.step(0.030, profiler_print_interval))
4304 dstream<<"Profiler:"<<std::endl;
4305 g_profiler.print(dstream);
4313 static int counter = 0;
4319 core::list<PlayerInfo> list = server.getPlayerInfo();
4320 core::list<PlayerInfo>::Iterator i;
4321 static u32 sum_old = 0;
4322 u32 sum = PIChecksum(list);
4325 dstream<<DTIME<<"Player info:"<<std::endl;
4326 for(i=list.begin(); i!=list.end(); i++)
4328 i->PrintLine(&dstream);