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);
108 BEGIN_DEBUG_EXCEPTION_HANDLER
110 bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info");
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 only_from_disk = 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)
169 only_from_disk = false;
174 if(enable_mapgen_debug_info)
175 dstream<<"EmergeThread: p="
176 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
177 <<"only_from_disk="<<only_from_disk<<std::endl;
179 ServerMap &map = ((ServerMap&)m_server->m_env.getMap());
181 //core::map<v3s16, MapBlock*> changed_blocks;
182 //core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
184 MapBlock *block = NULL;
185 bool got_block = true;
186 core::map<v3s16, MapBlock*> modified_blocks;
189 Fetch block from map or generate a single block
192 JMutexAutoLock envlock(m_server->m_env_mutex);
194 // Load sector if it isn't loaded
195 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
196 //map.loadSectorFull(p2d);
197 map.loadSectorMeta(p2d);
199 block = map.getBlockNoCreateNoEx(p);
200 if(!block || block->isDummy() || !block->isGenerated())
202 if(enable_mapgen_debug_info)
203 dstream<<"EmergeThread: not in memory, loading"<<std::endl;
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(only_from_disk == false)
218 if(block == NULL || block->isGenerated() == false)
220 if(enable_mapgen_debug_info)
221 dstream<<"EmergeThread: generating"<<std::endl;
222 block = map.generateBlock(p, modified_blocks);
226 if(enable_mapgen_debug_info)
227 dstream<<"EmergeThread: ended up with: "
228 <<analyze_block(block)<<std::endl;
237 Ignore map edit events, they will not need to be
238 sent to anybody because the block hasn't been sent
241 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
243 // Activate objects and stuff
244 m_server->m_env.activateBlock(block, 3600);
249 /*if(block->getLightingExpired()){
250 lighting_invalidated_blocks[block->getPos()] = block;
254 // TODO: Some additional checking and lighting updating,
259 JMutexAutoLock envlock(m_server->m_env_mutex);
264 Collect a list of blocks that have been modified in
265 addition to the fetched one.
269 if(lighting_invalidated_blocks.size() > 0)
271 /*dstream<<"lighting "<<lighting_invalidated_blocks.size()
272 <<" blocks"<<std::endl;*/
274 // 50-100ms for single block generation
275 //TimeTaker timer("** EmergeThread updateLighting");
277 // Update lighting without locking the environment mutex,
278 // add modified blocks to changed blocks
279 map.updateLighting(lighting_invalidated_blocks, modified_blocks);
282 // Add all from changed_blocks to modified_blocks
283 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
284 i.atEnd() == false; i++)
286 MapBlock *block = i.getNode()->getValue();
287 modified_blocks.insert(block->getPos(), block);
291 // If we got no block, there should be no invalidated blocks
294 //assert(lighting_invalidated_blocks.size() == 0);
300 Set sent status of modified blocks on clients
303 // NOTE: Server's clients are also behind the connection mutex
304 JMutexAutoLock lock(m_server->m_con_mutex);
307 Add the originally fetched block to the modified list
311 modified_blocks.insert(p, block);
315 Set the modified blocks unsent for all the clients
318 for(core::map<u16, RemoteClient*>::Iterator
319 i = m_server->m_clients.getIterator();
320 i.atEnd() == false; i++)
322 RemoteClient *client = i.getNode()->getValue();
324 if(modified_blocks.size() > 0)
326 // Remove block from sent history
327 client->SetBlocksNotSent(modified_blocks);
333 END_DEBUG_EXCEPTION_HANDLER
338 void RemoteClient::GetNextBlocks(Server *server, float dtime,
339 core::array<PrioritySortedBlockTransfer> &dest)
341 DSTACK(__FUNCTION_NAME);
344 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
347 m_nothing_to_send_pause_timer -= dtime;
349 if(m_nothing_to_send_pause_timer >= 0)
352 m_nearest_unsent_reset_timer = 0;
356 // Won't send anything if already sending
357 if(m_blocks_sending.size() >= g_settings.getU16
358 ("max_simultaneous_block_sends_per_client"))
360 //dstream<<"Not sending any blocks, Queue full."<<std::endl;
364 //TimeTaker timer("RemoteClient::GetNextBlocks");
366 Player *player = server->m_env.getPlayer(peer_id);
368 assert(player != NULL);
370 v3f playerpos = player->getPosition();
371 v3f playerspeed = player->getSpeed();
372 v3f playerspeeddir(0,0,0);
373 if(playerspeed.getLength() > 1.0*BS)
374 playerspeeddir = playerspeed / playerspeed.getLength();
375 // Predict to next block
376 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
378 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
380 v3s16 center = getNodeBlockPos(center_nodepos);
382 // Camera position and direction
384 playerpos + v3f(0, BS+BS/2, 0);
385 v3f camera_dir = v3f(0,0,1);
386 camera_dir.rotateYZBy(player->getPitch());
387 camera_dir.rotateXZBy(player->getYaw());
389 /*dstream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
390 <<camera_dir.Z<<")"<<std::endl;*/
393 Get the starting value of the block finder radius.
396 if(m_last_center != center)
398 m_nearest_unsent_d = 0;
399 m_last_center = center;
402 /*dstream<<"m_nearest_unsent_reset_timer="
403 <<m_nearest_unsent_reset_timer<<std::endl;*/
405 // This has to be incremented only when the nothing to send pause
407 m_nearest_unsent_reset_timer += dtime;
409 // Reset periodically to avoid possible bugs or other mishaps
410 if(m_nearest_unsent_reset_timer > 10.0)
412 m_nearest_unsent_reset_timer = 0;
413 m_nearest_unsent_d = 0;
414 /*dstream<<"Resetting m_nearest_unsent_d for "
415 <<server->getPlayerName(peer_id)<<std::endl;*/
418 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
419 s16 d_start = m_nearest_unsent_d;
421 //dstream<<"d_start="<<d_start<<std::endl;
423 u16 max_simul_sends_setting = g_settings.getU16
424 ("max_simultaneous_block_sends_per_client");
425 u16 max_simul_sends_usually = max_simul_sends_setting;
428 Check the time from last addNode/removeNode.
430 Decrease send rate if player is building stuff.
432 m_time_from_building += dtime;
433 if(m_time_from_building < g_settings.getFloat(
434 "full_block_send_enable_min_time_from_building"))
436 max_simul_sends_usually
437 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
441 Number of blocks sending + number of blocks selected for sending
443 u32 num_blocks_selected = m_blocks_sending.size();
446 next time d will be continued from the d from which the nearest
447 unsent block was found this time.
449 This is because not necessarily any of the blocks found this
450 time are actually sent.
452 s32 new_nearest_unsent_d = -1;
454 s16 d_max = g_settings.getS16("max_block_send_distance");
455 s16 d_max_gen = g_settings.getS16("max_block_generate_distance");
457 // Don't loop very much at a time
458 if(d_max > d_start+1)
460 /*if(d_max_gen > d_start+2)
461 d_max_gen = d_start+2;*/
463 //dstream<<"Starting from "<<d_start<<std::endl;
465 bool sending_something = false;
467 bool no_blocks_found_for_sending = true;
469 bool queue_is_full = false;
472 for(d = d_start; d <= d_max; d++)
474 //dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
477 If m_nearest_unsent_d was changed by the EmergeThread
478 (it can change it to 0 through SetBlockNotSent),
480 Else update m_nearest_unsent_d
482 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
484 d = m_nearest_unsent_d;
485 last_nearest_unsent_d = m_nearest_unsent_d;
489 Get the border/face dot coordinates of a "d-radiused"
492 core::list<v3s16> list;
493 getFacePositions(list, d);
495 core::list<v3s16>::Iterator li;
496 for(li=list.begin(); li!=list.end(); li++)
498 v3s16 p = *li + center;
502 - Don't allow too many simultaneous transfers
503 - EXCEPT when the blocks are very close
505 Also, don't send blocks that are already flying.
508 // Start with the usual maximum
509 u16 max_simul_dynamic = max_simul_sends_usually;
511 // If block is very close, allow full maximum
512 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
513 max_simul_dynamic = max_simul_sends_setting;
515 // Don't select too many blocks for sending
516 if(num_blocks_selected >= max_simul_dynamic)
518 queue_is_full = true;
519 goto queue_full_break;
522 // Don't send blocks that are currently being transferred
523 if(m_blocks_sending.find(p) != NULL)
529 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
530 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
531 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
532 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
533 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
534 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
537 // If this is true, inexistent block will be made from scratch
538 bool generate = d <= d_max_gen;
541 /*// Limit the generating area vertically to 2/3
542 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
545 // Limit the send area vertically to 2/3
546 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
552 If block is far away, don't generate it unless it is
558 // Block center y in nodes
559 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
560 // Don't generate if it's very high or very low
561 if(y < -64 || y > 64)
565 v2s16 p2d_nodes_center(
569 // Get ground height in nodes
570 s16 gh = server->m_env.getServerMap().findGroundLevel(
573 // If differs a lot, don't generate
574 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
576 // Actually, don't even send it
582 //dstream<<"d="<<d<<std::endl;
585 Don't generate or send if not in sight
588 if(isBlockInSight(p, camera_pos, camera_dir, 10000*BS) == false)
594 Don't send already sent blocks
597 if(m_blocks_sent.find(p) != NULL)
604 Check if map has this block
606 MapBlock *block = server->m_env.getMap().getBlockNoCreateNoEx(p);
608 bool surely_not_found_on_disk = false;
609 bool block_is_invalid = false;
612 // Reset usage timer, this block will be of use in the future.
613 block->resetUsageTimer();
615 // Block is dummy if data doesn't exist.
616 // It means it has been not found from disk and not generated
619 surely_not_found_on_disk = true;
622 // Block is valid if lighting is up-to-date and data exists
623 if(block->isValid() == false)
625 block_is_invalid = true;
628 /*if(block->isFullyGenerated() == false)
630 block_is_invalid = true;
635 ServerMap *map = (ServerMap*)(&server->m_env.getMap());
636 v2s16 chunkpos = map->sector_to_chunk(p2d);
637 if(map->chunkNonVolatile(chunkpos) == false)
638 block_is_invalid = true;
640 if(block->isGenerated() == false)
641 block_is_invalid = true;
644 If block is not close, don't send it unless it is near
647 Block is near ground level if night-time mesh
648 differs from day-time mesh.
652 if(block->dayNightDiffed() == false)
659 If block has been marked to not exist on disk (dummy)
660 and generating new ones is not wanted, skip block.
662 if(generate == false && surely_not_found_on_disk == true)
669 Record the lowest d from which a block has been
670 found being not sent and possibly to exist
672 if(no_blocks_found_for_sending)
675 new_nearest_unsent_d = d;
678 no_blocks_found_for_sending = false;
681 Add inexistent block to emerge queue.
683 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
685 //TODO: Get value from somewhere
686 // Allow only one block in emerge queue
687 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
688 // Allow two blocks in queue per client
689 if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
691 //dstream<<"Adding block to emerge queue"<<std::endl;
693 // Add it to the emerge queue and trigger the thread
696 if(generate == false)
697 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
699 server->m_emerge_queue.addBlock(peer_id, p, flags);
700 server->m_emergethread.trigger();
708 Add block to send queue
711 PrioritySortedBlockTransfer q((float)d, p, peer_id);
715 num_blocks_selected += 1;
716 sending_something = true;
721 //dstream<<"Stopped at "<<d<<std::endl;
723 if(no_blocks_found_for_sending)
725 if(queue_is_full == false)
726 new_nearest_unsent_d = d;
729 if(new_nearest_unsent_d != -1)
730 m_nearest_unsent_d = new_nearest_unsent_d;
732 if(sending_something == false)
734 m_nothing_to_send_counter++;
735 if((s16)m_nothing_to_send_counter >=
736 g_settings.getS16("max_block_send_distance"))
738 // Pause time in seconds
739 m_nothing_to_send_pause_timer = 1.0;
740 /*dstream<<"nothing to send to "
741 <<server->getPlayerName(peer_id)
742 <<" (d="<<d<<")"<<std::endl;*/
747 m_nothing_to_send_counter = 0;
750 /*timer_result = timer.stop(true);
751 if(timer_result != 0)
752 dstream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
755 void RemoteClient::SendObjectData(
758 core::map<v3s16, bool> &stepped_blocks
761 DSTACK(__FUNCTION_NAME);
763 // Can't send anything without knowing version
764 if(serialization_version == SER_FMT_VER_INVALID)
766 dstream<<"RemoteClient::SendObjectData(): Not sending, no version."
772 Send a TOCLIENT_OBJECTDATA packet.
776 u16 number of player positions
787 std::ostringstream os(std::ios_base::binary);
791 writeU16(buf, TOCLIENT_OBJECTDATA);
792 os.write((char*)buf, 2);
795 Get and write player data
798 // Get connected players
799 core::list<Player*> players = server->m_env.getPlayers(true);
801 // Write player count
802 u16 playercount = players.size();
803 writeU16(buf, playercount);
804 os.write((char*)buf, 2);
806 core::list<Player*>::Iterator i;
807 for(i = players.begin();
808 i != players.end(); i++)
812 v3f pf = player->getPosition();
813 v3f sf = player->getSpeed();
815 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
816 v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
817 s32 pitch_i (player->getPitch() * 100);
818 s32 yaw_i (player->getYaw() * 100);
820 writeU16(buf, player->peer_id);
821 os.write((char*)buf, 2);
822 writeV3S32(buf, position_i);
823 os.write((char*)buf, 12);
824 writeV3S32(buf, speed_i);
825 os.write((char*)buf, 12);
826 writeS32(buf, pitch_i);
827 os.write((char*)buf, 4);
828 writeS32(buf, yaw_i);
829 os.write((char*)buf, 4);
833 Get and write object data
839 For making players to be able to build to their nearby
840 environment (building is not possible on blocks that are not
843 - Add blocks to emerge queue if they are not found
845 SUGGESTION: These could be ignored from the backside of the player
848 Player *player = server->m_env.getPlayer(peer_id);
852 v3f playerpos = player->getPosition();
853 v3f playerspeed = player->getSpeed();
855 v3s16 center_nodepos = floatToInt(playerpos, BS);
856 v3s16 center = getNodeBlockPos(center_nodepos);
858 s16 d_max = g_settings.getS16("active_object_range");
860 // Number of blocks whose objects were written to bos
863 std::ostringstream bos(std::ios_base::binary);
865 for(s16 d = 0; d <= d_max; d++)
867 core::list<v3s16> list;
868 getFacePositions(list, d);
870 core::list<v3s16>::Iterator li;
871 for(li=list.begin(); li!=list.end(); li++)
873 v3s16 p = *li + center;
876 Ignore blocks that haven't been sent to the client
879 if(m_blocks_sent.find(p) == NULL)
883 // Try stepping block and add it to a send queue
888 MapBlock *block = server->m_env.getMap().getBlockNoCreate(p);
891 Step block if not in stepped_blocks and add to stepped_blocks.
893 if(stepped_blocks.find(p) == NULL)
895 block->stepObjects(dtime, true, server->m_env.getDayNightRatio());
896 stepped_blocks.insert(p, true);
897 block->setChangedFlag();
900 // Skip block if there are no objects
901 if(block->getObjectCount() == 0)
910 bos.write((char*)buf, 6);
913 //block->serializeObjects(bos, serialization_version); // DEPRECATED
920 Stop collecting objects if data is already too big
922 // Sum of player and object data sizes
923 s32 sum = (s32)os.tellp() + 2 + (s32)bos.tellp();
924 // break out if data too big
925 if(sum > MAX_OBJECTDATA_SIZE)
927 goto skip_subsequent;
931 catch(InvalidPositionException &e)
934 // Add it to the emerge queue and trigger the thread.
935 // Fetch the block only if it is on disk.
937 // Grab and increment counter
938 /*SharedPtr<JMutexAutoLock> lock
939 (m_num_blocks_in_emerge_queue.getLock());
940 m_num_blocks_in_emerge_queue.m_value++;*/
942 // Add to queue as an anonymous fetch from disk
943 u8 flags = BLOCK_EMERGE_FLAG_FROMDISK;
944 server->m_emerge_queue.addBlock(0, p, flags);
945 server->m_emergethread.trigger();
953 writeU16(buf, blockcount);
954 os.write((char*)buf, 2);
956 // Write block objects
963 //dstream<<"Server: Sending object data to "<<peer_id<<std::endl;
966 std::string s = os.str();
967 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
968 // Send as unreliable
969 server->m_con.Send(peer_id, 0, data, false);
972 void RemoteClient::GotBlock(v3s16 p)
974 if(m_blocks_sending.find(p) != NULL)
975 m_blocks_sending.remove(p);
978 /*dstream<<"RemoteClient::GotBlock(): Didn't find in"
979 " m_blocks_sending"<<std::endl;*/
980 m_excess_gotblocks++;
982 m_blocks_sent.insert(p, true);
985 void RemoteClient::SentBlock(v3s16 p)
987 if(m_blocks_sending.find(p) == NULL)
988 m_blocks_sending.insert(p, 0.0);
990 dstream<<"RemoteClient::SentBlock(): Sent block"
991 " already in m_blocks_sending"<<std::endl;
994 void RemoteClient::SetBlockNotSent(v3s16 p)
996 m_nearest_unsent_d = 0;
998 if(m_blocks_sending.find(p) != NULL)
999 m_blocks_sending.remove(p);
1000 if(m_blocks_sent.find(p) != NULL)
1001 m_blocks_sent.remove(p);
1004 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
1006 m_nearest_unsent_d = 0;
1008 for(core::map<v3s16, MapBlock*>::Iterator
1009 i = blocks.getIterator();
1010 i.atEnd()==false; i++)
1012 v3s16 p = i.getNode()->getKey();
1014 if(m_blocks_sending.find(p) != NULL)
1015 m_blocks_sending.remove(p);
1016 if(m_blocks_sent.find(p) != NULL)
1017 m_blocks_sent.remove(p);
1025 PlayerInfo::PlayerInfo()
1031 void PlayerInfo::PrintLine(std::ostream *s)
1034 (*s)<<"\""<<name<<"\" ("
1035 <<(position.X/10)<<","<<(position.Y/10)
1036 <<","<<(position.Z/10)<<") ";
1038 (*s)<<" avg_rtt="<<avg_rtt;
1042 u32 PIChecksum(core::list<PlayerInfo> &l)
1044 core::list<PlayerInfo>::Iterator i;
1047 for(i=l.begin(); i!=l.end(); i++)
1049 checksum += a * (i->id+1);
1050 checksum ^= 0x435aafcd;
1061 std::string mapsavedir
1063 m_env(new ServerMap(mapsavedir), this),
1064 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
1065 m_authmanager(mapsavedir+"/auth.txt"),
1067 m_emergethread(this),
1069 m_time_of_day_send_timer(0),
1071 m_mapsavedir(mapsavedir),
1072 m_shutdown_requested(false),
1073 m_ignore_map_edit_events(false),
1074 m_ignore_map_edit_events_peer_id(0)
1076 m_liquid_transform_timer = 0.0;
1077 m_print_info_timer = 0.0;
1078 m_objectdata_timer = 0.0;
1079 m_emergethread_trigger_timer = 0.0;
1080 m_savemap_timer = 0.0;
1084 m_step_dtime_mutex.Init();
1087 // Register us to receive map edit events
1088 m_env.getMap().addEventReceiver(this);
1090 // If file exists, load environment metadata
1091 if(fs::PathExists(m_mapsavedir+"/env_meta.txt"))
1093 dstream<<"Server: Loading environment metadata"<<std::endl;
1094 m_env.loadMeta(m_mapsavedir);
1098 dstream<<"Server: Loading players"<<std::endl;
1099 m_env.deSerializePlayers(m_mapsavedir);
1104 dstream<<"Server::~Server()"<<std::endl;
1107 Send shutdown message
1110 JMutexAutoLock conlock(m_con_mutex);
1112 std::wstring line = L"*** Server shutting down";
1115 Send the message to clients
1117 for(core::map<u16, RemoteClient*>::Iterator
1118 i = m_clients.getIterator();
1119 i.atEnd() == false; i++)
1121 // Get client and check that it is valid
1122 RemoteClient *client = i.getNode()->getValue();
1123 assert(client->peer_id == i.getNode()->getKey());
1124 if(client->serialization_version == SER_FMT_VER_INVALID)
1128 SendChatMessage(client->peer_id, line);
1130 catch(con::PeerNotFoundException &e)
1138 dstream<<"Server: Saving players"<<std::endl;
1139 m_env.serializePlayers(m_mapsavedir);
1142 Save environment metadata
1144 dstream<<"Server: Saving environment metadata"<<std::endl;
1145 m_env.saveMeta(m_mapsavedir);
1156 JMutexAutoLock clientslock(m_con_mutex);
1158 for(core::map<u16, RemoteClient*>::Iterator
1159 i = m_clients.getIterator();
1160 i.atEnd() == false; i++)
1163 // NOTE: These are removed by env destructor
1165 u16 peer_id = i.getNode()->getKey();
1166 JMutexAutoLock envlock(m_env_mutex);
1167 m_env.removePlayer(peer_id);
1171 delete i.getNode()->getValue();
1176 void Server::start(unsigned short port)
1178 DSTACK(__FUNCTION_NAME);
1179 // Stop thread if already running
1182 // Initialize connection
1183 m_con.setTimeoutMs(30);
1187 m_thread.setRun(true);
1190 dout_server<<"Server: Started on port "<<port<<std::endl;
1195 DSTACK(__FUNCTION_NAME);
1197 // Stop threads (set run=false first so both start stopping)
1198 m_thread.setRun(false);
1199 m_emergethread.setRun(false);
1201 m_emergethread.stop();
1203 dout_server<<"Server: Threads stopped"<<std::endl;
1206 void Server::step(float dtime)
1208 DSTACK(__FUNCTION_NAME);
1213 JMutexAutoLock lock(m_step_dtime_mutex);
1214 m_step_dtime += dtime;
1218 void Server::AsyncRunStep()
1220 DSTACK(__FUNCTION_NAME);
1224 JMutexAutoLock lock1(m_step_dtime_mutex);
1225 dtime = m_step_dtime;
1229 ScopeProfiler sp(&g_profiler, "Server: selecting and sending "
1230 "blocks to clients");
1231 // Send blocks to clients
1238 //dstream<<"Server steps "<<dtime<<std::endl;
1239 //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1242 JMutexAutoLock lock1(m_step_dtime_mutex);
1243 m_step_dtime -= dtime;
1250 m_uptime.set(m_uptime.get() + dtime);
1254 Update m_time_of_day and overall game time
1257 JMutexAutoLock envlock(m_env_mutex);
1259 m_time_counter += dtime;
1260 f32 speed = g_settings.getFloat("time_speed") * 24000./(24.*3600);
1261 u32 units = (u32)(m_time_counter*speed);
1262 m_time_counter -= (f32)units / speed;
1264 m_env.setTimeOfDay((m_env.getTimeOfDay() + units) % 24000);
1266 //dstream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1269 Send to clients at constant intervals
1272 m_time_of_day_send_timer -= dtime;
1273 if(m_time_of_day_send_timer < 0.0)
1275 m_time_of_day_send_timer = g_settings.getFloat("time_send_interval");
1277 //JMutexAutoLock envlock(m_env_mutex);
1278 JMutexAutoLock conlock(m_con_mutex);
1280 for(core::map<u16, RemoteClient*>::Iterator
1281 i = m_clients.getIterator();
1282 i.atEnd() == false; i++)
1284 RemoteClient *client = i.getNode()->getValue();
1285 //Player *player = m_env.getPlayer(client->peer_id);
1287 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1288 m_env.getTimeOfDay());
1290 m_con.Send(client->peer_id, 0, data, true);
1296 // Process connection's timeouts
1297 JMutexAutoLock lock2(m_con_mutex);
1298 ScopeProfiler sp(&g_profiler, "Server: connection timeout processing");
1299 m_con.RunTimeouts(dtime);
1303 // This has to be called so that the client list gets synced
1304 // with the peer list of the connection
1305 ScopeProfiler sp(&g_profiler, "Server: peer change handling");
1306 handlePeerChanges();
1310 JMutexAutoLock lock(m_env_mutex);
1312 ScopeProfiler sp(&g_profiler, "Server: environment step");
1316 const float map_timer_and_unload_dtime = 5.15;
1317 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1319 JMutexAutoLock lock(m_env_mutex);
1320 // Run Map's timers and unload unused data
1321 ScopeProfiler sp(&g_profiler, "Server: map timer and unload");
1322 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
1323 g_settings.getFloat("server_unload_unused_data_timeout"));
1333 m_liquid_transform_timer += dtime;
1334 if(m_liquid_transform_timer >= 1.00)
1336 m_liquid_transform_timer -= 1.00;
1338 JMutexAutoLock lock(m_env_mutex);
1340 ScopeProfiler sp(&g_profiler, "Server: liquid transform");
1342 core::map<v3s16, MapBlock*> modified_blocks;
1343 m_env.getMap().transformLiquids(modified_blocks);
1348 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1349 ServerMap &map = ((ServerMap&)m_env.getMap());
1350 map.updateLighting(modified_blocks, lighting_modified_blocks);
1352 // Add blocks modified by lighting to modified_blocks
1353 for(core::map<v3s16, MapBlock*>::Iterator
1354 i = lighting_modified_blocks.getIterator();
1355 i.atEnd() == false; i++)
1357 MapBlock *block = i.getNode()->getValue();
1358 modified_blocks.insert(block->getPos(), block);
1362 Set the modified blocks unsent for all the clients
1365 JMutexAutoLock lock2(m_con_mutex);
1367 for(core::map<u16, RemoteClient*>::Iterator
1368 i = m_clients.getIterator();
1369 i.atEnd() == false; i++)
1371 RemoteClient *client = i.getNode()->getValue();
1373 if(modified_blocks.size() > 0)
1375 // Remove block from sent history
1376 client->SetBlocksNotSent(modified_blocks);
1381 // Periodically print some info
1383 float &counter = m_print_info_timer;
1389 JMutexAutoLock lock2(m_con_mutex);
1391 for(core::map<u16, RemoteClient*>::Iterator
1392 i = m_clients.getIterator();
1393 i.atEnd() == false; i++)
1395 //u16 peer_id = i.getNode()->getKey();
1396 RemoteClient *client = i.getNode()->getValue();
1397 Player *player = m_env.getPlayer(client->peer_id);
1400 std::cout<<player->getName()<<"\t";
1401 client->PrintInfo(std::cout);
1406 //if(g_settings.getBool("enable_experimental"))
1410 Check added and deleted active objects
1413 //dstream<<"Server: Checking added and deleted active objects"<<std::endl;
1414 JMutexAutoLock envlock(m_env_mutex);
1415 JMutexAutoLock conlock(m_con_mutex);
1417 ScopeProfiler sp(&g_profiler, "Server: checking added and deleted objects");
1419 // Radius inside which objects are active
1422 for(core::map<u16, RemoteClient*>::Iterator
1423 i = m_clients.getIterator();
1424 i.atEnd() == false; i++)
1426 RemoteClient *client = i.getNode()->getValue();
1427 Player *player = m_env.getPlayer(client->peer_id);
1430 // This can happen if the client timeouts somehow
1431 /*dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1433 <<" has no associated player"<<std::endl;*/
1436 v3s16 pos = floatToInt(player->getPosition(), BS);
1438 core::map<u16, bool> removed_objects;
1439 core::map<u16, bool> added_objects;
1440 m_env.getRemovedActiveObjects(pos, radius,
1441 client->m_known_objects, removed_objects);
1442 m_env.getAddedActiveObjects(pos, radius,
1443 client->m_known_objects, added_objects);
1445 // Ignore if nothing happened
1446 if(removed_objects.size() == 0 && added_objects.size() == 0)
1448 //dstream<<"INFO: active objects: none changed"<<std::endl;
1452 std::string data_buffer;
1456 // Handle removed objects
1457 writeU16((u8*)buf, removed_objects.size());
1458 data_buffer.append(buf, 2);
1459 for(core::map<u16, bool>::Iterator
1460 i = removed_objects.getIterator();
1461 i.atEnd()==false; i++)
1464 u16 id = i.getNode()->getKey();
1465 ServerActiveObject* obj = m_env.getActiveObject(id);
1467 // Add to data buffer for sending
1468 writeU16((u8*)buf, i.getNode()->getKey());
1469 data_buffer.append(buf, 2);
1471 // Remove from known objects
1472 client->m_known_objects.remove(i.getNode()->getKey());
1474 if(obj && obj->m_known_by_count > 0)
1475 obj->m_known_by_count--;
1478 // Handle added objects
1479 writeU16((u8*)buf, added_objects.size());
1480 data_buffer.append(buf, 2);
1481 for(core::map<u16, bool>::Iterator
1482 i = added_objects.getIterator();
1483 i.atEnd()==false; i++)
1486 u16 id = i.getNode()->getKey();
1487 ServerActiveObject* obj = m_env.getActiveObject(id);
1490 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1492 dstream<<"WARNING: "<<__FUNCTION_NAME
1493 <<": NULL object"<<std::endl;
1495 type = obj->getType();
1497 // Add to data buffer for sending
1498 writeU16((u8*)buf, id);
1499 data_buffer.append(buf, 2);
1500 writeU8((u8*)buf, type);
1501 data_buffer.append(buf, 1);
1504 data_buffer.append(serializeLongString(
1505 obj->getClientInitializationData()));
1507 data_buffer.append(serializeLongString(""));
1509 // Add to known objects
1510 client->m_known_objects.insert(i.getNode()->getKey(), false);
1513 obj->m_known_by_count++;
1517 SharedBuffer<u8> reply(2 + data_buffer.size());
1518 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1519 memcpy((char*)&reply[2], data_buffer.c_str(),
1520 data_buffer.size());
1522 m_con.Send(client->peer_id, 0, reply, true);
1524 dstream<<"INFO: Server: Sent object remove/add: "
1525 <<removed_objects.size()<<" removed, "
1526 <<added_objects.size()<<" added, "
1527 <<"packet size is "<<reply.getSize()<<std::endl;
1532 Collect a list of all the objects known by the clients
1533 and report it back to the environment.
1536 core::map<u16, bool> all_known_objects;
1538 for(core::map<u16, RemoteClient*>::Iterator
1539 i = m_clients.getIterator();
1540 i.atEnd() == false; i++)
1542 RemoteClient *client = i.getNode()->getValue();
1543 // Go through all known objects of client
1544 for(core::map<u16, bool>::Iterator
1545 i = client->m_known_objects.getIterator();
1546 i.atEnd()==false; i++)
1548 u16 id = i.getNode()->getKey();
1549 all_known_objects[id] = true;
1553 m_env.setKnownActiveObjects(whatever);
1559 Send object messages
1562 JMutexAutoLock envlock(m_env_mutex);
1563 JMutexAutoLock conlock(m_con_mutex);
1565 ScopeProfiler sp(&g_profiler, "Server: sending object messages");
1568 // Value = data sent by object
1569 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1571 // Get active object messages from environment
1574 ActiveObjectMessage aom = m_env.getActiveObjectMessage();
1578 core::list<ActiveObjectMessage>* message_list = NULL;
1579 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1580 n = buffered_messages.find(aom.id);
1583 message_list = new core::list<ActiveObjectMessage>;
1584 buffered_messages.insert(aom.id, message_list);
1588 message_list = n->getValue();
1590 message_list->push_back(aom);
1593 // Route data to every client
1594 for(core::map<u16, RemoteClient*>::Iterator
1595 i = m_clients.getIterator();
1596 i.atEnd()==false; i++)
1598 RemoteClient *client = i.getNode()->getValue();
1599 std::string reliable_data;
1600 std::string unreliable_data;
1601 // Go through all objects in message buffer
1602 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1603 j = buffered_messages.getIterator();
1604 j.atEnd()==false; j++)
1606 // If object is not known by client, skip it
1607 u16 id = j.getNode()->getKey();
1608 if(client->m_known_objects.find(id) == NULL)
1610 // Get message list of object
1611 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1612 // Go through every message
1613 for(core::list<ActiveObjectMessage>::Iterator
1614 k = list->begin(); k != list->end(); k++)
1616 // Compose the full new data with header
1617 ActiveObjectMessage aom = *k;
1618 std::string new_data;
1621 writeU16((u8*)&buf[0], aom.id);
1622 new_data.append(buf, 2);
1624 new_data += serializeString(aom.datastring);
1625 // Add data to buffer
1627 reliable_data += new_data;
1629 unreliable_data += new_data;
1633 reliable_data and unreliable_data are now ready.
1636 if(reliable_data.size() > 0)
1638 SharedBuffer<u8> reply(2 + reliable_data.size());
1639 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1640 memcpy((char*)&reply[2], reliable_data.c_str(),
1641 reliable_data.size());
1643 m_con.Send(client->peer_id, 0, reply, true);
1645 if(unreliable_data.size() > 0)
1647 SharedBuffer<u8> reply(2 + unreliable_data.size());
1648 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1649 memcpy((char*)&reply[2], unreliable_data.c_str(),
1650 unreliable_data.size());
1651 // Send as unreliable
1652 m_con.Send(client->peer_id, 0, reply, false);
1655 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1657 dstream<<"INFO: Server: Size of object message data: "
1658 <<"reliable: "<<reliable_data.size()
1659 <<", unreliable: "<<unreliable_data.size()
1664 // Clear buffered_messages
1665 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1666 i = buffered_messages.getIterator();
1667 i.atEnd()==false; i++)
1669 delete i.getNode()->getValue();
1673 } // enable_experimental
1676 Send queued-for-sending map edit events.
1679 // Don't send too many at a time
1682 // Single change sending is disabled if queue size is not small
1683 bool disable_single_change_sending = false;
1684 if(m_unsent_map_edit_queue.size() >= 4)
1685 disable_single_change_sending = true;
1687 bool got_any_events = false;
1689 // We'll log the amount of each
1692 while(m_unsent_map_edit_queue.size() != 0)
1694 got_any_events = true;
1696 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1698 // Players far away from the change are stored here.
1699 // Instead of sending the changes, MapBlocks are set not sent
1701 core::list<u16> far_players;
1703 if(event->type == MEET_ADDNODE)
1705 //dstream<<"Server: MEET_ADDNODE"<<std::endl;
1706 prof.add("MEET_ADDNODE", 1);
1707 if(disable_single_change_sending)
1708 sendAddNode(event->p, event->n, event->already_known_by_peer,
1711 sendAddNode(event->p, event->n, event->already_known_by_peer,
1714 else if(event->type == MEET_REMOVENODE)
1716 //dstream<<"Server: MEET_REMOVENODE"<<std::endl;
1717 prof.add("MEET_REMOVENODE", 1);
1718 if(disable_single_change_sending)
1719 sendRemoveNode(event->p, event->already_known_by_peer,
1722 sendRemoveNode(event->p, event->already_known_by_peer,
1725 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1727 dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1728 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1729 setBlockNotSent(event->p);
1731 else if(event->type == MEET_OTHER)
1733 prof.add("MEET_OTHER", 1);
1734 dstream<<"WARNING: Server: MEET_OTHER not implemented"
1739 prof.add("unknown", 1);
1740 dstream<<"WARNING: Server: Unknown MapEditEvent "
1741 <<((u32)event->type)<<std::endl;
1745 Set blocks not sent to far players
1747 if(far_players.size() > 0)
1749 // Convert list format to that wanted by SetBlocksNotSent
1750 core::map<v3s16, MapBlock*> modified_blocks2;
1751 for(core::map<v3s16, bool>::Iterator
1752 i = event->modified_blocks.getIterator();
1753 i.atEnd()==false; i++)
1755 v3s16 p = i.getNode()->getKey();
1756 modified_blocks2.insert(p,
1757 m_env.getMap().getBlockNoCreateNoEx(p));
1759 // Set blocks not sent
1760 for(core::list<u16>::Iterator
1761 i = far_players.begin();
1762 i != far_players.end(); i++)
1765 RemoteClient *client = getClient(peer_id);
1768 client->SetBlocksNotSent(modified_blocks2);
1774 /*// Don't send too many at a time
1776 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1782 dstream<<"Server: MapEditEvents:"<<std::endl;
1783 prof.print(dstream);
1789 Send object positions
1790 TODO: Get rid of MapBlockObjects
1793 float &counter = m_objectdata_timer;
1795 if(counter >= g_settings.getFloat("objectdata_interval"))
1797 JMutexAutoLock lock1(m_env_mutex);
1798 JMutexAutoLock lock2(m_con_mutex);
1800 ScopeProfiler sp(&g_profiler, "Server: sending mbo positions");
1802 SendObjectData(counter);
1809 Trigger emergethread (it somehow gets to a non-triggered but
1810 bysy state sometimes)
1813 float &counter = m_emergethread_trigger_timer;
1819 m_emergethread.trigger();
1823 // Save map, players and auth stuff
1825 float &counter = m_savemap_timer;
1827 if(counter >= g_settings.getFloat("server_map_save_interval"))
1831 ScopeProfiler sp(&g_profiler, "Server: saving stuff");
1834 if(m_authmanager.isModified())
1835 m_authmanager.save();
1838 JMutexAutoLock lock(m_env_mutex);
1840 /*// Unload unused data (delete from memory)
1841 m_env.getMap().unloadUnusedData(
1842 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1844 /*u32 deleted_count = m_env.getMap().unloadUnusedData(
1845 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1848 // Save only changed parts
1849 m_env.getMap().save(true);
1851 /*if(deleted_count > 0)
1853 dout_server<<"Server: Unloaded "<<deleted_count
1854 <<" blocks from memory"<<std::endl;
1858 m_env.serializePlayers(m_mapsavedir);
1860 // Save environment metadata
1861 m_env.saveMeta(m_mapsavedir);
1866 void Server::Receive()
1868 DSTACK(__FUNCTION_NAME);
1869 u32 data_maxsize = 10000;
1870 Buffer<u8> data(data_maxsize);
1875 JMutexAutoLock conlock(m_con_mutex);
1876 datasize = m_con.Receive(peer_id, *data, data_maxsize);
1879 // This has to be called so that the client list gets synced
1880 // with the peer list of the connection
1881 handlePeerChanges();
1883 ProcessData(*data, datasize, peer_id);
1885 catch(con::InvalidIncomingDataException &e)
1887 derr_server<<"Server::Receive(): "
1888 "InvalidIncomingDataException: what()="
1889 <<e.what()<<std::endl;
1891 catch(con::PeerNotFoundException &e)
1893 //NOTE: This is not needed anymore
1895 // The peer has been disconnected.
1896 // Find the associated player and remove it.
1898 /*JMutexAutoLock envlock(m_env_mutex);
1900 dout_server<<"ServerThread: peer_id="<<peer_id
1901 <<" has apparently closed connection. "
1902 <<"Removing player."<<std::endl;
1904 m_env.removePlayer(peer_id);*/
1908 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1910 DSTACK(__FUNCTION_NAME);
1911 // Environment is locked first.
1912 JMutexAutoLock envlock(m_env_mutex);
1913 JMutexAutoLock conlock(m_con_mutex);
1917 peer = m_con.GetPeer(peer_id);
1919 catch(con::PeerNotFoundException &e)
1921 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1922 <<peer_id<<" not found"<<std::endl;
1926 u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1934 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1936 if(command == TOSERVER_INIT)
1938 // [0] u16 TOSERVER_INIT
1939 // [2] u8 SER_FMT_VER_HIGHEST
1940 // [3] u8[20] player_name
1941 // [23] u8[28] password <--- can be sent without this, from old versions
1943 if(datasize < 2+1+PLAYERNAME_SIZE)
1946 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1947 <<peer->id<<std::endl;
1949 // First byte after command is maximum supported
1950 // serialization version
1951 u8 client_max = data[2];
1952 u8 our_max = SER_FMT_VER_HIGHEST;
1953 // Use the highest version supported by both
1954 u8 deployed = core::min_(client_max, our_max);
1955 // If it's lower than the lowest supported, give up.
1956 if(deployed < SER_FMT_VER_LOWEST)
1957 deployed = SER_FMT_VER_INVALID;
1959 //peer->serialization_version = deployed;
1960 getClient(peer->id)->pending_serialization_version = deployed;
1962 if(deployed == SER_FMT_VER_INVALID)
1964 derr_server<<DTIME<<"Server: Cannot negotiate "
1965 "serialization version with peer "
1966 <<peer_id<<std::endl;
1975 char playername[PLAYERNAME_SIZE];
1976 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1978 playername[i] = data[3+i];
1980 playername[PLAYERNAME_SIZE-1] = 0;
1982 if(playername[0]=='\0')
1984 derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
1985 SendAccessDenied(m_con, peer_id,
1990 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1992 derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
1993 SendAccessDenied(m_con, peer_id,
1994 L"Name contains unallowed characters");
1999 char password[PASSWORD_SIZE];
2000 if(datasize == 2+1+PLAYERNAME_SIZE)
2002 // old version - assume blank password
2007 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2009 password[i] = data[23+i];
2011 password[PASSWORD_SIZE-1] = 0;
2014 std::string checkpwd;
2015 if(m_authmanager.exists(playername))
2017 checkpwd = m_authmanager.getPassword(playername);
2021 checkpwd = g_settings.get("default_password");
2024 if(password != checkpwd && checkpwd != "")
2026 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2027 <<": supplied invalid password for "
2028 <<playername<<std::endl;
2029 SendAccessDenied(m_con, peer_id, L"Invalid password");
2033 // Add player to auth manager
2034 if(m_authmanager.exists(playername) == false)
2036 derr_server<<DTIME<<"Server: adding player "<<playername
2037 <<" to auth manager"<<std::endl;
2038 m_authmanager.add(playername);
2039 m_authmanager.setPassword(playername, checkpwd);
2040 m_authmanager.setPrivs(playername,
2041 stringToPrivs(g_settings.get("default_privs")));
2042 m_authmanager.save();
2046 Player *player = emergePlayer(playername, password, peer_id);
2050 // DEBUG: Test serialization
2051 std::ostringstream test_os;
2052 player->serialize(test_os);
2053 dstream<<"Player serialization test: \""<<test_os.str()
2055 std::istringstream test_is(test_os.str());
2056 player->deSerialize(test_is);
2059 // If failed, cancel
2062 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2063 <<": failed to emerge player"<<std::endl;
2068 // If a client is already connected to the player, cancel
2069 if(player->peer_id != 0)
2071 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2072 <<" tried to connect to "
2073 "an already connected player (peer_id="
2074 <<player->peer_id<<")"<<std::endl;
2077 // Set client of player
2078 player->peer_id = peer_id;
2081 // Check if player doesn't exist
2083 throw con::InvalidIncomingDataException
2084 ("Server::ProcessData(): INIT: Player doesn't exist");
2086 /*// update name if it was supplied
2087 if(datasize >= 20+3)
2090 player->updateName((const char*)&data[3]);
2094 Answer with a TOCLIENT_INIT
2097 SharedBuffer<u8> reply(2+1+6+8);
2098 writeU16(&reply[0], TOCLIENT_INIT);
2099 writeU8(&reply[2], deployed);
2100 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2101 writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2104 m_con.Send(peer_id, 0, reply, true);
2108 Send complete position information
2110 SendMovePlayer(player);
2115 if(command == TOSERVER_INIT2)
2117 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2118 <<peer->id<<std::endl;
2121 getClient(peer->id)->serialization_version
2122 = getClient(peer->id)->pending_serialization_version;
2125 Send some initialization data
2128 // Send player info to all players
2131 // Send inventory to player
2132 UpdateCrafting(peer->id);
2133 SendInventory(peer->id);
2137 Player *player = m_env.getPlayer(peer_id);
2138 SendPlayerHP(player);
2143 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2144 m_env.getTimeOfDay());
2145 m_con.Send(peer->id, 0, data, true);
2148 // Send information about server to player in chat
2149 SendChatMessage(peer_id, getStatusString());
2151 // Send information about joining in chat
2153 std::wstring name = L"unknown";
2154 Player *player = m_env.getPlayer(peer_id);
2156 name = narrow_to_wide(player->getName());
2158 std::wstring message;
2161 message += L" joined game";
2162 BroadcastChatMessage(message);
2168 if(peer_ser_ver == SER_FMT_VER_INVALID)
2170 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2171 " serialization format invalid or not initialized."
2172 " Skipping incoming command="<<command<<std::endl;
2176 Player *player = m_env.getPlayer(peer_id);
2179 derr_server<<"Server::ProcessData(): Cancelling: "
2180 "No player for peer_id="<<peer_id
2184 if(command == TOSERVER_PLAYERPOS)
2186 if(datasize < 2+12+12+4+4)
2190 v3s32 ps = readV3S32(&data[start+2]);
2191 v3s32 ss = readV3S32(&data[start+2+12]);
2192 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2193 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2194 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2195 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2196 pitch = wrapDegrees(pitch);
2197 yaw = wrapDegrees(yaw);
2198 player->setPosition(position);
2199 player->setSpeed(speed);
2200 player->setPitch(pitch);
2201 player->setYaw(yaw);
2203 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2204 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2205 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2207 else if(command == TOSERVER_GOTBLOCKS)
2220 u16 count = data[2];
2221 for(u16 i=0; i<count; i++)
2223 if((s16)datasize < 2+1+(i+1)*6)
2224 throw con::InvalidIncomingDataException
2225 ("GOTBLOCKS length is too short");
2226 v3s16 p = readV3S16(&data[2+1+i*6]);
2227 /*dstream<<"Server: GOTBLOCKS ("
2228 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2229 RemoteClient *client = getClient(peer_id);
2230 client->GotBlock(p);
2233 else if(command == TOSERVER_DELETEDBLOCKS)
2246 u16 count = data[2];
2247 for(u16 i=0; i<count; i++)
2249 if((s16)datasize < 2+1+(i+1)*6)
2250 throw con::InvalidIncomingDataException
2251 ("DELETEDBLOCKS length is too short");
2252 v3s16 p = readV3S16(&data[2+1+i*6]);
2253 /*dstream<<"Server: DELETEDBLOCKS ("
2254 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2255 RemoteClient *client = getClient(peer_id);
2256 client->SetBlockNotSent(p);
2259 else if(command == TOSERVER_CLICK_OBJECT)
2264 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2269 [2] u8 button (0=left, 1=right)
2274 u8 button = readU8(&data[2]);
2276 p.X = readS16(&data[3]);
2277 p.Y = readS16(&data[5]);
2278 p.Z = readS16(&data[7]);
2279 s16 id = readS16(&data[9]);
2280 //u16 item_i = readU16(&data[11]);
2282 MapBlock *block = NULL;
2285 block = m_env.getMap().getBlockNoCreate(p);
2287 catch(InvalidPositionException &e)
2289 derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2293 MapBlockObject *obj = block->getObject(id);
2297 derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2301 //TODO: Check that object is reasonably close
2306 InventoryList *ilist = player->inventory.getList("main");
2307 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2310 // Skip if inventory has no free space
2311 if(ilist->getUsedSlots() == ilist->getSize())
2313 dout_server<<"Player inventory has no free space"<<std::endl;
2318 Create the inventory item
2320 InventoryItem *item = NULL;
2321 // If it is an item-object, take the item from it
2322 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2324 item = ((ItemObject*)obj)->createInventoryItem();
2326 // Else create an item of the object
2329 item = new MapBlockObjectItem
2330 (obj->getInventoryString());
2333 // Add to inventory and send inventory
2334 ilist->addItem(item);
2335 UpdateCrafting(player->peer_id);
2336 SendInventory(player->peer_id);
2339 // Remove from block
2340 block->removeObject(id);
2343 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2348 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2354 [2] u8 button (0=left, 1=right)
2358 u8 button = readU8(&data[2]);
2359 u16 id = readS16(&data[3]);
2360 u16 item_i = readU16(&data[11]);
2362 ServerActiveObject *obj = m_env.getActiveObject(id);
2366 derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2371 // Skip if object has been removed
2375 //TODO: Check that object is reasonably close
2377 // Left click, pick object up (usually)
2381 Try creating inventory item
2383 InventoryItem *item = obj->createPickedUpItem();
2387 if(g_settings.getBool("creative_mode") == false)
2389 InventoryList *ilist = player->inventory.getList("main");
2392 // Skip if inventory has no free space
2393 if(ilist->getUsedSlots() == ilist->getSize())
2395 dout_server<<"Player inventory has no free space"<<std::endl;
2399 // Add to inventory and send inventory
2400 ilist->addItem(item);
2401 UpdateCrafting(player->peer_id);
2402 SendInventory(player->peer_id);
2404 // Remove object from environment
2405 obj->m_removed = true;
2412 Item cannot be picked up. Punch it instead.
2415 ToolItem *titem = NULL;
2416 std::string toolname = "";
2418 InventoryList *mlist = player->inventory.getList("main");
2421 InventoryItem *item = mlist->getItem(item_i);
2422 if(item && (std::string)item->getName() == "ToolItem")
2424 titem = (ToolItem*)item;
2425 toolname = titem->getToolName();
2429 v3f playerpos = player->getPosition();
2430 v3f objpos = obj->getBasePosition();
2431 v3f dir = (objpos - playerpos).normalize();
2433 u16 wear = obj->punch(toolname, dir);
2437 bool weared_out = titem->addWear(wear);
2439 mlist->deleteItem(item_i);
2440 SendInventory(player->peer_id);
2444 // Right click, do something with object
2447 // Track hp changes super-crappily
2448 u16 oldhp = player->hp;
2451 obj->rightClick(player);
2454 if(player->hp != oldhp)
2456 SendPlayerHP(player);
2460 else if(command == TOSERVER_GROUND_ACTION)
2468 [3] v3s16 nodepos_undersurface
2469 [9] v3s16 nodepos_abovesurface
2474 2: stop digging (all parameters ignored)
2475 3: digging completed
2477 u8 action = readU8(&data[2]);
2479 p_under.X = readS16(&data[3]);
2480 p_under.Y = readS16(&data[5]);
2481 p_under.Z = readS16(&data[7]);
2483 p_over.X = readS16(&data[9]);
2484 p_over.Y = readS16(&data[11]);
2485 p_over.Z = readS16(&data[13]);
2486 u16 item_i = readU16(&data[15]);
2488 //TODO: Check that target is reasonably close
2496 NOTE: This can be used in the future to check if
2497 somebody is cheating, by checking the timing.
2504 else if(action == 2)
2507 RemoteClient *client = getClient(peer->id);
2508 JMutexAutoLock digmutex(client->m_dig_mutex);
2509 client->m_dig_tool_item = -1;
2514 3: Digging completed
2516 else if(action == 3)
2518 // Mandatory parameter; actually used for nothing
2519 core::map<v3s16, MapBlock*> modified_blocks;
2521 content_t material = CONTENT_IGNORE;
2522 u8 mineral = MINERAL_NONE;
2524 bool cannot_remove_node = false;
2528 MapNode n = m_env.getMap().getNode(p_under);
2530 mineral = n.getMineral();
2531 // Get material at position
2532 material = n.getContent();
2533 // If not yet cancelled
2534 if(cannot_remove_node == false)
2536 // If it's not diggable, do nothing
2537 if(content_diggable(material) == false)
2539 derr_server<<"Server: Not finishing digging: "
2540 <<"Node not diggable"
2542 cannot_remove_node = true;
2545 // If not yet cancelled
2546 if(cannot_remove_node == false)
2548 // Get node metadata
2549 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2550 if(meta && meta->nodeRemovalDisabled() == true)
2552 derr_server<<"Server: Not finishing digging: "
2553 <<"Node metadata disables removal"
2555 cannot_remove_node = true;
2559 catch(InvalidPositionException &e)
2561 derr_server<<"Server: Not finishing digging: Node not found."
2562 <<" Adding block to emerge queue."
2564 m_emerge_queue.addBlock(peer_id,
2565 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2566 cannot_remove_node = true;
2569 // Make sure the player is allowed to do it
2570 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2572 dstream<<"Player "<<player->getName()<<" cannot remove node"
2573 <<" because privileges are "<<getPlayerPrivs(player)
2575 cannot_remove_node = true;
2579 If node can't be removed, set block to be re-sent to
2582 if(cannot_remove_node)
2584 derr_server<<"Server: Not finishing digging."<<std::endl;
2586 // Client probably has wrong data.
2587 // Set block not sent, so that client will get
2589 dstream<<"Client "<<peer_id<<" tried to dig "
2590 <<"node; but node cannot be removed."
2591 <<" setting MapBlock not sent."<<std::endl;
2592 RemoteClient *client = getClient(peer_id);
2593 v3s16 blockpos = getNodeBlockPos(p_under);
2594 client->SetBlockNotSent(blockpos);
2600 Send the removal to all close-by players.
2601 - If other player is close, send REMOVENODE
2602 - Otherwise set blocks not sent
2604 core::list<u16> far_players;
2605 sendRemoveNode(p_under, peer_id, &far_players, 30);
2608 Update and send inventory
2611 if(g_settings.getBool("creative_mode") == false)
2616 InventoryList *mlist = player->inventory.getList("main");
2619 InventoryItem *item = mlist->getItem(item_i);
2620 if(item && (std::string)item->getName() == "ToolItem")
2622 ToolItem *titem = (ToolItem*)item;
2623 std::string toolname = titem->getToolName();
2625 // Get digging properties for material and tool
2626 DiggingProperties prop =
2627 getDiggingProperties(material, toolname);
2629 if(prop.diggable == false)
2631 derr_server<<"Server: WARNING: Player digged"
2632 <<" with impossible material + tool"
2633 <<" combination"<<std::endl;
2636 bool weared_out = titem->addWear(prop.wear);
2640 mlist->deleteItem(item_i);
2646 Add dug item to inventory
2649 InventoryItem *item = NULL;
2651 if(mineral != MINERAL_NONE)
2652 item = getDiggedMineralItem(mineral);
2657 std::string &dug_s = content_features(material).dug_item;
2660 std::istringstream is(dug_s, std::ios::binary);
2661 item = InventoryItem::deSerialize(is);
2667 // Add a item to inventory
2668 player->inventory.addItem("main", item);
2671 UpdateCrafting(player->peer_id);
2672 SendInventory(player->peer_id);
2678 (this takes some time so it is done after the quick stuff)
2681 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2683 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2686 Set blocks not sent to far players
2688 for(core::list<u16>::Iterator
2689 i = far_players.begin();
2690 i != far_players.end(); i++)
2693 RemoteClient *client = getClient(peer_id);
2696 client->SetBlocksNotSent(modified_blocks);
2703 else if(action == 1)
2706 InventoryList *ilist = player->inventory.getList("main");
2711 InventoryItem *item = ilist->getItem(item_i);
2713 // If there is no item, it is not possible to add it anywhere
2718 Handle material items
2720 if(std::string("MaterialItem") == item->getName())
2723 // Don't add a node if this is not a free space
2724 MapNode n2 = m_env.getMap().getNode(p_over);
2725 bool no_enough_privs =
2726 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2728 dstream<<"Player "<<player->getName()<<" cannot add node"
2729 <<" because privileges are "<<getPlayerPrivs(player)
2732 if(content_features(n2).buildable_to == false
2735 // Client probably has wrong data.
2736 // Set block not sent, so that client will get
2738 dstream<<"Client "<<peer_id<<" tried to place"
2739 <<" node in invalid position; setting"
2740 <<" MapBlock not sent."<<std::endl;
2741 RemoteClient *client = getClient(peer_id);
2742 v3s16 blockpos = getNodeBlockPos(p_over);
2743 client->SetBlockNotSent(blockpos);
2747 catch(InvalidPositionException &e)
2749 derr_server<<"Server: Ignoring ADDNODE: Node not found"
2750 <<" Adding block to emerge queue."
2752 m_emerge_queue.addBlock(peer_id,
2753 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2757 // Reset build time counter
2758 getClient(peer->id)->m_time_from_building = 0.0;
2761 MaterialItem *mitem = (MaterialItem*)item;
2763 n.setContent(mitem->getMaterial());
2765 // Calculate direction for wall mounted stuff
2766 if(content_features(n).wall_mounted)
2767 n.param2 = packDir(p_under - p_over);
2769 // Calculate the direction for furnaces and chests and stuff
2770 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2772 v3f playerpos = player->getPosition();
2773 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2774 blockpos = blockpos.normalize();
2776 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2790 Send to all close-by players
2792 core::list<u16> far_players;
2793 sendAddNode(p_over, n, 0, &far_players, 30);
2798 InventoryList *ilist = player->inventory.getList("main");
2799 if(g_settings.getBool("creative_mode") == false && ilist)
2801 // Remove from inventory and send inventory
2802 if(mitem->getCount() == 1)
2803 ilist->deleteItem(item_i);
2807 UpdateCrafting(peer_id);
2808 SendInventory(peer_id);
2814 This takes some time so it is done after the quick stuff
2816 core::map<v3s16, MapBlock*> modified_blocks;
2818 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2820 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2823 Set blocks not sent to far players
2825 for(core::list<u16>::Iterator
2826 i = far_players.begin();
2827 i != far_players.end(); i++)
2830 RemoteClient *client = getClient(peer_id);
2833 client->SetBlocksNotSent(modified_blocks);
2837 Calculate special events
2840 /*if(n.d == CONTENT_MESE)
2843 for(s16 z=-1; z<=1; z++)
2844 for(s16 y=-1; y<=1; y++)
2845 for(s16 x=-1; x<=1; x++)
2852 Place other item (not a block)
2856 v3s16 blockpos = getNodeBlockPos(p_over);
2859 Check that the block is loaded so that the item
2860 can properly be added to the static list too
2862 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2865 derr_server<<"Error while placing object: "
2866 "block not found"<<std::endl;
2870 dout_server<<"Placing a miscellaneous item on map"
2873 // Calculate a position for it
2874 v3f pos = intToFloat(p_over, BS);
2876 pos.Y -= BS*0.25; // let it drop a bit
2878 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2879 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2884 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2888 derr_server<<"WARNING: item resulted in NULL object, "
2889 <<"not placing onto map"
2894 // Add the object to the environment
2895 m_env.addActiveObject(obj);
2897 dout_server<<"Placed object"<<std::endl;
2899 if(g_settings.getBool("creative_mode") == false)
2901 // Delete the right amount of items from the slot
2902 u16 dropcount = item->getDropCount();
2904 // Delete item if all gone
2905 if(item->getCount() <= dropcount)
2907 if(item->getCount() < dropcount)
2908 dstream<<"WARNING: Server: dropped more items"
2909 <<" than the slot contains"<<std::endl;
2911 InventoryList *ilist = player->inventory.getList("main");
2913 // Remove from inventory and send inventory
2914 ilist->deleteItem(item_i);
2916 // Else decrement it
2918 item->remove(dropcount);
2921 UpdateCrafting(peer_id);
2922 SendInventory(peer_id);
2930 Catch invalid actions
2934 derr_server<<"WARNING: Server: Invalid action "
2935 <<action<<std::endl;
2939 else if(command == TOSERVER_RELEASE)
2948 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2951 else if(command == TOSERVER_SIGNTEXT)
2953 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2962 std::string datastring((char*)&data[2], datasize-2);
2963 std::istringstream is(datastring, std::ios_base::binary);
2966 is.read((char*)buf, 6);
2967 v3s16 blockpos = readV3S16(buf);
2968 is.read((char*)buf, 2);
2969 s16 id = readS16(buf);
2970 is.read((char*)buf, 2);
2971 u16 textlen = readU16(buf);
2973 for(u16 i=0; i<textlen; i++)
2975 is.read((char*)buf, 1);
2976 text += (char)buf[0];
2979 MapBlock *block = NULL;
2982 block = m_env.getMap().getBlockNoCreate(blockpos);
2984 catch(InvalidPositionException &e)
2986 derr_server<<"Error while setting sign text: "
2987 "block not found"<<std::endl;
2991 MapBlockObject *obj = block->getObject(id);
2994 derr_server<<"Error while setting sign text: "
2995 "object not found"<<std::endl;
2999 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
3001 derr_server<<"Error while setting sign text: "
3002 "object is not a sign"<<std::endl;
3006 ((SignObject*)obj)->setText(text);
3008 obj->getBlock()->setChangedFlag();
3010 else if(command == TOSERVER_SIGNNODETEXT)
3012 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3020 std::string datastring((char*)&data[2], datasize-2);
3021 std::istringstream is(datastring, std::ios_base::binary);
3024 is.read((char*)buf, 6);
3025 v3s16 p = readV3S16(buf);
3026 is.read((char*)buf, 2);
3027 u16 textlen = readU16(buf);
3029 for(u16 i=0; i<textlen; i++)
3031 is.read((char*)buf, 1);
3032 text += (char)buf[0];
3035 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3038 if(meta->typeId() != CONTENT_SIGN_WALL)
3040 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3041 signmeta->setText(text);
3043 v3s16 blockpos = getNodeBlockPos(p);
3044 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
3047 block->setChangedFlag();
3050 for(core::map<u16, RemoteClient*>::Iterator
3051 i = m_clients.getIterator();
3052 i.atEnd()==false; i++)
3054 RemoteClient *client = i.getNode()->getValue();
3055 client->SetBlockNotSent(blockpos);
3058 else if(command == TOSERVER_INVENTORY_ACTION)
3060 /*// Ignore inventory changes if in creative mode
3061 if(g_settings.getBool("creative_mode") == true)
3063 dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3067 // Strip command and create a stream
3068 std::string datastring((char*)&data[2], datasize-2);
3069 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3070 std::istringstream is(datastring, std::ios_base::binary);
3072 InventoryAction *a = InventoryAction::deSerialize(is);
3077 c.current_player = player;
3080 Handle craftresult specially if not in creative mode
3082 bool disable_action = false;
3083 if(a->getType() == IACTION_MOVE
3084 && g_settings.getBool("creative_mode") == false)
3086 IMoveAction *ma = (IMoveAction*)a;
3087 if(ma->to_inv == "current_player" &&
3088 ma->from_inv == "current_player")
3090 InventoryList *rlist = player->inventory.getList("craftresult");
3092 InventoryList *clist = player->inventory.getList("craft");
3094 InventoryList *mlist = player->inventory.getList("main");
3097 Craftresult is no longer preview if something
3100 if(ma->to_list == "craftresult"
3101 && ma->from_list != "craftresult")
3103 // If it currently is a preview, remove
3105 if(player->craftresult_is_preview)
3107 rlist->deleteItem(0);
3109 player->craftresult_is_preview = false;
3112 Crafting takes place if this condition is true.
3114 if(player->craftresult_is_preview &&
3115 ma->from_list == "craftresult")
3117 player->craftresult_is_preview = false;
3118 clist->decrementMaterials(1);
3121 If the craftresult is placed on itself, move it to
3122 main inventory instead of doing the action
3124 if(ma->to_list == "craftresult"
3125 && ma->from_list == "craftresult")
3127 disable_action = true;
3129 InventoryItem *item1 = rlist->changeItem(0, NULL);
3130 mlist->addItem(item1);
3135 if(disable_action == false)
3137 // Feed action to player inventory
3145 UpdateCrafting(player->peer_id);
3146 SendInventory(player->peer_id);
3151 dstream<<"TOSERVER_INVENTORY_ACTION: "
3152 <<"InventoryAction::deSerialize() returned NULL"
3156 else if(command == TOSERVER_CHAT_MESSAGE)
3164 std::string datastring((char*)&data[2], datasize-2);
3165 std::istringstream is(datastring, std::ios_base::binary);
3168 is.read((char*)buf, 2);
3169 u16 len = readU16(buf);
3171 std::wstring message;
3172 for(u16 i=0; i<len; i++)
3174 is.read((char*)buf, 2);
3175 message += (wchar_t)readU16(buf);
3178 // Get player name of this client
3179 std::wstring name = narrow_to_wide(player->getName());
3181 // Line to send to players
3183 // Whether to send to the player that sent the line
3184 bool send_to_sender = false;
3185 // Whether to send to other players
3186 bool send_to_others = false;
3188 // Local player gets all privileges regardless of
3189 // what's set on their account.
3190 u64 privs = getPlayerPrivs(player);
3193 std::wstring commandprefix = L"/#";
3194 if(message.substr(0, commandprefix.size()) == commandprefix)
3196 line += L"Server: ";
3198 message = message.substr(commandprefix.size());
3200 ServerCommandContext *ctx = new ServerCommandContext(
3201 str_split(message, L' '),
3207 line += processServerCommand(ctx);
3208 send_to_sender = ctx->flags & 1;
3209 send_to_others = ctx->flags & 2;
3215 if(privs & PRIV_SHOUT)
3221 send_to_others = true;
3225 line += L"Server: You are not allowed to shout";
3226 send_to_sender = true;
3232 dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3235 Send the message to clients
3237 for(core::map<u16, RemoteClient*>::Iterator
3238 i = m_clients.getIterator();
3239 i.atEnd() == false; i++)
3241 // Get client and check that it is valid
3242 RemoteClient *client = i.getNode()->getValue();
3243 assert(client->peer_id == i.getNode()->getKey());
3244 if(client->serialization_version == SER_FMT_VER_INVALID)
3248 bool sender_selected = (peer_id == client->peer_id);
3249 if(sender_selected == true && send_to_sender == false)
3251 if(sender_selected == false && send_to_others == false)
3254 SendChatMessage(client->peer_id, line);
3258 else if(command == TOSERVER_DAMAGE)
3260 if(g_settings.getBool("enable_damage"))
3262 std::string datastring((char*)&data[2], datasize-2);
3263 std::istringstream is(datastring, std::ios_base::binary);
3264 u8 damage = readU8(is);
3265 if(player->hp > damage)
3267 player->hp -= damage;
3273 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3276 v3f pos = findSpawnPos(m_env.getServerMap());
3277 player->setPosition(pos);
3279 SendMovePlayer(player);
3280 SendPlayerHP(player);
3282 //TODO: Throw items around
3286 SendPlayerHP(player);
3288 else if(command == TOSERVER_PASSWORD)
3291 [0] u16 TOSERVER_PASSWORD
3292 [2] u8[28] old password
3293 [30] u8[28] new password
3296 if(datasize != 2+PASSWORD_SIZE*2)
3298 /*char password[PASSWORD_SIZE];
3299 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3300 password[i] = data[2+i];
3301 password[PASSWORD_SIZE-1] = 0;*/
3303 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3311 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3313 char c = data[2+PASSWORD_SIZE+i];
3319 std::string playername = player->getName();
3321 if(m_authmanager.exists(playername) == false)
3323 dstream<<"Server: playername not found in authmanager"<<std::endl;
3324 // Wrong old password supplied!!
3325 SendChatMessage(peer_id, L"playername not found in authmanager");
3329 std::string checkpwd = m_authmanager.getPassword(playername);
3331 if(oldpwd != checkpwd)
3333 dstream<<"Server: invalid old password"<<std::endl;
3334 // Wrong old password supplied!!
3335 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3339 m_authmanager.setPassword(playername, newpwd);
3341 dstream<<"Server: password change successful for "<<playername
3343 SendChatMessage(peer_id, L"Password change successful");
3347 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3348 "unknown command "<<command<<std::endl;
3352 catch(SendFailedException &e)
3354 derr_server<<"Server::ProcessData(): SendFailedException: "
3360 void Server::onMapEditEvent(MapEditEvent *event)
3362 //dstream<<"Server::onMapEditEvent()"<<std::endl;
3363 if(m_ignore_map_edit_events)
3365 MapEditEvent *e = event->clone();
3366 m_unsent_map_edit_queue.push_back(e);
3369 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3371 if(id == "current_player")
3373 assert(c->current_player);
3374 return &(c->current_player->inventory);
3378 std::string id0 = fn.next(":");
3380 if(id0 == "nodemeta")
3383 p.X = stoi(fn.next(","));
3384 p.Y = stoi(fn.next(","));
3385 p.Z = stoi(fn.next(","));
3386 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3388 return meta->getInventory();
3389 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3390 <<"no metadata found"<<std::endl;
3394 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3397 void Server::inventoryModified(InventoryContext *c, std::string id)
3399 if(id == "current_player")
3401 assert(c->current_player);
3403 UpdateCrafting(c->current_player->peer_id);
3404 SendInventory(c->current_player->peer_id);
3409 std::string id0 = fn.next(":");
3411 if(id0 == "nodemeta")
3414 p.X = stoi(fn.next(","));
3415 p.Y = stoi(fn.next(","));
3416 p.Z = stoi(fn.next(","));
3417 v3s16 blockpos = getNodeBlockPos(p);
3419 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3421 meta->inventoryModified();
3423 for(core::map<u16, RemoteClient*>::Iterator
3424 i = m_clients.getIterator();
3425 i.atEnd()==false; i++)
3427 RemoteClient *client = i.getNode()->getValue();
3428 client->SetBlockNotSent(blockpos);
3434 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3437 core::list<PlayerInfo> Server::getPlayerInfo()
3439 DSTACK(__FUNCTION_NAME);
3440 JMutexAutoLock envlock(m_env_mutex);
3441 JMutexAutoLock conlock(m_con_mutex);
3443 core::list<PlayerInfo> list;
3445 core::list<Player*> players = m_env.getPlayers();
3447 core::list<Player*>::Iterator i;
3448 for(i = players.begin();
3449 i != players.end(); i++)
3453 Player *player = *i;
3456 con::Peer *peer = m_con.GetPeer(player->peer_id);
3457 // Copy info from peer to info struct
3459 info.address = peer->address;
3460 info.avg_rtt = peer->avg_rtt;
3462 catch(con::PeerNotFoundException &e)
3464 // Set dummy peer info
3466 info.address = Address(0,0,0,0,0);
3470 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3471 info.position = player->getPosition();
3473 list.push_back(info);
3480 void Server::peerAdded(con::Peer *peer)
3482 DSTACK(__FUNCTION_NAME);
3483 dout_server<<"Server::peerAdded(): peer->id="
3484 <<peer->id<<std::endl;
3487 c.type = PEER_ADDED;
3488 c.peer_id = peer->id;
3490 m_peer_change_queue.push_back(c);
3493 void Server::deletingPeer(con::Peer *peer, bool timeout)
3495 DSTACK(__FUNCTION_NAME);
3496 dout_server<<"Server::deletingPeer(): peer->id="
3497 <<peer->id<<", timeout="<<timeout<<std::endl;
3500 c.type = PEER_REMOVED;
3501 c.peer_id = peer->id;
3502 c.timeout = timeout;
3503 m_peer_change_queue.push_back(c);
3510 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3512 DSTACK(__FUNCTION_NAME);
3513 std::ostringstream os(std::ios_base::binary);
3515 writeU16(os, TOCLIENT_HP);
3519 std::string s = os.str();
3520 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3522 con.Send(peer_id, 0, data, true);
3525 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3526 const std::wstring &reason)
3528 DSTACK(__FUNCTION_NAME);
3529 std::ostringstream os(std::ios_base::binary);
3531 writeU16(os, TOCLIENT_ACCESS_DENIED);
3532 os<<serializeWideString(reason);
3535 std::string s = os.str();
3536 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3538 con.Send(peer_id, 0, data, true);
3542 Non-static send methods
3545 void Server::SendObjectData(float dtime)
3547 DSTACK(__FUNCTION_NAME);
3549 core::map<v3s16, bool> stepped_blocks;
3551 for(core::map<u16, RemoteClient*>::Iterator
3552 i = m_clients.getIterator();
3553 i.atEnd() == false; i++)
3555 u16 peer_id = i.getNode()->getKey();
3556 RemoteClient *client = i.getNode()->getValue();
3557 assert(client->peer_id == peer_id);
3559 if(client->serialization_version == SER_FMT_VER_INVALID)
3562 client->SendObjectData(this, dtime, stepped_blocks);
3566 void Server::SendPlayerInfos()
3568 DSTACK(__FUNCTION_NAME);
3570 //JMutexAutoLock envlock(m_env_mutex);
3572 // Get connected players
3573 core::list<Player*> players = m_env.getPlayers(true);
3575 u32 player_count = players.getSize();
3576 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3578 SharedBuffer<u8> data(datasize);
3579 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3582 core::list<Player*>::Iterator i;
3583 for(i = players.begin();
3584 i != players.end(); i++)
3586 Player *player = *i;
3588 /*dstream<<"Server sending player info for player with "
3589 "peer_id="<<player->peer_id<<std::endl;*/
3591 writeU16(&data[start], player->peer_id);
3592 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3593 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3594 start += 2+PLAYERNAME_SIZE;
3597 //JMutexAutoLock conlock(m_con_mutex);
3600 m_con.SendToAll(0, data, true);
3603 void Server::SendInventory(u16 peer_id)
3605 DSTACK(__FUNCTION_NAME);
3607 Player* player = m_env.getPlayer(peer_id);
3614 std::ostringstream os;
3615 //os.imbue(std::locale("C"));
3617 player->inventory.serialize(os);
3619 std::string s = os.str();
3621 SharedBuffer<u8> data(s.size()+2);
3622 writeU16(&data[0], TOCLIENT_INVENTORY);
3623 memcpy(&data[2], s.c_str(), s.size());
3626 m_con.Send(peer_id, 0, data, true);
3629 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3631 DSTACK(__FUNCTION_NAME);
3633 std::ostringstream os(std::ios_base::binary);
3637 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3638 os.write((char*)buf, 2);
3641 writeU16(buf, message.size());
3642 os.write((char*)buf, 2);
3645 for(u32 i=0; i<message.size(); i++)
3649 os.write((char*)buf, 2);
3653 std::string s = os.str();
3654 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3656 m_con.Send(peer_id, 0, data, true);
3659 void Server::BroadcastChatMessage(const std::wstring &message)
3661 for(core::map<u16, RemoteClient*>::Iterator
3662 i = m_clients.getIterator();
3663 i.atEnd() == false; i++)
3665 // Get client and check that it is valid
3666 RemoteClient *client = i.getNode()->getValue();
3667 assert(client->peer_id == i.getNode()->getKey());
3668 if(client->serialization_version == SER_FMT_VER_INVALID)
3671 SendChatMessage(client->peer_id, message);
3675 void Server::SendPlayerHP(Player *player)
3677 SendHP(m_con, player->peer_id, player->hp);
3680 void Server::SendMovePlayer(Player *player)
3682 DSTACK(__FUNCTION_NAME);
3683 std::ostringstream os(std::ios_base::binary);
3685 writeU16(os, TOCLIENT_MOVE_PLAYER);
3686 writeV3F1000(os, player->getPosition());
3687 writeF1000(os, player->getPitch());
3688 writeF1000(os, player->getYaw());
3691 v3f pos = player->getPosition();
3692 f32 pitch = player->getPitch();
3693 f32 yaw = player->getYaw();
3694 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3695 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3702 std::string s = os.str();
3703 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3705 m_con.Send(player->peer_id, 0, data, true);
3708 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3709 core::list<u16> *far_players, float far_d_nodes)
3711 float maxd = far_d_nodes*BS;
3712 v3f p_f = intToFloat(p, BS);
3716 SharedBuffer<u8> reply(replysize);
3717 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3718 writeS16(&reply[2], p.X);
3719 writeS16(&reply[4], p.Y);
3720 writeS16(&reply[6], p.Z);
3722 for(core::map<u16, RemoteClient*>::Iterator
3723 i = m_clients.getIterator();
3724 i.atEnd() == false; i++)
3726 // Get client and check that it is valid
3727 RemoteClient *client = i.getNode()->getValue();
3728 assert(client->peer_id == i.getNode()->getKey());
3729 if(client->serialization_version == SER_FMT_VER_INVALID)
3732 // Don't send if it's the same one
3733 if(client->peer_id == ignore_id)
3739 Player *player = m_env.getPlayer(client->peer_id);
3742 // If player is far away, only set modified blocks not sent
3743 v3f player_pos = player->getPosition();
3744 if(player_pos.getDistanceFrom(p_f) > maxd)
3746 far_players->push_back(client->peer_id);
3753 m_con.Send(client->peer_id, 0, reply, true);
3757 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3758 core::list<u16> *far_players, float far_d_nodes)
3760 float maxd = far_d_nodes*BS;
3761 v3f p_f = intToFloat(p, BS);
3763 for(core::map<u16, RemoteClient*>::Iterator
3764 i = m_clients.getIterator();
3765 i.atEnd() == false; i++)
3767 // Get client and check that it is valid
3768 RemoteClient *client = i.getNode()->getValue();
3769 assert(client->peer_id == i.getNode()->getKey());
3770 if(client->serialization_version == SER_FMT_VER_INVALID)
3773 // Don't send if it's the same one
3774 if(client->peer_id == ignore_id)
3780 Player *player = m_env.getPlayer(client->peer_id);
3783 // If player is far away, only set modified blocks not sent
3784 v3f player_pos = player->getPosition();
3785 if(player_pos.getDistanceFrom(p_f) > maxd)
3787 far_players->push_back(client->peer_id);
3794 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3795 SharedBuffer<u8> reply(replysize);
3796 writeU16(&reply[0], TOCLIENT_ADDNODE);
3797 writeS16(&reply[2], p.X);
3798 writeS16(&reply[4], p.Y);
3799 writeS16(&reply[6], p.Z);
3800 n.serialize(&reply[8], client->serialization_version);
3803 m_con.Send(client->peer_id, 0, reply, true);
3807 void Server::setBlockNotSent(v3s16 p)
3809 for(core::map<u16, RemoteClient*>::Iterator
3810 i = m_clients.getIterator();
3811 i.atEnd()==false; i++)
3813 RemoteClient *client = i.getNode()->getValue();
3814 client->SetBlockNotSent(p);
3818 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3820 DSTACK(__FUNCTION_NAME);
3822 v3s16 p = block->getPos();
3826 bool completely_air = true;
3827 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3828 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3829 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3831 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3833 completely_air = false;
3834 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3839 dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3841 dstream<<"[completely air] ";
3846 Create a packet with the block in the right format
3849 std::ostringstream os(std::ios_base::binary);
3850 block->serialize(os, ver);
3851 std::string s = os.str();
3852 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3854 u32 replysize = 8 + blockdata.getSize();
3855 SharedBuffer<u8> reply(replysize);
3856 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3857 writeS16(&reply[2], p.X);
3858 writeS16(&reply[4], p.Y);
3859 writeS16(&reply[6], p.Z);
3860 memcpy(&reply[8], *blockdata, blockdata.getSize());
3862 /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3863 <<": \tpacket size: "<<replysize<<std::endl;*/
3868 m_con.Send(peer_id, 1, reply, true);
3871 void Server::SendBlocks(float dtime)
3873 DSTACK(__FUNCTION_NAME);
3875 JMutexAutoLock envlock(m_env_mutex);
3876 JMutexAutoLock conlock(m_con_mutex);
3878 //TimeTaker timer("Server::SendBlocks");
3880 core::array<PrioritySortedBlockTransfer> queue;
3882 s32 total_sending = 0;
3885 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
3887 for(core::map<u16, RemoteClient*>::Iterator
3888 i = m_clients.getIterator();
3889 i.atEnd() == false; i++)
3891 RemoteClient *client = i.getNode()->getValue();
3892 assert(client->peer_id == i.getNode()->getKey());
3894 total_sending += client->SendingCount();
3896 if(client->serialization_version == SER_FMT_VER_INVALID)
3899 client->GetNextBlocks(this, dtime, queue);
3904 // Lowest priority number comes first.
3905 // Lowest is most important.
3908 for(u32 i=0; i<queue.size(); i++)
3910 //TODO: Calculate limit dynamically
3911 if(total_sending >= g_settings.getS32
3912 ("max_simultaneous_block_sends_server_total"))
3915 PrioritySortedBlockTransfer q = queue[i];
3917 MapBlock *block = NULL;
3920 block = m_env.getMap().getBlockNoCreate(q.pos);
3922 catch(InvalidPositionException &e)
3927 RemoteClient *client = getClient(q.peer_id);
3929 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3931 client->SentBlock(q.pos);
3941 void Server::UpdateCrafting(u16 peer_id)
3943 DSTACK(__FUNCTION_NAME);
3945 Player* player = m_env.getPlayer(peer_id);
3949 Calculate crafting stuff
3951 if(g_settings.getBool("creative_mode") == false)
3953 InventoryList *clist = player->inventory.getList("craft");
3954 InventoryList *rlist = player->inventory.getList("craftresult");
3956 if(rlist->getUsedSlots() == 0)
3957 player->craftresult_is_preview = true;
3959 if(rlist && player->craftresult_is_preview)
3961 rlist->clearItems();
3963 if(clist && rlist && player->craftresult_is_preview)
3965 InventoryItem *items[9];
3966 for(u16 i=0; i<9; i++)
3968 items[i] = clist->getItem(i);
3971 // Get result of crafting grid
3972 InventoryItem *result = craft_get_result(items);
3974 rlist->addItem(result);
3977 } // if creative_mode == false
3980 RemoteClient* Server::getClient(u16 peer_id)
3982 DSTACK(__FUNCTION_NAME);
3983 //JMutexAutoLock lock(m_con_mutex);
3984 core::map<u16, RemoteClient*>::Node *n;
3985 n = m_clients.find(peer_id);
3986 // A client should exist for all peers
3988 return n->getValue();
3991 std::wstring Server::getStatusString()
3993 std::wostringstream os(std::ios_base::binary);
3996 os<<L"version="<<narrow_to_wide(VERSION_STRING);
3998 os<<L", uptime="<<m_uptime.get();
3999 // Information about clients
4001 for(core::map<u16, RemoteClient*>::Iterator
4002 i = m_clients.getIterator();
4003 i.atEnd() == false; i++)
4005 // Get client and check that it is valid
4006 RemoteClient *client = i.getNode()->getValue();
4007 assert(client->peer_id == i.getNode()->getKey());
4008 if(client->serialization_version == SER_FMT_VER_INVALID)
4011 Player *player = m_env.getPlayer(client->peer_id);
4012 // Get name of player
4013 std::wstring name = L"unknown";
4015 name = narrow_to_wide(player->getName());
4016 // Add name to information string
4020 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
4021 os<<" WARNING: Map saving is disabled."<<std::endl;
4025 v3f findSpawnPos(ServerMap &map)
4027 //return v3f(50,50,50)*BS;
4030 s16 groundheight = 0;
4033 nodepos = v2s16(0,0);
4038 // Try to find a good place a few times
4039 for(s32 i=0; i<1000; i++)
4042 // We're going to try to throw the player to this position
4043 nodepos = v2s16(-range + (myrand()%(range*2)),
4044 -range + (myrand()%(range*2)));
4045 v2s16 sectorpos = getNodeSectorPos(nodepos);
4046 // Get sector (NOTE: Don't get because it's slow)
4047 //m_env.getMap().emergeSector(sectorpos);
4048 // Get ground height at point (fallbacks to heightmap function)
4049 groundheight = map.findGroundLevel(nodepos);
4050 // Don't go underwater
4051 if(groundheight < WATER_LEVEL)
4053 //dstream<<"-> Underwater"<<std::endl;
4056 // Don't go to high places
4057 if(groundheight > WATER_LEVEL + 4)
4059 //dstream<<"-> Underwater"<<std::endl;
4063 // Found a good place
4064 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4069 // If no suitable place was not found, go above water at least.
4070 if(groundheight < WATER_LEVEL)
4071 groundheight = WATER_LEVEL;
4073 return intToFloat(v3s16(
4080 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4083 Try to get an existing player
4085 Player *player = m_env.getPlayer(name);
4088 // If player is already connected, cancel
4089 if(player->peer_id != 0)
4091 dstream<<"emergePlayer(): Player already connected"<<std::endl;
4096 player->peer_id = peer_id;
4098 // Reset inventory to creative if in creative mode
4099 if(g_settings.getBool("creative_mode"))
4101 craft_set_creative_inventory(player);
4108 If player with the wanted peer_id already exists, cancel.
4110 if(m_env.getPlayer(peer_id) != NULL)
4112 dstream<<"emergePlayer(): Player with wrong name but same"
4113 " peer_id already exists"<<std::endl;
4121 player = new ServerRemotePlayer();
4122 //player->peer_id = c.peer_id;
4123 //player->peer_id = PEER_ID_INEXISTENT;
4124 player->peer_id = peer_id;
4125 player->updateName(name);
4126 m_authmanager.add(name);
4127 m_authmanager.setPassword(name, password);
4128 m_authmanager.setPrivs(name,
4129 stringToPrivs(g_settings.get("default_privs")));
4135 dstream<<"Server: Finding spawn place for player \""
4136 <<player->getName()<<"\""<<std::endl;
4138 v3f pos = findSpawnPos(m_env.getServerMap());
4140 player->setPosition(pos);
4143 Add player to environment
4146 m_env.addPlayer(player);
4149 Add stuff to inventory
4152 if(g_settings.getBool("creative_mode"))
4154 craft_set_creative_inventory(player);
4156 else if(g_settings.getBool("give_initial_stuff"))
4158 craft_give_initial_stuff(player);
4163 } // create new player
4166 void Server::handlePeerChange(PeerChange &c)
4168 JMutexAutoLock envlock(m_env_mutex);
4169 JMutexAutoLock conlock(m_con_mutex);
4171 if(c.type == PEER_ADDED)
4178 core::map<u16, RemoteClient*>::Node *n;
4179 n = m_clients.find(c.peer_id);
4180 // The client shouldn't already exist
4184 RemoteClient *client = new RemoteClient();
4185 client->peer_id = c.peer_id;
4186 m_clients.insert(client->peer_id, client);
4189 else if(c.type == PEER_REMOVED)
4196 core::map<u16, RemoteClient*>::Node *n;
4197 n = m_clients.find(c.peer_id);
4198 // The client should exist
4202 Mark objects to be not known by the client
4204 RemoteClient *client = n->getValue();
4206 for(core::map<u16, bool>::Iterator
4207 i = client->m_known_objects.getIterator();
4208 i.atEnd()==false; i++)
4211 u16 id = i.getNode()->getKey();
4212 ServerActiveObject* obj = m_env.getActiveObject(id);
4214 if(obj && obj->m_known_by_count > 0)
4215 obj->m_known_by_count--;
4218 // Collect information about leaving in chat
4219 std::wstring message;
4221 std::wstring name = L"unknown";
4222 Player *player = m_env.getPlayer(c.peer_id);
4224 name = narrow_to_wide(player->getName());
4228 message += L" left game";
4230 message += L" (timed out)";
4235 m_env.removePlayer(c.peer_id);
4238 // Set player client disconnected
4240 Player *player = m_env.getPlayer(c.peer_id);
4242 player->peer_id = 0;
4246 delete m_clients[c.peer_id];
4247 m_clients.remove(c.peer_id);
4249 // Send player info to all remaining clients
4252 // Send leave chat message to all remaining clients
4253 BroadcastChatMessage(message);
4262 void Server::handlePeerChanges()
4264 while(m_peer_change_queue.size() > 0)
4266 PeerChange c = m_peer_change_queue.pop_front();
4268 dout_server<<"Server: Handling peer change: "
4269 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4272 handlePeerChange(c);
4276 u64 Server::getPlayerPrivs(Player *player)
4280 std::string playername = player->getName();
4281 // Local player gets all privileges regardless of
4282 // what's set on their account.
4283 if(g_settings.get("name") == playername)
4289 return getPlayerAuthPrivs(playername);
4293 void dedicated_server_loop(Server &server, bool &kill)
4295 DSTACK(__FUNCTION_NAME);
4297 dstream<<DTIME<<std::endl;
4298 dstream<<"========================"<<std::endl;
4299 dstream<<"Running dedicated server"<<std::endl;
4300 dstream<<"========================"<<std::endl;
4303 IntervalLimiter m_profiler_interval;
4307 // This is kind of a hack but can be done like this
4308 // because server.step() is very light
4310 ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4315 if(server.getShutdownRequested() || kill)
4317 dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4324 float profiler_print_interval =
4325 g_settings.getFloat("profiler_print_interval");
4326 if(profiler_print_interval != 0)
4328 if(m_profiler_interval.step(0.030, profiler_print_interval))
4330 dstream<<"Profiler:"<<std::endl;
4331 g_profiler.print(dstream);
4339 static int counter = 0;
4345 core::list<PlayerInfo> list = server.getPlayerInfo();
4346 core::list<PlayerInfo>::Iterator i;
4347 static u32 sum_old = 0;
4348 u32 sum = PIChecksum(list);
4351 dstream<<DTIME<<"Player info:"<<std::endl;
4352 for(i=list.begin(); i!=list.end(); i++)
4354 i->PrintLine(&dstream);