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 //TODO: Check that object is reasonably close
2373 // Left click, pick object up (usually)
2376 InventoryList *ilist = player->inventory.getList("main");
2377 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2380 // Skip if inventory has no free space
2381 if(ilist->getUsedSlots() == ilist->getSize())
2383 dout_server<<"Player inventory has no free space"<<std::endl;
2387 // Skip if object has been removed
2392 Create the inventory item
2394 InventoryItem *item = obj->createPickedUpItem();
2398 // Add to inventory and send inventory
2399 ilist->addItem(item);
2400 UpdateCrafting(player->peer_id);
2401 SendInventory(player->peer_id);
2403 // Remove object from environment
2404 obj->m_removed = true;
2409 Item cannot be picked up. Punch it instead.
2412 ToolItem *titem = NULL;
2413 std::string toolname = "";
2415 InventoryList *mlist = player->inventory.getList("main");
2418 InventoryItem *item = mlist->getItem(item_i);
2419 if(item && (std::string)item->getName() == "ToolItem")
2421 titem = (ToolItem*)item;
2422 toolname = titem->getToolName();
2426 v3f playerpos = player->getPosition();
2427 v3f objpos = obj->getBasePosition();
2428 v3f dir = (objpos - playerpos).normalize();
2430 u16 wear = obj->punch(toolname, dir);
2434 bool weared_out = titem->addWear(wear);
2436 mlist->deleteItem(item_i);
2437 SendInventory(player->peer_id);
2443 else if(command == TOSERVER_GROUND_ACTION)
2451 [3] v3s16 nodepos_undersurface
2452 [9] v3s16 nodepos_abovesurface
2457 2: stop digging (all parameters ignored)
2458 3: digging completed
2460 u8 action = readU8(&data[2]);
2462 p_under.X = readS16(&data[3]);
2463 p_under.Y = readS16(&data[5]);
2464 p_under.Z = readS16(&data[7]);
2466 p_over.X = readS16(&data[9]);
2467 p_over.Y = readS16(&data[11]);
2468 p_over.Z = readS16(&data[13]);
2469 u16 item_i = readU16(&data[15]);
2471 //TODO: Check that target is reasonably close
2479 NOTE: This can be used in the future to check if
2480 somebody is cheating, by checking the timing.
2487 else if(action == 2)
2490 RemoteClient *client = getClient(peer->id);
2491 JMutexAutoLock digmutex(client->m_dig_mutex);
2492 client->m_dig_tool_item = -1;
2497 3: Digging completed
2499 else if(action == 3)
2501 // Mandatory parameter; actually used for nothing
2502 core::map<v3s16, MapBlock*> modified_blocks;
2504 content_t material = CONTENT_IGNORE;
2505 u8 mineral = MINERAL_NONE;
2507 bool cannot_remove_node = false;
2511 MapNode n = m_env.getMap().getNode(p_under);
2513 mineral = n.getMineral();
2514 // Get material at position
2515 material = n.getContent();
2516 // If not yet cancelled
2517 if(cannot_remove_node == false)
2519 // If it's not diggable, do nothing
2520 if(content_diggable(material) == false)
2522 derr_server<<"Server: Not finishing digging: "
2523 <<"Node not diggable"
2525 cannot_remove_node = true;
2528 // If not yet cancelled
2529 if(cannot_remove_node == false)
2531 // Get node metadata
2532 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2533 if(meta && meta->nodeRemovalDisabled() == true)
2535 derr_server<<"Server: Not finishing digging: "
2536 <<"Node metadata disables removal"
2538 cannot_remove_node = true;
2542 catch(InvalidPositionException &e)
2544 derr_server<<"Server: Not finishing digging: Node not found."
2545 <<" Adding block to emerge queue."
2547 m_emerge_queue.addBlock(peer_id,
2548 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2549 cannot_remove_node = true;
2552 // Make sure the player is allowed to do it
2553 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2555 dstream<<"Player "<<player->getName()<<" cannot remove node"
2556 <<" because privileges are "<<getPlayerPrivs(player)
2558 cannot_remove_node = true;
2562 If node can't be removed, set block to be re-sent to
2565 if(cannot_remove_node)
2567 derr_server<<"Server: Not finishing digging."<<std::endl;
2569 // Client probably has wrong data.
2570 // Set block not sent, so that client will get
2572 dstream<<"Client "<<peer_id<<" tried to dig "
2573 <<"node; but node cannot be removed."
2574 <<" setting MapBlock not sent."<<std::endl;
2575 RemoteClient *client = getClient(peer_id);
2576 v3s16 blockpos = getNodeBlockPos(p_under);
2577 client->SetBlockNotSent(blockpos);
2583 Send the removal to all close-by players.
2584 - If other player is close, send REMOVENODE
2585 - Otherwise set blocks not sent
2587 core::list<u16> far_players;
2588 sendRemoveNode(p_under, peer_id, &far_players, 30);
2591 Update and send inventory
2594 if(g_settings.getBool("creative_mode") == false)
2599 InventoryList *mlist = player->inventory.getList("main");
2602 InventoryItem *item = mlist->getItem(item_i);
2603 if(item && (std::string)item->getName() == "ToolItem")
2605 ToolItem *titem = (ToolItem*)item;
2606 std::string toolname = titem->getToolName();
2608 // Get digging properties for material and tool
2609 DiggingProperties prop =
2610 getDiggingProperties(material, toolname);
2612 if(prop.diggable == false)
2614 derr_server<<"Server: WARNING: Player digged"
2615 <<" with impossible material + tool"
2616 <<" combination"<<std::endl;
2619 bool weared_out = titem->addWear(prop.wear);
2623 mlist->deleteItem(item_i);
2629 Add dug item to inventory
2632 InventoryItem *item = NULL;
2634 if(mineral != MINERAL_NONE)
2635 item = getDiggedMineralItem(mineral);
2640 std::string &dug_s = content_features(material).dug_item;
2643 std::istringstream is(dug_s, std::ios::binary);
2644 item = InventoryItem::deSerialize(is);
2650 // Add a item to inventory
2651 player->inventory.addItem("main", item);
2654 UpdateCrafting(player->peer_id);
2655 SendInventory(player->peer_id);
2661 (this takes some time so it is done after the quick stuff)
2664 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2666 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2669 Set blocks not sent to far players
2671 for(core::list<u16>::Iterator
2672 i = far_players.begin();
2673 i != far_players.end(); i++)
2676 RemoteClient *client = getClient(peer_id);
2679 client->SetBlocksNotSent(modified_blocks);
2686 else if(action == 1)
2689 InventoryList *ilist = player->inventory.getList("main");
2694 InventoryItem *item = ilist->getItem(item_i);
2696 // If there is no item, it is not possible to add it anywhere
2701 Handle material items
2703 if(std::string("MaterialItem") == item->getName())
2706 // Don't add a node if this is not a free space
2707 MapNode n2 = m_env.getMap().getNode(p_over);
2708 bool no_enough_privs =
2709 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2711 dstream<<"Player "<<player->getName()<<" cannot add node"
2712 <<" because privileges are "<<getPlayerPrivs(player)
2715 if(content_features(n2).buildable_to == false
2718 // Client probably has wrong data.
2719 // Set block not sent, so that client will get
2721 dstream<<"Client "<<peer_id<<" tried to place"
2722 <<" node in invalid position; setting"
2723 <<" MapBlock not sent."<<std::endl;
2724 RemoteClient *client = getClient(peer_id);
2725 v3s16 blockpos = getNodeBlockPos(p_over);
2726 client->SetBlockNotSent(blockpos);
2730 catch(InvalidPositionException &e)
2732 derr_server<<"Server: Ignoring ADDNODE: Node not found"
2733 <<" Adding block to emerge queue."
2735 m_emerge_queue.addBlock(peer_id,
2736 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2740 // Reset build time counter
2741 getClient(peer->id)->m_time_from_building = 0.0;
2744 MaterialItem *mitem = (MaterialItem*)item;
2746 n.setContent(mitem->getMaterial());
2748 // Calculate direction for wall mounted stuff
2749 if(content_features(n).wall_mounted)
2750 n.param2 = packDir(p_under - p_over);
2752 // Calculate the direction for furnaces and chests and stuff
2753 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2755 v3f playerpos = player->getPosition();
2756 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2757 blockpos = blockpos.normalize();
2759 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2773 Send to all close-by players
2775 core::list<u16> far_players;
2776 sendAddNode(p_over, n, 0, &far_players, 30);
2781 InventoryList *ilist = player->inventory.getList("main");
2782 if(g_settings.getBool("creative_mode") == false && ilist)
2784 // Remove from inventory and send inventory
2785 if(mitem->getCount() == 1)
2786 ilist->deleteItem(item_i);
2790 UpdateCrafting(peer_id);
2791 SendInventory(peer_id);
2797 This takes some time so it is done after the quick stuff
2799 core::map<v3s16, MapBlock*> modified_blocks;
2801 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2803 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2806 Set blocks not sent to far players
2808 for(core::list<u16>::Iterator
2809 i = far_players.begin();
2810 i != far_players.end(); i++)
2813 RemoteClient *client = getClient(peer_id);
2816 client->SetBlocksNotSent(modified_blocks);
2820 Calculate special events
2823 /*if(n.d == CONTENT_MESE)
2826 for(s16 z=-1; z<=1; z++)
2827 for(s16 y=-1; y<=1; y++)
2828 for(s16 x=-1; x<=1; x++)
2835 Place other item (not a block)
2839 v3s16 blockpos = getNodeBlockPos(p_over);
2842 Check that the block is loaded so that the item
2843 can properly be added to the static list too
2845 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2848 derr_server<<"Error while placing object: "
2849 "block not found"<<std::endl;
2853 dout_server<<"Placing a miscellaneous item on map"
2856 // Calculate a position for it
2857 v3f pos = intToFloat(p_over, BS);
2859 pos.Y -= BS*0.25; // let it drop a bit
2861 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2862 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2867 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2871 derr_server<<"WARNING: item resulted in NULL object, "
2872 <<"not placing onto map"
2877 // Add the object to the environment
2878 m_env.addActiveObject(obj);
2880 dout_server<<"Placed object"<<std::endl;
2882 if(g_settings.getBool("creative_mode") == false)
2884 // Delete the right amount of items from the slot
2885 u16 dropcount = item->getDropCount();
2887 // Delete item if all gone
2888 if(item->getCount() <= dropcount)
2890 if(item->getCount() < dropcount)
2891 dstream<<"WARNING: Server: dropped more items"
2892 <<" than the slot contains"<<std::endl;
2894 InventoryList *ilist = player->inventory.getList("main");
2896 // Remove from inventory and send inventory
2897 ilist->deleteItem(item_i);
2899 // Else decrement it
2901 item->remove(dropcount);
2904 UpdateCrafting(peer_id);
2905 SendInventory(peer_id);
2913 Catch invalid actions
2917 derr_server<<"WARNING: Server: Invalid action "
2918 <<action<<std::endl;
2922 else if(command == TOSERVER_RELEASE)
2931 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2934 else if(command == TOSERVER_SIGNTEXT)
2936 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2945 std::string datastring((char*)&data[2], datasize-2);
2946 std::istringstream is(datastring, std::ios_base::binary);
2949 is.read((char*)buf, 6);
2950 v3s16 blockpos = readV3S16(buf);
2951 is.read((char*)buf, 2);
2952 s16 id = readS16(buf);
2953 is.read((char*)buf, 2);
2954 u16 textlen = readU16(buf);
2956 for(u16 i=0; i<textlen; i++)
2958 is.read((char*)buf, 1);
2959 text += (char)buf[0];
2962 MapBlock *block = NULL;
2965 block = m_env.getMap().getBlockNoCreate(blockpos);
2967 catch(InvalidPositionException &e)
2969 derr_server<<"Error while setting sign text: "
2970 "block not found"<<std::endl;
2974 MapBlockObject *obj = block->getObject(id);
2977 derr_server<<"Error while setting sign text: "
2978 "object not found"<<std::endl;
2982 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
2984 derr_server<<"Error while setting sign text: "
2985 "object is not a sign"<<std::endl;
2989 ((SignObject*)obj)->setText(text);
2991 obj->getBlock()->setChangedFlag();
2993 else if(command == TOSERVER_SIGNNODETEXT)
2995 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3003 std::string datastring((char*)&data[2], datasize-2);
3004 std::istringstream is(datastring, std::ios_base::binary);
3007 is.read((char*)buf, 6);
3008 v3s16 p = readV3S16(buf);
3009 is.read((char*)buf, 2);
3010 u16 textlen = readU16(buf);
3012 for(u16 i=0; i<textlen; i++)
3014 is.read((char*)buf, 1);
3015 text += (char)buf[0];
3018 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3021 if(meta->typeId() != CONTENT_SIGN_WALL)
3023 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3024 signmeta->setText(text);
3026 v3s16 blockpos = getNodeBlockPos(p);
3027 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
3030 block->setChangedFlag();
3033 for(core::map<u16, RemoteClient*>::Iterator
3034 i = m_clients.getIterator();
3035 i.atEnd()==false; i++)
3037 RemoteClient *client = i.getNode()->getValue();
3038 client->SetBlockNotSent(blockpos);
3041 else if(command == TOSERVER_INVENTORY_ACTION)
3043 /*// Ignore inventory changes if in creative mode
3044 if(g_settings.getBool("creative_mode") == true)
3046 dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3050 // Strip command and create a stream
3051 std::string datastring((char*)&data[2], datasize-2);
3052 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3053 std::istringstream is(datastring, std::ios_base::binary);
3055 InventoryAction *a = InventoryAction::deSerialize(is);
3060 c.current_player = player;
3063 Handle craftresult specially if not in creative mode
3065 bool disable_action = false;
3066 if(a->getType() == IACTION_MOVE
3067 && g_settings.getBool("creative_mode") == false)
3069 IMoveAction *ma = (IMoveAction*)a;
3070 if(ma->to_inv == "current_player" &&
3071 ma->from_inv == "current_player")
3073 InventoryList *rlist = player->inventory.getList("craftresult");
3075 InventoryList *clist = player->inventory.getList("craft");
3077 InventoryList *mlist = player->inventory.getList("main");
3080 Craftresult is no longer preview if something
3083 if(ma->to_list == "craftresult"
3084 && ma->from_list != "craftresult")
3086 // If it currently is a preview, remove
3088 if(player->craftresult_is_preview)
3090 rlist->deleteItem(0);
3092 player->craftresult_is_preview = false;
3095 Crafting takes place if this condition is true.
3097 if(player->craftresult_is_preview &&
3098 ma->from_list == "craftresult")
3100 player->craftresult_is_preview = false;
3101 clist->decrementMaterials(1);
3104 If the craftresult is placed on itself, move it to
3105 main inventory instead of doing the action
3107 if(ma->to_list == "craftresult"
3108 && ma->from_list == "craftresult")
3110 disable_action = true;
3112 InventoryItem *item1 = rlist->changeItem(0, NULL);
3113 mlist->addItem(item1);
3118 if(disable_action == false)
3120 // Feed action to player inventory
3128 UpdateCrafting(player->peer_id);
3129 SendInventory(player->peer_id);
3134 dstream<<"TOSERVER_INVENTORY_ACTION: "
3135 <<"InventoryAction::deSerialize() returned NULL"
3139 else if(command == TOSERVER_CHAT_MESSAGE)
3147 std::string datastring((char*)&data[2], datasize-2);
3148 std::istringstream is(datastring, std::ios_base::binary);
3151 is.read((char*)buf, 2);
3152 u16 len = readU16(buf);
3154 std::wstring message;
3155 for(u16 i=0; i<len; i++)
3157 is.read((char*)buf, 2);
3158 message += (wchar_t)readU16(buf);
3161 // Get player name of this client
3162 std::wstring name = narrow_to_wide(player->getName());
3164 // Line to send to players
3166 // Whether to send to the player that sent the line
3167 bool send_to_sender = false;
3168 // Whether to send to other players
3169 bool send_to_others = false;
3171 // Local player gets all privileges regardless of
3172 // what's set on their account.
3173 u64 privs = getPlayerPrivs(player);
3176 std::wstring commandprefix = L"/#";
3177 if(message.substr(0, commandprefix.size()) == commandprefix)
3179 line += L"Server: ";
3181 message = message.substr(commandprefix.size());
3183 ServerCommandContext *ctx = new ServerCommandContext(
3184 str_split(message, L' '),
3190 line += processServerCommand(ctx);
3191 send_to_sender = ctx->flags & 1;
3192 send_to_others = ctx->flags & 2;
3198 if(privs & PRIV_SHOUT)
3204 send_to_others = true;
3208 line += L"Server: You are not allowed to shout";
3209 send_to_sender = true;
3215 dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3218 Send the message to clients
3220 for(core::map<u16, RemoteClient*>::Iterator
3221 i = m_clients.getIterator();
3222 i.atEnd() == false; i++)
3224 // Get client and check that it is valid
3225 RemoteClient *client = i.getNode()->getValue();
3226 assert(client->peer_id == i.getNode()->getKey());
3227 if(client->serialization_version == SER_FMT_VER_INVALID)
3231 bool sender_selected = (peer_id == client->peer_id);
3232 if(sender_selected == true && send_to_sender == false)
3234 if(sender_selected == false && send_to_others == false)
3237 SendChatMessage(client->peer_id, line);
3241 else if(command == TOSERVER_DAMAGE)
3243 if(g_settings.getBool("enable_damage"))
3245 std::string datastring((char*)&data[2], datasize-2);
3246 std::istringstream is(datastring, std::ios_base::binary);
3247 u8 damage = readU8(is);
3248 if(player->hp > damage)
3250 player->hp -= damage;
3256 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3259 v3f pos = findSpawnPos(m_env.getServerMap());
3260 player->setPosition(pos);
3262 SendMovePlayer(player);
3263 SendPlayerHP(player);
3265 //TODO: Throw items around
3269 SendPlayerHP(player);
3271 else if(command == TOSERVER_PASSWORD)
3274 [0] u16 TOSERVER_PASSWORD
3275 [2] u8[28] old password
3276 [30] u8[28] new password
3279 if(datasize != 2+PASSWORD_SIZE*2)
3281 /*char password[PASSWORD_SIZE];
3282 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3283 password[i] = data[2+i];
3284 password[PASSWORD_SIZE-1] = 0;*/
3286 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3294 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3296 char c = data[2+PASSWORD_SIZE+i];
3302 std::string playername = player->getName();
3304 if(m_authmanager.exists(playername) == false)
3306 dstream<<"Server: playername not found in authmanager"<<std::endl;
3307 // Wrong old password supplied!!
3308 SendChatMessage(peer_id, L"playername not found in authmanager");
3312 std::string checkpwd = m_authmanager.getPassword(playername);
3314 if(oldpwd != checkpwd)
3316 dstream<<"Server: invalid old password"<<std::endl;
3317 // Wrong old password supplied!!
3318 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3322 m_authmanager.setPassword(playername, newpwd);
3324 dstream<<"Server: password change successful for "<<playername
3326 SendChatMessage(peer_id, L"Password change successful");
3330 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3331 "unknown command "<<command<<std::endl;
3335 catch(SendFailedException &e)
3337 derr_server<<"Server::ProcessData(): SendFailedException: "
3343 void Server::onMapEditEvent(MapEditEvent *event)
3345 //dstream<<"Server::onMapEditEvent()"<<std::endl;
3346 if(m_ignore_map_edit_events)
3348 MapEditEvent *e = event->clone();
3349 m_unsent_map_edit_queue.push_back(e);
3352 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3354 if(id == "current_player")
3356 assert(c->current_player);
3357 return &(c->current_player->inventory);
3361 std::string id0 = fn.next(":");
3363 if(id0 == "nodemeta")
3366 p.X = stoi(fn.next(","));
3367 p.Y = stoi(fn.next(","));
3368 p.Z = stoi(fn.next(","));
3369 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3371 return meta->getInventory();
3372 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3373 <<"no metadata found"<<std::endl;
3377 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3380 void Server::inventoryModified(InventoryContext *c, std::string id)
3382 if(id == "current_player")
3384 assert(c->current_player);
3386 UpdateCrafting(c->current_player->peer_id);
3387 SendInventory(c->current_player->peer_id);
3392 std::string id0 = fn.next(":");
3394 if(id0 == "nodemeta")
3397 p.X = stoi(fn.next(","));
3398 p.Y = stoi(fn.next(","));
3399 p.Z = stoi(fn.next(","));
3400 v3s16 blockpos = getNodeBlockPos(p);
3402 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3404 meta->inventoryModified();
3406 for(core::map<u16, RemoteClient*>::Iterator
3407 i = m_clients.getIterator();
3408 i.atEnd()==false; i++)
3410 RemoteClient *client = i.getNode()->getValue();
3411 client->SetBlockNotSent(blockpos);
3417 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3420 core::list<PlayerInfo> Server::getPlayerInfo()
3422 DSTACK(__FUNCTION_NAME);
3423 JMutexAutoLock envlock(m_env_mutex);
3424 JMutexAutoLock conlock(m_con_mutex);
3426 core::list<PlayerInfo> list;
3428 core::list<Player*> players = m_env.getPlayers();
3430 core::list<Player*>::Iterator i;
3431 for(i = players.begin();
3432 i != players.end(); i++)
3436 Player *player = *i;
3439 con::Peer *peer = m_con.GetPeer(player->peer_id);
3440 // Copy info from peer to info struct
3442 info.address = peer->address;
3443 info.avg_rtt = peer->avg_rtt;
3445 catch(con::PeerNotFoundException &e)
3447 // Set dummy peer info
3449 info.address = Address(0,0,0,0,0);
3453 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3454 info.position = player->getPosition();
3456 list.push_back(info);
3463 void Server::peerAdded(con::Peer *peer)
3465 DSTACK(__FUNCTION_NAME);
3466 dout_server<<"Server::peerAdded(): peer->id="
3467 <<peer->id<<std::endl;
3470 c.type = PEER_ADDED;
3471 c.peer_id = peer->id;
3473 m_peer_change_queue.push_back(c);
3476 void Server::deletingPeer(con::Peer *peer, bool timeout)
3478 DSTACK(__FUNCTION_NAME);
3479 dout_server<<"Server::deletingPeer(): peer->id="
3480 <<peer->id<<", timeout="<<timeout<<std::endl;
3483 c.type = PEER_REMOVED;
3484 c.peer_id = peer->id;
3485 c.timeout = timeout;
3486 m_peer_change_queue.push_back(c);
3493 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3495 DSTACK(__FUNCTION_NAME);
3496 std::ostringstream os(std::ios_base::binary);
3498 writeU16(os, TOCLIENT_HP);
3502 std::string s = os.str();
3503 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3505 con.Send(peer_id, 0, data, true);
3508 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3509 const std::wstring &reason)
3511 DSTACK(__FUNCTION_NAME);
3512 std::ostringstream os(std::ios_base::binary);
3514 writeU16(os, TOCLIENT_ACCESS_DENIED);
3515 os<<serializeWideString(reason);
3518 std::string s = os.str();
3519 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3521 con.Send(peer_id, 0, data, true);
3525 Non-static send methods
3528 void Server::SendObjectData(float dtime)
3530 DSTACK(__FUNCTION_NAME);
3532 core::map<v3s16, bool> stepped_blocks;
3534 for(core::map<u16, RemoteClient*>::Iterator
3535 i = m_clients.getIterator();
3536 i.atEnd() == false; i++)
3538 u16 peer_id = i.getNode()->getKey();
3539 RemoteClient *client = i.getNode()->getValue();
3540 assert(client->peer_id == peer_id);
3542 if(client->serialization_version == SER_FMT_VER_INVALID)
3545 client->SendObjectData(this, dtime, stepped_blocks);
3549 void Server::SendPlayerInfos()
3551 DSTACK(__FUNCTION_NAME);
3553 //JMutexAutoLock envlock(m_env_mutex);
3555 // Get connected players
3556 core::list<Player*> players = m_env.getPlayers(true);
3558 u32 player_count = players.getSize();
3559 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3561 SharedBuffer<u8> data(datasize);
3562 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3565 core::list<Player*>::Iterator i;
3566 for(i = players.begin();
3567 i != players.end(); i++)
3569 Player *player = *i;
3571 /*dstream<<"Server sending player info for player with "
3572 "peer_id="<<player->peer_id<<std::endl;*/
3574 writeU16(&data[start], player->peer_id);
3575 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3576 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3577 start += 2+PLAYERNAME_SIZE;
3580 //JMutexAutoLock conlock(m_con_mutex);
3583 m_con.SendToAll(0, data, true);
3586 void Server::SendInventory(u16 peer_id)
3588 DSTACK(__FUNCTION_NAME);
3590 Player* player = m_env.getPlayer(peer_id);
3597 std::ostringstream os;
3598 //os.imbue(std::locale("C"));
3600 player->inventory.serialize(os);
3602 std::string s = os.str();
3604 SharedBuffer<u8> data(s.size()+2);
3605 writeU16(&data[0], TOCLIENT_INVENTORY);
3606 memcpy(&data[2], s.c_str(), s.size());
3609 m_con.Send(peer_id, 0, data, true);
3612 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3614 DSTACK(__FUNCTION_NAME);
3616 std::ostringstream os(std::ios_base::binary);
3620 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3621 os.write((char*)buf, 2);
3624 writeU16(buf, message.size());
3625 os.write((char*)buf, 2);
3628 for(u32 i=0; i<message.size(); i++)
3632 os.write((char*)buf, 2);
3636 std::string s = os.str();
3637 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3639 m_con.Send(peer_id, 0, data, true);
3642 void Server::BroadcastChatMessage(const std::wstring &message)
3644 for(core::map<u16, RemoteClient*>::Iterator
3645 i = m_clients.getIterator();
3646 i.atEnd() == false; i++)
3648 // Get client and check that it is valid
3649 RemoteClient *client = i.getNode()->getValue();
3650 assert(client->peer_id == i.getNode()->getKey());
3651 if(client->serialization_version == SER_FMT_VER_INVALID)
3654 SendChatMessage(client->peer_id, message);
3658 void Server::SendPlayerHP(Player *player)
3660 SendHP(m_con, player->peer_id, player->hp);
3663 void Server::SendMovePlayer(Player *player)
3665 DSTACK(__FUNCTION_NAME);
3666 std::ostringstream os(std::ios_base::binary);
3668 writeU16(os, TOCLIENT_MOVE_PLAYER);
3669 writeV3F1000(os, player->getPosition());
3670 writeF1000(os, player->getPitch());
3671 writeF1000(os, player->getYaw());
3674 v3f pos = player->getPosition();
3675 f32 pitch = player->getPitch();
3676 f32 yaw = player->getYaw();
3677 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3678 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3685 std::string s = os.str();
3686 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3688 m_con.Send(player->peer_id, 0, data, true);
3691 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3692 core::list<u16> *far_players, float far_d_nodes)
3694 float maxd = far_d_nodes*BS;
3695 v3f p_f = intToFloat(p, BS);
3699 SharedBuffer<u8> reply(replysize);
3700 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3701 writeS16(&reply[2], p.X);
3702 writeS16(&reply[4], p.Y);
3703 writeS16(&reply[6], p.Z);
3705 for(core::map<u16, RemoteClient*>::Iterator
3706 i = m_clients.getIterator();
3707 i.atEnd() == false; i++)
3709 // Get client and check that it is valid
3710 RemoteClient *client = i.getNode()->getValue();
3711 assert(client->peer_id == i.getNode()->getKey());
3712 if(client->serialization_version == SER_FMT_VER_INVALID)
3715 // Don't send if it's the same one
3716 if(client->peer_id == ignore_id)
3722 Player *player = m_env.getPlayer(client->peer_id);
3725 // If player is far away, only set modified blocks not sent
3726 v3f player_pos = player->getPosition();
3727 if(player_pos.getDistanceFrom(p_f) > maxd)
3729 far_players->push_back(client->peer_id);
3736 m_con.Send(client->peer_id, 0, reply, true);
3740 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3741 core::list<u16> *far_players, float far_d_nodes)
3743 float maxd = far_d_nodes*BS;
3744 v3f p_f = intToFloat(p, BS);
3746 for(core::map<u16, RemoteClient*>::Iterator
3747 i = m_clients.getIterator();
3748 i.atEnd() == false; i++)
3750 // Get client and check that it is valid
3751 RemoteClient *client = i.getNode()->getValue();
3752 assert(client->peer_id == i.getNode()->getKey());
3753 if(client->serialization_version == SER_FMT_VER_INVALID)
3756 // Don't send if it's the same one
3757 if(client->peer_id == ignore_id)
3763 Player *player = m_env.getPlayer(client->peer_id);
3766 // If player is far away, only set modified blocks not sent
3767 v3f player_pos = player->getPosition();
3768 if(player_pos.getDistanceFrom(p_f) > maxd)
3770 far_players->push_back(client->peer_id);
3777 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3778 SharedBuffer<u8> reply(replysize);
3779 writeU16(&reply[0], TOCLIENT_ADDNODE);
3780 writeS16(&reply[2], p.X);
3781 writeS16(&reply[4], p.Y);
3782 writeS16(&reply[6], p.Z);
3783 n.serialize(&reply[8], client->serialization_version);
3786 m_con.Send(client->peer_id, 0, reply, true);
3790 void Server::setBlockNotSent(v3s16 p)
3792 for(core::map<u16, RemoteClient*>::Iterator
3793 i = m_clients.getIterator();
3794 i.atEnd()==false; i++)
3796 RemoteClient *client = i.getNode()->getValue();
3797 client->SetBlockNotSent(p);
3801 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3803 DSTACK(__FUNCTION_NAME);
3805 v3s16 p = block->getPos();
3809 bool completely_air = true;
3810 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3811 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3812 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3814 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3816 completely_air = false;
3817 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3822 dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3824 dstream<<"[completely air] ";
3829 Create a packet with the block in the right format
3832 std::ostringstream os(std::ios_base::binary);
3833 block->serialize(os, ver);
3834 std::string s = os.str();
3835 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3837 u32 replysize = 8 + blockdata.getSize();
3838 SharedBuffer<u8> reply(replysize);
3839 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3840 writeS16(&reply[2], p.X);
3841 writeS16(&reply[4], p.Y);
3842 writeS16(&reply[6], p.Z);
3843 memcpy(&reply[8], *blockdata, blockdata.getSize());
3845 /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3846 <<": \tpacket size: "<<replysize<<std::endl;*/
3851 m_con.Send(peer_id, 1, reply, true);
3854 void Server::SendBlocks(float dtime)
3856 DSTACK(__FUNCTION_NAME);
3858 JMutexAutoLock envlock(m_env_mutex);
3859 JMutexAutoLock conlock(m_con_mutex);
3861 //TimeTaker timer("Server::SendBlocks");
3863 core::array<PrioritySortedBlockTransfer> queue;
3865 s32 total_sending = 0;
3868 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
3870 for(core::map<u16, RemoteClient*>::Iterator
3871 i = m_clients.getIterator();
3872 i.atEnd() == false; i++)
3874 RemoteClient *client = i.getNode()->getValue();
3875 assert(client->peer_id == i.getNode()->getKey());
3877 total_sending += client->SendingCount();
3879 if(client->serialization_version == SER_FMT_VER_INVALID)
3882 client->GetNextBlocks(this, dtime, queue);
3887 // Lowest priority number comes first.
3888 // Lowest is most important.
3891 for(u32 i=0; i<queue.size(); i++)
3893 //TODO: Calculate limit dynamically
3894 if(total_sending >= g_settings.getS32
3895 ("max_simultaneous_block_sends_server_total"))
3898 PrioritySortedBlockTransfer q = queue[i];
3900 MapBlock *block = NULL;
3903 block = m_env.getMap().getBlockNoCreate(q.pos);
3905 catch(InvalidPositionException &e)
3910 RemoteClient *client = getClient(q.peer_id);
3912 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3914 client->SentBlock(q.pos);
3924 void Server::UpdateCrafting(u16 peer_id)
3926 DSTACK(__FUNCTION_NAME);
3928 Player* player = m_env.getPlayer(peer_id);
3932 Calculate crafting stuff
3934 if(g_settings.getBool("creative_mode") == false)
3936 InventoryList *clist = player->inventory.getList("craft");
3937 InventoryList *rlist = player->inventory.getList("craftresult");
3939 if(rlist->getUsedSlots() == 0)
3940 player->craftresult_is_preview = true;
3942 if(rlist && player->craftresult_is_preview)
3944 rlist->clearItems();
3946 if(clist && rlist && player->craftresult_is_preview)
3948 InventoryItem *items[9];
3949 for(u16 i=0; i<9; i++)
3951 items[i] = clist->getItem(i);
3954 // Get result of crafting grid
3955 InventoryItem *result = craft_get_result(items);
3957 rlist->addItem(result);
3960 } // if creative_mode == false
3963 RemoteClient* Server::getClient(u16 peer_id)
3965 DSTACK(__FUNCTION_NAME);
3966 //JMutexAutoLock lock(m_con_mutex);
3967 core::map<u16, RemoteClient*>::Node *n;
3968 n = m_clients.find(peer_id);
3969 // A client should exist for all peers
3971 return n->getValue();
3974 std::wstring Server::getStatusString()
3976 std::wostringstream os(std::ios_base::binary);
3979 os<<L"version="<<narrow_to_wide(VERSION_STRING);
3981 os<<L", uptime="<<m_uptime.get();
3982 // Information about clients
3984 for(core::map<u16, RemoteClient*>::Iterator
3985 i = m_clients.getIterator();
3986 i.atEnd() == false; i++)
3988 // Get client and check that it is valid
3989 RemoteClient *client = i.getNode()->getValue();
3990 assert(client->peer_id == i.getNode()->getKey());
3991 if(client->serialization_version == SER_FMT_VER_INVALID)
3994 Player *player = m_env.getPlayer(client->peer_id);
3995 // Get name of player
3996 std::wstring name = L"unknown";
3998 name = narrow_to_wide(player->getName());
3999 // Add name to information string
4003 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
4004 os<<" WARNING: Map saving is disabled."<<std::endl;
4008 v3f findSpawnPos(ServerMap &map)
4010 //return v3f(50,50,50)*BS;
4013 s16 groundheight = 0;
4016 nodepos = v2s16(0,0);
4021 // Try to find a good place a few times
4022 for(s32 i=0; i<1000; i++)
4025 // We're going to try to throw the player to this position
4026 nodepos = v2s16(-range + (myrand()%(range*2)),
4027 -range + (myrand()%(range*2)));
4028 v2s16 sectorpos = getNodeSectorPos(nodepos);
4029 // Get sector (NOTE: Don't get because it's slow)
4030 //m_env.getMap().emergeSector(sectorpos);
4031 // Get ground height at point (fallbacks to heightmap function)
4032 groundheight = map.findGroundLevel(nodepos);
4033 // Don't go underwater
4034 if(groundheight < WATER_LEVEL)
4036 //dstream<<"-> Underwater"<<std::endl;
4039 // Don't go to high places
4040 if(groundheight > WATER_LEVEL + 4)
4042 //dstream<<"-> Underwater"<<std::endl;
4046 // Found a good place
4047 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4052 // If no suitable place was not found, go above water at least.
4053 if(groundheight < WATER_LEVEL)
4054 groundheight = WATER_LEVEL;
4056 return intToFloat(v3s16(
4063 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4066 Try to get an existing player
4068 Player *player = m_env.getPlayer(name);
4071 // If player is already connected, cancel
4072 if(player->peer_id != 0)
4074 dstream<<"emergePlayer(): Player already connected"<<std::endl;
4079 player->peer_id = peer_id;
4081 // Reset inventory to creative if in creative mode
4082 if(g_settings.getBool("creative_mode"))
4084 craft_set_creative_inventory(player);
4091 If player with the wanted peer_id already exists, cancel.
4093 if(m_env.getPlayer(peer_id) != NULL)
4095 dstream<<"emergePlayer(): Player with wrong name but same"
4096 " peer_id already exists"<<std::endl;
4104 player = new ServerRemotePlayer();
4105 //player->peer_id = c.peer_id;
4106 //player->peer_id = PEER_ID_INEXISTENT;
4107 player->peer_id = peer_id;
4108 player->updateName(name);
4109 m_authmanager.add(name);
4110 m_authmanager.setPassword(name, password);
4111 m_authmanager.setPrivs(name,
4112 stringToPrivs(g_settings.get("default_privs")));
4118 dstream<<"Server: Finding spawn place for player \""
4119 <<player->getName()<<"\""<<std::endl;
4121 v3f pos = findSpawnPos(m_env.getServerMap());
4123 player->setPosition(pos);
4126 Add player to environment
4129 m_env.addPlayer(player);
4132 Add stuff to inventory
4135 if(g_settings.getBool("creative_mode"))
4137 craft_set_creative_inventory(player);
4139 else if(g_settings.getBool("give_initial_stuff"))
4141 craft_give_initial_stuff(player);
4146 } // create new player
4149 void Server::handlePeerChange(PeerChange &c)
4151 JMutexAutoLock envlock(m_env_mutex);
4152 JMutexAutoLock conlock(m_con_mutex);
4154 if(c.type == PEER_ADDED)
4161 core::map<u16, RemoteClient*>::Node *n;
4162 n = m_clients.find(c.peer_id);
4163 // The client shouldn't already exist
4167 RemoteClient *client = new RemoteClient();
4168 client->peer_id = c.peer_id;
4169 m_clients.insert(client->peer_id, client);
4172 else if(c.type == PEER_REMOVED)
4179 core::map<u16, RemoteClient*>::Node *n;
4180 n = m_clients.find(c.peer_id);
4181 // The client should exist
4185 Mark objects to be not known by the client
4187 RemoteClient *client = n->getValue();
4189 for(core::map<u16, bool>::Iterator
4190 i = client->m_known_objects.getIterator();
4191 i.atEnd()==false; i++)
4194 u16 id = i.getNode()->getKey();
4195 ServerActiveObject* obj = m_env.getActiveObject(id);
4197 if(obj && obj->m_known_by_count > 0)
4198 obj->m_known_by_count--;
4201 // Collect information about leaving in chat
4202 std::wstring message;
4204 std::wstring name = L"unknown";
4205 Player *player = m_env.getPlayer(c.peer_id);
4207 name = narrow_to_wide(player->getName());
4211 message += L" left game";
4213 message += L" (timed out)";
4218 m_env.removePlayer(c.peer_id);
4221 // Set player client disconnected
4223 Player *player = m_env.getPlayer(c.peer_id);
4225 player->peer_id = 0;
4229 delete m_clients[c.peer_id];
4230 m_clients.remove(c.peer_id);
4232 // Send player info to all remaining clients
4235 // Send leave chat message to all remaining clients
4236 BroadcastChatMessage(message);
4245 void Server::handlePeerChanges()
4247 while(m_peer_change_queue.size() > 0)
4249 PeerChange c = m_peer_change_queue.pop_front();
4251 dout_server<<"Server: Handling peer change: "
4252 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4255 handlePeerChange(c);
4259 u64 Server::getPlayerPrivs(Player *player)
4263 std::string playername = player->getName();
4264 // Local player gets all privileges regardless of
4265 // what's set on their account.
4266 if(g_settings.get("name") == playername)
4272 return getPlayerAuthPrivs(playername);
4276 void dedicated_server_loop(Server &server, bool &kill)
4278 DSTACK(__FUNCTION_NAME);
4280 dstream<<DTIME<<std::endl;
4281 dstream<<"========================"<<std::endl;
4282 dstream<<"Running dedicated server"<<std::endl;
4283 dstream<<"========================"<<std::endl;
4286 IntervalLimiter m_profiler_interval;
4290 // This is kind of a hack but can be done like this
4291 // because server.step() is very light
4293 ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4298 if(server.getShutdownRequested() || kill)
4300 dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4307 float profiler_print_interval =
4308 g_settings.getFloat("profiler_print_interval");
4309 if(profiler_print_interval != 0)
4311 if(m_profiler_interval.step(0.030, profiler_print_interval))
4313 dstream<<"Profiler:"<<std::endl;
4314 g_profiler.print(dstream);
4322 static int counter = 0;
4328 core::list<PlayerInfo> list = server.getPlayerInfo();
4329 core::list<PlayerInfo>::Iterator i;
4330 static u32 sum_old = 0;
4331 u32 sum = PIChecksum(list);
4334 dstream<<DTIME<<"Player info:"<<std::endl;
4335 for(i=list.begin(); i!=list.end(); i++)
4337 i->PrintLine(&dstream);