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,
1062 std::string configpath
1064 m_env(new ServerMap(mapsavedir), this),
1065 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
1066 m_authmanager(mapsavedir+"/auth.txt"),
1068 m_emergethread(this),
1070 m_time_of_day_send_timer(0),
1072 m_mapsavedir(mapsavedir),
1073 m_configpath(configpath),
1074 m_shutdown_requested(false),
1075 m_ignore_map_edit_events(false),
1076 m_ignore_map_edit_events_peer_id(0)
1078 m_liquid_transform_timer = 0.0;
1079 m_print_info_timer = 0.0;
1080 m_objectdata_timer = 0.0;
1081 m_emergethread_trigger_timer = 0.0;
1082 m_savemap_timer = 0.0;
1086 m_step_dtime_mutex.Init();
1089 // Register us to receive map edit events
1090 m_env.getMap().addEventReceiver(this);
1092 // If file exists, load environment metadata
1093 if(fs::PathExists(m_mapsavedir+"/env_meta.txt"))
1095 dstream<<"Server: Loading environment metadata"<<std::endl;
1096 m_env.loadMeta(m_mapsavedir);
1100 dstream<<"Server: Loading players"<<std::endl;
1101 m_env.deSerializePlayers(m_mapsavedir);
1106 dstream<<"Server::~Server()"<<std::endl;
1109 Send shutdown message
1112 JMutexAutoLock conlock(m_con_mutex);
1114 std::wstring line = L"*** Server shutting down";
1117 Send the message to clients
1119 for(core::map<u16, RemoteClient*>::Iterator
1120 i = m_clients.getIterator();
1121 i.atEnd() == false; i++)
1123 // Get client and check that it is valid
1124 RemoteClient *client = i.getNode()->getValue();
1125 assert(client->peer_id == i.getNode()->getKey());
1126 if(client->serialization_version == SER_FMT_VER_INVALID)
1130 SendChatMessage(client->peer_id, line);
1132 catch(con::PeerNotFoundException &e)
1140 dstream<<"Server: Saving players"<<std::endl;
1141 m_env.serializePlayers(m_mapsavedir);
1144 Save environment metadata
1146 dstream<<"Server: Saving environment metadata"<<std::endl;
1147 m_env.saveMeta(m_mapsavedir);
1158 JMutexAutoLock clientslock(m_con_mutex);
1160 for(core::map<u16, RemoteClient*>::Iterator
1161 i = m_clients.getIterator();
1162 i.atEnd() == false; i++)
1165 // NOTE: These are removed by env destructor
1167 u16 peer_id = i.getNode()->getKey();
1168 JMutexAutoLock envlock(m_env_mutex);
1169 m_env.removePlayer(peer_id);
1173 delete i.getNode()->getValue();
1178 void Server::start(unsigned short port)
1180 DSTACK(__FUNCTION_NAME);
1181 // Stop thread if already running
1184 // Initialize connection
1185 m_con.setTimeoutMs(30);
1189 m_thread.setRun(true);
1192 dout_server<<"Server: Started on port "<<port<<std::endl;
1197 DSTACK(__FUNCTION_NAME);
1199 // Stop threads (set run=false first so both start stopping)
1200 m_thread.setRun(false);
1201 m_emergethread.setRun(false);
1203 m_emergethread.stop();
1205 dout_server<<"Server: Threads stopped"<<std::endl;
1208 void Server::step(float dtime)
1210 DSTACK(__FUNCTION_NAME);
1215 JMutexAutoLock lock(m_step_dtime_mutex);
1216 m_step_dtime += dtime;
1220 void Server::AsyncRunStep()
1222 DSTACK(__FUNCTION_NAME);
1226 JMutexAutoLock lock1(m_step_dtime_mutex);
1227 dtime = m_step_dtime;
1231 ScopeProfiler sp(&g_profiler, "Server: selecting and sending "
1232 "blocks to clients");
1233 // Send blocks to clients
1240 //dstream<<"Server steps "<<dtime<<std::endl;
1241 //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1244 JMutexAutoLock lock1(m_step_dtime_mutex);
1245 m_step_dtime -= dtime;
1252 m_uptime.set(m_uptime.get() + dtime);
1256 Update m_time_of_day and overall game time
1259 JMutexAutoLock envlock(m_env_mutex);
1261 m_time_counter += dtime;
1262 f32 speed = g_settings.getFloat("time_speed") * 24000./(24.*3600);
1263 u32 units = (u32)(m_time_counter*speed);
1264 m_time_counter -= (f32)units / speed;
1266 m_env.setTimeOfDay((m_env.getTimeOfDay() + units) % 24000);
1268 //dstream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1271 Send to clients at constant intervals
1274 m_time_of_day_send_timer -= dtime;
1275 if(m_time_of_day_send_timer < 0.0)
1277 m_time_of_day_send_timer = g_settings.getFloat("time_send_interval");
1279 //JMutexAutoLock envlock(m_env_mutex);
1280 JMutexAutoLock conlock(m_con_mutex);
1282 for(core::map<u16, RemoteClient*>::Iterator
1283 i = m_clients.getIterator();
1284 i.atEnd() == false; i++)
1286 RemoteClient *client = i.getNode()->getValue();
1287 //Player *player = m_env.getPlayer(client->peer_id);
1289 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1290 m_env.getTimeOfDay());
1292 m_con.Send(client->peer_id, 0, data, true);
1298 // Process connection's timeouts
1299 JMutexAutoLock lock2(m_con_mutex);
1300 ScopeProfiler sp(&g_profiler, "Server: connection timeout processing");
1301 m_con.RunTimeouts(dtime);
1305 // This has to be called so that the client list gets synced
1306 // with the peer list of the connection
1307 ScopeProfiler sp(&g_profiler, "Server: peer change handling");
1308 handlePeerChanges();
1312 JMutexAutoLock lock(m_env_mutex);
1314 ScopeProfiler sp(&g_profiler, "Server: environment step");
1318 const float map_timer_and_unload_dtime = 5.15;
1319 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1321 JMutexAutoLock lock(m_env_mutex);
1322 // Run Map's timers and unload unused data
1323 ScopeProfiler sp(&g_profiler, "Server: map timer and unload");
1324 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
1325 g_settings.getFloat("server_unload_unused_data_timeout"));
1335 m_liquid_transform_timer += dtime;
1336 if(m_liquid_transform_timer >= 1.00)
1338 m_liquid_transform_timer -= 1.00;
1340 JMutexAutoLock lock(m_env_mutex);
1342 ScopeProfiler sp(&g_profiler, "Server: liquid transform");
1344 core::map<v3s16, MapBlock*> modified_blocks;
1345 m_env.getMap().transformLiquids(modified_blocks);
1350 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1351 ServerMap &map = ((ServerMap&)m_env.getMap());
1352 map.updateLighting(modified_blocks, lighting_modified_blocks);
1354 // Add blocks modified by lighting to modified_blocks
1355 for(core::map<v3s16, MapBlock*>::Iterator
1356 i = lighting_modified_blocks.getIterator();
1357 i.atEnd() == false; i++)
1359 MapBlock *block = i.getNode()->getValue();
1360 modified_blocks.insert(block->getPos(), block);
1364 Set the modified blocks unsent for all the clients
1367 JMutexAutoLock lock2(m_con_mutex);
1369 for(core::map<u16, RemoteClient*>::Iterator
1370 i = m_clients.getIterator();
1371 i.atEnd() == false; i++)
1373 RemoteClient *client = i.getNode()->getValue();
1375 if(modified_blocks.size() > 0)
1377 // Remove block from sent history
1378 client->SetBlocksNotSent(modified_blocks);
1383 // Periodically print some info
1385 float &counter = m_print_info_timer;
1391 JMutexAutoLock lock2(m_con_mutex);
1393 for(core::map<u16, RemoteClient*>::Iterator
1394 i = m_clients.getIterator();
1395 i.atEnd() == false; i++)
1397 //u16 peer_id = i.getNode()->getKey();
1398 RemoteClient *client = i.getNode()->getValue();
1399 Player *player = m_env.getPlayer(client->peer_id);
1402 std::cout<<player->getName()<<"\t";
1403 client->PrintInfo(std::cout);
1408 //if(g_settings.getBool("enable_experimental"))
1412 Check added and deleted active objects
1415 //dstream<<"Server: Checking added and deleted active objects"<<std::endl;
1416 JMutexAutoLock envlock(m_env_mutex);
1417 JMutexAutoLock conlock(m_con_mutex);
1419 ScopeProfiler sp(&g_profiler, "Server: checking added and deleted objects");
1421 // Radius inside which objects are active
1424 for(core::map<u16, RemoteClient*>::Iterator
1425 i = m_clients.getIterator();
1426 i.atEnd() == false; i++)
1428 RemoteClient *client = i.getNode()->getValue();
1429 Player *player = m_env.getPlayer(client->peer_id);
1432 // This can happen if the client timeouts somehow
1433 /*dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1435 <<" has no associated player"<<std::endl;*/
1438 v3s16 pos = floatToInt(player->getPosition(), BS);
1440 core::map<u16, bool> removed_objects;
1441 core::map<u16, bool> added_objects;
1442 m_env.getRemovedActiveObjects(pos, radius,
1443 client->m_known_objects, removed_objects);
1444 m_env.getAddedActiveObjects(pos, radius,
1445 client->m_known_objects, added_objects);
1447 // Ignore if nothing happened
1448 if(removed_objects.size() == 0 && added_objects.size() == 0)
1450 //dstream<<"INFO: active objects: none changed"<<std::endl;
1454 std::string data_buffer;
1458 // Handle removed objects
1459 writeU16((u8*)buf, removed_objects.size());
1460 data_buffer.append(buf, 2);
1461 for(core::map<u16, bool>::Iterator
1462 i = removed_objects.getIterator();
1463 i.atEnd()==false; i++)
1466 u16 id = i.getNode()->getKey();
1467 ServerActiveObject* obj = m_env.getActiveObject(id);
1469 // Add to data buffer for sending
1470 writeU16((u8*)buf, i.getNode()->getKey());
1471 data_buffer.append(buf, 2);
1473 // Remove from known objects
1474 client->m_known_objects.remove(i.getNode()->getKey());
1476 if(obj && obj->m_known_by_count > 0)
1477 obj->m_known_by_count--;
1480 // Handle added objects
1481 writeU16((u8*)buf, added_objects.size());
1482 data_buffer.append(buf, 2);
1483 for(core::map<u16, bool>::Iterator
1484 i = added_objects.getIterator();
1485 i.atEnd()==false; i++)
1488 u16 id = i.getNode()->getKey();
1489 ServerActiveObject* obj = m_env.getActiveObject(id);
1492 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1494 dstream<<"WARNING: "<<__FUNCTION_NAME
1495 <<": NULL object"<<std::endl;
1497 type = obj->getType();
1499 // Add to data buffer for sending
1500 writeU16((u8*)buf, id);
1501 data_buffer.append(buf, 2);
1502 writeU8((u8*)buf, type);
1503 data_buffer.append(buf, 1);
1506 data_buffer.append(serializeLongString(
1507 obj->getClientInitializationData()));
1509 data_buffer.append(serializeLongString(""));
1511 // Add to known objects
1512 client->m_known_objects.insert(i.getNode()->getKey(), false);
1515 obj->m_known_by_count++;
1519 SharedBuffer<u8> reply(2 + data_buffer.size());
1520 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1521 memcpy((char*)&reply[2], data_buffer.c_str(),
1522 data_buffer.size());
1524 m_con.Send(client->peer_id, 0, reply, true);
1526 dstream<<"INFO: Server: Sent object remove/add: "
1527 <<removed_objects.size()<<" removed, "
1528 <<added_objects.size()<<" added, "
1529 <<"packet size is "<<reply.getSize()<<std::endl;
1534 Collect a list of all the objects known by the clients
1535 and report it back to the environment.
1538 core::map<u16, bool> all_known_objects;
1540 for(core::map<u16, RemoteClient*>::Iterator
1541 i = m_clients.getIterator();
1542 i.atEnd() == false; i++)
1544 RemoteClient *client = i.getNode()->getValue();
1545 // Go through all known objects of client
1546 for(core::map<u16, bool>::Iterator
1547 i = client->m_known_objects.getIterator();
1548 i.atEnd()==false; i++)
1550 u16 id = i.getNode()->getKey();
1551 all_known_objects[id] = true;
1555 m_env.setKnownActiveObjects(whatever);
1561 Send object messages
1564 JMutexAutoLock envlock(m_env_mutex);
1565 JMutexAutoLock conlock(m_con_mutex);
1567 ScopeProfiler sp(&g_profiler, "Server: sending object messages");
1570 // Value = data sent by object
1571 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1573 // Get active object messages from environment
1576 ActiveObjectMessage aom = m_env.getActiveObjectMessage();
1580 core::list<ActiveObjectMessage>* message_list = NULL;
1581 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1582 n = buffered_messages.find(aom.id);
1585 message_list = new core::list<ActiveObjectMessage>;
1586 buffered_messages.insert(aom.id, message_list);
1590 message_list = n->getValue();
1592 message_list->push_back(aom);
1595 // Route data to every client
1596 for(core::map<u16, RemoteClient*>::Iterator
1597 i = m_clients.getIterator();
1598 i.atEnd()==false; i++)
1600 RemoteClient *client = i.getNode()->getValue();
1601 std::string reliable_data;
1602 std::string unreliable_data;
1603 // Go through all objects in message buffer
1604 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1605 j = buffered_messages.getIterator();
1606 j.atEnd()==false; j++)
1608 // If object is not known by client, skip it
1609 u16 id = j.getNode()->getKey();
1610 if(client->m_known_objects.find(id) == NULL)
1612 // Get message list of object
1613 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1614 // Go through every message
1615 for(core::list<ActiveObjectMessage>::Iterator
1616 k = list->begin(); k != list->end(); k++)
1618 // Compose the full new data with header
1619 ActiveObjectMessage aom = *k;
1620 std::string new_data;
1623 writeU16((u8*)&buf[0], aom.id);
1624 new_data.append(buf, 2);
1626 new_data += serializeString(aom.datastring);
1627 // Add data to buffer
1629 reliable_data += new_data;
1631 unreliable_data += new_data;
1635 reliable_data and unreliable_data are now ready.
1638 if(reliable_data.size() > 0)
1640 SharedBuffer<u8> reply(2 + reliable_data.size());
1641 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1642 memcpy((char*)&reply[2], reliable_data.c_str(),
1643 reliable_data.size());
1645 m_con.Send(client->peer_id, 0, reply, true);
1647 if(unreliable_data.size() > 0)
1649 SharedBuffer<u8> reply(2 + unreliable_data.size());
1650 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1651 memcpy((char*)&reply[2], unreliable_data.c_str(),
1652 unreliable_data.size());
1653 // Send as unreliable
1654 m_con.Send(client->peer_id, 0, reply, false);
1657 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1659 dstream<<"INFO: Server: Size of object message data: "
1660 <<"reliable: "<<reliable_data.size()
1661 <<", unreliable: "<<unreliable_data.size()
1666 // Clear buffered_messages
1667 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1668 i = buffered_messages.getIterator();
1669 i.atEnd()==false; i++)
1671 delete i.getNode()->getValue();
1675 } // enable_experimental
1678 Send queued-for-sending map edit events.
1681 // Don't send too many at a time
1684 // Single change sending is disabled if queue size is not small
1685 bool disable_single_change_sending = false;
1686 if(m_unsent_map_edit_queue.size() >= 4)
1687 disable_single_change_sending = true;
1689 bool got_any_events = false;
1691 // We'll log the amount of each
1694 while(m_unsent_map_edit_queue.size() != 0)
1696 got_any_events = true;
1698 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1700 // Players far away from the change are stored here.
1701 // Instead of sending the changes, MapBlocks are set not sent
1703 core::list<u16> far_players;
1705 if(event->type == MEET_ADDNODE)
1707 //dstream<<"Server: MEET_ADDNODE"<<std::endl;
1708 prof.add("MEET_ADDNODE", 1);
1709 if(disable_single_change_sending)
1710 sendAddNode(event->p, event->n, event->already_known_by_peer,
1713 sendAddNode(event->p, event->n, event->already_known_by_peer,
1716 else if(event->type == MEET_REMOVENODE)
1718 //dstream<<"Server: MEET_REMOVENODE"<<std::endl;
1719 prof.add("MEET_REMOVENODE", 1);
1720 if(disable_single_change_sending)
1721 sendRemoveNode(event->p, event->already_known_by_peer,
1724 sendRemoveNode(event->p, event->already_known_by_peer,
1727 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1729 dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1730 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1731 setBlockNotSent(event->p);
1733 else if(event->type == MEET_OTHER)
1735 prof.add("MEET_OTHER", 1);
1736 dstream<<"WARNING: Server: MEET_OTHER not implemented"
1741 prof.add("unknown", 1);
1742 dstream<<"WARNING: Server: Unknown MapEditEvent "
1743 <<((u32)event->type)<<std::endl;
1747 Set blocks not sent to far players
1749 if(far_players.size() > 0)
1751 // Convert list format to that wanted by SetBlocksNotSent
1752 core::map<v3s16, MapBlock*> modified_blocks2;
1753 for(core::map<v3s16, bool>::Iterator
1754 i = event->modified_blocks.getIterator();
1755 i.atEnd()==false; i++)
1757 v3s16 p = i.getNode()->getKey();
1758 modified_blocks2.insert(p,
1759 m_env.getMap().getBlockNoCreateNoEx(p));
1761 // Set blocks not sent
1762 for(core::list<u16>::Iterator
1763 i = far_players.begin();
1764 i != far_players.end(); i++)
1767 RemoteClient *client = getClient(peer_id);
1770 client->SetBlocksNotSent(modified_blocks2);
1776 /*// Don't send too many at a time
1778 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1784 dstream<<"Server: MapEditEvents:"<<std::endl;
1785 prof.print(dstream);
1791 Send object positions
1792 TODO: Get rid of MapBlockObjects
1795 float &counter = m_objectdata_timer;
1797 if(counter >= g_settings.getFloat("objectdata_interval"))
1799 JMutexAutoLock lock1(m_env_mutex);
1800 JMutexAutoLock lock2(m_con_mutex);
1802 ScopeProfiler sp(&g_profiler, "Server: sending mbo positions");
1804 SendObjectData(counter);
1811 Trigger emergethread (it somehow gets to a non-triggered but
1812 bysy state sometimes)
1815 float &counter = m_emergethread_trigger_timer;
1821 m_emergethread.trigger();
1825 // Save map, players and auth stuff
1827 float &counter = m_savemap_timer;
1829 if(counter >= g_settings.getFloat("server_map_save_interval"))
1833 ScopeProfiler sp(&g_profiler, "Server: saving stuff");
1836 if(m_authmanager.isModified())
1837 m_authmanager.save();
1840 JMutexAutoLock lock(m_env_mutex);
1842 /*// Unload unused data (delete from memory)
1843 m_env.getMap().unloadUnusedData(
1844 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1846 /*u32 deleted_count = m_env.getMap().unloadUnusedData(
1847 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1850 // Save only changed parts
1851 m_env.getMap().save(true);
1853 /*if(deleted_count > 0)
1855 dout_server<<"Server: Unloaded "<<deleted_count
1856 <<" blocks from memory"<<std::endl;
1860 m_env.serializePlayers(m_mapsavedir);
1862 // Save environment metadata
1863 m_env.saveMeta(m_mapsavedir);
1868 void Server::Receive()
1870 DSTACK(__FUNCTION_NAME);
1871 u32 data_maxsize = 10000;
1872 Buffer<u8> data(data_maxsize);
1877 JMutexAutoLock conlock(m_con_mutex);
1878 datasize = m_con.Receive(peer_id, *data, data_maxsize);
1881 // This has to be called so that the client list gets synced
1882 // with the peer list of the connection
1883 handlePeerChanges();
1885 ProcessData(*data, datasize, peer_id);
1887 catch(con::InvalidIncomingDataException &e)
1889 derr_server<<"Server::Receive(): "
1890 "InvalidIncomingDataException: what()="
1891 <<e.what()<<std::endl;
1893 catch(con::PeerNotFoundException &e)
1895 //NOTE: This is not needed anymore
1897 // The peer has been disconnected.
1898 // Find the associated player and remove it.
1900 /*JMutexAutoLock envlock(m_env_mutex);
1902 dout_server<<"ServerThread: peer_id="<<peer_id
1903 <<" has apparently closed connection. "
1904 <<"Removing player."<<std::endl;
1906 m_env.removePlayer(peer_id);*/
1910 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1912 DSTACK(__FUNCTION_NAME);
1913 // Environment is locked first.
1914 JMutexAutoLock envlock(m_env_mutex);
1915 JMutexAutoLock conlock(m_con_mutex);
1919 peer = m_con.GetPeer(peer_id);
1921 catch(con::PeerNotFoundException &e)
1923 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1924 <<peer_id<<" not found"<<std::endl;
1928 u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1936 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1938 if(command == TOSERVER_INIT)
1940 // [0] u16 TOSERVER_INIT
1941 // [2] u8 SER_FMT_VER_HIGHEST
1942 // [3] u8[20] player_name
1943 // [23] u8[28] password <--- can be sent without this, from old versions
1945 if(datasize < 2+1+PLAYERNAME_SIZE)
1948 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1949 <<peer->id<<std::endl;
1951 // First byte after command is maximum supported
1952 // serialization version
1953 u8 client_max = data[2];
1954 u8 our_max = SER_FMT_VER_HIGHEST;
1955 // Use the highest version supported by both
1956 u8 deployed = core::min_(client_max, our_max);
1957 // If it's lower than the lowest supported, give up.
1958 if(deployed < SER_FMT_VER_LOWEST)
1959 deployed = SER_FMT_VER_INVALID;
1961 //peer->serialization_version = deployed;
1962 getClient(peer->id)->pending_serialization_version = deployed;
1964 if(deployed == SER_FMT_VER_INVALID)
1966 derr_server<<DTIME<<"Server: Cannot negotiate "
1967 "serialization version with peer "
1968 <<peer_id<<std::endl;
1969 SendAccessDenied(m_con, peer_id,
1970 L"Your client is too old (map format)");
1975 Read and check network protocol version
1978 u16 net_proto_version = 0;
1979 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1981 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1984 getClient(peer->id)->net_proto_version = net_proto_version;
1986 if(net_proto_version == 0)
1988 SendAccessDenied(m_con, peer_id,
1989 L"Your client is too old. Please upgrade.");
1998 char playername[PLAYERNAME_SIZE];
1999 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2001 playername[i] = data[3+i];
2003 playername[PLAYERNAME_SIZE-1] = 0;
2005 if(playername[0]=='\0')
2007 derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
2008 SendAccessDenied(m_con, peer_id,
2013 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2015 derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
2016 SendAccessDenied(m_con, peer_id,
2017 L"Name contains unallowed characters");
2022 char password[PASSWORD_SIZE];
2023 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2025 // old version - assume blank password
2030 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2032 password[i] = data[23+i];
2034 password[PASSWORD_SIZE-1] = 0;
2037 std::string checkpwd;
2038 if(m_authmanager.exists(playername))
2040 checkpwd = m_authmanager.getPassword(playername);
2044 checkpwd = g_settings.get("default_password");
2047 /*dstream<<"Server: Client gave password '"<<password
2048 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2050 if(password != checkpwd && m_authmanager.exists(playername))
2052 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2053 <<": supplied invalid password for "
2054 <<playername<<std::endl;
2055 SendAccessDenied(m_con, peer_id, L"Invalid password");
2059 // Add player to auth manager
2060 if(m_authmanager.exists(playername) == false)
2062 derr_server<<DTIME<<"Server: adding player "<<playername
2063 <<" to auth manager"<<std::endl;
2064 m_authmanager.add(playername);
2065 m_authmanager.setPassword(playername, checkpwd);
2066 m_authmanager.setPrivs(playername,
2067 stringToPrivs(g_settings.get("default_privs")));
2068 m_authmanager.save();
2072 Player *player = emergePlayer(playername, password, peer_id);
2076 // DEBUG: Test serialization
2077 std::ostringstream test_os;
2078 player->serialize(test_os);
2079 dstream<<"Player serialization test: \""<<test_os.str()
2081 std::istringstream test_is(test_os.str());
2082 player->deSerialize(test_is);
2085 // If failed, cancel
2088 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2089 <<": failed to emerge player"<<std::endl;
2094 // If a client is already connected to the player, cancel
2095 if(player->peer_id != 0)
2097 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2098 <<" tried to connect to "
2099 "an already connected player (peer_id="
2100 <<player->peer_id<<")"<<std::endl;
2103 // Set client of player
2104 player->peer_id = peer_id;
2107 // Check if player doesn't exist
2109 throw con::InvalidIncomingDataException
2110 ("Server::ProcessData(): INIT: Player doesn't exist");
2112 /*// update name if it was supplied
2113 if(datasize >= 20+3)
2116 player->updateName((const char*)&data[3]);
2120 Answer with a TOCLIENT_INIT
2123 SharedBuffer<u8> reply(2+1+6+8);
2124 writeU16(&reply[0], TOCLIENT_INIT);
2125 writeU8(&reply[2], deployed);
2126 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2127 writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2130 m_con.Send(peer_id, 0, reply, true);
2134 Send complete position information
2136 SendMovePlayer(player);
2141 if(command == TOSERVER_INIT2)
2143 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2144 <<peer->id<<std::endl;
2147 getClient(peer->id)->serialization_version
2148 = getClient(peer->id)->pending_serialization_version;
2151 Send some initialization data
2154 // Send player info to all players
2157 // Send inventory to player
2158 UpdateCrafting(peer->id);
2159 SendInventory(peer->id);
2163 Player *player = m_env.getPlayer(peer_id);
2164 SendPlayerHP(player);
2169 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2170 m_env.getTimeOfDay());
2171 m_con.Send(peer->id, 0, data, true);
2174 // Send information about server to player in chat
2175 SendChatMessage(peer_id, getStatusString());
2177 // Send information about joining in chat
2179 std::wstring name = L"unknown";
2180 Player *player = m_env.getPlayer(peer_id);
2182 name = narrow_to_wide(player->getName());
2184 std::wstring message;
2187 message += L" joined game";
2188 BroadcastChatMessage(message);
2191 // Warnings about protocol version can be issued here
2192 /*if(getClient(peer->id)->net_proto_version == 0)
2194 SendChatMessage(peer_id, L"# Server: NOTE: YOUR CLIENT IS OLD AND DOES NOT WORK PROPERLY WITH THIS SERVER");
2200 if(peer_ser_ver == SER_FMT_VER_INVALID)
2202 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2203 " serialization format invalid or not initialized."
2204 " Skipping incoming command="<<command<<std::endl;
2208 Player *player = m_env.getPlayer(peer_id);
2211 derr_server<<"Server::ProcessData(): Cancelling: "
2212 "No player for peer_id="<<peer_id
2216 if(command == TOSERVER_PLAYERPOS)
2218 if(datasize < 2+12+12+4+4)
2222 v3s32 ps = readV3S32(&data[start+2]);
2223 v3s32 ss = readV3S32(&data[start+2+12]);
2224 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2225 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2226 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2227 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2228 pitch = wrapDegrees(pitch);
2229 yaw = wrapDegrees(yaw);
2230 player->setPosition(position);
2231 player->setSpeed(speed);
2232 player->setPitch(pitch);
2233 player->setYaw(yaw);
2235 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2236 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2237 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2239 else if(command == TOSERVER_GOTBLOCKS)
2252 u16 count = data[2];
2253 for(u16 i=0; i<count; i++)
2255 if((s16)datasize < 2+1+(i+1)*6)
2256 throw con::InvalidIncomingDataException
2257 ("GOTBLOCKS length is too short");
2258 v3s16 p = readV3S16(&data[2+1+i*6]);
2259 /*dstream<<"Server: GOTBLOCKS ("
2260 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2261 RemoteClient *client = getClient(peer_id);
2262 client->GotBlock(p);
2265 else if(command == TOSERVER_DELETEDBLOCKS)
2278 u16 count = data[2];
2279 for(u16 i=0; i<count; i++)
2281 if((s16)datasize < 2+1+(i+1)*6)
2282 throw con::InvalidIncomingDataException
2283 ("DELETEDBLOCKS length is too short");
2284 v3s16 p = readV3S16(&data[2+1+i*6]);
2285 /*dstream<<"Server: DELETEDBLOCKS ("
2286 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2287 RemoteClient *client = getClient(peer_id);
2288 client->SetBlockNotSent(p);
2291 else if(command == TOSERVER_CLICK_OBJECT)
2296 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2301 [2] u8 button (0=left, 1=right)
2306 u8 button = readU8(&data[2]);
2308 p.X = readS16(&data[3]);
2309 p.Y = readS16(&data[5]);
2310 p.Z = readS16(&data[7]);
2311 s16 id = readS16(&data[9]);
2312 //u16 item_i = readU16(&data[11]);
2314 MapBlock *block = NULL;
2317 block = m_env.getMap().getBlockNoCreate(p);
2319 catch(InvalidPositionException &e)
2321 derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2325 MapBlockObject *obj = block->getObject(id);
2329 derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2333 //TODO: Check that object is reasonably close
2338 InventoryList *ilist = player->inventory.getList("main");
2339 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2342 // Skip if inventory has no free space
2343 if(ilist->getUsedSlots() == ilist->getSize())
2345 dout_server<<"Player inventory has no free space"<<std::endl;
2350 Create the inventory item
2352 InventoryItem *item = NULL;
2353 // If it is an item-object, take the item from it
2354 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2356 item = ((ItemObject*)obj)->createInventoryItem();
2358 // Else create an item of the object
2361 item = new MapBlockObjectItem
2362 (obj->getInventoryString());
2365 // Add to inventory and send inventory
2366 ilist->addItem(item);
2367 UpdateCrafting(player->peer_id);
2368 SendInventory(player->peer_id);
2371 // Remove from block
2372 block->removeObject(id);
2375 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2380 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2386 [2] u8 button (0=left, 1=right)
2390 u8 button = readU8(&data[2]);
2391 u16 id = readS16(&data[3]);
2392 u16 item_i = readU16(&data[11]);
2394 ServerActiveObject *obj = m_env.getActiveObject(id);
2398 derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2403 // Skip if object has been removed
2407 //TODO: Check that object is reasonably close
2409 // Left click, pick object up (usually)
2413 Try creating inventory item
2415 InventoryItem *item = obj->createPickedUpItem();
2419 InventoryList *ilist = player->inventory.getList("main");
2422 if(g_settings.getBool("creative_mode") == false)
2424 // Skip if inventory has no free space
2425 if(ilist->getUsedSlots() == ilist->getSize())
2427 dout_server<<"Player inventory has no free space"<<std::endl;
2431 // Add to inventory and send inventory
2432 ilist->addItem(item);
2433 UpdateCrafting(player->peer_id);
2434 SendInventory(player->peer_id);
2437 // Remove object from environment
2438 obj->m_removed = true;
2444 Item cannot be picked up. Punch it instead.
2447 ToolItem *titem = NULL;
2448 std::string toolname = "";
2450 InventoryList *mlist = player->inventory.getList("main");
2453 InventoryItem *item = mlist->getItem(item_i);
2454 if(item && (std::string)item->getName() == "ToolItem")
2456 titem = (ToolItem*)item;
2457 toolname = titem->getToolName();
2461 v3f playerpos = player->getPosition();
2462 v3f objpos = obj->getBasePosition();
2463 v3f dir = (objpos - playerpos).normalize();
2465 u16 wear = obj->punch(toolname, dir);
2469 bool weared_out = titem->addWear(wear);
2471 mlist->deleteItem(item_i);
2472 SendInventory(player->peer_id);
2476 // Right click, do something with object
2479 // Track hp changes super-crappily
2480 u16 oldhp = player->hp;
2483 obj->rightClick(player);
2486 if(player->hp != oldhp)
2488 SendPlayerHP(player);
2492 else if(command == TOSERVER_GROUND_ACTION)
2500 [3] v3s16 nodepos_undersurface
2501 [9] v3s16 nodepos_abovesurface
2506 2: stop digging (all parameters ignored)
2507 3: digging completed
2509 u8 action = readU8(&data[2]);
2511 p_under.X = readS16(&data[3]);
2512 p_under.Y = readS16(&data[5]);
2513 p_under.Z = readS16(&data[7]);
2515 p_over.X = readS16(&data[9]);
2516 p_over.Y = readS16(&data[11]);
2517 p_over.Z = readS16(&data[13]);
2518 u16 item_i = readU16(&data[15]);
2520 //TODO: Check that target is reasonably close
2528 NOTE: This can be used in the future to check if
2529 somebody is cheating, by checking the timing.
2536 else if(action == 2)
2539 RemoteClient *client = getClient(peer->id);
2540 JMutexAutoLock digmutex(client->m_dig_mutex);
2541 client->m_dig_tool_item = -1;
2546 3: Digging completed
2548 else if(action == 3)
2550 // Mandatory parameter; actually used for nothing
2551 core::map<v3s16, MapBlock*> modified_blocks;
2553 content_t material = CONTENT_IGNORE;
2554 u8 mineral = MINERAL_NONE;
2556 bool cannot_remove_node = false;
2560 MapNode n = m_env.getMap().getNode(p_under);
2562 mineral = n.getMineral();
2563 // Get material at position
2564 material = n.getContent();
2565 // If not yet cancelled
2566 if(cannot_remove_node == false)
2568 // If it's not diggable, do nothing
2569 if(content_diggable(material) == false)
2571 derr_server<<"Server: Not finishing digging: "
2572 <<"Node not diggable"
2574 cannot_remove_node = true;
2577 // If not yet cancelled
2578 if(cannot_remove_node == false)
2580 // Get node metadata
2581 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2582 if(meta && meta->nodeRemovalDisabled() == true)
2584 derr_server<<"Server: Not finishing digging: "
2585 <<"Node metadata disables removal"
2587 cannot_remove_node = true;
2591 catch(InvalidPositionException &e)
2593 derr_server<<"Server: Not finishing digging: Node not found."
2594 <<" Adding block to emerge queue."
2596 m_emerge_queue.addBlock(peer_id,
2597 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2598 cannot_remove_node = true;
2601 // Make sure the player is allowed to do it
2602 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2604 dstream<<"Player "<<player->getName()<<" cannot remove node"
2605 <<" because privileges are "<<getPlayerPrivs(player)
2607 cannot_remove_node = true;
2611 If node can't be removed, set block to be re-sent to
2614 if(cannot_remove_node)
2616 derr_server<<"Server: Not finishing digging."<<std::endl;
2618 // Client probably has wrong data.
2619 // Set block not sent, so that client will get
2621 dstream<<"Client "<<peer_id<<" tried to dig "
2622 <<"node; but node cannot be removed."
2623 <<" setting MapBlock not sent."<<std::endl;
2624 RemoteClient *client = getClient(peer_id);
2625 v3s16 blockpos = getNodeBlockPos(p_under);
2626 client->SetBlockNotSent(blockpos);
2632 Send the removal to all close-by players.
2633 - If other player is close, send REMOVENODE
2634 - Otherwise set blocks not sent
2636 core::list<u16> far_players;
2637 sendRemoveNode(p_under, peer_id, &far_players, 30);
2640 Update and send inventory
2643 if(g_settings.getBool("creative_mode") == false)
2648 InventoryList *mlist = player->inventory.getList("main");
2651 InventoryItem *item = mlist->getItem(item_i);
2652 if(item && (std::string)item->getName() == "ToolItem")
2654 ToolItem *titem = (ToolItem*)item;
2655 std::string toolname = titem->getToolName();
2657 // Get digging properties for material and tool
2658 DiggingProperties prop =
2659 getDiggingProperties(material, toolname);
2661 if(prop.diggable == false)
2663 derr_server<<"Server: WARNING: Player digged"
2664 <<" with impossible material + tool"
2665 <<" combination"<<std::endl;
2668 bool weared_out = titem->addWear(prop.wear);
2672 mlist->deleteItem(item_i);
2678 Add dug item to inventory
2681 InventoryItem *item = NULL;
2683 if(mineral != MINERAL_NONE)
2684 item = getDiggedMineralItem(mineral);
2689 std::string &dug_s = content_features(material).dug_item;
2692 std::istringstream is(dug_s, std::ios::binary);
2693 item = InventoryItem::deSerialize(is);
2699 // Add a item to inventory
2700 player->inventory.addItem("main", item);
2703 UpdateCrafting(player->peer_id);
2704 SendInventory(player->peer_id);
2710 (this takes some time so it is done after the quick stuff)
2713 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2715 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2718 Set blocks not sent to far players
2720 for(core::list<u16>::Iterator
2721 i = far_players.begin();
2722 i != far_players.end(); i++)
2725 RemoteClient *client = getClient(peer_id);
2728 client->SetBlocksNotSent(modified_blocks);
2735 else if(action == 1)
2738 InventoryList *ilist = player->inventory.getList("main");
2743 InventoryItem *item = ilist->getItem(item_i);
2745 // If there is no item, it is not possible to add it anywhere
2750 Handle material items
2752 if(std::string("MaterialItem") == item->getName())
2755 // Don't add a node if this is not a free space
2756 MapNode n2 = m_env.getMap().getNode(p_over);
2757 bool no_enough_privs =
2758 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2760 dstream<<"Player "<<player->getName()<<" cannot add node"
2761 <<" because privileges are "<<getPlayerPrivs(player)
2764 if(content_features(n2).buildable_to == false
2767 // Client probably has wrong data.
2768 // Set block not sent, so that client will get
2770 dstream<<"Client "<<peer_id<<" tried to place"
2771 <<" node in invalid position; setting"
2772 <<" MapBlock not sent."<<std::endl;
2773 RemoteClient *client = getClient(peer_id);
2774 v3s16 blockpos = getNodeBlockPos(p_over);
2775 client->SetBlockNotSent(blockpos);
2779 catch(InvalidPositionException &e)
2781 derr_server<<"Server: Ignoring ADDNODE: Node not found"
2782 <<" Adding block to emerge queue."
2784 m_emerge_queue.addBlock(peer_id,
2785 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2789 // Reset build time counter
2790 getClient(peer->id)->m_time_from_building = 0.0;
2793 MaterialItem *mitem = (MaterialItem*)item;
2795 n.setContent(mitem->getMaterial());
2797 // Calculate direction for wall mounted stuff
2798 if(content_features(n).wall_mounted)
2799 n.param2 = packDir(p_under - p_over);
2801 // Calculate the direction for furnaces and chests and stuff
2802 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2804 v3f playerpos = player->getPosition();
2805 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2806 blockpos = blockpos.normalize();
2808 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2822 Send to all close-by players
2824 core::list<u16> far_players;
2825 sendAddNode(p_over, n, 0, &far_players, 30);
2830 InventoryList *ilist = player->inventory.getList("main");
2831 if(g_settings.getBool("creative_mode") == false && ilist)
2833 // Remove from inventory and send inventory
2834 if(mitem->getCount() == 1)
2835 ilist->deleteItem(item_i);
2839 UpdateCrafting(peer_id);
2840 SendInventory(peer_id);
2846 This takes some time so it is done after the quick stuff
2848 core::map<v3s16, MapBlock*> modified_blocks;
2850 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2852 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2855 Set blocks not sent to far players
2857 for(core::list<u16>::Iterator
2858 i = far_players.begin();
2859 i != far_players.end(); i++)
2862 RemoteClient *client = getClient(peer_id);
2865 client->SetBlocksNotSent(modified_blocks);
2869 Calculate special events
2872 /*if(n.d == CONTENT_MESE)
2875 for(s16 z=-1; z<=1; z++)
2876 for(s16 y=-1; y<=1; y++)
2877 for(s16 x=-1; x<=1; x++)
2884 Place other item (not a block)
2888 v3s16 blockpos = getNodeBlockPos(p_over);
2891 Check that the block is loaded so that the item
2892 can properly be added to the static list too
2894 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2897 derr_server<<"Error while placing object: "
2898 "block not found"<<std::endl;
2902 dout_server<<"Placing a miscellaneous item on map"
2905 // Calculate a position for it
2906 v3f pos = intToFloat(p_over, BS);
2908 pos.Y -= BS*0.25; // let it drop a bit
2910 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2911 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2916 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2920 derr_server<<"WARNING: item resulted in NULL object, "
2921 <<"not placing onto map"
2926 // Add the object to the environment
2927 m_env.addActiveObject(obj);
2929 dout_server<<"Placed object"<<std::endl;
2931 if(g_settings.getBool("creative_mode") == false)
2933 // Delete the right amount of items from the slot
2934 u16 dropcount = item->getDropCount();
2936 // Delete item if all gone
2937 if(item->getCount() <= dropcount)
2939 if(item->getCount() < dropcount)
2940 dstream<<"WARNING: Server: dropped more items"
2941 <<" than the slot contains"<<std::endl;
2943 InventoryList *ilist = player->inventory.getList("main");
2945 // Remove from inventory and send inventory
2946 ilist->deleteItem(item_i);
2948 // Else decrement it
2950 item->remove(dropcount);
2953 UpdateCrafting(peer_id);
2954 SendInventory(peer_id);
2962 Catch invalid actions
2966 derr_server<<"WARNING: Server: Invalid action "
2967 <<action<<std::endl;
2971 else if(command == TOSERVER_RELEASE)
2980 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2983 else if(command == TOSERVER_SIGNTEXT)
2985 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2994 std::string datastring((char*)&data[2], datasize-2);
2995 std::istringstream is(datastring, std::ios_base::binary);
2998 is.read((char*)buf, 6);
2999 v3s16 blockpos = readV3S16(buf);
3000 is.read((char*)buf, 2);
3001 s16 id = readS16(buf);
3002 is.read((char*)buf, 2);
3003 u16 textlen = readU16(buf);
3005 for(u16 i=0; i<textlen; i++)
3007 is.read((char*)buf, 1);
3008 text += (char)buf[0];
3011 MapBlock *block = NULL;
3014 block = m_env.getMap().getBlockNoCreate(blockpos);
3016 catch(InvalidPositionException &e)
3018 derr_server<<"Error while setting sign text: "
3019 "block not found"<<std::endl;
3023 MapBlockObject *obj = block->getObject(id);
3026 derr_server<<"Error while setting sign text: "
3027 "object not found"<<std::endl;
3031 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
3033 derr_server<<"Error while setting sign text: "
3034 "object is not a sign"<<std::endl;
3038 ((SignObject*)obj)->setText(text);
3040 obj->getBlock()->setChangedFlag();
3042 else if(command == TOSERVER_SIGNNODETEXT)
3044 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3052 std::string datastring((char*)&data[2], datasize-2);
3053 std::istringstream is(datastring, std::ios_base::binary);
3056 is.read((char*)buf, 6);
3057 v3s16 p = readV3S16(buf);
3058 is.read((char*)buf, 2);
3059 u16 textlen = readU16(buf);
3061 for(u16 i=0; i<textlen; i++)
3063 is.read((char*)buf, 1);
3064 text += (char)buf[0];
3067 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3070 if(meta->typeId() != CONTENT_SIGN_WALL)
3072 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3073 signmeta->setText(text);
3075 v3s16 blockpos = getNodeBlockPos(p);
3076 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
3079 block->setChangedFlag();
3082 for(core::map<u16, RemoteClient*>::Iterator
3083 i = m_clients.getIterator();
3084 i.atEnd()==false; i++)
3086 RemoteClient *client = i.getNode()->getValue();
3087 client->SetBlockNotSent(blockpos);
3090 else if(command == TOSERVER_INVENTORY_ACTION)
3092 /*// Ignore inventory changes if in creative mode
3093 if(g_settings.getBool("creative_mode") == true)
3095 dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3099 // Strip command and create a stream
3100 std::string datastring((char*)&data[2], datasize-2);
3101 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3102 std::istringstream is(datastring, std::ios_base::binary);
3104 InventoryAction *a = InventoryAction::deSerialize(is);
3109 c.current_player = player;
3112 Handle craftresult specially if not in creative mode
3114 bool disable_action = false;
3115 if(a->getType() == IACTION_MOVE
3116 && g_settings.getBool("creative_mode") == false)
3118 IMoveAction *ma = (IMoveAction*)a;
3119 if(ma->to_inv == "current_player" &&
3120 ma->from_inv == "current_player")
3122 InventoryList *rlist = player->inventory.getList("craftresult");
3124 InventoryList *clist = player->inventory.getList("craft");
3126 InventoryList *mlist = player->inventory.getList("main");
3129 Craftresult is no longer preview if something
3132 if(ma->to_list == "craftresult"
3133 && ma->from_list != "craftresult")
3135 // If it currently is a preview, remove
3137 if(player->craftresult_is_preview)
3139 rlist->deleteItem(0);
3141 player->craftresult_is_preview = false;
3144 Crafting takes place if this condition is true.
3146 if(player->craftresult_is_preview &&
3147 ma->from_list == "craftresult")
3149 player->craftresult_is_preview = false;
3150 clist->decrementMaterials(1);
3153 If the craftresult is placed on itself, move it to
3154 main inventory instead of doing the action
3156 if(ma->to_list == "craftresult"
3157 && ma->from_list == "craftresult")
3159 disable_action = true;
3161 InventoryItem *item1 = rlist->changeItem(0, NULL);
3162 mlist->addItem(item1);
3167 if(disable_action == false)
3169 // Feed action to player inventory
3177 UpdateCrafting(player->peer_id);
3178 SendInventory(player->peer_id);
3183 dstream<<"TOSERVER_INVENTORY_ACTION: "
3184 <<"InventoryAction::deSerialize() returned NULL"
3188 else if(command == TOSERVER_CHAT_MESSAGE)
3196 std::string datastring((char*)&data[2], datasize-2);
3197 std::istringstream is(datastring, std::ios_base::binary);
3200 is.read((char*)buf, 2);
3201 u16 len = readU16(buf);
3203 std::wstring message;
3204 for(u16 i=0; i<len; i++)
3206 is.read((char*)buf, 2);
3207 message += (wchar_t)readU16(buf);
3210 // Get player name of this client
3211 std::wstring name = narrow_to_wide(player->getName());
3213 // Line to send to players
3215 // Whether to send to the player that sent the line
3216 bool send_to_sender = false;
3217 // Whether to send to other players
3218 bool send_to_others = false;
3220 // Local player gets all privileges regardless of
3221 // what's set on their account.
3222 u64 privs = getPlayerPrivs(player);
3225 std::wstring commandprefix = L"/#";
3226 if(message.substr(0, commandprefix.size()) == commandprefix)
3228 line += L"Server: ";
3230 message = message.substr(commandprefix.size());
3232 WStrfnd f1(message);
3233 f1.next(L" "); // Skip over /#whatever
3234 std::wstring paramstring = f1.next(L"");
3236 ServerCommandContext *ctx = new ServerCommandContext(
3237 str_split(message, L' '),
3244 line += processServerCommand(ctx);
3245 send_to_sender = ctx->flags & 1;
3246 send_to_others = ctx->flags & 2;
3252 if(privs & PRIV_SHOUT)
3258 send_to_others = true;
3262 line += L"Server: You are not allowed to shout";
3263 send_to_sender = true;
3269 dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3272 Send the message to clients
3274 for(core::map<u16, RemoteClient*>::Iterator
3275 i = m_clients.getIterator();
3276 i.atEnd() == false; i++)
3278 // Get client and check that it is valid
3279 RemoteClient *client = i.getNode()->getValue();
3280 assert(client->peer_id == i.getNode()->getKey());
3281 if(client->serialization_version == SER_FMT_VER_INVALID)
3285 bool sender_selected = (peer_id == client->peer_id);
3286 if(sender_selected == true && send_to_sender == false)
3288 if(sender_selected == false && send_to_others == false)
3291 SendChatMessage(client->peer_id, line);
3295 else if(command == TOSERVER_DAMAGE)
3297 if(g_settings.getBool("enable_damage"))
3299 std::string datastring((char*)&data[2], datasize-2);
3300 std::istringstream is(datastring, std::ios_base::binary);
3301 u8 damage = readU8(is);
3302 if(player->hp > damage)
3304 player->hp -= damage;
3310 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3313 v3f pos = findSpawnPos(m_env.getServerMap());
3314 player->setPosition(pos);
3316 SendMovePlayer(player);
3317 SendPlayerHP(player);
3319 //TODO: Throw items around
3323 SendPlayerHP(player);
3325 else if(command == TOSERVER_PASSWORD)
3328 [0] u16 TOSERVER_PASSWORD
3329 [2] u8[28] old password
3330 [30] u8[28] new password
3333 if(datasize != 2+PASSWORD_SIZE*2)
3335 /*char password[PASSWORD_SIZE];
3336 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3337 password[i] = data[2+i];
3338 password[PASSWORD_SIZE-1] = 0;*/
3340 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3348 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3350 char c = data[2+PASSWORD_SIZE+i];
3356 dstream<<"Server: Client requests a password change from "
3357 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3359 std::string playername = player->getName();
3361 if(m_authmanager.exists(playername) == false)
3363 dstream<<"Server: playername not found in authmanager"<<std::endl;
3364 // Wrong old password supplied!!
3365 SendChatMessage(peer_id, L"playername not found in authmanager");
3369 std::string checkpwd = m_authmanager.getPassword(playername);
3371 if(oldpwd != checkpwd)
3373 dstream<<"Server: invalid old password"<<std::endl;
3374 // Wrong old password supplied!!
3375 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3379 m_authmanager.setPassword(playername, newpwd);
3381 dstream<<"Server: password change successful for "<<playername
3383 SendChatMessage(peer_id, L"Password change successful");
3387 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3388 "unknown command "<<command<<std::endl;
3392 catch(SendFailedException &e)
3394 derr_server<<"Server::ProcessData(): SendFailedException: "
3400 void Server::onMapEditEvent(MapEditEvent *event)
3402 //dstream<<"Server::onMapEditEvent()"<<std::endl;
3403 if(m_ignore_map_edit_events)
3405 MapEditEvent *e = event->clone();
3406 m_unsent_map_edit_queue.push_back(e);
3409 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3411 if(id == "current_player")
3413 assert(c->current_player);
3414 return &(c->current_player->inventory);
3418 std::string id0 = fn.next(":");
3420 if(id0 == "nodemeta")
3423 p.X = stoi(fn.next(","));
3424 p.Y = stoi(fn.next(","));
3425 p.Z = stoi(fn.next(","));
3426 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3428 return meta->getInventory();
3429 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3430 <<"no metadata found"<<std::endl;
3434 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3437 void Server::inventoryModified(InventoryContext *c, std::string id)
3439 if(id == "current_player")
3441 assert(c->current_player);
3443 UpdateCrafting(c->current_player->peer_id);
3444 SendInventory(c->current_player->peer_id);
3449 std::string id0 = fn.next(":");
3451 if(id0 == "nodemeta")
3454 p.X = stoi(fn.next(","));
3455 p.Y = stoi(fn.next(","));
3456 p.Z = stoi(fn.next(","));
3457 v3s16 blockpos = getNodeBlockPos(p);
3459 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3461 meta->inventoryModified();
3463 for(core::map<u16, RemoteClient*>::Iterator
3464 i = m_clients.getIterator();
3465 i.atEnd()==false; i++)
3467 RemoteClient *client = i.getNode()->getValue();
3468 client->SetBlockNotSent(blockpos);
3474 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3477 core::list<PlayerInfo> Server::getPlayerInfo()
3479 DSTACK(__FUNCTION_NAME);
3480 JMutexAutoLock envlock(m_env_mutex);
3481 JMutexAutoLock conlock(m_con_mutex);
3483 core::list<PlayerInfo> list;
3485 core::list<Player*> players = m_env.getPlayers();
3487 core::list<Player*>::Iterator i;
3488 for(i = players.begin();
3489 i != players.end(); i++)
3493 Player *player = *i;
3496 con::Peer *peer = m_con.GetPeer(player->peer_id);
3497 // Copy info from peer to info struct
3499 info.address = peer->address;
3500 info.avg_rtt = peer->avg_rtt;
3502 catch(con::PeerNotFoundException &e)
3504 // Set dummy peer info
3506 info.address = Address(0,0,0,0,0);
3510 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3511 info.position = player->getPosition();
3513 list.push_back(info);
3520 void Server::peerAdded(con::Peer *peer)
3522 DSTACK(__FUNCTION_NAME);
3523 dout_server<<"Server::peerAdded(): peer->id="
3524 <<peer->id<<std::endl;
3527 c.type = PEER_ADDED;
3528 c.peer_id = peer->id;
3530 m_peer_change_queue.push_back(c);
3533 void Server::deletingPeer(con::Peer *peer, bool timeout)
3535 DSTACK(__FUNCTION_NAME);
3536 dout_server<<"Server::deletingPeer(): peer->id="
3537 <<peer->id<<", timeout="<<timeout<<std::endl;
3540 c.type = PEER_REMOVED;
3541 c.peer_id = peer->id;
3542 c.timeout = timeout;
3543 m_peer_change_queue.push_back(c);
3550 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3552 DSTACK(__FUNCTION_NAME);
3553 std::ostringstream os(std::ios_base::binary);
3555 writeU16(os, TOCLIENT_HP);
3559 std::string s = os.str();
3560 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3562 con.Send(peer_id, 0, data, true);
3565 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3566 const std::wstring &reason)
3568 DSTACK(__FUNCTION_NAME);
3569 std::ostringstream os(std::ios_base::binary);
3571 writeU16(os, TOCLIENT_ACCESS_DENIED);
3572 os<<serializeWideString(reason);
3575 std::string s = os.str();
3576 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3578 con.Send(peer_id, 0, data, true);
3582 Non-static send methods
3585 void Server::SendObjectData(float dtime)
3587 DSTACK(__FUNCTION_NAME);
3589 core::map<v3s16, bool> stepped_blocks;
3591 for(core::map<u16, RemoteClient*>::Iterator
3592 i = m_clients.getIterator();
3593 i.atEnd() == false; i++)
3595 u16 peer_id = i.getNode()->getKey();
3596 RemoteClient *client = i.getNode()->getValue();
3597 assert(client->peer_id == peer_id);
3599 if(client->serialization_version == SER_FMT_VER_INVALID)
3602 client->SendObjectData(this, dtime, stepped_blocks);
3606 void Server::SendPlayerInfos()
3608 DSTACK(__FUNCTION_NAME);
3610 //JMutexAutoLock envlock(m_env_mutex);
3612 // Get connected players
3613 core::list<Player*> players = m_env.getPlayers(true);
3615 u32 player_count = players.getSize();
3616 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3618 SharedBuffer<u8> data(datasize);
3619 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3622 core::list<Player*>::Iterator i;
3623 for(i = players.begin();
3624 i != players.end(); i++)
3626 Player *player = *i;
3628 /*dstream<<"Server sending player info for player with "
3629 "peer_id="<<player->peer_id<<std::endl;*/
3631 writeU16(&data[start], player->peer_id);
3632 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3633 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3634 start += 2+PLAYERNAME_SIZE;
3637 //JMutexAutoLock conlock(m_con_mutex);
3640 m_con.SendToAll(0, data, true);
3643 void Server::SendInventory(u16 peer_id)
3645 DSTACK(__FUNCTION_NAME);
3647 Player* player = m_env.getPlayer(peer_id);
3654 std::ostringstream os;
3655 //os.imbue(std::locale("C"));
3657 player->inventory.serialize(os);
3659 std::string s = os.str();
3661 SharedBuffer<u8> data(s.size()+2);
3662 writeU16(&data[0], TOCLIENT_INVENTORY);
3663 memcpy(&data[2], s.c_str(), s.size());
3666 m_con.Send(peer_id, 0, data, true);
3669 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3671 DSTACK(__FUNCTION_NAME);
3673 std::ostringstream os(std::ios_base::binary);
3677 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3678 os.write((char*)buf, 2);
3681 writeU16(buf, message.size());
3682 os.write((char*)buf, 2);
3685 for(u32 i=0; i<message.size(); i++)
3689 os.write((char*)buf, 2);
3693 std::string s = os.str();
3694 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3696 m_con.Send(peer_id, 0, data, true);
3699 void Server::BroadcastChatMessage(const std::wstring &message)
3701 for(core::map<u16, RemoteClient*>::Iterator
3702 i = m_clients.getIterator();
3703 i.atEnd() == false; i++)
3705 // Get client and check that it is valid
3706 RemoteClient *client = i.getNode()->getValue();
3707 assert(client->peer_id == i.getNode()->getKey());
3708 if(client->serialization_version == SER_FMT_VER_INVALID)
3711 SendChatMessage(client->peer_id, message);
3715 void Server::SendPlayerHP(Player *player)
3717 SendHP(m_con, player->peer_id, player->hp);
3720 void Server::SendMovePlayer(Player *player)
3722 DSTACK(__FUNCTION_NAME);
3723 std::ostringstream os(std::ios_base::binary);
3725 writeU16(os, TOCLIENT_MOVE_PLAYER);
3726 writeV3F1000(os, player->getPosition());
3727 writeF1000(os, player->getPitch());
3728 writeF1000(os, player->getYaw());
3731 v3f pos = player->getPosition();
3732 f32 pitch = player->getPitch();
3733 f32 yaw = player->getYaw();
3734 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3735 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3742 std::string s = os.str();
3743 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3745 m_con.Send(player->peer_id, 0, data, true);
3748 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3749 core::list<u16> *far_players, float far_d_nodes)
3751 float maxd = far_d_nodes*BS;
3752 v3f p_f = intToFloat(p, BS);
3756 SharedBuffer<u8> reply(replysize);
3757 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3758 writeS16(&reply[2], p.X);
3759 writeS16(&reply[4], p.Y);
3760 writeS16(&reply[6], p.Z);
3762 for(core::map<u16, RemoteClient*>::Iterator
3763 i = m_clients.getIterator();
3764 i.atEnd() == false; i++)
3766 // Get client and check that it is valid
3767 RemoteClient *client = i.getNode()->getValue();
3768 assert(client->peer_id == i.getNode()->getKey());
3769 if(client->serialization_version == SER_FMT_VER_INVALID)
3772 // Don't send if it's the same one
3773 if(client->peer_id == ignore_id)
3779 Player *player = m_env.getPlayer(client->peer_id);
3782 // If player is far away, only set modified blocks not sent
3783 v3f player_pos = player->getPosition();
3784 if(player_pos.getDistanceFrom(p_f) > maxd)
3786 far_players->push_back(client->peer_id);
3793 m_con.Send(client->peer_id, 0, reply, true);
3797 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3798 core::list<u16> *far_players, float far_d_nodes)
3800 float maxd = far_d_nodes*BS;
3801 v3f p_f = intToFloat(p, BS);
3803 for(core::map<u16, RemoteClient*>::Iterator
3804 i = m_clients.getIterator();
3805 i.atEnd() == false; i++)
3807 // Get client and check that it is valid
3808 RemoteClient *client = i.getNode()->getValue();
3809 assert(client->peer_id == i.getNode()->getKey());
3810 if(client->serialization_version == SER_FMT_VER_INVALID)
3813 // Don't send if it's the same one
3814 if(client->peer_id == ignore_id)
3820 Player *player = m_env.getPlayer(client->peer_id);
3823 // If player is far away, only set modified blocks not sent
3824 v3f player_pos = player->getPosition();
3825 if(player_pos.getDistanceFrom(p_f) > maxd)
3827 far_players->push_back(client->peer_id);
3834 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3835 SharedBuffer<u8> reply(replysize);
3836 writeU16(&reply[0], TOCLIENT_ADDNODE);
3837 writeS16(&reply[2], p.X);
3838 writeS16(&reply[4], p.Y);
3839 writeS16(&reply[6], p.Z);
3840 n.serialize(&reply[8], client->serialization_version);
3843 m_con.Send(client->peer_id, 0, reply, true);
3847 void Server::setBlockNotSent(v3s16 p)
3849 for(core::map<u16, RemoteClient*>::Iterator
3850 i = m_clients.getIterator();
3851 i.atEnd()==false; i++)
3853 RemoteClient *client = i.getNode()->getValue();
3854 client->SetBlockNotSent(p);
3858 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3860 DSTACK(__FUNCTION_NAME);
3862 v3s16 p = block->getPos();
3866 bool completely_air = true;
3867 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3868 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3869 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3871 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3873 completely_air = false;
3874 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3879 dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3881 dstream<<"[completely air] ";
3886 Create a packet with the block in the right format
3889 std::ostringstream os(std::ios_base::binary);
3890 block->serialize(os, ver);
3891 std::string s = os.str();
3892 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3894 u32 replysize = 8 + blockdata.getSize();
3895 SharedBuffer<u8> reply(replysize);
3896 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3897 writeS16(&reply[2], p.X);
3898 writeS16(&reply[4], p.Y);
3899 writeS16(&reply[6], p.Z);
3900 memcpy(&reply[8], *blockdata, blockdata.getSize());
3902 /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3903 <<": \tpacket size: "<<replysize<<std::endl;*/
3908 m_con.Send(peer_id, 1, reply, true);
3911 void Server::SendBlocks(float dtime)
3913 DSTACK(__FUNCTION_NAME);
3915 JMutexAutoLock envlock(m_env_mutex);
3916 JMutexAutoLock conlock(m_con_mutex);
3918 //TimeTaker timer("Server::SendBlocks");
3920 core::array<PrioritySortedBlockTransfer> queue;
3922 s32 total_sending = 0;
3925 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
3927 for(core::map<u16, RemoteClient*>::Iterator
3928 i = m_clients.getIterator();
3929 i.atEnd() == false; i++)
3931 RemoteClient *client = i.getNode()->getValue();
3932 assert(client->peer_id == i.getNode()->getKey());
3934 total_sending += client->SendingCount();
3936 if(client->serialization_version == SER_FMT_VER_INVALID)
3939 client->GetNextBlocks(this, dtime, queue);
3944 // Lowest priority number comes first.
3945 // Lowest is most important.
3948 for(u32 i=0; i<queue.size(); i++)
3950 //TODO: Calculate limit dynamically
3951 if(total_sending >= g_settings.getS32
3952 ("max_simultaneous_block_sends_server_total"))
3955 PrioritySortedBlockTransfer q = queue[i];
3957 MapBlock *block = NULL;
3960 block = m_env.getMap().getBlockNoCreate(q.pos);
3962 catch(InvalidPositionException &e)
3967 RemoteClient *client = getClient(q.peer_id);
3969 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3971 client->SentBlock(q.pos);
3981 void Server::UpdateCrafting(u16 peer_id)
3983 DSTACK(__FUNCTION_NAME);
3985 Player* player = m_env.getPlayer(peer_id);
3989 Calculate crafting stuff
3991 if(g_settings.getBool("creative_mode") == false)
3993 InventoryList *clist = player->inventory.getList("craft");
3994 InventoryList *rlist = player->inventory.getList("craftresult");
3996 if(rlist->getUsedSlots() == 0)
3997 player->craftresult_is_preview = true;
3999 if(rlist && player->craftresult_is_preview)
4001 rlist->clearItems();
4003 if(clist && rlist && player->craftresult_is_preview)
4005 InventoryItem *items[9];
4006 for(u16 i=0; i<9; i++)
4008 items[i] = clist->getItem(i);
4011 // Get result of crafting grid
4012 InventoryItem *result = craft_get_result(items);
4014 rlist->addItem(result);
4017 } // if creative_mode == false
4020 RemoteClient* Server::getClient(u16 peer_id)
4022 DSTACK(__FUNCTION_NAME);
4023 //JMutexAutoLock lock(m_con_mutex);
4024 core::map<u16, RemoteClient*>::Node *n;
4025 n = m_clients.find(peer_id);
4026 // A client should exist for all peers
4028 return n->getValue();
4031 std::wstring Server::getStatusString()
4033 std::wostringstream os(std::ios_base::binary);
4036 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4038 os<<L", uptime="<<m_uptime.get();
4039 // Information about clients
4041 for(core::map<u16, RemoteClient*>::Iterator
4042 i = m_clients.getIterator();
4043 i.atEnd() == false; i++)
4045 // Get client and check that it is valid
4046 RemoteClient *client = i.getNode()->getValue();
4047 assert(client->peer_id == i.getNode()->getKey());
4048 if(client->serialization_version == SER_FMT_VER_INVALID)
4051 Player *player = m_env.getPlayer(client->peer_id);
4052 // Get name of player
4053 std::wstring name = L"unknown";
4055 name = narrow_to_wide(player->getName());
4056 // Add name to information string
4060 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
4061 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4062 if(g_settings.get("motd") != "")
4063 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings.get("motd"));
4067 v3f findSpawnPos(ServerMap &map)
4069 //return v3f(50,50,50)*BS;
4072 s16 groundheight = 0;
4075 nodepos = v2s16(0,0);
4080 // Try to find a good place a few times
4081 for(s32 i=0; i<1000; i++)
4084 // We're going to try to throw the player to this position
4085 nodepos = v2s16(-range + (myrand()%(range*2)),
4086 -range + (myrand()%(range*2)));
4087 v2s16 sectorpos = getNodeSectorPos(nodepos);
4088 // Get sector (NOTE: Don't get because it's slow)
4089 //m_env.getMap().emergeSector(sectorpos);
4090 // Get ground height at point (fallbacks to heightmap function)
4091 groundheight = map.findGroundLevel(nodepos);
4092 // Don't go underwater
4093 if(groundheight < WATER_LEVEL)
4095 //dstream<<"-> Underwater"<<std::endl;
4098 // Don't go to high places
4099 if(groundheight > WATER_LEVEL + 4)
4101 //dstream<<"-> Underwater"<<std::endl;
4105 // Found a good place
4106 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4111 // If no suitable place was not found, go above water at least.
4112 if(groundheight < WATER_LEVEL)
4113 groundheight = WATER_LEVEL;
4115 return intToFloat(v3s16(
4122 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4125 Try to get an existing player
4127 Player *player = m_env.getPlayer(name);
4130 // If player is already connected, cancel
4131 if(player->peer_id != 0)
4133 dstream<<"emergePlayer(): Player already connected"<<std::endl;
4138 player->peer_id = peer_id;
4140 // Reset inventory to creative if in creative mode
4141 if(g_settings.getBool("creative_mode"))
4143 // Warning: double code below
4144 // Backup actual inventory
4145 player->inventory_backup = new Inventory();
4146 *(player->inventory_backup) = player->inventory;
4147 // Set creative inventory
4148 craft_set_creative_inventory(player);
4155 If player with the wanted peer_id already exists, cancel.
4157 if(m_env.getPlayer(peer_id) != NULL)
4159 dstream<<"emergePlayer(): Player with wrong name but same"
4160 " peer_id already exists"<<std::endl;
4168 player = new ServerRemotePlayer();
4169 //player->peer_id = c.peer_id;
4170 //player->peer_id = PEER_ID_INEXISTENT;
4171 player->peer_id = peer_id;
4172 player->updateName(name);
4173 m_authmanager.add(name);
4174 m_authmanager.setPassword(name, password);
4175 m_authmanager.setPrivs(name,
4176 stringToPrivs(g_settings.get("default_privs")));
4182 dstream<<"Server: Finding spawn place for player \""
4183 <<player->getName()<<"\""<<std::endl;
4185 v3f pos = findSpawnPos(m_env.getServerMap());
4187 player->setPosition(pos);
4190 Add player to environment
4193 m_env.addPlayer(player);
4196 Add stuff to inventory
4199 if(g_settings.getBool("creative_mode"))
4201 // Warning: double code above
4202 // Backup actual inventory
4203 player->inventory_backup = new Inventory();
4204 *(player->inventory_backup) = player->inventory;
4205 // Set creative inventory
4206 craft_set_creative_inventory(player);
4208 else if(g_settings.getBool("give_initial_stuff"))
4210 craft_give_initial_stuff(player);
4215 } // create new player
4218 void Server::handlePeerChange(PeerChange &c)
4220 JMutexAutoLock envlock(m_env_mutex);
4221 JMutexAutoLock conlock(m_con_mutex);
4223 if(c.type == PEER_ADDED)
4230 core::map<u16, RemoteClient*>::Node *n;
4231 n = m_clients.find(c.peer_id);
4232 // The client shouldn't already exist
4236 RemoteClient *client = new RemoteClient();
4237 client->peer_id = c.peer_id;
4238 m_clients.insert(client->peer_id, client);
4241 else if(c.type == PEER_REMOVED)
4248 core::map<u16, RemoteClient*>::Node *n;
4249 n = m_clients.find(c.peer_id);
4250 // The client should exist
4254 Mark objects to be not known by the client
4256 RemoteClient *client = n->getValue();
4258 for(core::map<u16, bool>::Iterator
4259 i = client->m_known_objects.getIterator();
4260 i.atEnd()==false; i++)
4263 u16 id = i.getNode()->getKey();
4264 ServerActiveObject* obj = m_env.getActiveObject(id);
4266 if(obj && obj->m_known_by_count > 0)
4267 obj->m_known_by_count--;
4270 // Collect information about leaving in chat
4271 std::wstring message;
4273 std::wstring name = L"unknown";
4274 Player *player = m_env.getPlayer(c.peer_id);
4276 name = narrow_to_wide(player->getName());
4280 message += L" left game";
4282 message += L" (timed out)";
4287 m_env.removePlayer(c.peer_id);
4290 // Set player client disconnected
4292 Player *player = m_env.getPlayer(c.peer_id);
4294 player->peer_id = 0;
4298 delete m_clients[c.peer_id];
4299 m_clients.remove(c.peer_id);
4301 // Send player info to all remaining clients
4304 // Send leave chat message to all remaining clients
4305 BroadcastChatMessage(message);
4314 void Server::handlePeerChanges()
4316 while(m_peer_change_queue.size() > 0)
4318 PeerChange c = m_peer_change_queue.pop_front();
4320 dout_server<<"Server: Handling peer change: "
4321 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4324 handlePeerChange(c);
4328 u64 Server::getPlayerPrivs(Player *player)
4332 std::string playername = player->getName();
4333 // Local player gets all privileges regardless of
4334 // what's set on their account.
4335 if(g_settings.get("name") == playername)
4341 return getPlayerAuthPrivs(playername);
4345 void dedicated_server_loop(Server &server, bool &kill)
4347 DSTACK(__FUNCTION_NAME);
4349 dstream<<DTIME<<std::endl;
4350 dstream<<"========================"<<std::endl;
4351 dstream<<"Running dedicated server"<<std::endl;
4352 dstream<<"========================"<<std::endl;
4355 IntervalLimiter m_profiler_interval;
4359 // This is kind of a hack but can be done like this
4360 // because server.step() is very light
4362 ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4367 if(server.getShutdownRequested() || kill)
4369 dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4376 float profiler_print_interval =
4377 g_settings.getFloat("profiler_print_interval");
4378 if(profiler_print_interval != 0)
4380 if(m_profiler_interval.step(0.030, profiler_print_interval))
4382 dstream<<"Profiler:"<<std::endl;
4383 g_profiler.print(dstream);
4391 static int counter = 0;
4397 core::list<PlayerInfo> list = server.getPlayerInfo();
4398 core::list<PlayerInfo>::Iterator i;
4399 static u32 sum_old = 0;
4400 u32 sum = PIChecksum(list);
4403 dstream<<DTIME<<"Player info:"<<std::endl;
4404 for(i=list.begin(); i!=list.end(); i++)
4406 i->PrintLine(&dstream);