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"
39 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
41 class MapEditEventIgnorer
44 MapEditEventIgnorer(bool *flag):
53 ~MapEditEventIgnorer()
66 void * ServerThread::Thread()
70 DSTACK(__FUNCTION_NAME);
72 BEGIN_DEBUG_EXCEPTION_HANDLER
77 //TimeTaker timer("AsyncRunStep() + Receive()");
80 //TimeTaker timer("AsyncRunStep()");
81 m_server->AsyncRunStep();
84 //dout_server<<"Running m_server->Receive()"<<std::endl;
87 catch(con::NoIncomingDataException &e)
90 catch(con::PeerNotFoundException &e)
92 dout_server<<"Server: PeerNotFoundException"<<std::endl;
96 END_DEBUG_EXCEPTION_HANDLER
101 void * EmergeThread::Thread()
105 DSTACK(__FUNCTION_NAME);
109 BEGIN_DEBUG_EXCEPTION_HANDLER
112 Get block info from queue, emerge them and send them
115 After queue is empty, exit.
119 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
123 SharedPtr<QueuedBlockEmerge> q(qptr);
129 Do not generate over-limit
131 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
132 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
133 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
134 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
135 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
136 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
139 //derr_server<<"EmergeThread::Thread(): running"<<std::endl;
141 //TimeTaker timer("block emerge");
144 Try to emerge it from somewhere.
146 If it is only wanted as optional, only loading from disk
151 Check if any peer wants it as non-optional. In that case it
154 Also decrement the emerge queue count in clients.
157 bool optional = true;
160 core::map<u16, u8>::Iterator i;
161 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
163 //u16 peer_id = i.getNode()->getKey();
166 u8 flags = i.getNode()->getValue();
167 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
173 /*dstream<<"EmergeThread: p="
174 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
175 <<"optional="<<optional<<std::endl;*/
177 ServerMap &map = ((ServerMap&)m_server->m_env.getMap());
179 //core::map<v3s16, MapBlock*> changed_blocks;
180 //core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
182 MapBlock *block = NULL;
183 bool got_block = true;
184 core::map<v3s16, MapBlock*> modified_blocks;
186 bool only_from_disk = false;
189 only_from_disk = true;
192 Fetch block from map or generate a single block
195 JMutexAutoLock envlock(m_server->m_env_mutex);
197 // Load sector if it isn't loaded
198 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
199 //map.loadSectorFull(p2d);
200 map.loadSectorMeta(p2d);
202 block = map.getBlockNoCreateNoEx(p);
203 if(!block || block->isDummy() || !block->isGenerated())
205 // Get, load or create sector
206 /*ServerMapSector *sector =
207 (ServerMapSector*)map.createSector(p2d);*/
209 // Load/generate block
211 /*block = map.emergeBlock(p, sector, changed_blocks,
212 lighting_invalidated_blocks);*/
214 block = map.loadBlock(p);
216 if(block == NULL && only_from_disk == false)
217 block = map.generateBlock(p, modified_blocks);
218 //block = map.generateBlock(p, changed_blocks);
219 /*block = map.generateBlock(p, block, sector, changed_blocks,
220 lighting_invalidated_blocks);*/
229 Ignore map edit events, they will not need to be
230 sent to anybody because the block hasn't been sent
233 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
235 // Activate objects and stuff
236 m_server->m_env.activateBlock(block, 3600);
241 /*if(block->getLightingExpired()){
242 lighting_invalidated_blocks[block->getPos()] = block;
246 // TODO: Some additional checking and lighting updating,
251 JMutexAutoLock envlock(m_server->m_env_mutex);
256 Collect a list of blocks that have been modified in
257 addition to the fetched one.
261 if(lighting_invalidated_blocks.size() > 0)
263 /*dstream<<"lighting "<<lighting_invalidated_blocks.size()
264 <<" blocks"<<std::endl;*/
266 // 50-100ms for single block generation
267 //TimeTaker timer("** EmergeThread updateLighting");
269 // Update lighting without locking the environment mutex,
270 // add modified blocks to changed blocks
271 map.updateLighting(lighting_invalidated_blocks, modified_blocks);
274 // Add all from changed_blocks to modified_blocks
275 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
276 i.atEnd() == false; i++)
278 MapBlock *block = i.getNode()->getValue();
279 modified_blocks.insert(block->getPos(), block);
283 // If we got no block, there should be no invalidated blocks
286 //assert(lighting_invalidated_blocks.size() == 0);
292 Set sent status of modified blocks on clients
295 // NOTE: Server's clients are also behind the connection mutex
296 JMutexAutoLock lock(m_server->m_con_mutex);
299 Add the originally fetched block to the modified list
303 modified_blocks.insert(p, block);
307 Set the modified blocks unsent for all the clients
310 for(core::map<u16, RemoteClient*>::Iterator
311 i = m_server->m_clients.getIterator();
312 i.atEnd() == false; i++)
314 RemoteClient *client = i.getNode()->getValue();
316 if(modified_blocks.size() > 0)
318 // Remove block from sent history
319 client->SetBlocksNotSent(modified_blocks);
325 END_DEBUG_EXCEPTION_HANDLER
330 void RemoteClient::GetNextBlocks(Server *server, float dtime,
331 core::array<PrioritySortedBlockTransfer> &dest)
333 DSTACK(__FUNCTION_NAME);
336 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
339 m_nothing_to_send_pause_timer -= dtime;
341 if(m_nothing_to_send_pause_timer >= 0)
344 m_nearest_unsent_reset_timer = 0;
348 // Won't send anything if already sending
349 if(m_blocks_sending.size() >= g_settings.getU16
350 ("max_simultaneous_block_sends_per_client"))
352 //dstream<<"Not sending any blocks, Queue full."<<std::endl;
356 //TimeTaker timer("RemoteClient::GetNextBlocks");
358 Player *player = server->m_env.getPlayer(peer_id);
360 assert(player != NULL);
362 v3f playerpos = player->getPosition();
363 v3f playerspeed = player->getSpeed();
364 v3f playerspeeddir(0,0,0);
365 if(playerspeed.getLength() > 1.0*BS)
366 playerspeeddir = playerspeed / playerspeed.getLength();
367 // Predict to next block
368 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
370 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
372 v3s16 center = getNodeBlockPos(center_nodepos);
374 // Camera position and direction
376 playerpos + v3f(0, BS+BS/2, 0);
377 v3f camera_dir = v3f(0,0,1);
378 camera_dir.rotateYZBy(player->getPitch());
379 camera_dir.rotateXZBy(player->getYaw());
381 /*dstream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
382 <<camera_dir.Z<<")"<<std::endl;*/
385 Get the starting value of the block finder radius.
388 if(m_last_center != center)
390 m_nearest_unsent_d = 0;
391 m_last_center = center;
394 /*dstream<<"m_nearest_unsent_reset_timer="
395 <<m_nearest_unsent_reset_timer<<std::endl;*/
397 // This has to be incremented only when the nothing to send pause
399 m_nearest_unsent_reset_timer += dtime;
401 // Reset periodically to avoid possible bugs or other mishaps
402 if(m_nearest_unsent_reset_timer > 10.0)
404 m_nearest_unsent_reset_timer = 0;
405 m_nearest_unsent_d = 0;
406 /*dstream<<"Resetting m_nearest_unsent_d for "
407 <<server->getPlayerName(peer_id)<<std::endl;*/
410 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
411 s16 d_start = m_nearest_unsent_d;
413 //dstream<<"d_start="<<d_start<<std::endl;
415 u16 max_simul_sends_setting = g_settings.getU16
416 ("max_simultaneous_block_sends_per_client");
417 u16 max_simul_sends_usually = max_simul_sends_setting;
420 Check the time from last addNode/removeNode.
422 Decrease send rate if player is building stuff.
424 m_time_from_building += dtime;
425 if(m_time_from_building < g_settings.getFloat(
426 "full_block_send_enable_min_time_from_building"))
428 max_simul_sends_usually
429 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
433 Number of blocks sending + number of blocks selected for sending
435 u32 num_blocks_selected = m_blocks_sending.size();
438 next time d will be continued from the d from which the nearest
439 unsent block was found this time.
441 This is because not necessarily any of the blocks found this
442 time are actually sent.
444 s32 new_nearest_unsent_d = -1;
446 s16 d_max = g_settings.getS16("max_block_send_distance");
447 s16 d_max_gen = g_settings.getS16("max_block_generate_distance");
449 // Don't loop very much at a time
450 if(d_max > d_start+1)
452 /*if(d_max_gen > d_start+2)
453 d_max_gen = d_start+2;*/
455 //dstream<<"Starting from "<<d_start<<std::endl;
457 bool sending_something = false;
459 bool no_blocks_found_for_sending = true;
461 bool queue_is_full = false;
464 for(d = d_start; d <= d_max; d++)
466 //dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
469 If m_nearest_unsent_d was changed by the EmergeThread
470 (it can change it to 0 through SetBlockNotSent),
472 Else update m_nearest_unsent_d
474 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
476 d = m_nearest_unsent_d;
477 last_nearest_unsent_d = m_nearest_unsent_d;
481 Get the border/face dot coordinates of a "d-radiused"
484 core::list<v3s16> list;
485 getFacePositions(list, d);
487 core::list<v3s16>::Iterator li;
488 for(li=list.begin(); li!=list.end(); li++)
490 v3s16 p = *li + center;
494 - Don't allow too many simultaneous transfers
495 - EXCEPT when the blocks are very close
497 Also, don't send blocks that are already flying.
500 // Start with the usual maximum
501 u16 max_simul_dynamic = max_simul_sends_usually;
503 // If block is very close, allow full maximum
504 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
505 max_simul_dynamic = max_simul_sends_setting;
507 // Don't select too many blocks for sending
508 if(num_blocks_selected >= max_simul_dynamic)
510 queue_is_full = true;
511 goto queue_full_break;
514 // Don't send blocks that are currently being transferred
515 if(m_blocks_sending.find(p) != NULL)
521 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
522 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
523 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
524 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
525 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
526 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
529 // If this is true, inexistent block will be made from scratch
530 bool generate = d <= d_max_gen;
533 /*// Limit the generating area vertically to 2/3
534 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
537 // Limit the send area vertically to 2/3
538 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
544 If block is far away, don't generate it unless it is
550 // Block center y in nodes
551 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
552 // Don't generate if it's very high or very low
553 if(y < -64 || y > 64)
557 v2s16 p2d_nodes_center(
561 // Get ground height in nodes
562 s16 gh = server->m_env.getServerMap().findGroundLevel(
565 // If differs a lot, don't generate
566 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
568 // Actually, don't even send it
574 //dstream<<"d="<<d<<std::endl;
577 Don't generate or send if not in sight
580 if(isBlockInSight(p, camera_pos, camera_dir, 10000*BS) == false)
586 Don't send already sent blocks
589 if(m_blocks_sent.find(p) != NULL)
596 Check if map has this block
598 MapBlock *block = server->m_env.getMap().getBlockNoCreateNoEx(p);
600 bool surely_not_found_on_disk = false;
601 bool block_is_invalid = false;
604 // Block is dummy if data doesn't exist.
605 // It means it has been not found from disk and not generated
608 surely_not_found_on_disk = true;
611 // Block is valid if lighting is up-to-date and data exists
612 if(block->isValid() == false)
614 block_is_invalid = true;
617 /*if(block->isFullyGenerated() == false)
619 block_is_invalid = true;
624 ServerMap *map = (ServerMap*)(&server->m_env.getMap());
625 v2s16 chunkpos = map->sector_to_chunk(p2d);
626 if(map->chunkNonVolatile(chunkpos) == false)
627 block_is_invalid = true;
629 if(block->isGenerated() == false)
630 block_is_invalid = true;
633 If block is not close, don't send it unless it is near
636 Block is near ground level if night-time mesh
637 differs from day-time mesh.
641 if(block->dayNightDiffed() == false)
648 If block has been marked to not exist on disk (dummy)
649 and generating new ones is not wanted, skip block.
651 if(generate == false && surely_not_found_on_disk == true)
658 Record the lowest d from which a block has been
659 found being not sent and possibly to exist
661 if(no_blocks_found_for_sending)
664 new_nearest_unsent_d = d;
667 no_blocks_found_for_sending = false;
670 Add inexistent block to emerge queue.
672 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
674 //TODO: Get value from somewhere
675 // Allow only one block in emerge queue
676 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
677 // Allow two blocks in queue per client
678 if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
680 //dstream<<"Adding block to emerge queue"<<std::endl;
682 // Add it to the emerge queue and trigger the thread
685 if(generate == false)
686 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
688 server->m_emerge_queue.addBlock(peer_id, p, flags);
689 server->m_emergethread.trigger();
697 Add block to send queue
700 PrioritySortedBlockTransfer q((float)d, p, peer_id);
704 num_blocks_selected += 1;
705 sending_something = true;
710 //dstream<<"Stopped at "<<d<<std::endl;
712 if(no_blocks_found_for_sending)
714 if(queue_is_full == false)
715 new_nearest_unsent_d = d;
718 if(new_nearest_unsent_d != -1)
719 m_nearest_unsent_d = new_nearest_unsent_d;
721 if(sending_something == false)
723 m_nothing_to_send_counter++;
724 if((s16)m_nothing_to_send_counter >=
725 g_settings.getS16("max_block_send_distance"))
727 // Pause time in seconds
728 m_nothing_to_send_pause_timer = 1.0;
729 /*dstream<<"nothing to send to "
730 <<server->getPlayerName(peer_id)
731 <<" (d="<<d<<")"<<std::endl;*/
736 m_nothing_to_send_counter = 0;
739 /*timer_result = timer.stop(true);
740 if(timer_result != 0)
741 dstream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
744 void RemoteClient::SendObjectData(
747 core::map<v3s16, bool> &stepped_blocks
750 DSTACK(__FUNCTION_NAME);
752 // Can't send anything without knowing version
753 if(serialization_version == SER_FMT_VER_INVALID)
755 dstream<<"RemoteClient::SendObjectData(): Not sending, no version."
761 Send a TOCLIENT_OBJECTDATA packet.
765 u16 number of player positions
776 std::ostringstream os(std::ios_base::binary);
780 writeU16(buf, TOCLIENT_OBJECTDATA);
781 os.write((char*)buf, 2);
784 Get and write player data
787 // Get connected players
788 core::list<Player*> players = server->m_env.getPlayers(true);
790 // Write player count
791 u16 playercount = players.size();
792 writeU16(buf, playercount);
793 os.write((char*)buf, 2);
795 core::list<Player*>::Iterator i;
796 for(i = players.begin();
797 i != players.end(); i++)
801 v3f pf = player->getPosition();
802 v3f sf = player->getSpeed();
804 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
805 v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
806 s32 pitch_i (player->getPitch() * 100);
807 s32 yaw_i (player->getYaw() * 100);
809 writeU16(buf, player->peer_id);
810 os.write((char*)buf, 2);
811 writeV3S32(buf, position_i);
812 os.write((char*)buf, 12);
813 writeV3S32(buf, speed_i);
814 os.write((char*)buf, 12);
815 writeS32(buf, pitch_i);
816 os.write((char*)buf, 4);
817 writeS32(buf, yaw_i);
818 os.write((char*)buf, 4);
822 Get and write object data
828 For making players to be able to build to their nearby
829 environment (building is not possible on blocks that are not
832 - Add blocks to emerge queue if they are not found
834 SUGGESTION: These could be ignored from the backside of the player
837 Player *player = server->m_env.getPlayer(peer_id);
841 v3f playerpos = player->getPosition();
842 v3f playerspeed = player->getSpeed();
844 v3s16 center_nodepos = floatToInt(playerpos, BS);
845 v3s16 center = getNodeBlockPos(center_nodepos);
847 s16 d_max = g_settings.getS16("active_object_range");
849 // Number of blocks whose objects were written to bos
852 std::ostringstream bos(std::ios_base::binary);
854 for(s16 d = 0; d <= d_max; d++)
856 core::list<v3s16> list;
857 getFacePositions(list, d);
859 core::list<v3s16>::Iterator li;
860 for(li=list.begin(); li!=list.end(); li++)
862 v3s16 p = *li + center;
865 Ignore blocks that haven't been sent to the client
868 if(m_blocks_sent.find(p) == NULL)
872 // Try stepping block and add it to a send queue
877 MapBlock *block = server->m_env.getMap().getBlockNoCreate(p);
880 Step block if not in stepped_blocks and add to stepped_blocks.
882 if(stepped_blocks.find(p) == NULL)
884 block->stepObjects(dtime, true, server->m_env.getDayNightRatio());
885 stepped_blocks.insert(p, true);
886 block->setChangedFlag();
889 // Skip block if there are no objects
890 if(block->getObjectCount() == 0)
899 bos.write((char*)buf, 6);
902 //block->serializeObjects(bos, serialization_version); // DEPRECATED
909 Stop collecting objects if data is already too big
911 // Sum of player and object data sizes
912 s32 sum = (s32)os.tellp() + 2 + (s32)bos.tellp();
913 // break out if data too big
914 if(sum > MAX_OBJECTDATA_SIZE)
916 goto skip_subsequent;
920 catch(InvalidPositionException &e)
923 // Add it to the emerge queue and trigger the thread.
924 // Fetch the block only if it is on disk.
926 // Grab and increment counter
927 /*SharedPtr<JMutexAutoLock> lock
928 (m_num_blocks_in_emerge_queue.getLock());
929 m_num_blocks_in_emerge_queue.m_value++;*/
931 // Add to queue as an anonymous fetch from disk
932 u8 flags = BLOCK_EMERGE_FLAG_FROMDISK;
933 server->m_emerge_queue.addBlock(0, p, flags);
934 server->m_emergethread.trigger();
942 writeU16(buf, blockcount);
943 os.write((char*)buf, 2);
945 // Write block objects
952 //dstream<<"Server: Sending object data to "<<peer_id<<std::endl;
955 std::string s = os.str();
956 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
957 // Send as unreliable
958 server->m_con.Send(peer_id, 0, data, false);
961 void RemoteClient::GotBlock(v3s16 p)
963 if(m_blocks_sending.find(p) != NULL)
964 m_blocks_sending.remove(p);
967 /*dstream<<"RemoteClient::GotBlock(): Didn't find in"
968 " m_blocks_sending"<<std::endl;*/
969 m_excess_gotblocks++;
971 m_blocks_sent.insert(p, true);
974 void RemoteClient::SentBlock(v3s16 p)
976 if(m_blocks_sending.find(p) == NULL)
977 m_blocks_sending.insert(p, 0.0);
979 dstream<<"RemoteClient::SentBlock(): Sent block"
980 " already in m_blocks_sending"<<std::endl;
983 void RemoteClient::SetBlockNotSent(v3s16 p)
985 m_nearest_unsent_d = 0;
987 if(m_blocks_sending.find(p) != NULL)
988 m_blocks_sending.remove(p);
989 if(m_blocks_sent.find(p) != NULL)
990 m_blocks_sent.remove(p);
993 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
995 m_nearest_unsent_d = 0;
997 for(core::map<v3s16, MapBlock*>::Iterator
998 i = blocks.getIterator();
999 i.atEnd()==false; i++)
1001 v3s16 p = i.getNode()->getKey();
1003 if(m_blocks_sending.find(p) != NULL)
1004 m_blocks_sending.remove(p);
1005 if(m_blocks_sent.find(p) != NULL)
1006 m_blocks_sent.remove(p);
1014 PlayerInfo::PlayerInfo()
1020 void PlayerInfo::PrintLine(std::ostream *s)
1023 (*s)<<"\""<<name<<"\" ("
1024 <<(position.X/10)<<","<<(position.Y/10)
1025 <<","<<(position.Z/10)<<") ";
1027 (*s)<<" avg_rtt="<<avg_rtt;
1031 u32 PIChecksum(core::list<PlayerInfo> &l)
1033 core::list<PlayerInfo>::Iterator i;
1036 for(i=l.begin(); i!=l.end(); i++)
1038 checksum += a * (i->id+1);
1039 checksum ^= 0x435aafcd;
1050 std::string mapsavedir
1052 m_env(new ServerMap(mapsavedir), this),
1053 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
1054 m_authmanager(mapsavedir+"/auth.txt"),
1056 m_emergethread(this),
1058 m_time_of_day_send_timer(0),
1060 m_mapsavedir(mapsavedir),
1061 m_shutdown_requested(false),
1062 m_ignore_map_edit_events(false),
1063 m_ignore_map_edit_events_peer_id(0)
1065 m_liquid_transform_timer = 0.0;
1066 m_print_info_timer = 0.0;
1067 m_objectdata_timer = 0.0;
1068 m_emergethread_trigger_timer = 0.0;
1069 m_savemap_timer = 0.0;
1073 m_step_dtime_mutex.Init();
1076 // Register us to receive map edit events
1077 m_env.getMap().addEventReceiver(this);
1079 // If file exists, load environment metadata
1080 if(fs::PathExists(m_mapsavedir+"/env_meta.txt"))
1082 dstream<<"Server: Loading environment metadata"<<std::endl;
1083 m_env.loadMeta(m_mapsavedir);
1087 dstream<<"Server: Loading players"<<std::endl;
1088 m_env.deSerializePlayers(m_mapsavedir);
1093 dstream<<"Server::~Server()"<<std::endl;
1096 Send shutdown message
1099 JMutexAutoLock conlock(m_con_mutex);
1101 std::wstring line = L"*** Server shutting down";
1104 Send the message to clients
1106 for(core::map<u16, RemoteClient*>::Iterator
1107 i = m_clients.getIterator();
1108 i.atEnd() == false; i++)
1110 // Get client and check that it is valid
1111 RemoteClient *client = i.getNode()->getValue();
1112 assert(client->peer_id == i.getNode()->getKey());
1113 if(client->serialization_version == SER_FMT_VER_INVALID)
1117 SendChatMessage(client->peer_id, line);
1119 catch(con::PeerNotFoundException &e)
1127 dstream<<"Server: Saving players"<<std::endl;
1128 m_env.serializePlayers(m_mapsavedir);
1131 Save environment metadata
1133 dstream<<"Server: Saving environment metadata"<<std::endl;
1134 m_env.saveMeta(m_mapsavedir);
1145 JMutexAutoLock clientslock(m_con_mutex);
1147 for(core::map<u16, RemoteClient*>::Iterator
1148 i = m_clients.getIterator();
1149 i.atEnd() == false; i++)
1152 // NOTE: These are removed by env destructor
1154 u16 peer_id = i.getNode()->getKey();
1155 JMutexAutoLock envlock(m_env_mutex);
1156 m_env.removePlayer(peer_id);
1160 delete i.getNode()->getValue();
1165 void Server::start(unsigned short port)
1167 DSTACK(__FUNCTION_NAME);
1168 // Stop thread if already running
1171 // Initialize connection
1172 m_con.setTimeoutMs(30);
1176 m_thread.setRun(true);
1179 dout_server<<"Server: Started on port "<<port<<std::endl;
1184 DSTACK(__FUNCTION_NAME);
1186 // Stop threads (set run=false first so both start stopping)
1187 m_thread.setRun(false);
1188 m_emergethread.setRun(false);
1190 m_emergethread.stop();
1192 dout_server<<"Server: Threads stopped"<<std::endl;
1195 void Server::step(float dtime)
1197 DSTACK(__FUNCTION_NAME);
1202 JMutexAutoLock lock(m_step_dtime_mutex);
1203 m_step_dtime += dtime;
1207 void Server::AsyncRunStep()
1209 DSTACK(__FUNCTION_NAME);
1213 JMutexAutoLock lock1(m_step_dtime_mutex);
1214 dtime = m_step_dtime;
1218 ScopeProfiler sp(&g_profiler, "Server: selecting and sending "
1219 "blocks to clients");
1220 // Send blocks to clients
1227 //dstream<<"Server steps "<<dtime<<std::endl;
1228 //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1231 JMutexAutoLock lock1(m_step_dtime_mutex);
1232 m_step_dtime -= dtime;
1239 m_uptime.set(m_uptime.get() + dtime);
1243 Update m_time_of_day and overall game time
1246 JMutexAutoLock envlock(m_env_mutex);
1248 m_time_counter += dtime;
1249 f32 speed = g_settings.getFloat("time_speed") * 24000./(24.*3600);
1250 u32 units = (u32)(m_time_counter*speed);
1251 m_time_counter -= (f32)units / speed;
1253 m_env.setTimeOfDay((m_env.getTimeOfDay() + units) % 24000);
1255 //dstream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1258 Send to clients at constant intervals
1261 m_time_of_day_send_timer -= dtime;
1262 if(m_time_of_day_send_timer < 0.0)
1264 m_time_of_day_send_timer = g_settings.getFloat("time_send_interval");
1266 //JMutexAutoLock envlock(m_env_mutex);
1267 JMutexAutoLock conlock(m_con_mutex);
1269 for(core::map<u16, RemoteClient*>::Iterator
1270 i = m_clients.getIterator();
1271 i.atEnd() == false; i++)
1273 RemoteClient *client = i.getNode()->getValue();
1274 //Player *player = m_env.getPlayer(client->peer_id);
1276 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1277 m_env.getTimeOfDay());
1279 m_con.Send(client->peer_id, 0, data, true);
1285 // Process connection's timeouts
1286 JMutexAutoLock lock2(m_con_mutex);
1287 ScopeProfiler sp(&g_profiler, "Server: connection timeout processing");
1288 m_con.RunTimeouts(dtime);
1292 // This has to be called so that the client list gets synced
1293 // with the peer list of the connection
1294 ScopeProfiler sp(&g_profiler, "Server: peer change handling");
1295 handlePeerChanges();
1300 // This also runs Map's timers
1301 JMutexAutoLock lock(m_env_mutex);
1302 ScopeProfiler sp(&g_profiler, "Server: environment step");
1313 m_liquid_transform_timer += dtime;
1314 if(m_liquid_transform_timer >= 1.00)
1316 m_liquid_transform_timer -= 1.00;
1318 JMutexAutoLock lock(m_env_mutex);
1320 ScopeProfiler sp(&g_profiler, "Server: liquid transform");
1322 core::map<v3s16, MapBlock*> modified_blocks;
1323 m_env.getMap().transformLiquids(modified_blocks);
1328 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1329 ServerMap &map = ((ServerMap&)m_env.getMap());
1330 map.updateLighting(modified_blocks, lighting_modified_blocks);
1332 // Add blocks modified by lighting to modified_blocks
1333 for(core::map<v3s16, MapBlock*>::Iterator
1334 i = lighting_modified_blocks.getIterator();
1335 i.atEnd() == false; i++)
1337 MapBlock *block = i.getNode()->getValue();
1338 modified_blocks.insert(block->getPos(), block);
1342 Set the modified blocks unsent for all the clients
1345 JMutexAutoLock lock2(m_con_mutex);
1347 for(core::map<u16, RemoteClient*>::Iterator
1348 i = m_clients.getIterator();
1349 i.atEnd() == false; i++)
1351 RemoteClient *client = i.getNode()->getValue();
1353 if(modified_blocks.size() > 0)
1355 // Remove block from sent history
1356 client->SetBlocksNotSent(modified_blocks);
1361 // Periodically print some info
1363 float &counter = m_print_info_timer;
1369 JMutexAutoLock lock2(m_con_mutex);
1371 for(core::map<u16, RemoteClient*>::Iterator
1372 i = m_clients.getIterator();
1373 i.atEnd() == false; i++)
1375 //u16 peer_id = i.getNode()->getKey();
1376 RemoteClient *client = i.getNode()->getValue();
1377 Player *player = m_env.getPlayer(client->peer_id);
1380 std::cout<<player->getName()<<"\t";
1381 client->PrintInfo(std::cout);
1386 //if(g_settings.getBool("enable_experimental"))
1390 Check added and deleted active objects
1393 //dstream<<"Server: Checking added and deleted active objects"<<std::endl;
1394 JMutexAutoLock envlock(m_env_mutex);
1395 JMutexAutoLock conlock(m_con_mutex);
1397 ScopeProfiler sp(&g_profiler, "Server: checking added and deleted objects");
1399 // Radius inside which objects are active
1402 for(core::map<u16, RemoteClient*>::Iterator
1403 i = m_clients.getIterator();
1404 i.atEnd() == false; i++)
1406 RemoteClient *client = i.getNode()->getValue();
1407 Player *player = m_env.getPlayer(client->peer_id);
1410 // This can happen if the client timeouts somehow
1411 /*dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1413 <<" has no associated player"<<std::endl;*/
1416 v3s16 pos = floatToInt(player->getPosition(), BS);
1418 core::map<u16, bool> removed_objects;
1419 core::map<u16, bool> added_objects;
1420 m_env.getRemovedActiveObjects(pos, radius,
1421 client->m_known_objects, removed_objects);
1422 m_env.getAddedActiveObjects(pos, radius,
1423 client->m_known_objects, added_objects);
1425 // Ignore if nothing happened
1426 if(removed_objects.size() == 0 && added_objects.size() == 0)
1428 //dstream<<"INFO: active objects: none changed"<<std::endl;
1432 std::string data_buffer;
1436 // Handle removed objects
1437 writeU16((u8*)buf, removed_objects.size());
1438 data_buffer.append(buf, 2);
1439 for(core::map<u16, bool>::Iterator
1440 i = removed_objects.getIterator();
1441 i.atEnd()==false; i++)
1444 u16 id = i.getNode()->getKey();
1445 ServerActiveObject* obj = m_env.getActiveObject(id);
1447 // Add to data buffer for sending
1448 writeU16((u8*)buf, i.getNode()->getKey());
1449 data_buffer.append(buf, 2);
1451 // Remove from known objects
1452 client->m_known_objects.remove(i.getNode()->getKey());
1454 if(obj && obj->m_known_by_count > 0)
1455 obj->m_known_by_count--;
1458 // Handle added objects
1459 writeU16((u8*)buf, added_objects.size());
1460 data_buffer.append(buf, 2);
1461 for(core::map<u16, bool>::Iterator
1462 i = added_objects.getIterator();
1463 i.atEnd()==false; i++)
1466 u16 id = i.getNode()->getKey();
1467 ServerActiveObject* obj = m_env.getActiveObject(id);
1470 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1472 dstream<<"WARNING: "<<__FUNCTION_NAME
1473 <<": NULL object"<<std::endl;
1475 type = obj->getType();
1477 // Add to data buffer for sending
1478 writeU16((u8*)buf, id);
1479 data_buffer.append(buf, 2);
1480 writeU8((u8*)buf, type);
1481 data_buffer.append(buf, 1);
1484 data_buffer.append(serializeLongString(
1485 obj->getClientInitializationData()));
1487 data_buffer.append(serializeLongString(""));
1489 // Add to known objects
1490 client->m_known_objects.insert(i.getNode()->getKey(), false);
1493 obj->m_known_by_count++;
1497 SharedBuffer<u8> reply(2 + data_buffer.size());
1498 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1499 memcpy((char*)&reply[2], data_buffer.c_str(),
1500 data_buffer.size());
1502 m_con.Send(client->peer_id, 0, reply, true);
1504 dstream<<"INFO: Server: Sent object remove/add: "
1505 <<removed_objects.size()<<" removed, "
1506 <<added_objects.size()<<" added, "
1507 <<"packet size is "<<reply.getSize()<<std::endl;
1512 Collect a list of all the objects known by the clients
1513 and report it back to the environment.
1516 core::map<u16, bool> all_known_objects;
1518 for(core::map<u16, RemoteClient*>::Iterator
1519 i = m_clients.getIterator();
1520 i.atEnd() == false; i++)
1522 RemoteClient *client = i.getNode()->getValue();
1523 // Go through all known objects of client
1524 for(core::map<u16, bool>::Iterator
1525 i = client->m_known_objects.getIterator();
1526 i.atEnd()==false; i++)
1528 u16 id = i.getNode()->getKey();
1529 all_known_objects[id] = true;
1533 m_env.setKnownActiveObjects(whatever);
1539 Send object messages
1542 JMutexAutoLock envlock(m_env_mutex);
1543 JMutexAutoLock conlock(m_con_mutex);
1545 ScopeProfiler sp(&g_profiler, "Server: sending object messages");
1548 // Value = data sent by object
1549 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1551 // Get active object messages from environment
1554 ActiveObjectMessage aom = m_env.getActiveObjectMessage();
1558 core::list<ActiveObjectMessage>* message_list = NULL;
1559 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1560 n = buffered_messages.find(aom.id);
1563 message_list = new core::list<ActiveObjectMessage>;
1564 buffered_messages.insert(aom.id, message_list);
1568 message_list = n->getValue();
1570 message_list->push_back(aom);
1573 // Route data to every client
1574 for(core::map<u16, RemoteClient*>::Iterator
1575 i = m_clients.getIterator();
1576 i.atEnd()==false; i++)
1578 RemoteClient *client = i.getNode()->getValue();
1579 std::string reliable_data;
1580 std::string unreliable_data;
1581 // Go through all objects in message buffer
1582 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1583 j = buffered_messages.getIterator();
1584 j.atEnd()==false; j++)
1586 // If object is not known by client, skip it
1587 u16 id = j.getNode()->getKey();
1588 if(client->m_known_objects.find(id) == NULL)
1590 // Get message list of object
1591 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1592 // Go through every message
1593 for(core::list<ActiveObjectMessage>::Iterator
1594 k = list->begin(); k != list->end(); k++)
1596 // Compose the full new data with header
1597 ActiveObjectMessage aom = *k;
1598 std::string new_data;
1601 writeU16((u8*)&buf[0], aom.id);
1602 new_data.append(buf, 2);
1604 new_data += serializeString(aom.datastring);
1605 // Add data to buffer
1607 reliable_data += new_data;
1609 unreliable_data += new_data;
1613 reliable_data and unreliable_data are now ready.
1616 if(reliable_data.size() > 0)
1618 SharedBuffer<u8> reply(2 + reliable_data.size());
1619 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1620 memcpy((char*)&reply[2], reliable_data.c_str(),
1621 reliable_data.size());
1623 m_con.Send(client->peer_id, 0, reply, true);
1625 if(unreliable_data.size() > 0)
1627 SharedBuffer<u8> reply(2 + unreliable_data.size());
1628 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1629 memcpy((char*)&reply[2], unreliable_data.c_str(),
1630 unreliable_data.size());
1631 // Send as unreliable
1632 m_con.Send(client->peer_id, 0, reply, false);
1635 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1637 dstream<<"INFO: Server: Size of object message data: "
1638 <<"reliable: "<<reliable_data.size()
1639 <<", unreliable: "<<unreliable_data.size()
1644 // Clear buffered_messages
1645 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1646 i = buffered_messages.getIterator();
1647 i.atEnd()==false; i++)
1649 delete i.getNode()->getValue();
1653 } // enable_experimental
1656 Send queued-for-sending map edit events.
1659 // Don't send too many at a time
1662 // Single change sending is disabled if queue size is not small
1663 bool disable_single_change_sending = false;
1664 if(m_unsent_map_edit_queue.size() >= 4)
1665 disable_single_change_sending = true;
1667 while(m_unsent_map_edit_queue.size() != 0)
1669 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1671 // Players far away from the change are stored here.
1672 // Instead of sending the changes, MapBlocks are set not sent
1674 core::list<u16> far_players;
1676 if(event->type == MEET_ADDNODE)
1678 dstream<<"Server: MEET_ADDNODE"<<std::endl;
1679 if(disable_single_change_sending)
1680 sendAddNode(event->p, event->n, event->already_known_by_peer,
1683 sendAddNode(event->p, event->n, event->already_known_by_peer,
1686 else if(event->type == MEET_REMOVENODE)
1688 dstream<<"Server: MEET_REMOVENODE"<<std::endl;
1689 if(disable_single_change_sending)
1690 sendRemoveNode(event->p, event->already_known_by_peer,
1693 sendRemoveNode(event->p, event->already_known_by_peer,
1696 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1698 dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1699 setBlockNotSent(event->p);
1701 else if(event->type == MEET_OTHER)
1703 dstream<<"WARNING: Server: MEET_OTHER not implemented"
1708 dstream<<"WARNING: Server: Unknown MapEditEvent "
1709 <<((u32)event->type)<<std::endl;
1713 Set blocks not sent to far players
1715 if(far_players.size() > 0)
1717 core::map<v3s16, MapBlock*> modified_blocks2;
1718 for(core::map<v3s16, bool>::Iterator
1719 i = event->modified_blocks.getIterator();
1720 i.atEnd()==false; i++)
1722 v3s16 p = i.getNode()->getKey();
1723 modified_blocks2.insert(p,
1724 m_env.getMap().getBlockNoCreateNoEx(p));
1726 for(core::list<u16>::Iterator
1727 i = far_players.begin();
1728 i != far_players.end(); i++)
1731 RemoteClient *client = getClient(peer_id);
1734 client->SetBlocksNotSent(modified_blocks2);
1740 /*// Don't send too many at a time
1742 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1748 Send object positions
1749 TODO: Get rid of MapBlockObjects
1752 float &counter = m_objectdata_timer;
1754 if(counter >= g_settings.getFloat("objectdata_interval"))
1756 JMutexAutoLock lock1(m_env_mutex);
1757 JMutexAutoLock lock2(m_con_mutex);
1759 ScopeProfiler sp(&g_profiler, "Server: sending mbo positions");
1761 SendObjectData(counter);
1769 TODO: Move to ServerEnvironment and utilize active block stuff
1772 //TimeTaker timer("Step node metadata");
1774 JMutexAutoLock envlock(m_env_mutex);
1775 JMutexAutoLock conlock(m_con_mutex);
1777 ScopeProfiler sp(&g_profiler, "Server: stepping node metadata");
1779 core::map<v3s16, MapBlock*> changed_blocks;
1780 m_env.getMap().nodeMetadataStep(dtime, changed_blocks);
1782 // Use setBlockNotSent
1784 for(core::map<v3s16, MapBlock*>::Iterator
1785 i = changed_blocks.getIterator();
1786 i.atEnd() == false; i++)
1788 MapBlock *block = i.getNode()->getValue();
1790 for(core::map<u16, RemoteClient*>::Iterator
1791 i = m_clients.getIterator();
1792 i.atEnd()==false; i++)
1794 RemoteClient *client = i.getNode()->getValue();
1795 client->SetBlockNotSent(block->getPos());
1801 Trigger emergethread (it somehow gets to a non-triggered but
1802 bysy state sometimes)
1805 float &counter = m_emergethread_trigger_timer;
1811 m_emergethread.trigger();
1815 // Save map, players and auth stuff
1817 float &counter = m_savemap_timer;
1819 if(counter >= g_settings.getFloat("server_map_save_interval"))
1823 ScopeProfiler sp(&g_profiler, "Server: saving stuff");
1826 if(m_authmanager.isModified())
1827 m_authmanager.save();
1830 JMutexAutoLock lock(m_env_mutex);
1831 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == true)
1833 // Save only changed parts
1834 m_env.getMap().save(true);
1836 // Delete unused sectors
1837 u32 deleted_count = m_env.getMap().unloadUnusedData(
1838 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1839 if(deleted_count > 0)
1841 dout_server<<"Server: Unloaded "<<deleted_count
1842 <<" sectors from memory"<<std::endl;
1846 m_env.serializePlayers(m_mapsavedir);
1848 // Save environment metadata
1849 m_env.saveMeta(m_mapsavedir);
1855 void Server::Receive()
1857 DSTACK(__FUNCTION_NAME);
1858 u32 data_maxsize = 10000;
1859 Buffer<u8> data(data_maxsize);
1864 JMutexAutoLock conlock(m_con_mutex);
1865 datasize = m_con.Receive(peer_id, *data, data_maxsize);
1868 // This has to be called so that the client list gets synced
1869 // with the peer list of the connection
1870 handlePeerChanges();
1872 ProcessData(*data, datasize, peer_id);
1874 catch(con::InvalidIncomingDataException &e)
1876 derr_server<<"Server::Receive(): "
1877 "InvalidIncomingDataException: what()="
1878 <<e.what()<<std::endl;
1880 catch(con::PeerNotFoundException &e)
1882 //NOTE: This is not needed anymore
1884 // The peer has been disconnected.
1885 // Find the associated player and remove it.
1887 /*JMutexAutoLock envlock(m_env_mutex);
1889 dout_server<<"ServerThread: peer_id="<<peer_id
1890 <<" has apparently closed connection. "
1891 <<"Removing player."<<std::endl;
1893 m_env.removePlayer(peer_id);*/
1897 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1899 DSTACK(__FUNCTION_NAME);
1900 // Environment is locked first.
1901 JMutexAutoLock envlock(m_env_mutex);
1902 JMutexAutoLock conlock(m_con_mutex);
1906 peer = m_con.GetPeer(peer_id);
1908 catch(con::PeerNotFoundException &e)
1910 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1911 <<peer_id<<" not found"<<std::endl;
1915 u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1923 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1925 if(command == TOSERVER_INIT)
1927 // [0] u16 TOSERVER_INIT
1928 // [2] u8 SER_FMT_VER_HIGHEST
1929 // [3] u8[20] player_name
1930 // [23] u8[28] password <--- can be sent without this, from old versions
1932 if(datasize < 2+1+PLAYERNAME_SIZE)
1935 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1936 <<peer->id<<std::endl;
1938 // First byte after command is maximum supported
1939 // serialization version
1940 u8 client_max = data[2];
1941 u8 our_max = SER_FMT_VER_HIGHEST;
1942 // Use the highest version supported by both
1943 u8 deployed = core::min_(client_max, our_max);
1944 // If it's lower than the lowest supported, give up.
1945 if(deployed < SER_FMT_VER_LOWEST)
1946 deployed = SER_FMT_VER_INVALID;
1948 //peer->serialization_version = deployed;
1949 getClient(peer->id)->pending_serialization_version = deployed;
1951 if(deployed == SER_FMT_VER_INVALID)
1953 derr_server<<DTIME<<"Server: Cannot negotiate "
1954 "serialization version with peer "
1955 <<peer_id<<std::endl;
1964 char playername[PLAYERNAME_SIZE];
1965 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1967 playername[i] = data[3+i];
1969 playername[PLAYERNAME_SIZE-1] = 0;
1971 if(playername[0]=='\0')
1973 derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
1974 SendAccessDenied(m_con, peer_id,
1979 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1981 derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
1982 SendAccessDenied(m_con, peer_id,
1983 L"Name contains unallowed characters");
1988 char password[PASSWORD_SIZE];
1989 if(datasize == 2+1+PLAYERNAME_SIZE)
1991 // old version - assume blank password
1996 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1998 password[i] = data[23+i];
2000 password[PASSWORD_SIZE-1] = 0;
2003 std::string checkpwd;
2004 if(m_authmanager.exists(playername))
2006 checkpwd = m_authmanager.getPassword(playername);
2010 checkpwd = g_settings.get("default_password");
2013 if(password != checkpwd && checkpwd != "")
2015 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2016 <<": supplied invalid password for "
2017 <<playername<<std::endl;
2018 SendAccessDenied(m_con, peer_id, L"Invalid password");
2022 // Add player to auth manager
2023 if(m_authmanager.exists(playername) == false)
2025 derr_server<<DTIME<<"Server: adding player "<<playername
2026 <<" to auth manager"<<std::endl;
2027 m_authmanager.add(playername);
2028 m_authmanager.setPassword(playername, checkpwd);
2029 m_authmanager.setPrivs(playername,
2030 stringToPrivs(g_settings.get("default_privs")));
2031 m_authmanager.save();
2035 Player *player = emergePlayer(playername, password, peer_id);
2039 // DEBUG: Test serialization
2040 std::ostringstream test_os;
2041 player->serialize(test_os);
2042 dstream<<"Player serialization test: \""<<test_os.str()
2044 std::istringstream test_is(test_os.str());
2045 player->deSerialize(test_is);
2048 // If failed, cancel
2051 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2052 <<": failed to emerge player"<<std::endl;
2057 // If a client is already connected to the player, cancel
2058 if(player->peer_id != 0)
2060 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2061 <<" tried to connect to "
2062 "an already connected player (peer_id="
2063 <<player->peer_id<<")"<<std::endl;
2066 // Set client of player
2067 player->peer_id = peer_id;
2070 // Check if player doesn't exist
2072 throw con::InvalidIncomingDataException
2073 ("Server::ProcessData(): INIT: Player doesn't exist");
2075 /*// update name if it was supplied
2076 if(datasize >= 20+3)
2079 player->updateName((const char*)&data[3]);
2083 Answer with a TOCLIENT_INIT
2086 SharedBuffer<u8> reply(2+1+6+8);
2087 writeU16(&reply[0], TOCLIENT_INIT);
2088 writeU8(&reply[2], deployed);
2089 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2090 writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2093 m_con.Send(peer_id, 0, reply, true);
2097 Send complete position information
2099 SendMovePlayer(player);
2104 if(command == TOSERVER_INIT2)
2106 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2107 <<peer->id<<std::endl;
2110 getClient(peer->id)->serialization_version
2111 = getClient(peer->id)->pending_serialization_version;
2114 Send some initialization data
2117 // Send player info to all players
2120 // Send inventory to player
2121 UpdateCrafting(peer->id);
2122 SendInventory(peer->id);
2126 Player *player = m_env.getPlayer(peer_id);
2127 SendPlayerHP(player);
2132 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2133 m_env.getTimeOfDay());
2134 m_con.Send(peer->id, 0, data, true);
2137 // Send information about server to player in chat
2138 SendChatMessage(peer_id, getStatusString());
2140 // Send information about joining in chat
2142 std::wstring name = L"unknown";
2143 Player *player = m_env.getPlayer(peer_id);
2145 name = narrow_to_wide(player->getName());
2147 std::wstring message;
2150 message += L" joined game";
2151 BroadcastChatMessage(message);
2157 if(peer_ser_ver == SER_FMT_VER_INVALID)
2159 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2160 " serialization format invalid or not initialized."
2161 " Skipping incoming command="<<command<<std::endl;
2165 Player *player = m_env.getPlayer(peer_id);
2168 derr_server<<"Server::ProcessData(): Cancelling: "
2169 "No player for peer_id="<<peer_id
2173 if(command == TOSERVER_PLAYERPOS)
2175 if(datasize < 2+12+12+4+4)
2179 v3s32 ps = readV3S32(&data[start+2]);
2180 v3s32 ss = readV3S32(&data[start+2+12]);
2181 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2182 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2183 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2184 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2185 pitch = wrapDegrees(pitch);
2186 yaw = wrapDegrees(yaw);
2187 player->setPosition(position);
2188 player->setSpeed(speed);
2189 player->setPitch(pitch);
2190 player->setYaw(yaw);
2192 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2193 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2194 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2196 else if(command == TOSERVER_GOTBLOCKS)
2209 u16 count = data[2];
2210 for(u16 i=0; i<count; i++)
2212 if((s16)datasize < 2+1+(i+1)*6)
2213 throw con::InvalidIncomingDataException
2214 ("GOTBLOCKS length is too short");
2215 v3s16 p = readV3S16(&data[2+1+i*6]);
2216 /*dstream<<"Server: GOTBLOCKS ("
2217 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2218 RemoteClient *client = getClient(peer_id);
2219 client->GotBlock(p);
2222 else if(command == TOSERVER_DELETEDBLOCKS)
2235 u16 count = data[2];
2236 for(u16 i=0; i<count; i++)
2238 if((s16)datasize < 2+1+(i+1)*6)
2239 throw con::InvalidIncomingDataException
2240 ("DELETEDBLOCKS length is too short");
2241 v3s16 p = readV3S16(&data[2+1+i*6]);
2242 /*dstream<<"Server: DELETEDBLOCKS ("
2243 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2244 RemoteClient *client = getClient(peer_id);
2245 client->SetBlockNotSent(p);
2248 else if(command == TOSERVER_CLICK_OBJECT)
2253 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2258 [2] u8 button (0=left, 1=right)
2263 u8 button = readU8(&data[2]);
2265 p.X = readS16(&data[3]);
2266 p.Y = readS16(&data[5]);
2267 p.Z = readS16(&data[7]);
2268 s16 id = readS16(&data[9]);
2269 //u16 item_i = readU16(&data[11]);
2271 MapBlock *block = NULL;
2274 block = m_env.getMap().getBlockNoCreate(p);
2276 catch(InvalidPositionException &e)
2278 derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2282 MapBlockObject *obj = block->getObject(id);
2286 derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2290 //TODO: Check that object is reasonably close
2295 InventoryList *ilist = player->inventory.getList("main");
2296 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2299 // Skip if inventory has no free space
2300 if(ilist->getUsedSlots() == ilist->getSize())
2302 dout_server<<"Player inventory has no free space"<<std::endl;
2307 Create the inventory item
2309 InventoryItem *item = NULL;
2310 // If it is an item-object, take the item from it
2311 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2313 item = ((ItemObject*)obj)->createInventoryItem();
2315 // Else create an item of the object
2318 item = new MapBlockObjectItem
2319 (obj->getInventoryString());
2322 // Add to inventory and send inventory
2323 ilist->addItem(item);
2324 UpdateCrafting(player->peer_id);
2325 SendInventory(player->peer_id);
2328 // Remove from block
2329 block->removeObject(id);
2332 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2337 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2343 [2] u8 button (0=left, 1=right)
2347 u8 button = readU8(&data[2]);
2348 u16 id = readS16(&data[3]);
2349 u16 item_i = readU16(&data[11]);
2351 ServerActiveObject *obj = m_env.getActiveObject(id);
2355 derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2360 //TODO: Check that object is reasonably close
2362 // Left click, pick object up (usually)
2365 InventoryList *ilist = player->inventory.getList("main");
2366 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2369 // Skip if inventory has no free space
2370 if(ilist->getUsedSlots() == ilist->getSize())
2372 dout_server<<"Player inventory has no free space"<<std::endl;
2376 // Skip if object has been removed
2381 Create the inventory item
2383 InventoryItem *item = obj->createPickedUpItem();
2387 // Add to inventory and send inventory
2388 ilist->addItem(item);
2389 UpdateCrafting(player->peer_id);
2390 SendInventory(player->peer_id);
2392 // Remove object from environment
2393 obj->m_removed = true;
2398 Item cannot be picked up. Punch it instead.
2401 ToolItem *titem = NULL;
2402 std::string toolname = "";
2404 InventoryList *mlist = player->inventory.getList("main");
2407 InventoryItem *item = mlist->getItem(item_i);
2408 if(item && (std::string)item->getName() == "ToolItem")
2410 titem = (ToolItem*)item;
2411 toolname = titem->getToolName();
2415 u16 wear = obj->punch(toolname);
2419 bool weared_out = titem->addWear(wear);
2421 mlist->deleteItem(item_i);
2422 SendInventory(player->peer_id);
2428 else if(command == TOSERVER_GROUND_ACTION)
2436 [3] v3s16 nodepos_undersurface
2437 [9] v3s16 nodepos_abovesurface
2442 2: stop digging (all parameters ignored)
2443 3: digging completed
2445 u8 action = readU8(&data[2]);
2447 p_under.X = readS16(&data[3]);
2448 p_under.Y = readS16(&data[5]);
2449 p_under.Z = readS16(&data[7]);
2451 p_over.X = readS16(&data[9]);
2452 p_over.Y = readS16(&data[11]);
2453 p_over.Z = readS16(&data[13]);
2454 u16 item_i = readU16(&data[15]);
2456 //TODO: Check that target is reasonably close
2464 NOTE: This can be used in the future to check if
2465 somebody is cheating, by checking the timing.
2472 else if(action == 2)
2475 RemoteClient *client = getClient(peer->id);
2476 JMutexAutoLock digmutex(client->m_dig_mutex);
2477 client->m_dig_tool_item = -1;
2482 3: Digging completed
2484 else if(action == 3)
2486 // Mandatory parameter; actually used for nothing
2487 core::map<v3s16, MapBlock*> modified_blocks;
2489 u8 material = CONTENT_IGNORE;
2490 u8 mineral = MINERAL_NONE;
2492 bool cannot_remove_node = false;
2496 MapNode n = m_env.getMap().getNode(p_under);
2498 mineral = n.getMineral();
2499 // Get material at position
2501 // If not yet cancelled
2502 if(cannot_remove_node == false)
2504 // If it's not diggable, do nothing
2505 if(content_diggable(material) == false)
2507 derr_server<<"Server: Not finishing digging: "
2508 <<"Node not diggable"
2510 cannot_remove_node = true;
2513 // If not yet cancelled
2514 if(cannot_remove_node == false)
2516 // Get node metadata
2517 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2518 if(meta && meta->nodeRemovalDisabled() == true)
2520 derr_server<<"Server: Not finishing digging: "
2521 <<"Node metadata disables removal"
2523 cannot_remove_node = true;
2527 catch(InvalidPositionException &e)
2529 derr_server<<"Server: Not finishing digging: Node not found."
2530 <<" Adding block to emerge queue."
2532 m_emerge_queue.addBlock(peer_id,
2533 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2534 cannot_remove_node = true;
2537 // Make sure the player is allowed to do it
2538 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2540 dstream<<"Player "<<player->getName()<<" cannot remove node"
2541 <<" because privileges are "<<getPlayerPrivs(player)
2543 cannot_remove_node = true;
2547 If node can't be removed, set block to be re-sent to
2550 if(cannot_remove_node)
2552 derr_server<<"Server: Not finishing digging."<<std::endl;
2554 // Client probably has wrong data.
2555 // Set block not sent, so that client will get
2557 dstream<<"Client "<<peer_id<<" tried to dig "
2558 <<"node; but node cannot be removed."
2559 <<" setting MapBlock not sent."<<std::endl;
2560 RemoteClient *client = getClient(peer_id);
2561 v3s16 blockpos = getNodeBlockPos(p_under);
2562 client->SetBlockNotSent(blockpos);
2568 Send the removal to all close-by players.
2569 - If other player is close, send REMOVENODE
2570 - Otherwise set blocks not sent
2572 core::list<u16> far_players;
2573 sendRemoveNode(p_under, peer_id, &far_players, 30);
2576 Update and send inventory
2579 if(g_settings.getBool("creative_mode") == false)
2584 InventoryList *mlist = player->inventory.getList("main");
2587 InventoryItem *item = mlist->getItem(item_i);
2588 if(item && (std::string)item->getName() == "ToolItem")
2590 ToolItem *titem = (ToolItem*)item;
2591 std::string toolname = titem->getToolName();
2593 // Get digging properties for material and tool
2594 DiggingProperties prop =
2595 getDiggingProperties(material, toolname);
2597 if(prop.diggable == false)
2599 derr_server<<"Server: WARNING: Player digged"
2600 <<" with impossible material + tool"
2601 <<" combination"<<std::endl;
2604 bool weared_out = titem->addWear(prop.wear);
2608 mlist->deleteItem(item_i);
2614 Add dug item to inventory
2617 InventoryItem *item = NULL;
2619 if(mineral != MINERAL_NONE)
2620 item = getDiggedMineralItem(mineral);
2625 std::string &dug_s = content_features(material).dug_item;
2628 std::istringstream is(dug_s, std::ios::binary);
2629 item = InventoryItem::deSerialize(is);
2635 // Add a item to inventory
2636 player->inventory.addItem("main", item);
2639 UpdateCrafting(player->peer_id);
2640 SendInventory(player->peer_id);
2646 (this takes some time so it is done after the quick stuff)
2649 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2651 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2654 Set blocks not sent to far players
2656 for(core::list<u16>::Iterator
2657 i = far_players.begin();
2658 i != far_players.end(); i++)
2661 RemoteClient *client = getClient(peer_id);
2664 client->SetBlocksNotSent(modified_blocks);
2671 else if(action == 1)
2674 InventoryList *ilist = player->inventory.getList("main");
2679 InventoryItem *item = ilist->getItem(item_i);
2681 // If there is no item, it is not possible to add it anywhere
2686 Handle material items
2688 if(std::string("MaterialItem") == item->getName())
2691 // Don't add a node if this is not a free space
2692 MapNode n2 = m_env.getMap().getNode(p_over);
2693 bool no_enough_privs =
2694 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2696 dstream<<"Player "<<player->getName()<<" cannot add node"
2697 <<" because privileges are "<<getPlayerPrivs(player)
2700 if(content_buildable_to(n2.d) == false
2703 // Client probably has wrong data.
2704 // Set block not sent, so that client will get
2706 dstream<<"Client "<<peer_id<<" tried to place"
2707 <<" node in invalid position; setting"
2708 <<" MapBlock not sent."<<std::endl;
2709 RemoteClient *client = getClient(peer_id);
2710 v3s16 blockpos = getNodeBlockPos(p_over);
2711 client->SetBlockNotSent(blockpos);
2715 catch(InvalidPositionException &e)
2717 derr_server<<"Server: Ignoring ADDNODE: Node not found"
2718 <<" Adding block to emerge queue."
2720 m_emerge_queue.addBlock(peer_id,
2721 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2725 // Reset build time counter
2726 getClient(peer->id)->m_time_from_building = 0.0;
2729 MaterialItem *mitem = (MaterialItem*)item;
2731 n.d = mitem->getMaterial();
2732 if(content_features(n.d).wall_mounted)
2733 n.dir = packDir(p_under - p_over);
2736 Send to all close-by players
2738 core::list<u16> far_players;
2739 sendAddNode(p_over, n, 0, &far_players, 30);
2744 InventoryList *ilist = player->inventory.getList("main");
2745 if(g_settings.getBool("creative_mode") == false && ilist)
2747 // Remove from inventory and send inventory
2748 if(mitem->getCount() == 1)
2749 ilist->deleteItem(item_i);
2753 UpdateCrafting(peer_id);
2754 SendInventory(peer_id);
2760 This takes some time so it is done after the quick stuff
2762 core::map<v3s16, MapBlock*> modified_blocks;
2764 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2766 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2769 Set blocks not sent to far players
2771 for(core::list<u16>::Iterator
2772 i = far_players.begin();
2773 i != far_players.end(); i++)
2776 RemoteClient *client = getClient(peer_id);
2779 client->SetBlocksNotSent(modified_blocks);
2783 Calculate special events
2786 /*if(n.d == CONTENT_MESE)
2789 for(s16 z=-1; z<=1; z++)
2790 for(s16 y=-1; y<=1; y++)
2791 for(s16 x=-1; x<=1; x++)
2798 Place other item (not a block)
2802 v3s16 blockpos = getNodeBlockPos(p_over);
2805 Check that the block is loaded so that the item
2806 can properly be added to the static list too
2808 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2811 derr_server<<"Error while placing object: "
2812 "block not found"<<std::endl;
2816 dout_server<<"Placing a miscellaneous item on map"
2819 // Calculate a position for it
2820 v3f pos = intToFloat(p_over, BS);
2822 pos.Y -= BS*0.25; // let it drop a bit
2824 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2825 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2830 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2834 derr_server<<"WARNING: item resulted in NULL object, "
2835 <<"not placing onto map"
2840 // Add the object to the environment
2841 m_env.addActiveObject(obj);
2843 dout_server<<"Placed object"<<std::endl;
2845 if(g_settings.getBool("creative_mode") == false)
2847 // Delete the right amount of items from the slot
2848 u16 dropcount = item->getDropCount();
2850 // Delete item if all gone
2851 if(item->getCount() <= dropcount)
2853 if(item->getCount() < dropcount)
2854 dstream<<"WARNING: Server: dropped more items"
2855 <<" than the slot contains"<<std::endl;
2857 InventoryList *ilist = player->inventory.getList("main");
2859 // Remove from inventory and send inventory
2860 ilist->deleteItem(item_i);
2862 // Else decrement it
2864 item->remove(dropcount);
2867 UpdateCrafting(peer_id);
2868 SendInventory(peer_id);
2876 Catch invalid actions
2880 derr_server<<"WARNING: Server: Invalid action "
2881 <<action<<std::endl;
2885 else if(command == TOSERVER_RELEASE)
2894 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2897 else if(command == TOSERVER_SIGNTEXT)
2899 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2908 std::string datastring((char*)&data[2], datasize-2);
2909 std::istringstream is(datastring, std::ios_base::binary);
2912 is.read((char*)buf, 6);
2913 v3s16 blockpos = readV3S16(buf);
2914 is.read((char*)buf, 2);
2915 s16 id = readS16(buf);
2916 is.read((char*)buf, 2);
2917 u16 textlen = readU16(buf);
2919 for(u16 i=0; i<textlen; i++)
2921 is.read((char*)buf, 1);
2922 text += (char)buf[0];
2925 MapBlock *block = NULL;
2928 block = m_env.getMap().getBlockNoCreate(blockpos);
2930 catch(InvalidPositionException &e)
2932 derr_server<<"Error while setting sign text: "
2933 "block not found"<<std::endl;
2937 MapBlockObject *obj = block->getObject(id);
2940 derr_server<<"Error while setting sign text: "
2941 "object not found"<<std::endl;
2945 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
2947 derr_server<<"Error while setting sign text: "
2948 "object is not a sign"<<std::endl;
2952 ((SignObject*)obj)->setText(text);
2954 obj->getBlock()->setChangedFlag();
2956 else if(command == TOSERVER_SIGNNODETEXT)
2958 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2966 std::string datastring((char*)&data[2], datasize-2);
2967 std::istringstream is(datastring, std::ios_base::binary);
2970 is.read((char*)buf, 6);
2971 v3s16 p = readV3S16(buf);
2972 is.read((char*)buf, 2);
2973 u16 textlen = readU16(buf);
2975 for(u16 i=0; i<textlen; i++)
2977 is.read((char*)buf, 1);
2978 text += (char)buf[0];
2981 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2984 if(meta->typeId() != CONTENT_SIGN_WALL)
2986 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2987 signmeta->setText(text);
2989 v3s16 blockpos = getNodeBlockPos(p);
2990 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2993 block->setChangedFlag();
2996 for(core::map<u16, RemoteClient*>::Iterator
2997 i = m_clients.getIterator();
2998 i.atEnd()==false; i++)
3000 RemoteClient *client = i.getNode()->getValue();
3001 client->SetBlockNotSent(blockpos);
3004 else if(command == TOSERVER_INVENTORY_ACTION)
3006 /*// Ignore inventory changes if in creative mode
3007 if(g_settings.getBool("creative_mode") == true)
3009 dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3013 // Strip command and create a stream
3014 std::string datastring((char*)&data[2], datasize-2);
3015 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3016 std::istringstream is(datastring, std::ios_base::binary);
3018 InventoryAction *a = InventoryAction::deSerialize(is);
3023 c.current_player = player;
3026 Handle craftresult specially if not in creative mode
3028 bool disable_action = false;
3029 if(a->getType() == IACTION_MOVE
3030 && g_settings.getBool("creative_mode") == false)
3032 IMoveAction *ma = (IMoveAction*)a;
3033 if(ma->to_inv == "current_player" &&
3034 ma->from_inv == "current_player")
3036 InventoryList *rlist = player->inventory.getList("craftresult");
3038 InventoryList *clist = player->inventory.getList("craft");
3040 InventoryList *mlist = player->inventory.getList("main");
3043 Craftresult is no longer preview if something
3046 if(ma->to_list == "craftresult"
3047 && ma->from_list != "craftresult")
3049 // If it currently is a preview, remove
3051 if(player->craftresult_is_preview)
3053 rlist->deleteItem(0);
3055 player->craftresult_is_preview = false;
3058 Crafting takes place if this condition is true.
3060 if(player->craftresult_is_preview &&
3061 ma->from_list == "craftresult")
3063 player->craftresult_is_preview = false;
3064 clist->decrementMaterials(1);
3067 If the craftresult is placed on itself, move it to
3068 main inventory instead of doing the action
3070 if(ma->to_list == "craftresult"
3071 && ma->from_list == "craftresult")
3073 disable_action = true;
3075 InventoryItem *item1 = rlist->changeItem(0, NULL);
3076 mlist->addItem(item1);
3081 if(disable_action == false)
3083 // Feed action to player inventory
3091 UpdateCrafting(player->peer_id);
3092 SendInventory(player->peer_id);
3097 dstream<<"TOSERVER_INVENTORY_ACTION: "
3098 <<"InventoryAction::deSerialize() returned NULL"
3102 else if(command == TOSERVER_CHAT_MESSAGE)
3110 std::string datastring((char*)&data[2], datasize-2);
3111 std::istringstream is(datastring, std::ios_base::binary);
3114 is.read((char*)buf, 2);
3115 u16 len = readU16(buf);
3117 std::wstring message;
3118 for(u16 i=0; i<len; i++)
3120 is.read((char*)buf, 2);
3121 message += (wchar_t)readU16(buf);
3124 // Get player name of this client
3125 std::wstring name = narrow_to_wide(player->getName());
3127 // Line to send to players
3129 // Whether to send to the player that sent the line
3130 bool send_to_sender = false;
3131 // Whether to send to other players
3132 bool send_to_others = false;
3134 // Local player gets all privileges regardless of
3135 // what's set on their account.
3136 u64 privs = getPlayerPrivs(player);
3139 std::wstring commandprefix = L"/#";
3140 if(message.substr(0, commandprefix.size()) == commandprefix)
3142 line += L"Server: ";
3144 message = message.substr(commandprefix.size());
3146 ServerCommandContext *ctx = new ServerCommandContext(
3147 str_split(message, L' '),
3153 line += processServerCommand(ctx);
3154 send_to_sender = ctx->flags & 1;
3155 send_to_others = ctx->flags & 2;
3161 if(privs & PRIV_SHOUT)
3167 send_to_others = true;
3171 line += L"Server: You are not allowed to shout";
3172 send_to_sender = true;
3178 dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3181 Send the message to clients
3183 for(core::map<u16, RemoteClient*>::Iterator
3184 i = m_clients.getIterator();
3185 i.atEnd() == false; i++)
3187 // Get client and check that it is valid
3188 RemoteClient *client = i.getNode()->getValue();
3189 assert(client->peer_id == i.getNode()->getKey());
3190 if(client->serialization_version == SER_FMT_VER_INVALID)
3194 bool sender_selected = (peer_id == client->peer_id);
3195 if(sender_selected == true && send_to_sender == false)
3197 if(sender_selected == false && send_to_others == false)
3200 SendChatMessage(client->peer_id, line);
3204 else if(command == TOSERVER_DAMAGE)
3206 if(g_settings.getBool("enable_damage"))
3208 std::string datastring((char*)&data[2], datasize-2);
3209 std::istringstream is(datastring, std::ios_base::binary);
3210 u8 damage = readU8(is);
3211 if(player->hp > damage)
3213 player->hp -= damage;
3219 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3222 v3f pos = findSpawnPos(m_env.getServerMap());
3223 player->setPosition(pos);
3225 SendMovePlayer(player);
3226 SendPlayerHP(player);
3228 //TODO: Throw items around
3232 SendPlayerHP(player);
3234 else if(command == TOSERVER_PASSWORD)
3237 [0] u16 TOSERVER_PASSWORD
3238 [2] u8[28] old password
3239 [30] u8[28] new password
3242 if(datasize != 2+PASSWORD_SIZE*2)
3244 /*char password[PASSWORD_SIZE];
3245 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3246 password[i] = data[2+i];
3247 password[PASSWORD_SIZE-1] = 0;*/
3249 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3257 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3259 char c = data[2+PASSWORD_SIZE+i];
3265 std::string playername = player->getName();
3267 if(m_authmanager.exists(playername) == false)
3269 dstream<<"Server: playername not found in authmanager"<<std::endl;
3270 // Wrong old password supplied!!
3271 SendChatMessage(peer_id, L"playername not found in authmanager");
3275 std::string checkpwd = m_authmanager.getPassword(playername);
3277 if(oldpwd != checkpwd)
3279 dstream<<"Server: invalid old password"<<std::endl;
3280 // Wrong old password supplied!!
3281 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3285 m_authmanager.setPassword(playername, newpwd);
3287 dstream<<"Server: password change successful for "<<playername
3289 SendChatMessage(peer_id, L"Password change successful");
3293 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3294 "unknown command "<<command<<std::endl;
3298 catch(SendFailedException &e)
3300 derr_server<<"Server::ProcessData(): SendFailedException: "
3306 void Server::onMapEditEvent(MapEditEvent *event)
3308 dstream<<"Server::onMapEditEvent()"<<std::endl;
3309 if(m_ignore_map_edit_events)
3311 MapEditEvent *e = event->clone();
3312 m_unsent_map_edit_queue.push_back(e);
3315 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3317 if(id == "current_player")
3319 assert(c->current_player);
3320 return &(c->current_player->inventory);
3324 std::string id0 = fn.next(":");
3326 if(id0 == "nodemeta")
3329 p.X = stoi(fn.next(","));
3330 p.Y = stoi(fn.next(","));
3331 p.Z = stoi(fn.next(","));
3332 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3334 return meta->getInventory();
3335 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3336 <<"no metadata found"<<std::endl;
3340 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3343 void Server::inventoryModified(InventoryContext *c, std::string id)
3345 if(id == "current_player")
3347 assert(c->current_player);
3349 UpdateCrafting(c->current_player->peer_id);
3350 SendInventory(c->current_player->peer_id);
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 v3s16 blockpos = getNodeBlockPos(p);
3365 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3367 meta->inventoryModified();
3369 for(core::map<u16, RemoteClient*>::Iterator
3370 i = m_clients.getIterator();
3371 i.atEnd()==false; i++)
3373 RemoteClient *client = i.getNode()->getValue();
3374 client->SetBlockNotSent(blockpos);
3380 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3383 core::list<PlayerInfo> Server::getPlayerInfo()
3385 DSTACK(__FUNCTION_NAME);
3386 JMutexAutoLock envlock(m_env_mutex);
3387 JMutexAutoLock conlock(m_con_mutex);
3389 core::list<PlayerInfo> list;
3391 core::list<Player*> players = m_env.getPlayers();
3393 core::list<Player*>::Iterator i;
3394 for(i = players.begin();
3395 i != players.end(); i++)
3399 Player *player = *i;
3402 con::Peer *peer = m_con.GetPeer(player->peer_id);
3403 // Copy info from peer to info struct
3405 info.address = peer->address;
3406 info.avg_rtt = peer->avg_rtt;
3408 catch(con::PeerNotFoundException &e)
3410 // Set dummy peer info
3412 info.address = Address(0,0,0,0,0);
3416 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3417 info.position = player->getPosition();
3419 list.push_back(info);
3426 void Server::peerAdded(con::Peer *peer)
3428 DSTACK(__FUNCTION_NAME);
3429 dout_server<<"Server::peerAdded(): peer->id="
3430 <<peer->id<<std::endl;
3433 c.type = PEER_ADDED;
3434 c.peer_id = peer->id;
3436 m_peer_change_queue.push_back(c);
3439 void Server::deletingPeer(con::Peer *peer, bool timeout)
3441 DSTACK(__FUNCTION_NAME);
3442 dout_server<<"Server::deletingPeer(): peer->id="
3443 <<peer->id<<", timeout="<<timeout<<std::endl;
3446 c.type = PEER_REMOVED;
3447 c.peer_id = peer->id;
3448 c.timeout = timeout;
3449 m_peer_change_queue.push_back(c);
3456 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3458 DSTACK(__FUNCTION_NAME);
3459 std::ostringstream os(std::ios_base::binary);
3461 writeU16(os, TOCLIENT_HP);
3465 std::string s = os.str();
3466 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3468 con.Send(peer_id, 0, data, true);
3471 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3472 const std::wstring &reason)
3474 DSTACK(__FUNCTION_NAME);
3475 std::ostringstream os(std::ios_base::binary);
3477 writeU16(os, TOCLIENT_ACCESS_DENIED);
3478 os<<serializeWideString(reason);
3481 std::string s = os.str();
3482 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3484 con.Send(peer_id, 0, data, true);
3488 Non-static send methods
3491 void Server::SendObjectData(float dtime)
3493 DSTACK(__FUNCTION_NAME);
3495 core::map<v3s16, bool> stepped_blocks;
3497 for(core::map<u16, RemoteClient*>::Iterator
3498 i = m_clients.getIterator();
3499 i.atEnd() == false; i++)
3501 u16 peer_id = i.getNode()->getKey();
3502 RemoteClient *client = i.getNode()->getValue();
3503 assert(client->peer_id == peer_id);
3505 if(client->serialization_version == SER_FMT_VER_INVALID)
3508 client->SendObjectData(this, dtime, stepped_blocks);
3512 void Server::SendPlayerInfos()
3514 DSTACK(__FUNCTION_NAME);
3516 //JMutexAutoLock envlock(m_env_mutex);
3518 // Get connected players
3519 core::list<Player*> players = m_env.getPlayers(true);
3521 u32 player_count = players.getSize();
3522 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3524 SharedBuffer<u8> data(datasize);
3525 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3528 core::list<Player*>::Iterator i;
3529 for(i = players.begin();
3530 i != players.end(); i++)
3532 Player *player = *i;
3534 /*dstream<<"Server sending player info for player with "
3535 "peer_id="<<player->peer_id<<std::endl;*/
3537 writeU16(&data[start], player->peer_id);
3538 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3539 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3540 start += 2+PLAYERNAME_SIZE;
3543 //JMutexAutoLock conlock(m_con_mutex);
3546 m_con.SendToAll(0, data, true);
3549 void Server::SendInventory(u16 peer_id)
3551 DSTACK(__FUNCTION_NAME);
3553 Player* player = m_env.getPlayer(peer_id);
3560 std::ostringstream os;
3561 //os.imbue(std::locale("C"));
3563 player->inventory.serialize(os);
3565 std::string s = os.str();
3567 SharedBuffer<u8> data(s.size()+2);
3568 writeU16(&data[0], TOCLIENT_INVENTORY);
3569 memcpy(&data[2], s.c_str(), s.size());
3572 m_con.Send(peer_id, 0, data, true);
3575 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3577 DSTACK(__FUNCTION_NAME);
3579 std::ostringstream os(std::ios_base::binary);
3583 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3584 os.write((char*)buf, 2);
3587 writeU16(buf, message.size());
3588 os.write((char*)buf, 2);
3591 for(u32 i=0; i<message.size(); i++)
3595 os.write((char*)buf, 2);
3599 std::string s = os.str();
3600 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3602 m_con.Send(peer_id, 0, data, true);
3605 void Server::BroadcastChatMessage(const std::wstring &message)
3607 for(core::map<u16, RemoteClient*>::Iterator
3608 i = m_clients.getIterator();
3609 i.atEnd() == false; i++)
3611 // Get client and check that it is valid
3612 RemoteClient *client = i.getNode()->getValue();
3613 assert(client->peer_id == i.getNode()->getKey());
3614 if(client->serialization_version == SER_FMT_VER_INVALID)
3617 SendChatMessage(client->peer_id, message);
3621 void Server::SendPlayerHP(Player *player)
3623 SendHP(m_con, player->peer_id, player->hp);
3626 void Server::SendMovePlayer(Player *player)
3628 DSTACK(__FUNCTION_NAME);
3629 std::ostringstream os(std::ios_base::binary);
3631 writeU16(os, TOCLIENT_MOVE_PLAYER);
3632 writeV3F1000(os, player->getPosition());
3633 writeF1000(os, player->getPitch());
3634 writeF1000(os, player->getYaw());
3637 v3f pos = player->getPosition();
3638 f32 pitch = player->getPitch();
3639 f32 yaw = player->getYaw();
3640 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3641 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3648 std::string s = os.str();
3649 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3651 m_con.Send(player->peer_id, 0, data, true);
3654 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3655 core::list<u16> *far_players, float far_d_nodes)
3657 float maxd = far_d_nodes*BS;
3658 v3f p_f = intToFloat(p, BS);
3662 SharedBuffer<u8> reply(replysize);
3663 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3664 writeS16(&reply[2], p.X);
3665 writeS16(&reply[4], p.Y);
3666 writeS16(&reply[6], p.Z);
3668 for(core::map<u16, RemoteClient*>::Iterator
3669 i = m_clients.getIterator();
3670 i.atEnd() == false; i++)
3672 // Get client and check that it is valid
3673 RemoteClient *client = i.getNode()->getValue();
3674 assert(client->peer_id == i.getNode()->getKey());
3675 if(client->serialization_version == SER_FMT_VER_INVALID)
3678 // Don't send if it's the same one
3679 if(client->peer_id == ignore_id)
3685 Player *player = m_env.getPlayer(client->peer_id);
3688 // If player is far away, only set modified blocks not sent
3689 v3f player_pos = player->getPosition();
3690 if(player_pos.getDistanceFrom(p_f) > maxd)
3692 far_players->push_back(client->peer_id);
3699 m_con.Send(client->peer_id, 0, reply, true);
3703 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3704 core::list<u16> *far_players, float far_d_nodes)
3706 float maxd = far_d_nodes*BS;
3707 v3f p_f = intToFloat(p, BS);
3709 for(core::map<u16, RemoteClient*>::Iterator
3710 i = m_clients.getIterator();
3711 i.atEnd() == false; i++)
3713 // Get client and check that it is valid
3714 RemoteClient *client = i.getNode()->getValue();
3715 assert(client->peer_id == i.getNode()->getKey());
3716 if(client->serialization_version == SER_FMT_VER_INVALID)
3719 // Don't send if it's the same one
3720 if(client->peer_id == ignore_id)
3726 Player *player = m_env.getPlayer(client->peer_id);
3729 // If player is far away, only set modified blocks not sent
3730 v3f player_pos = player->getPosition();
3731 if(player_pos.getDistanceFrom(p_f) > maxd)
3733 far_players->push_back(client->peer_id);
3740 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3741 SharedBuffer<u8> reply(replysize);
3742 writeU16(&reply[0], TOCLIENT_ADDNODE);
3743 writeS16(&reply[2], p.X);
3744 writeS16(&reply[4], p.Y);
3745 writeS16(&reply[6], p.Z);
3746 n.serialize(&reply[8], client->serialization_version);
3749 m_con.Send(client->peer_id, 0, reply, true);
3753 void Server::setBlockNotSent(v3s16 p)
3755 for(core::map<u16, RemoteClient*>::Iterator
3756 i = m_clients.getIterator();
3757 i.atEnd()==false; i++)
3759 RemoteClient *client = i.getNode()->getValue();
3760 client->SetBlockNotSent(p);
3764 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3766 DSTACK(__FUNCTION_NAME);
3768 v3s16 p = block->getPos();
3772 bool completely_air = true;
3773 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3774 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3775 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3777 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3779 completely_air = false;
3780 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3785 dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3787 dstream<<"[completely air] ";
3792 Create a packet with the block in the right format
3795 std::ostringstream os(std::ios_base::binary);
3796 block->serialize(os, ver);
3797 std::string s = os.str();
3798 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3800 u32 replysize = 8 + blockdata.getSize();
3801 SharedBuffer<u8> reply(replysize);
3802 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3803 writeS16(&reply[2], p.X);
3804 writeS16(&reply[4], p.Y);
3805 writeS16(&reply[6], p.Z);
3806 memcpy(&reply[8], *blockdata, blockdata.getSize());
3808 /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3809 <<": \tpacket size: "<<replysize<<std::endl;*/
3814 m_con.Send(peer_id, 1, reply, true);
3817 void Server::SendBlocks(float dtime)
3819 DSTACK(__FUNCTION_NAME);
3821 JMutexAutoLock envlock(m_env_mutex);
3822 JMutexAutoLock conlock(m_con_mutex);
3824 //TimeTaker timer("Server::SendBlocks");
3826 core::array<PrioritySortedBlockTransfer> queue;
3828 s32 total_sending = 0;
3831 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
3833 for(core::map<u16, RemoteClient*>::Iterator
3834 i = m_clients.getIterator();
3835 i.atEnd() == false; i++)
3837 RemoteClient *client = i.getNode()->getValue();
3838 assert(client->peer_id == i.getNode()->getKey());
3840 total_sending += client->SendingCount();
3842 if(client->serialization_version == SER_FMT_VER_INVALID)
3845 client->GetNextBlocks(this, dtime, queue);
3850 // Lowest priority number comes first.
3851 // Lowest is most important.
3854 for(u32 i=0; i<queue.size(); i++)
3856 //TODO: Calculate limit dynamically
3857 if(total_sending >= g_settings.getS32
3858 ("max_simultaneous_block_sends_server_total"))
3861 PrioritySortedBlockTransfer q = queue[i];
3863 MapBlock *block = NULL;
3866 block = m_env.getMap().getBlockNoCreate(q.pos);
3868 catch(InvalidPositionException &e)
3873 RemoteClient *client = getClient(q.peer_id);
3875 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3877 client->SentBlock(q.pos);
3887 void Server::UpdateCrafting(u16 peer_id)
3889 DSTACK(__FUNCTION_NAME);
3891 Player* player = m_env.getPlayer(peer_id);
3895 Calculate crafting stuff
3897 if(g_settings.getBool("creative_mode") == false)
3899 InventoryList *clist = player->inventory.getList("craft");
3900 InventoryList *rlist = player->inventory.getList("craftresult");
3902 if(rlist->getUsedSlots() == 0)
3903 player->craftresult_is_preview = true;
3905 if(rlist && player->craftresult_is_preview)
3907 rlist->clearItems();
3909 if(clist && rlist && player->craftresult_is_preview)
3911 InventoryItem *items[9];
3912 for(u16 i=0; i<9; i++)
3914 items[i] = clist->getItem(i);
3917 // Get result of crafting grid
3918 InventoryItem *result = craft_get_result(items);
3920 rlist->addItem(result);
3923 } // if creative_mode == false
3926 RemoteClient* Server::getClient(u16 peer_id)
3928 DSTACK(__FUNCTION_NAME);
3929 //JMutexAutoLock lock(m_con_mutex);
3930 core::map<u16, RemoteClient*>::Node *n;
3931 n = m_clients.find(peer_id);
3932 // A client should exist for all peers
3934 return n->getValue();
3937 std::wstring Server::getStatusString()
3939 std::wostringstream os(std::ios_base::binary);
3942 os<<L"version="<<narrow_to_wide(VERSION_STRING);
3944 os<<L", uptime="<<m_uptime.get();
3945 // Information about clients
3947 for(core::map<u16, RemoteClient*>::Iterator
3948 i = m_clients.getIterator();
3949 i.atEnd() == false; i++)
3951 // Get client and check that it is valid
3952 RemoteClient *client = i.getNode()->getValue();
3953 assert(client->peer_id == i.getNode()->getKey());
3954 if(client->serialization_version == SER_FMT_VER_INVALID)
3957 Player *player = m_env.getPlayer(client->peer_id);
3958 // Get name of player
3959 std::wstring name = L"unknown";
3961 name = narrow_to_wide(player->getName());
3962 // Add name to information string
3966 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
3967 os<<" WARNING: Map saving is disabled."<<std::endl;
3971 v3f findSpawnPos(ServerMap &map)
3973 //return v3f(50,50,50)*BS;
3976 s16 groundheight = 0;
3979 nodepos = v2s16(0,0);
3984 // Try to find a good place a few times
3985 for(s32 i=0; i<1000; i++)
3988 // We're going to try to throw the player to this position
3989 nodepos = v2s16(-range + (myrand()%(range*2)),
3990 -range + (myrand()%(range*2)));
3991 v2s16 sectorpos = getNodeSectorPos(nodepos);
3992 // Get sector (NOTE: Don't get because it's slow)
3993 //m_env.getMap().emergeSector(sectorpos);
3994 // Get ground height at point (fallbacks to heightmap function)
3995 groundheight = map.findGroundLevel(nodepos);
3996 // Don't go underwater
3997 if(groundheight < WATER_LEVEL)
3999 //dstream<<"-> Underwater"<<std::endl;
4002 // Don't go to high places
4003 if(groundheight > WATER_LEVEL + 4)
4005 //dstream<<"-> Underwater"<<std::endl;
4009 // Found a good place
4010 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4015 // If no suitable place was not found, go above water at least.
4016 if(groundheight < WATER_LEVEL)
4017 groundheight = WATER_LEVEL;
4019 return intToFloat(v3s16(
4026 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4029 Try to get an existing player
4031 Player *player = m_env.getPlayer(name);
4034 // If player is already connected, cancel
4035 if(player->peer_id != 0)
4037 dstream<<"emergePlayer(): Player already connected"<<std::endl;
4042 player->peer_id = peer_id;
4044 // Reset inventory to creative if in creative mode
4045 if(g_settings.getBool("creative_mode"))
4047 craft_set_creative_inventory(player);
4054 If player with the wanted peer_id already exists, cancel.
4056 if(m_env.getPlayer(peer_id) != NULL)
4058 dstream<<"emergePlayer(): Player with wrong name but same"
4059 " peer_id already exists"<<std::endl;
4067 player = new ServerRemotePlayer();
4068 //player->peer_id = c.peer_id;
4069 //player->peer_id = PEER_ID_INEXISTENT;
4070 player->peer_id = peer_id;
4071 player->updateName(name);
4072 m_authmanager.add(name);
4073 m_authmanager.setPassword(name, password);
4074 m_authmanager.setPrivs(name,
4075 stringToPrivs(g_settings.get("default_privs")));
4081 dstream<<"Server: Finding spawn place for player \""
4082 <<player->getName()<<"\""<<std::endl;
4084 v3f pos = findSpawnPos(m_env.getServerMap());
4086 player->setPosition(pos);
4089 Add player to environment
4092 m_env.addPlayer(player);
4095 Add stuff to inventory
4098 if(g_settings.getBool("creative_mode"))
4100 craft_set_creative_inventory(player);
4102 else if(g_settings.getBool("give_initial_stuff"))
4104 craft_give_initial_stuff(player);
4109 } // create new player
4112 void Server::handlePeerChange(PeerChange &c)
4114 JMutexAutoLock envlock(m_env_mutex);
4115 JMutexAutoLock conlock(m_con_mutex);
4117 if(c.type == PEER_ADDED)
4124 core::map<u16, RemoteClient*>::Node *n;
4125 n = m_clients.find(c.peer_id);
4126 // The client shouldn't already exist
4130 RemoteClient *client = new RemoteClient();
4131 client->peer_id = c.peer_id;
4132 m_clients.insert(client->peer_id, client);
4135 else if(c.type == PEER_REMOVED)
4142 core::map<u16, RemoteClient*>::Node *n;
4143 n = m_clients.find(c.peer_id);
4144 // The client should exist
4148 Mark objects to be not known by the client
4150 RemoteClient *client = n->getValue();
4152 for(core::map<u16, bool>::Iterator
4153 i = client->m_known_objects.getIterator();
4154 i.atEnd()==false; i++)
4157 u16 id = i.getNode()->getKey();
4158 ServerActiveObject* obj = m_env.getActiveObject(id);
4160 if(obj && obj->m_known_by_count > 0)
4161 obj->m_known_by_count--;
4164 // Collect information about leaving in chat
4165 std::wstring message;
4167 std::wstring name = L"unknown";
4168 Player *player = m_env.getPlayer(c.peer_id);
4170 name = narrow_to_wide(player->getName());
4174 message += L" left game";
4176 message += L" (timed out)";
4181 m_env.removePlayer(c.peer_id);
4184 // Set player client disconnected
4186 Player *player = m_env.getPlayer(c.peer_id);
4188 player->peer_id = 0;
4192 delete m_clients[c.peer_id];
4193 m_clients.remove(c.peer_id);
4195 // Send player info to all remaining clients
4198 // Send leave chat message to all remaining clients
4199 BroadcastChatMessage(message);
4208 void Server::handlePeerChanges()
4210 while(m_peer_change_queue.size() > 0)
4212 PeerChange c = m_peer_change_queue.pop_front();
4214 dout_server<<"Server: Handling peer change: "
4215 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4218 handlePeerChange(c);
4222 u64 Server::getPlayerPrivs(Player *player)
4226 std::string playername = player->getName();
4227 // Local player gets all privileges regardless of
4228 // what's set on their account.
4229 if(g_settings.get("name") == playername)
4235 return getPlayerAuthPrivs(playername);
4239 void dedicated_server_loop(Server &server, bool &kill)
4241 DSTACK(__FUNCTION_NAME);
4243 dstream<<DTIME<<std::endl;
4244 dstream<<"========================"<<std::endl;
4245 dstream<<"Running dedicated server"<<std::endl;
4246 dstream<<"========================"<<std::endl;
4249 IntervalLimiter m_profiler_interval;
4253 // This is kind of a hack but can be done like this
4254 // because server.step() is very light
4256 ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4261 if(server.getShutdownRequested() || kill)
4263 dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4270 float profiler_print_interval =
4271 g_settings.getFloat("profiler_print_interval");
4272 if(profiler_print_interval != 0)
4274 if(m_profiler_interval.step(0.030, profiler_print_interval))
4276 dstream<<"Profiler:"<<std::endl;
4277 g_profiler.print(dstream);
4285 static int counter = 0;
4291 core::list<PlayerInfo> list = server.getPlayerInfo();
4292 core::list<PlayerInfo>::Iterator i;
4293 static u32 sum_old = 0;
4294 u32 sum = PIChecksum(list);
4297 dstream<<DTIME<<"Player info:"<<std::endl;
4298 for(i=list.begin(); i!=list.end(); i++)
4300 i->PrintLine(&dstream);