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
383 v3f camera_pos = player->getEyePosition();
384 v3f camera_dir = v3f(0,0,1);
385 camera_dir.rotateYZBy(player->getPitch());
386 camera_dir.rotateXZBy(player->getYaw());
388 /*dstream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
389 <<camera_dir.Z<<")"<<std::endl;*/
392 Get the starting value of the block finder radius.
395 if(m_last_center != center)
397 m_nearest_unsent_d = 0;
398 m_last_center = center;
401 /*dstream<<"m_nearest_unsent_reset_timer="
402 <<m_nearest_unsent_reset_timer<<std::endl;*/
404 // This has to be incremented only when the nothing to send pause
406 m_nearest_unsent_reset_timer += dtime;
408 // Reset periodically to avoid possible bugs or other mishaps
409 if(m_nearest_unsent_reset_timer > 10.0)
411 m_nearest_unsent_reset_timer = 0;
412 m_nearest_unsent_d = 0;
413 /*dstream<<"Resetting m_nearest_unsent_d for "
414 <<server->getPlayerName(peer_id)<<std::endl;*/
417 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
418 s16 d_start = m_nearest_unsent_d;
420 //dstream<<"d_start="<<d_start<<std::endl;
422 u16 max_simul_sends_setting = g_settings.getU16
423 ("max_simultaneous_block_sends_per_client");
424 u16 max_simul_sends_usually = max_simul_sends_setting;
427 Check the time from last addNode/removeNode.
429 Decrease send rate if player is building stuff.
431 m_time_from_building += dtime;
432 if(m_time_from_building < g_settings.getFloat(
433 "full_block_send_enable_min_time_from_building"))
435 max_simul_sends_usually
436 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
440 Number of blocks sending + number of blocks selected for sending
442 u32 num_blocks_selected = m_blocks_sending.size();
445 next time d will be continued from the d from which the nearest
446 unsent block was found this time.
448 This is because not necessarily any of the blocks found this
449 time are actually sent.
451 s32 new_nearest_unsent_d = -1;
453 s16 d_max = g_settings.getS16("max_block_send_distance");
454 s16 d_max_gen = g_settings.getS16("max_block_generate_distance");
456 // Don't loop very much at a time
457 if(d_max > d_start+1)
459 /*if(d_max_gen > d_start+2)
460 d_max_gen = d_start+2;*/
462 //dstream<<"Starting from "<<d_start<<std::endl;
464 bool sending_something = false;
466 bool no_blocks_found_for_sending = true;
468 bool queue_is_full = false;
471 for(d = d_start; d <= d_max; d++)
473 //dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
476 If m_nearest_unsent_d was changed by the EmergeThread
477 (it can change it to 0 through SetBlockNotSent),
479 Else update m_nearest_unsent_d
481 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
483 d = m_nearest_unsent_d;
484 last_nearest_unsent_d = m_nearest_unsent_d;
488 Get the border/face dot coordinates of a "d-radiused"
491 core::list<v3s16> list;
492 getFacePositions(list, d);
494 core::list<v3s16>::Iterator li;
495 for(li=list.begin(); li!=list.end(); li++)
497 v3s16 p = *li + center;
501 - Don't allow too many simultaneous transfers
502 - EXCEPT when the blocks are very close
504 Also, don't send blocks that are already flying.
507 // Start with the usual maximum
508 u16 max_simul_dynamic = max_simul_sends_usually;
510 // If block is very close, allow full maximum
511 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
512 max_simul_dynamic = max_simul_sends_setting;
514 // Don't select too many blocks for sending
515 if(num_blocks_selected >= max_simul_dynamic)
517 queue_is_full = true;
518 goto queue_full_break;
521 // Don't send blocks that are currently being transferred
522 if(m_blocks_sending.find(p) != NULL)
528 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
529 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
530 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
531 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
532 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
533 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
536 // If this is true, inexistent block will be made from scratch
537 bool generate = d <= d_max_gen;
540 /*// Limit the generating area vertically to 2/3
541 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
544 // Limit the send area vertically to 2/3
545 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
551 If block is far away, don't generate it unless it is
557 // Block center y in nodes
558 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
559 // Don't generate if it's very high or very low
560 if(y < -64 || y > 64)
564 v2s16 p2d_nodes_center(
568 // Get ground height in nodes
569 s16 gh = server->m_env.getServerMap().findGroundLevel(
572 // If differs a lot, don't generate
573 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
575 // Actually, don't even send it
581 //dstream<<"d="<<d<<std::endl;
584 Don't generate or send if not in sight
587 if(isBlockInSight(p, camera_pos, camera_dir, 10000*BS) == false)
593 Don't send already sent blocks
596 if(m_blocks_sent.find(p) != NULL)
603 Check if map has this block
605 MapBlock *block = server->m_env.getMap().getBlockNoCreateNoEx(p);
607 bool surely_not_found_on_disk = false;
608 bool block_is_invalid = false;
611 // Reset usage timer, this block will be of use in the future.
612 block->resetUsageTimer();
614 // Block is dummy if data doesn't exist.
615 // It means it has been not found from disk and not generated
618 surely_not_found_on_disk = true;
621 // Block is valid if lighting is up-to-date and data exists
622 if(block->isValid() == false)
624 block_is_invalid = true;
627 /*if(block->isFullyGenerated() == false)
629 block_is_invalid = true;
634 ServerMap *map = (ServerMap*)(&server->m_env.getMap());
635 v2s16 chunkpos = map->sector_to_chunk(p2d);
636 if(map->chunkNonVolatile(chunkpos) == false)
637 block_is_invalid = true;
639 if(block->isGenerated() == false)
640 block_is_invalid = true;
643 If block is not close, don't send it unless it is near
646 Block is near ground level if night-time mesh
647 differs from day-time mesh.
651 if(block->dayNightDiffed() == false)
658 If block has been marked to not exist on disk (dummy)
659 and generating new ones is not wanted, skip block.
661 if(generate == false && surely_not_found_on_disk == true)
668 Record the lowest d from which a block has been
669 found being not sent and possibly to exist
671 if(no_blocks_found_for_sending)
674 new_nearest_unsent_d = d;
677 no_blocks_found_for_sending = false;
680 Add inexistent block to emerge queue.
682 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
684 //TODO: Get value from somewhere
685 // Allow only one block in emerge queue
686 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
687 // Allow two blocks in queue per client
688 if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
690 //dstream<<"Adding block to emerge queue"<<std::endl;
692 // Add it to the emerge queue and trigger the thread
695 if(generate == false)
696 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
698 server->m_emerge_queue.addBlock(peer_id, p, flags);
699 server->m_emergethread.trigger();
707 Add block to send queue
710 PrioritySortedBlockTransfer q((float)d, p, peer_id);
714 num_blocks_selected += 1;
715 sending_something = true;
720 //dstream<<"Stopped at "<<d<<std::endl;
722 if(no_blocks_found_for_sending)
724 if(queue_is_full == false)
725 new_nearest_unsent_d = d;
728 if(new_nearest_unsent_d != -1)
729 m_nearest_unsent_d = new_nearest_unsent_d;
731 if(sending_something == false)
733 m_nothing_to_send_counter++;
734 if((s16)m_nothing_to_send_counter >=
735 g_settings.getS16("max_block_send_distance"))
737 // Pause time in seconds
738 m_nothing_to_send_pause_timer = 1.0;
739 /*dstream<<"nothing to send to "
740 <<server->getPlayerName(peer_id)
741 <<" (d="<<d<<")"<<std::endl;*/
746 m_nothing_to_send_counter = 0;
749 /*timer_result = timer.stop(true);
750 if(timer_result != 0)
751 dstream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
754 void RemoteClient::SendObjectData(
757 core::map<v3s16, bool> &stepped_blocks
760 DSTACK(__FUNCTION_NAME);
762 // Can't send anything without knowing version
763 if(serialization_version == SER_FMT_VER_INVALID)
765 dstream<<"RemoteClient::SendObjectData(): Not sending, no version."
771 Send a TOCLIENT_OBJECTDATA packet.
775 u16 number of player positions
786 std::ostringstream os(std::ios_base::binary);
790 writeU16(buf, TOCLIENT_OBJECTDATA);
791 os.write((char*)buf, 2);
794 Get and write player data
797 // Get connected players
798 core::list<Player*> players = server->m_env.getPlayers(true);
800 // Write player count
801 u16 playercount = players.size();
802 writeU16(buf, playercount);
803 os.write((char*)buf, 2);
805 core::list<Player*>::Iterator i;
806 for(i = players.begin();
807 i != players.end(); i++)
811 v3f pf = player->getPosition();
812 v3f sf = player->getSpeed();
814 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
815 v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
816 s32 pitch_i (player->getPitch() * 100);
817 s32 yaw_i (player->getYaw() * 100);
819 writeU16(buf, player->peer_id);
820 os.write((char*)buf, 2);
821 writeV3S32(buf, position_i);
822 os.write((char*)buf, 12);
823 writeV3S32(buf, speed_i);
824 os.write((char*)buf, 12);
825 writeS32(buf, pitch_i);
826 os.write((char*)buf, 4);
827 writeS32(buf, yaw_i);
828 os.write((char*)buf, 4);
832 Get and write object data
838 For making players to be able to build to their nearby
839 environment (building is not possible on blocks that are not
842 - Add blocks to emerge queue if they are not found
844 SUGGESTION: These could be ignored from the backside of the player
847 Player *player = server->m_env.getPlayer(peer_id);
851 v3f playerpos = player->getPosition();
852 v3f playerspeed = player->getSpeed();
854 v3s16 center_nodepos = floatToInt(playerpos, BS);
855 v3s16 center = getNodeBlockPos(center_nodepos);
857 s16 d_max = g_settings.getS16("active_object_range");
859 // Number of blocks whose objects were written to bos
862 std::ostringstream bos(std::ios_base::binary);
864 for(s16 d = 0; d <= d_max; d++)
866 core::list<v3s16> list;
867 getFacePositions(list, d);
869 core::list<v3s16>::Iterator li;
870 for(li=list.begin(); li!=list.end(); li++)
872 v3s16 p = *li + center;
875 Ignore blocks that haven't been sent to the client
878 if(m_blocks_sent.find(p) == NULL)
882 // Try stepping block and add it to a send queue
887 MapBlock *block = server->m_env.getMap().getBlockNoCreate(p);
890 Step block if not in stepped_blocks and add to stepped_blocks.
892 if(stepped_blocks.find(p) == NULL)
894 block->stepObjects(dtime, true, server->m_env.getDayNightRatio());
895 stepped_blocks.insert(p, true);
896 block->setChangedFlag();
899 // Skip block if there are no objects
900 if(block->getObjectCount() == 0)
909 bos.write((char*)buf, 6);
912 //block->serializeObjects(bos, serialization_version); // DEPRECATED
919 Stop collecting objects if data is already too big
921 // Sum of player and object data sizes
922 s32 sum = (s32)os.tellp() + 2 + (s32)bos.tellp();
923 // break out if data too big
924 if(sum > MAX_OBJECTDATA_SIZE)
926 goto skip_subsequent;
930 catch(InvalidPositionException &e)
933 // Add it to the emerge queue and trigger the thread.
934 // Fetch the block only if it is on disk.
936 // Grab and increment counter
937 /*SharedPtr<JMutexAutoLock> lock
938 (m_num_blocks_in_emerge_queue.getLock());
939 m_num_blocks_in_emerge_queue.m_value++;*/
941 // Add to queue as an anonymous fetch from disk
942 u8 flags = BLOCK_EMERGE_FLAG_FROMDISK;
943 server->m_emerge_queue.addBlock(0, p, flags);
944 server->m_emergethread.trigger();
952 writeU16(buf, blockcount);
953 os.write((char*)buf, 2);
955 // Write block objects
962 //dstream<<"Server: Sending object data to "<<peer_id<<std::endl;
965 std::string s = os.str();
966 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
967 // Send as unreliable
968 server->m_con.Send(peer_id, 0, data, false);
971 void RemoteClient::GotBlock(v3s16 p)
973 if(m_blocks_sending.find(p) != NULL)
974 m_blocks_sending.remove(p);
977 /*dstream<<"RemoteClient::GotBlock(): Didn't find in"
978 " m_blocks_sending"<<std::endl;*/
979 m_excess_gotblocks++;
981 m_blocks_sent.insert(p, true);
984 void RemoteClient::SentBlock(v3s16 p)
986 if(m_blocks_sending.find(p) == NULL)
987 m_blocks_sending.insert(p, 0.0);
989 dstream<<"RemoteClient::SentBlock(): Sent block"
990 " already in m_blocks_sending"<<std::endl;
993 void RemoteClient::SetBlockNotSent(v3s16 p)
995 m_nearest_unsent_d = 0;
997 if(m_blocks_sending.find(p) != NULL)
998 m_blocks_sending.remove(p);
999 if(m_blocks_sent.find(p) != NULL)
1000 m_blocks_sent.remove(p);
1003 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
1005 m_nearest_unsent_d = 0;
1007 for(core::map<v3s16, MapBlock*>::Iterator
1008 i = blocks.getIterator();
1009 i.atEnd()==false; i++)
1011 v3s16 p = i.getNode()->getKey();
1013 if(m_blocks_sending.find(p) != NULL)
1014 m_blocks_sending.remove(p);
1015 if(m_blocks_sent.find(p) != NULL)
1016 m_blocks_sent.remove(p);
1024 PlayerInfo::PlayerInfo()
1030 void PlayerInfo::PrintLine(std::ostream *s)
1033 (*s)<<"\""<<name<<"\" ("
1034 <<(position.X/10)<<","<<(position.Y/10)
1035 <<","<<(position.Z/10)<<") ";
1037 (*s)<<" avg_rtt="<<avg_rtt;
1041 u32 PIChecksum(core::list<PlayerInfo> &l)
1043 core::list<PlayerInfo>::Iterator i;
1046 for(i=l.begin(); i!=l.end(); i++)
1048 checksum += a * (i->id+1);
1049 checksum ^= 0x435aafcd;
1060 std::string mapsavedir,
1061 std::string configpath
1063 m_env(new ServerMap(mapsavedir), this),
1064 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
1065 m_authmanager(mapsavedir+"/auth.txt"),
1066 m_banmanager(mapsavedir+"/ipban.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 dstream<<"Server: MEET_OTHER"<<std::endl;
1736 prof.add("MEET_OTHER", 1);
1737 for(core::map<v3s16, bool>::Iterator
1738 i = event->modified_blocks.getIterator();
1739 i.atEnd()==false; i++)
1741 v3s16 p = i.getNode()->getKey();
1747 prof.add("unknown", 1);
1748 dstream<<"WARNING: Server: Unknown MapEditEvent "
1749 <<((u32)event->type)<<std::endl;
1753 Set blocks not sent to far players
1755 if(far_players.size() > 0)
1757 // Convert list format to that wanted by SetBlocksNotSent
1758 core::map<v3s16, MapBlock*> modified_blocks2;
1759 for(core::map<v3s16, bool>::Iterator
1760 i = event->modified_blocks.getIterator();
1761 i.atEnd()==false; i++)
1763 v3s16 p = i.getNode()->getKey();
1764 modified_blocks2.insert(p,
1765 m_env.getMap().getBlockNoCreateNoEx(p));
1767 // Set blocks not sent
1768 for(core::list<u16>::Iterator
1769 i = far_players.begin();
1770 i != far_players.end(); i++)
1773 RemoteClient *client = getClient(peer_id);
1776 client->SetBlocksNotSent(modified_blocks2);
1782 /*// Don't send too many at a time
1784 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1790 dstream<<"Server: MapEditEvents:"<<std::endl;
1791 prof.print(dstream);
1797 Send object positions
1798 TODO: Get rid of MapBlockObjects
1801 float &counter = m_objectdata_timer;
1803 if(counter >= g_settings.getFloat("objectdata_interval"))
1805 JMutexAutoLock lock1(m_env_mutex);
1806 JMutexAutoLock lock2(m_con_mutex);
1808 ScopeProfiler sp(&g_profiler, "Server: sending mbo positions");
1810 SendObjectData(counter);
1817 Trigger emergethread (it somehow gets to a non-triggered but
1818 bysy state sometimes)
1821 float &counter = m_emergethread_trigger_timer;
1827 m_emergethread.trigger();
1831 // Save map, players and auth stuff
1833 float &counter = m_savemap_timer;
1835 if(counter >= g_settings.getFloat("server_map_save_interval"))
1839 ScopeProfiler sp(&g_profiler, "Server: saving stuff");
1842 if(m_authmanager.isModified())
1843 m_authmanager.save();
1846 if(m_banmanager.isModified())
1847 m_banmanager.save();
1850 JMutexAutoLock lock(m_env_mutex);
1852 /*// Unload unused data (delete from memory)
1853 m_env.getMap().unloadUnusedData(
1854 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1856 /*u32 deleted_count = m_env.getMap().unloadUnusedData(
1857 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1860 // Save only changed parts
1861 m_env.getMap().save(true);
1863 /*if(deleted_count > 0)
1865 dout_server<<"Server: Unloaded "<<deleted_count
1866 <<" blocks from memory"<<std::endl;
1870 m_env.serializePlayers(m_mapsavedir);
1872 // Save environment metadata
1873 m_env.saveMeta(m_mapsavedir);
1878 void Server::Receive()
1880 DSTACK(__FUNCTION_NAME);
1881 u32 data_maxsize = 10000;
1882 Buffer<u8> data(data_maxsize);
1887 JMutexAutoLock conlock(m_con_mutex);
1888 datasize = m_con.Receive(peer_id, *data, data_maxsize);
1891 // This has to be called so that the client list gets synced
1892 // with the peer list of the connection
1893 handlePeerChanges();
1895 ProcessData(*data, datasize, peer_id);
1897 catch(con::InvalidIncomingDataException &e)
1899 derr_server<<"Server::Receive(): "
1900 "InvalidIncomingDataException: what()="
1901 <<e.what()<<std::endl;
1903 catch(con::PeerNotFoundException &e)
1905 //NOTE: This is not needed anymore
1907 // The peer has been disconnected.
1908 // Find the associated player and remove it.
1910 /*JMutexAutoLock envlock(m_env_mutex);
1912 dout_server<<"ServerThread: peer_id="<<peer_id
1913 <<" has apparently closed connection. "
1914 <<"Removing player."<<std::endl;
1916 m_env.removePlayer(peer_id);*/
1920 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1922 DSTACK(__FUNCTION_NAME);
1923 // Environment is locked first.
1924 JMutexAutoLock envlock(m_env_mutex);
1925 JMutexAutoLock conlock(m_con_mutex);
1929 peer = m_con.GetPeer(peer_id);
1931 catch(con::PeerNotFoundException &e)
1933 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1934 <<peer_id<<" not found"<<std::endl;
1938 // drop player if is ip is banned
1939 if(m_banmanager.isIpBanned(peer->address.serializeString())){
1940 SendAccessDenied(m_con, peer_id,
1941 L"Your ip is banned. Banned name was "
1942 +narrow_to_wide(m_banmanager.getBanName(
1943 peer->address.serializeString())));
1944 m_con.deletePeer(peer_id, false);
1948 u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1956 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1958 if(command == TOSERVER_INIT)
1960 // [0] u16 TOSERVER_INIT
1961 // [2] u8 SER_FMT_VER_HIGHEST
1962 // [3] u8[20] player_name
1963 // [23] u8[28] password <--- can be sent without this, from old versions
1965 if(datasize < 2+1+PLAYERNAME_SIZE)
1968 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1969 <<peer->id<<std::endl;
1971 // First byte after command is maximum supported
1972 // serialization version
1973 u8 client_max = data[2];
1974 u8 our_max = SER_FMT_VER_HIGHEST;
1975 // Use the highest version supported by both
1976 u8 deployed = core::min_(client_max, our_max);
1977 // If it's lower than the lowest supported, give up.
1978 if(deployed < SER_FMT_VER_LOWEST)
1979 deployed = SER_FMT_VER_INVALID;
1981 //peer->serialization_version = deployed;
1982 getClient(peer->id)->pending_serialization_version = deployed;
1984 if(deployed == SER_FMT_VER_INVALID)
1986 derr_server<<DTIME<<"Server: Cannot negotiate "
1987 "serialization version with peer "
1988 <<peer_id<<std::endl;
1989 SendAccessDenied(m_con, peer_id,
1990 L"Your client is too old (map format)");
1995 Read and check network protocol version
1998 u16 net_proto_version = 0;
1999 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2001 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2004 getClient(peer->id)->net_proto_version = net_proto_version;
2006 if(net_proto_version == 0)
2008 SendAccessDenied(m_con, peer_id,
2009 L"Your client is too old. Please upgrade.");
2018 char playername[PLAYERNAME_SIZE];
2019 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2021 playername[i] = data[3+i];
2023 playername[PLAYERNAME_SIZE-1] = 0;
2025 if(playername[0]=='\0')
2027 derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
2028 SendAccessDenied(m_con, peer_id,
2033 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2035 derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
2036 SendAccessDenied(m_con, peer_id,
2037 L"Name contains unallowed characters");
2042 char password[PASSWORD_SIZE];
2043 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2045 // old version - assume blank password
2050 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2052 password[i] = data[23+i];
2054 password[PASSWORD_SIZE-1] = 0;
2057 std::string checkpwd;
2058 if(m_authmanager.exists(playername))
2060 checkpwd = m_authmanager.getPassword(playername);
2064 checkpwd = g_settings.get("default_password");
2067 /*dstream<<"Server: Client gave password '"<<password
2068 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2070 if(password != checkpwd && m_authmanager.exists(playername))
2072 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2073 <<": supplied invalid password for "
2074 <<playername<<std::endl;
2075 SendAccessDenied(m_con, peer_id, L"Invalid password");
2079 // Add player to auth manager
2080 if(m_authmanager.exists(playername) == false)
2082 derr_server<<DTIME<<"Server: adding player "<<playername
2083 <<" to auth manager"<<std::endl;
2084 m_authmanager.add(playername);
2085 m_authmanager.setPassword(playername, checkpwd);
2086 m_authmanager.setPrivs(playername,
2087 stringToPrivs(g_settings.get("default_privs")));
2088 m_authmanager.save();
2092 Player *player = emergePlayer(playername, password, peer_id);
2096 // DEBUG: Test serialization
2097 std::ostringstream test_os;
2098 player->serialize(test_os);
2099 dstream<<"Player serialization test: \""<<test_os.str()
2101 std::istringstream test_is(test_os.str());
2102 player->deSerialize(test_is);
2105 // If failed, cancel
2108 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2109 <<": failed to emerge player"<<std::endl;
2114 // If a client is already connected to the player, cancel
2115 if(player->peer_id != 0)
2117 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2118 <<" tried to connect to "
2119 "an already connected player (peer_id="
2120 <<player->peer_id<<")"<<std::endl;
2123 // Set client of player
2124 player->peer_id = peer_id;
2127 // Check if player doesn't exist
2129 throw con::InvalidIncomingDataException
2130 ("Server::ProcessData(): INIT: Player doesn't exist");
2132 /*// update name if it was supplied
2133 if(datasize >= 20+3)
2136 player->updateName((const char*)&data[3]);
2140 Answer with a TOCLIENT_INIT
2143 SharedBuffer<u8> reply(2+1+6+8);
2144 writeU16(&reply[0], TOCLIENT_INIT);
2145 writeU8(&reply[2], deployed);
2146 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2147 writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2150 m_con.Send(peer_id, 0, reply, true);
2154 Send complete position information
2156 SendMovePlayer(player);
2161 if(command == TOSERVER_INIT2)
2163 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2164 <<peer->id<<std::endl;
2167 getClient(peer->id)->serialization_version
2168 = getClient(peer->id)->pending_serialization_version;
2171 Send some initialization data
2174 // Send player info to all players
2177 // Send inventory to player
2178 UpdateCrafting(peer->id);
2179 SendInventory(peer->id);
2181 // Send player items to all players
2186 Player *player = m_env.getPlayer(peer_id);
2187 SendPlayerHP(player);
2192 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2193 m_env.getTimeOfDay());
2194 m_con.Send(peer->id, 0, data, true);
2197 // Send information about server to player in chat
2198 SendChatMessage(peer_id, getStatusString());
2200 // Send information about joining in chat
2202 std::wstring name = L"unknown";
2203 Player *player = m_env.getPlayer(peer_id);
2205 name = narrow_to_wide(player->getName());
2207 std::wstring message;
2210 message += L" joined game";
2211 BroadcastChatMessage(message);
2214 // Warnings about protocol version can be issued here
2215 /*if(getClient(peer->id)->net_proto_version == 0)
2217 SendChatMessage(peer_id, L"# Server: NOTE: YOUR CLIENT IS OLD AND DOES NOT WORK PROPERLY WITH THIS SERVER");
2223 if(peer_ser_ver == SER_FMT_VER_INVALID)
2225 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2226 " serialization format invalid or not initialized."
2227 " Skipping incoming command="<<command<<std::endl;
2231 Player *player = m_env.getPlayer(peer_id);
2234 derr_server<<"Server::ProcessData(): Cancelling: "
2235 "No player for peer_id="<<peer_id
2239 if(command == TOSERVER_PLAYERPOS)
2241 if(datasize < 2+12+12+4+4)
2245 v3s32 ps = readV3S32(&data[start+2]);
2246 v3s32 ss = readV3S32(&data[start+2+12]);
2247 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2248 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2249 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2250 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2251 pitch = wrapDegrees(pitch);
2252 yaw = wrapDegrees(yaw);
2253 player->setPosition(position);
2254 player->setSpeed(speed);
2255 player->setPitch(pitch);
2256 player->setYaw(yaw);
2258 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2259 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2260 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2262 else if(command == TOSERVER_GOTBLOCKS)
2275 u16 count = data[2];
2276 for(u16 i=0; i<count; i++)
2278 if((s16)datasize < 2+1+(i+1)*6)
2279 throw con::InvalidIncomingDataException
2280 ("GOTBLOCKS length is too short");
2281 v3s16 p = readV3S16(&data[2+1+i*6]);
2282 /*dstream<<"Server: GOTBLOCKS ("
2283 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2284 RemoteClient *client = getClient(peer_id);
2285 client->GotBlock(p);
2288 else if(command == TOSERVER_DELETEDBLOCKS)
2301 u16 count = data[2];
2302 for(u16 i=0; i<count; i++)
2304 if((s16)datasize < 2+1+(i+1)*6)
2305 throw con::InvalidIncomingDataException
2306 ("DELETEDBLOCKS length is too short");
2307 v3s16 p = readV3S16(&data[2+1+i*6]);
2308 /*dstream<<"Server: DELETEDBLOCKS ("
2309 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2310 RemoteClient *client = getClient(peer_id);
2311 client->SetBlockNotSent(p);
2314 else if(command == TOSERVER_CLICK_OBJECT)
2319 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2324 [2] u8 button (0=left, 1=right)
2329 u8 button = readU8(&data[2]);
2331 p.X = readS16(&data[3]);
2332 p.Y = readS16(&data[5]);
2333 p.Z = readS16(&data[7]);
2334 s16 id = readS16(&data[9]);
2335 //u16 item_i = readU16(&data[11]);
2337 MapBlock *block = NULL;
2340 block = m_env.getMap().getBlockNoCreate(p);
2342 catch(InvalidPositionException &e)
2344 derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2348 MapBlockObject *obj = block->getObject(id);
2352 derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2356 //TODO: Check that object is reasonably close
2361 InventoryList *ilist = player->inventory.getList("main");
2362 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2365 // Skip if inventory has no free space
2366 if(ilist->getUsedSlots() == ilist->getSize())
2368 dout_server<<"Player inventory has no free space"<<std::endl;
2373 Create the inventory item
2375 InventoryItem *item = NULL;
2376 // If it is an item-object, take the item from it
2377 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2379 item = ((ItemObject*)obj)->createInventoryItem();
2381 // Else create an item of the object
2384 item = new MapBlockObjectItem
2385 (obj->getInventoryString());
2388 // Add to inventory and send inventory
2389 ilist->addItem(item);
2390 UpdateCrafting(player->peer_id);
2391 SendInventory(player->peer_id);
2394 // Remove from block
2395 block->removeObject(id);
2398 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2403 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2409 [2] u8 button (0=left, 1=right)
2413 u8 button = readU8(&data[2]);
2414 u16 id = readS16(&data[3]);
2415 u16 item_i = readU16(&data[11]);
2417 ServerActiveObject *obj = m_env.getActiveObject(id);
2421 derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2426 // Skip if object has been removed
2430 //TODO: Check that object is reasonably close
2432 // Left click, pick object up (usually)
2436 Try creating inventory item
2438 InventoryItem *item = obj->createPickedUpItem();
2442 InventoryList *ilist = player->inventory.getList("main");
2445 if(g_settings.getBool("creative_mode") == false)
2447 // Skip if inventory has no free space
2448 if(ilist->getUsedSlots() == ilist->getSize())
2450 dout_server<<"Player inventory has no free space"<<std::endl;
2454 // Add to inventory and send inventory
2455 ilist->addItem(item);
2456 UpdateCrafting(player->peer_id);
2457 SendInventory(player->peer_id);
2460 // Remove object from environment
2461 obj->m_removed = true;
2467 Item cannot be picked up. Punch it instead.
2470 ToolItem *titem = NULL;
2471 std::string toolname = "";
2473 InventoryList *mlist = player->inventory.getList("main");
2476 InventoryItem *item = mlist->getItem(item_i);
2477 if(item && (std::string)item->getName() == "ToolItem")
2479 titem = (ToolItem*)item;
2480 toolname = titem->getToolName();
2484 v3f playerpos = player->getPosition();
2485 v3f objpos = obj->getBasePosition();
2486 v3f dir = (objpos - playerpos).normalize();
2488 u16 wear = obj->punch(toolname, dir);
2492 bool weared_out = titem->addWear(wear);
2494 mlist->deleteItem(item_i);
2495 SendInventory(player->peer_id);
2499 // Right click, do something with object
2502 // Track hp changes super-crappily
2503 u16 oldhp = player->hp;
2506 obj->rightClick(player);
2509 if(player->hp != oldhp)
2511 SendPlayerHP(player);
2515 else if(command == TOSERVER_GROUND_ACTION)
2523 [3] v3s16 nodepos_undersurface
2524 [9] v3s16 nodepos_abovesurface
2529 2: stop digging (all parameters ignored)
2530 3: digging completed
2532 u8 action = readU8(&data[2]);
2534 p_under.X = readS16(&data[3]);
2535 p_under.Y = readS16(&data[5]);
2536 p_under.Z = readS16(&data[7]);
2538 p_over.X = readS16(&data[9]);
2539 p_over.Y = readS16(&data[11]);
2540 p_over.Z = readS16(&data[13]);
2541 u16 item_i = readU16(&data[15]);
2543 //TODO: Check that target is reasonably close
2551 NOTE: This can be used in the future to check if
2552 somebody is cheating, by checking the timing.
2559 else if(action == 2)
2562 RemoteClient *client = getClient(peer->id);
2563 JMutexAutoLock digmutex(client->m_dig_mutex);
2564 client->m_dig_tool_item = -1;
2569 3: Digging completed
2571 else if(action == 3)
2573 // Mandatory parameter; actually used for nothing
2574 core::map<v3s16, MapBlock*> modified_blocks;
2576 content_t material = CONTENT_IGNORE;
2577 u8 mineral = MINERAL_NONE;
2579 bool cannot_remove_node = false;
2583 MapNode n = m_env.getMap().getNode(p_under);
2585 mineral = n.getMineral();
2586 // Get material at position
2587 material = n.getContent();
2588 // If not yet cancelled
2589 if(cannot_remove_node == false)
2591 // If it's not diggable, do nothing
2592 if(content_diggable(material) == false)
2594 derr_server<<"Server: Not finishing digging: "
2595 <<"Node not diggable"
2597 cannot_remove_node = true;
2600 // If not yet cancelled
2601 if(cannot_remove_node == false)
2603 // Get node metadata
2604 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2605 if(meta && meta->nodeRemovalDisabled() == true)
2607 derr_server<<"Server: Not finishing digging: "
2608 <<"Node metadata disables removal"
2610 cannot_remove_node = true;
2614 catch(InvalidPositionException &e)
2616 derr_server<<"Server: Not finishing digging: Node not found."
2617 <<" Adding block to emerge queue."
2619 m_emerge_queue.addBlock(peer_id,
2620 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2621 cannot_remove_node = true;
2624 // Make sure the player is allowed to do it
2625 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2627 dstream<<"Player "<<player->getName()<<" cannot remove node"
2628 <<" because privileges are "<<getPlayerPrivs(player)
2630 cannot_remove_node = true;
2634 If node can't be removed, set block to be re-sent to
2637 if(cannot_remove_node)
2639 derr_server<<"Server: Not finishing digging."<<std::endl;
2641 // Client probably has wrong data.
2642 // Set block not sent, so that client will get
2644 dstream<<"Client "<<peer_id<<" tried to dig "
2645 <<"node; but node cannot be removed."
2646 <<" setting MapBlock not sent."<<std::endl;
2647 RemoteClient *client = getClient(peer_id);
2648 v3s16 blockpos = getNodeBlockPos(p_under);
2649 client->SetBlockNotSent(blockpos);
2655 Send the removal to all close-by players.
2656 - If other player is close, send REMOVENODE
2657 - Otherwise set blocks not sent
2659 core::list<u16> far_players;
2660 sendRemoveNode(p_under, peer_id, &far_players, 30);
2663 Update and send inventory
2666 if(g_settings.getBool("creative_mode") == false)
2671 InventoryList *mlist = player->inventory.getList("main");
2674 InventoryItem *item = mlist->getItem(item_i);
2675 if(item && (std::string)item->getName() == "ToolItem")
2677 ToolItem *titem = (ToolItem*)item;
2678 std::string toolname = titem->getToolName();
2680 // Get digging properties for material and tool
2681 DiggingProperties prop =
2682 getDiggingProperties(material, toolname);
2684 if(prop.diggable == false)
2686 derr_server<<"Server: WARNING: Player digged"
2687 <<" with impossible material + tool"
2688 <<" combination"<<std::endl;
2691 bool weared_out = titem->addWear(prop.wear);
2695 mlist->deleteItem(item_i);
2701 Add dug item to inventory
2704 InventoryItem *item = NULL;
2706 if(mineral != MINERAL_NONE)
2707 item = getDiggedMineralItem(mineral);
2712 std::string &dug_s = content_features(material).dug_item;
2715 std::istringstream is(dug_s, std::ios::binary);
2716 item = InventoryItem::deSerialize(is);
2722 // Add a item to inventory
2723 player->inventory.addItem("main", item);
2726 UpdateCrafting(player->peer_id);
2727 SendInventory(player->peer_id);
2733 (this takes some time so it is done after the quick stuff)
2736 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2738 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2741 Set blocks not sent to far players
2743 for(core::list<u16>::Iterator
2744 i = far_players.begin();
2745 i != far_players.end(); i++)
2748 RemoteClient *client = getClient(peer_id);
2751 client->SetBlocksNotSent(modified_blocks);
2758 else if(action == 1)
2761 InventoryList *ilist = player->inventory.getList("main");
2766 InventoryItem *item = ilist->getItem(item_i);
2768 // If there is no item, it is not possible to add it anywhere
2773 Handle material items
2775 if(std::string("MaterialItem") == item->getName())
2778 // Don't add a node if this is not a free space
2779 MapNode n2 = m_env.getMap().getNode(p_over);
2780 bool no_enough_privs =
2781 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2783 dstream<<"Player "<<player->getName()<<" cannot add node"
2784 <<" because privileges are "<<getPlayerPrivs(player)
2787 if(content_features(n2).buildable_to == false
2790 // Client probably has wrong data.
2791 // Set block not sent, so that client will get
2793 dstream<<"Client "<<peer_id<<" tried to place"
2794 <<" node in invalid position; setting"
2795 <<" MapBlock not sent."<<std::endl;
2796 RemoteClient *client = getClient(peer_id);
2797 v3s16 blockpos = getNodeBlockPos(p_over);
2798 client->SetBlockNotSent(blockpos);
2802 catch(InvalidPositionException &e)
2804 derr_server<<"Server: Ignoring ADDNODE: Node not found"
2805 <<" Adding block to emerge queue."
2807 m_emerge_queue.addBlock(peer_id,
2808 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2812 // Reset build time counter
2813 getClient(peer->id)->m_time_from_building = 0.0;
2816 MaterialItem *mitem = (MaterialItem*)item;
2818 n.setContent(mitem->getMaterial());
2820 // Calculate direction for wall mounted stuff
2821 if(content_features(n).wall_mounted)
2822 n.param2 = packDir(p_under - p_over);
2824 // Calculate the direction for furnaces and chests and stuff
2825 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2827 v3f playerpos = player->getPosition();
2828 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2829 blockpos = blockpos.normalize();
2831 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2845 Send to all close-by players
2847 core::list<u16> far_players;
2848 sendAddNode(p_over, n, 0, &far_players, 30);
2853 InventoryList *ilist = player->inventory.getList("main");
2854 if(g_settings.getBool("creative_mode") == false && ilist)
2856 // Remove from inventory and send inventory
2857 if(mitem->getCount() == 1)
2858 ilist->deleteItem(item_i);
2862 UpdateCrafting(peer_id);
2863 SendInventory(peer_id);
2869 This takes some time so it is done after the quick stuff
2871 core::map<v3s16, MapBlock*> modified_blocks;
2873 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2875 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2878 Set blocks not sent to far players
2880 for(core::list<u16>::Iterator
2881 i = far_players.begin();
2882 i != far_players.end(); i++)
2885 RemoteClient *client = getClient(peer_id);
2888 client->SetBlocksNotSent(modified_blocks);
2892 Calculate special events
2895 /*if(n.d == CONTENT_MESE)
2898 for(s16 z=-1; z<=1; z++)
2899 for(s16 y=-1; y<=1; y++)
2900 for(s16 x=-1; x<=1; x++)
2907 Place other item (not a block)
2911 v3s16 blockpos = getNodeBlockPos(p_over);
2914 Check that the block is loaded so that the item
2915 can properly be added to the static list too
2917 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2920 derr_server<<"Error while placing object: "
2921 "block not found"<<std::endl;
2925 dout_server<<"Placing a miscellaneous item on map"
2928 // Calculate a position for it
2929 v3f pos = intToFloat(p_over, BS);
2931 pos.Y -= BS*0.25; // let it drop a bit
2933 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2934 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2939 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2943 derr_server<<"WARNING: item resulted in NULL object, "
2944 <<"not placing onto map"
2949 // Add the object to the environment
2950 m_env.addActiveObject(obj);
2952 dout_server<<"Placed object"<<std::endl;
2954 if(g_settings.getBool("creative_mode") == false)
2956 // Delete the right amount of items from the slot
2957 u16 dropcount = item->getDropCount();
2959 // Delete item if all gone
2960 if(item->getCount() <= dropcount)
2962 if(item->getCount() < dropcount)
2963 dstream<<"WARNING: Server: dropped more items"
2964 <<" than the slot contains"<<std::endl;
2966 InventoryList *ilist = player->inventory.getList("main");
2968 // Remove from inventory and send inventory
2969 ilist->deleteItem(item_i);
2971 // Else decrement it
2973 item->remove(dropcount);
2976 UpdateCrafting(peer_id);
2977 SendInventory(peer_id);
2985 Catch invalid actions
2989 derr_server<<"WARNING: Server: Invalid action "
2990 <<action<<std::endl;
2994 else if(command == TOSERVER_RELEASE)
3003 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
3006 else if(command == TOSERVER_SIGNTEXT)
3008 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3017 std::string datastring((char*)&data[2], datasize-2);
3018 std::istringstream is(datastring, std::ios_base::binary);
3021 is.read((char*)buf, 6);
3022 v3s16 blockpos = readV3S16(buf);
3023 is.read((char*)buf, 2);
3024 s16 id = readS16(buf);
3025 is.read((char*)buf, 2);
3026 u16 textlen = readU16(buf);
3028 for(u16 i=0; i<textlen; i++)
3030 is.read((char*)buf, 1);
3031 text += (char)buf[0];
3034 MapBlock *block = NULL;
3037 block = m_env.getMap().getBlockNoCreate(blockpos);
3039 catch(InvalidPositionException &e)
3041 derr_server<<"Error while setting sign text: "
3042 "block not found"<<std::endl;
3046 MapBlockObject *obj = block->getObject(id);
3049 derr_server<<"Error while setting sign text: "
3050 "object not found"<<std::endl;
3054 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
3056 derr_server<<"Error while setting sign text: "
3057 "object is not a sign"<<std::endl;
3061 ((SignObject*)obj)->setText(text);
3063 obj->getBlock()->setChangedFlag();
3065 else if(command == TOSERVER_SIGNNODETEXT)
3067 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3075 std::string datastring((char*)&data[2], datasize-2);
3076 std::istringstream is(datastring, std::ios_base::binary);
3079 is.read((char*)buf, 6);
3080 v3s16 p = readV3S16(buf);
3081 is.read((char*)buf, 2);
3082 u16 textlen = readU16(buf);
3084 for(u16 i=0; i<textlen; i++)
3086 is.read((char*)buf, 1);
3087 text += (char)buf[0];
3090 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3093 if(meta->typeId() != CONTENT_SIGN_WALL)
3095 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3096 signmeta->setText(text);
3098 v3s16 blockpos = getNodeBlockPos(p);
3099 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
3102 block->setChangedFlag();
3105 for(core::map<u16, RemoteClient*>::Iterator
3106 i = m_clients.getIterator();
3107 i.atEnd()==false; i++)
3109 RemoteClient *client = i.getNode()->getValue();
3110 client->SetBlockNotSent(blockpos);
3113 else if(command == TOSERVER_INVENTORY_ACTION)
3115 /*// Ignore inventory changes if in creative mode
3116 if(g_settings.getBool("creative_mode") == true)
3118 dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3122 // Strip command and create a stream
3123 std::string datastring((char*)&data[2], datasize-2);
3124 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3125 std::istringstream is(datastring, std::ios_base::binary);
3127 InventoryAction *a = InventoryAction::deSerialize(is);
3132 c.current_player = player;
3135 Handle craftresult specially if not in creative mode
3137 bool disable_action = false;
3138 if(a->getType() == IACTION_MOVE
3139 && g_settings.getBool("creative_mode") == false)
3141 IMoveAction *ma = (IMoveAction*)a;
3142 if(ma->to_inv == "current_player" &&
3143 ma->from_inv == "current_player")
3145 InventoryList *rlist = player->inventory.getList("craftresult");
3147 InventoryList *clist = player->inventory.getList("craft");
3149 InventoryList *mlist = player->inventory.getList("main");
3152 Craftresult is no longer preview if something
3155 if(ma->to_list == "craftresult"
3156 && ma->from_list != "craftresult")
3158 // If it currently is a preview, remove
3160 if(player->craftresult_is_preview)
3162 rlist->deleteItem(0);
3164 player->craftresult_is_preview = false;
3167 Crafting takes place if this condition is true.
3169 if(player->craftresult_is_preview &&
3170 ma->from_list == "craftresult")
3172 player->craftresult_is_preview = false;
3173 clist->decrementMaterials(1);
3176 If the craftresult is placed on itself, move it to
3177 main inventory instead of doing the action
3179 if(ma->to_list == "craftresult"
3180 && ma->from_list == "craftresult")
3182 disable_action = true;
3184 InventoryItem *item1 = rlist->changeItem(0, NULL);
3185 mlist->addItem(item1);
3190 if(disable_action == false)
3192 // Feed action to player inventory
3200 UpdateCrafting(player->peer_id);
3201 SendInventory(player->peer_id);
3206 dstream<<"TOSERVER_INVENTORY_ACTION: "
3207 <<"InventoryAction::deSerialize() returned NULL"
3211 else if(command == TOSERVER_CHAT_MESSAGE)
3219 std::string datastring((char*)&data[2], datasize-2);
3220 std::istringstream is(datastring, std::ios_base::binary);
3223 is.read((char*)buf, 2);
3224 u16 len = readU16(buf);
3226 std::wstring message;
3227 for(u16 i=0; i<len; i++)
3229 is.read((char*)buf, 2);
3230 message += (wchar_t)readU16(buf);
3233 // Get player name of this client
3234 std::wstring name = narrow_to_wide(player->getName());
3236 // Line to send to players
3238 // Whether to send to the player that sent the line
3239 bool send_to_sender = false;
3240 // Whether to send to other players
3241 bool send_to_others = false;
3243 // Local player gets all privileges regardless of
3244 // what's set on their account.
3245 u64 privs = getPlayerPrivs(player);
3248 if(message[0] == L'/')
3250 size_t strip_size = 1;
3251 if (message[1] == L'#') // support old-style commans
3253 message = message.substr(strip_size);
3255 WStrfnd f1(message);
3256 f1.next(L" "); // Skip over /#whatever
3257 std::wstring paramstring = f1.next(L"");
3259 ServerCommandContext *ctx = new ServerCommandContext(
3260 str_split(message, L' '),
3267 std::wstring reply(processServerCommand(ctx));
3268 send_to_sender = ctx->flags & SEND_TO_SENDER;
3269 send_to_others = ctx->flags & SEND_TO_OTHERS;
3271 if (ctx->flags & SEND_NO_PREFIX)
3274 line += L"Server: " + reply;
3281 if(privs & PRIV_SHOUT)
3287 send_to_others = true;
3291 line += L"Server: You are not allowed to shout";
3292 send_to_sender = true;
3298 dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3301 Send the message to clients
3303 for(core::map<u16, RemoteClient*>::Iterator
3304 i = m_clients.getIterator();
3305 i.atEnd() == false; i++)
3307 // Get client and check that it is valid
3308 RemoteClient *client = i.getNode()->getValue();
3309 assert(client->peer_id == i.getNode()->getKey());
3310 if(client->serialization_version == SER_FMT_VER_INVALID)
3314 bool sender_selected = (peer_id == client->peer_id);
3315 if(sender_selected == true && send_to_sender == false)
3317 if(sender_selected == false && send_to_others == false)
3320 SendChatMessage(client->peer_id, line);
3324 else if(command == TOSERVER_DAMAGE)
3326 if(g_settings.getBool("enable_damage"))
3328 std::string datastring((char*)&data[2], datasize-2);
3329 std::istringstream is(datastring, std::ios_base::binary);
3330 u8 damage = readU8(is);
3331 if(player->hp > damage)
3333 player->hp -= damage;
3339 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3342 v3f pos = findSpawnPos(m_env.getServerMap());
3343 player->setPosition(pos);
3345 SendMovePlayer(player);
3346 SendPlayerHP(player);
3348 //TODO: Throw items around
3352 SendPlayerHP(player);
3354 else if(command == TOSERVER_PASSWORD)
3357 [0] u16 TOSERVER_PASSWORD
3358 [2] u8[28] old password
3359 [30] u8[28] new password
3362 if(datasize != 2+PASSWORD_SIZE*2)
3364 /*char password[PASSWORD_SIZE];
3365 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3366 password[i] = data[2+i];
3367 password[PASSWORD_SIZE-1] = 0;*/
3369 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3377 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3379 char c = data[2+PASSWORD_SIZE+i];
3385 dstream<<"Server: Client requests a password change from "
3386 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3388 std::string playername = player->getName();
3390 if(m_authmanager.exists(playername) == false)
3392 dstream<<"Server: playername not found in authmanager"<<std::endl;
3393 // Wrong old password supplied!!
3394 SendChatMessage(peer_id, L"playername not found in authmanager");
3398 std::string checkpwd = m_authmanager.getPassword(playername);
3400 if(oldpwd != checkpwd)
3402 dstream<<"Server: invalid old password"<<std::endl;
3403 // Wrong old password supplied!!
3404 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3408 m_authmanager.setPassword(playername, newpwd);
3410 dstream<<"Server: password change successful for "<<playername
3412 SendChatMessage(peer_id, L"Password change successful");
3414 else if (command == TOSERVER_PLAYERITEM)
3419 u16 item = readU16(&data[2]);
3420 player->wieldItem(item);
3421 SendWieldedItem(player);
3425 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3426 "unknown command "<<command<<std::endl;
3430 catch(SendFailedException &e)
3432 derr_server<<"Server::ProcessData(): SendFailedException: "
3438 void Server::onMapEditEvent(MapEditEvent *event)
3440 //dstream<<"Server::onMapEditEvent()"<<std::endl;
3441 if(m_ignore_map_edit_events)
3443 MapEditEvent *e = event->clone();
3444 m_unsent_map_edit_queue.push_back(e);
3447 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3449 if(id == "current_player")
3451 assert(c->current_player);
3452 return &(c->current_player->inventory);
3456 std::string id0 = fn.next(":");
3458 if(id0 == "nodemeta")
3461 p.X = stoi(fn.next(","));
3462 p.Y = stoi(fn.next(","));
3463 p.Z = stoi(fn.next(","));
3464 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3466 return meta->getInventory();
3467 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3468 <<"no metadata found"<<std::endl;
3472 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3475 void Server::inventoryModified(InventoryContext *c, std::string id)
3477 if(id == "current_player")
3479 assert(c->current_player);
3481 UpdateCrafting(c->current_player->peer_id);
3482 SendInventory(c->current_player->peer_id);
3487 std::string id0 = fn.next(":");
3489 if(id0 == "nodemeta")
3492 p.X = stoi(fn.next(","));
3493 p.Y = stoi(fn.next(","));
3494 p.Z = stoi(fn.next(","));
3495 v3s16 blockpos = getNodeBlockPos(p);
3497 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3499 meta->inventoryModified();
3501 for(core::map<u16, RemoteClient*>::Iterator
3502 i = m_clients.getIterator();
3503 i.atEnd()==false; i++)
3505 RemoteClient *client = i.getNode()->getValue();
3506 client->SetBlockNotSent(blockpos);
3512 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3515 core::list<PlayerInfo> Server::getPlayerInfo()
3517 DSTACK(__FUNCTION_NAME);
3518 JMutexAutoLock envlock(m_env_mutex);
3519 JMutexAutoLock conlock(m_con_mutex);
3521 core::list<PlayerInfo> list;
3523 core::list<Player*> players = m_env.getPlayers();
3525 core::list<Player*>::Iterator i;
3526 for(i = players.begin();
3527 i != players.end(); i++)
3531 Player *player = *i;
3534 con::Peer *peer = m_con.GetPeer(player->peer_id);
3535 // Copy info from peer to info struct
3537 info.address = peer->address;
3538 info.avg_rtt = peer->avg_rtt;
3540 catch(con::PeerNotFoundException &e)
3542 // Set dummy peer info
3544 info.address = Address(0,0,0,0,0);
3548 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3549 info.position = player->getPosition();
3551 list.push_back(info);
3558 void Server::peerAdded(con::Peer *peer)
3560 DSTACK(__FUNCTION_NAME);
3561 dout_server<<"Server::peerAdded(): peer->id="
3562 <<peer->id<<std::endl;
3565 c.type = PEER_ADDED;
3566 c.peer_id = peer->id;
3568 m_peer_change_queue.push_back(c);
3571 void Server::deletingPeer(con::Peer *peer, bool timeout)
3573 DSTACK(__FUNCTION_NAME);
3574 dout_server<<"Server::deletingPeer(): peer->id="
3575 <<peer->id<<", timeout="<<timeout<<std::endl;
3578 c.type = PEER_REMOVED;
3579 c.peer_id = peer->id;
3580 c.timeout = timeout;
3581 m_peer_change_queue.push_back(c);
3588 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3590 DSTACK(__FUNCTION_NAME);
3591 std::ostringstream os(std::ios_base::binary);
3593 writeU16(os, TOCLIENT_HP);
3597 std::string s = os.str();
3598 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3600 con.Send(peer_id, 0, data, true);
3603 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3604 const std::wstring &reason)
3606 DSTACK(__FUNCTION_NAME);
3607 std::ostringstream os(std::ios_base::binary);
3609 writeU16(os, TOCLIENT_ACCESS_DENIED);
3610 os<<serializeWideString(reason);
3613 std::string s = os.str();
3614 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3616 con.Send(peer_id, 0, data, true);
3620 Non-static send methods
3623 void Server::SendObjectData(float dtime)
3625 DSTACK(__FUNCTION_NAME);
3627 core::map<v3s16, bool> stepped_blocks;
3629 for(core::map<u16, RemoteClient*>::Iterator
3630 i = m_clients.getIterator();
3631 i.atEnd() == false; i++)
3633 u16 peer_id = i.getNode()->getKey();
3634 RemoteClient *client = i.getNode()->getValue();
3635 assert(client->peer_id == peer_id);
3637 if(client->serialization_version == SER_FMT_VER_INVALID)
3640 client->SendObjectData(this, dtime, stepped_blocks);
3644 void Server::SendPlayerInfos()
3646 DSTACK(__FUNCTION_NAME);
3648 //JMutexAutoLock envlock(m_env_mutex);
3650 // Get connected players
3651 core::list<Player*> players = m_env.getPlayers(true);
3653 u32 player_count = players.getSize();
3654 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3656 SharedBuffer<u8> data(datasize);
3657 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3660 core::list<Player*>::Iterator i;
3661 for(i = players.begin();
3662 i != players.end(); i++)
3664 Player *player = *i;
3666 /*dstream<<"Server sending player info for player with "
3667 "peer_id="<<player->peer_id<<std::endl;*/
3669 writeU16(&data[start], player->peer_id);
3670 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3671 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3672 start += 2+PLAYERNAME_SIZE;
3675 //JMutexAutoLock conlock(m_con_mutex);
3678 m_con.SendToAll(0, data, true);
3681 void Server::SendInventory(u16 peer_id)
3683 DSTACK(__FUNCTION_NAME);
3685 Player* player = m_env.getPlayer(peer_id);
3692 std::ostringstream os;
3693 //os.imbue(std::locale("C"));
3695 player->inventory.serialize(os);
3697 std::string s = os.str();
3699 SharedBuffer<u8> data(s.size()+2);
3700 writeU16(&data[0], TOCLIENT_INVENTORY);
3701 memcpy(&data[2], s.c_str(), s.size());
3704 m_con.Send(peer_id, 0, data, true);
3707 std::string getWieldedItemString(const Player *player)
3709 const InventoryItem *item = player->getWieldItem();
3711 return std::string("");
3712 std::ostringstream os(std::ios_base::binary);
3713 item->serialize(os);
3717 void Server::SendWieldedItem(const Player* player)
3719 DSTACK(__FUNCTION_NAME);
3723 std::ostringstream os(std::ios_base::binary);
3725 writeU16(os, TOCLIENT_PLAYERITEM);
3727 writeU16(os, player->peer_id);
3728 os<<serializeString(getWieldedItemString(player));
3731 std::string s = os.str();
3732 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3734 m_con.SendToAll(0, data, true);
3737 void Server::SendPlayerItems()
3739 DSTACK(__FUNCTION_NAME);
3741 std::ostringstream os(std::ios_base::binary);
3742 core::list<Player *> players = m_env.getPlayers(true);
3744 writeU16(os, TOCLIENT_PLAYERITEM);
3745 writeU16(os, players.size());
3746 core::list<Player *>::Iterator i;
3747 for(i = players.begin(); i != players.end(); ++i)
3750 writeU16(os, p->peer_id);
3751 os<<serializeString(getWieldedItemString(p));
3755 std::string s = os.str();
3756 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3758 m_con.SendToAll(0, data, true);
3761 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3763 DSTACK(__FUNCTION_NAME);
3765 std::ostringstream os(std::ios_base::binary);
3769 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3770 os.write((char*)buf, 2);
3773 writeU16(buf, message.size());
3774 os.write((char*)buf, 2);
3777 for(u32 i=0; i<message.size(); i++)
3781 os.write((char*)buf, 2);
3785 std::string s = os.str();
3786 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3788 m_con.Send(peer_id, 0, data, true);
3791 void Server::BroadcastChatMessage(const std::wstring &message)
3793 for(core::map<u16, RemoteClient*>::Iterator
3794 i = m_clients.getIterator();
3795 i.atEnd() == false; i++)
3797 // Get client and check that it is valid
3798 RemoteClient *client = i.getNode()->getValue();
3799 assert(client->peer_id == i.getNode()->getKey());
3800 if(client->serialization_version == SER_FMT_VER_INVALID)
3803 SendChatMessage(client->peer_id, message);
3807 void Server::SendPlayerHP(Player *player)
3809 SendHP(m_con, player->peer_id, player->hp);
3812 void Server::SendMovePlayer(Player *player)
3814 DSTACK(__FUNCTION_NAME);
3815 std::ostringstream os(std::ios_base::binary);
3817 writeU16(os, TOCLIENT_MOVE_PLAYER);
3818 writeV3F1000(os, player->getPosition());
3819 writeF1000(os, player->getPitch());
3820 writeF1000(os, player->getYaw());
3823 v3f pos = player->getPosition();
3824 f32 pitch = player->getPitch();
3825 f32 yaw = player->getYaw();
3826 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3827 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3834 std::string s = os.str();
3835 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3837 m_con.Send(player->peer_id, 0, data, true);
3840 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3841 core::list<u16> *far_players, float far_d_nodes)
3843 float maxd = far_d_nodes*BS;
3844 v3f p_f = intToFloat(p, BS);
3848 SharedBuffer<u8> reply(replysize);
3849 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3850 writeS16(&reply[2], p.X);
3851 writeS16(&reply[4], p.Y);
3852 writeS16(&reply[6], p.Z);
3854 for(core::map<u16, RemoteClient*>::Iterator
3855 i = m_clients.getIterator();
3856 i.atEnd() == false; i++)
3858 // Get client and check that it is valid
3859 RemoteClient *client = i.getNode()->getValue();
3860 assert(client->peer_id == i.getNode()->getKey());
3861 if(client->serialization_version == SER_FMT_VER_INVALID)
3864 // Don't send if it's the same one
3865 if(client->peer_id == ignore_id)
3871 Player *player = m_env.getPlayer(client->peer_id);
3874 // If player is far away, only set modified blocks not sent
3875 v3f player_pos = player->getPosition();
3876 if(player_pos.getDistanceFrom(p_f) > maxd)
3878 far_players->push_back(client->peer_id);
3885 m_con.Send(client->peer_id, 0, reply, true);
3889 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3890 core::list<u16> *far_players, float far_d_nodes)
3892 float maxd = far_d_nodes*BS;
3893 v3f p_f = intToFloat(p, BS);
3895 for(core::map<u16, RemoteClient*>::Iterator
3896 i = m_clients.getIterator();
3897 i.atEnd() == false; i++)
3899 // Get client and check that it is valid
3900 RemoteClient *client = i.getNode()->getValue();
3901 assert(client->peer_id == i.getNode()->getKey());
3902 if(client->serialization_version == SER_FMT_VER_INVALID)
3905 // Don't send if it's the same one
3906 if(client->peer_id == ignore_id)
3912 Player *player = m_env.getPlayer(client->peer_id);
3915 // If player is far away, only set modified blocks not sent
3916 v3f player_pos = player->getPosition();
3917 if(player_pos.getDistanceFrom(p_f) > maxd)
3919 far_players->push_back(client->peer_id);
3926 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3927 SharedBuffer<u8> reply(replysize);
3928 writeU16(&reply[0], TOCLIENT_ADDNODE);
3929 writeS16(&reply[2], p.X);
3930 writeS16(&reply[4], p.Y);
3931 writeS16(&reply[6], p.Z);
3932 n.serialize(&reply[8], client->serialization_version);
3935 m_con.Send(client->peer_id, 0, reply, true);
3939 void Server::setBlockNotSent(v3s16 p)
3941 for(core::map<u16, RemoteClient*>::Iterator
3942 i = m_clients.getIterator();
3943 i.atEnd()==false; i++)
3945 RemoteClient *client = i.getNode()->getValue();
3946 client->SetBlockNotSent(p);
3950 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3952 DSTACK(__FUNCTION_NAME);
3954 v3s16 p = block->getPos();
3958 bool completely_air = true;
3959 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3960 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3961 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3963 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3965 completely_air = false;
3966 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3971 dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3973 dstream<<"[completely air] ";
3978 Create a packet with the block in the right format
3981 std::ostringstream os(std::ios_base::binary);
3982 block->serialize(os, ver);
3983 std::string s = os.str();
3984 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3986 u32 replysize = 8 + blockdata.getSize();
3987 SharedBuffer<u8> reply(replysize);
3988 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3989 writeS16(&reply[2], p.X);
3990 writeS16(&reply[4], p.Y);
3991 writeS16(&reply[6], p.Z);
3992 memcpy(&reply[8], *blockdata, blockdata.getSize());
3994 /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3995 <<": \tpacket size: "<<replysize<<std::endl;*/
4000 m_con.Send(peer_id, 1, reply, true);
4003 void Server::SendBlocks(float dtime)
4005 DSTACK(__FUNCTION_NAME);
4007 JMutexAutoLock envlock(m_env_mutex);
4008 JMutexAutoLock conlock(m_con_mutex);
4010 //TimeTaker timer("Server::SendBlocks");
4012 core::array<PrioritySortedBlockTransfer> queue;
4014 s32 total_sending = 0;
4017 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
4019 for(core::map<u16, RemoteClient*>::Iterator
4020 i = m_clients.getIterator();
4021 i.atEnd() == false; i++)
4023 RemoteClient *client = i.getNode()->getValue();
4024 assert(client->peer_id == i.getNode()->getKey());
4026 total_sending += client->SendingCount();
4028 if(client->serialization_version == SER_FMT_VER_INVALID)
4031 client->GetNextBlocks(this, dtime, queue);
4036 // Lowest priority number comes first.
4037 // Lowest is most important.
4040 for(u32 i=0; i<queue.size(); i++)
4042 //TODO: Calculate limit dynamically
4043 if(total_sending >= g_settings.getS32
4044 ("max_simultaneous_block_sends_server_total"))
4047 PrioritySortedBlockTransfer q = queue[i];
4049 MapBlock *block = NULL;
4052 block = m_env.getMap().getBlockNoCreate(q.pos);
4054 catch(InvalidPositionException &e)
4059 RemoteClient *client = getClient(q.peer_id);
4061 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4063 client->SentBlock(q.pos);
4073 void Server::UpdateCrafting(u16 peer_id)
4075 DSTACK(__FUNCTION_NAME);
4077 Player* player = m_env.getPlayer(peer_id);
4081 Calculate crafting stuff
4083 if(g_settings.getBool("creative_mode") == false)
4085 InventoryList *clist = player->inventory.getList("craft");
4086 InventoryList *rlist = player->inventory.getList("craftresult");
4088 if(rlist->getUsedSlots() == 0)
4089 player->craftresult_is_preview = true;
4091 if(rlist && player->craftresult_is_preview)
4093 rlist->clearItems();
4095 if(clist && rlist && player->craftresult_is_preview)
4097 InventoryItem *items[9];
4098 for(u16 i=0; i<9; i++)
4100 items[i] = clist->getItem(i);
4103 // Get result of crafting grid
4104 InventoryItem *result = craft_get_result(items);
4106 rlist->addItem(result);
4109 } // if creative_mode == false
4112 RemoteClient* Server::getClient(u16 peer_id)
4114 DSTACK(__FUNCTION_NAME);
4115 //JMutexAutoLock lock(m_con_mutex);
4116 core::map<u16, RemoteClient*>::Node *n;
4117 n = m_clients.find(peer_id);
4118 // A client should exist for all peers
4120 return n->getValue();
4123 std::wstring Server::getStatusString()
4125 std::wostringstream os(std::ios_base::binary);
4128 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4130 os<<L", uptime="<<m_uptime.get();
4131 // Information about clients
4133 for(core::map<u16, RemoteClient*>::Iterator
4134 i = m_clients.getIterator();
4135 i.atEnd() == false; i++)
4137 // Get client and check that it is valid
4138 RemoteClient *client = i.getNode()->getValue();
4139 assert(client->peer_id == i.getNode()->getKey());
4140 if(client->serialization_version == SER_FMT_VER_INVALID)
4143 Player *player = m_env.getPlayer(client->peer_id);
4144 // Get name of player
4145 std::wstring name = L"unknown";
4147 name = narrow_to_wide(player->getName());
4148 // Add name to information string
4152 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
4153 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4154 if(g_settings.get("motd") != "")
4155 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings.get("motd"));
4159 v3f findSpawnPos(ServerMap &map)
4161 //return v3f(50,50,50)*BS;
4164 s16 groundheight = 0;
4167 nodepos = v2s16(0,0);
4172 // Try to find a good place a few times
4173 for(s32 i=0; i<1000; i++)
4176 // We're going to try to throw the player to this position
4177 nodepos = v2s16(-range + (myrand()%(range*2)),
4178 -range + (myrand()%(range*2)));
4179 v2s16 sectorpos = getNodeSectorPos(nodepos);
4180 // Get sector (NOTE: Don't get because it's slow)
4181 //m_env.getMap().emergeSector(sectorpos);
4182 // Get ground height at point (fallbacks to heightmap function)
4183 groundheight = map.findGroundLevel(nodepos);
4184 // Don't go underwater
4185 if(groundheight < WATER_LEVEL)
4187 //dstream<<"-> Underwater"<<std::endl;
4190 // Don't go to high places
4191 if(groundheight > WATER_LEVEL + 4)
4193 //dstream<<"-> Underwater"<<std::endl;
4197 // Found a good place
4198 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4203 // If no suitable place was not found, go above water at least.
4204 if(groundheight < WATER_LEVEL)
4205 groundheight = WATER_LEVEL;
4207 return intToFloat(v3s16(
4214 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4217 Try to get an existing player
4219 Player *player = m_env.getPlayer(name);
4222 // If player is already connected, cancel
4223 if(player->peer_id != 0)
4225 dstream<<"emergePlayer(): Player already connected"<<std::endl;
4230 player->peer_id = peer_id;
4232 // Reset inventory to creative if in creative mode
4233 if(g_settings.getBool("creative_mode"))
4235 // Warning: double code below
4236 // Backup actual inventory
4237 player->inventory_backup = new Inventory();
4238 *(player->inventory_backup) = player->inventory;
4239 // Set creative inventory
4240 craft_set_creative_inventory(player);
4247 If player with the wanted peer_id already exists, cancel.
4249 if(m_env.getPlayer(peer_id) != NULL)
4251 dstream<<"emergePlayer(): Player with wrong name but same"
4252 " peer_id already exists"<<std::endl;
4260 player = new ServerRemotePlayer();
4261 //player->peer_id = c.peer_id;
4262 //player->peer_id = PEER_ID_INEXISTENT;
4263 player->peer_id = peer_id;
4264 player->updateName(name);
4265 m_authmanager.add(name);
4266 m_authmanager.setPassword(name, password);
4267 m_authmanager.setPrivs(name,
4268 stringToPrivs(g_settings.get("default_privs")));
4274 dstream<<"Server: Finding spawn place for player \""
4275 <<player->getName()<<"\""<<std::endl;
4277 v3f pos = findSpawnPos(m_env.getServerMap());
4279 player->setPosition(pos);
4282 Add player to environment
4285 m_env.addPlayer(player);
4288 Add stuff to inventory
4291 if(g_settings.getBool("creative_mode"))
4293 // Warning: double code above
4294 // Backup actual inventory
4295 player->inventory_backup = new Inventory();
4296 *(player->inventory_backup) = player->inventory;
4297 // Set creative inventory
4298 craft_set_creative_inventory(player);
4300 else if(g_settings.getBool("give_initial_stuff"))
4302 craft_give_initial_stuff(player);
4307 } // create new player
4310 void Server::handlePeerChange(PeerChange &c)
4312 JMutexAutoLock envlock(m_env_mutex);
4313 JMutexAutoLock conlock(m_con_mutex);
4315 if(c.type == PEER_ADDED)
4322 core::map<u16, RemoteClient*>::Node *n;
4323 n = m_clients.find(c.peer_id);
4324 // The client shouldn't already exist
4328 RemoteClient *client = new RemoteClient();
4329 client->peer_id = c.peer_id;
4330 m_clients.insert(client->peer_id, client);
4333 else if(c.type == PEER_REMOVED)
4340 core::map<u16, RemoteClient*>::Node *n;
4341 n = m_clients.find(c.peer_id);
4342 // The client should exist
4346 Mark objects to be not known by the client
4348 RemoteClient *client = n->getValue();
4350 for(core::map<u16, bool>::Iterator
4351 i = client->m_known_objects.getIterator();
4352 i.atEnd()==false; i++)
4355 u16 id = i.getNode()->getKey();
4356 ServerActiveObject* obj = m_env.getActiveObject(id);
4358 if(obj && obj->m_known_by_count > 0)
4359 obj->m_known_by_count--;
4362 // Collect information about leaving in chat
4363 std::wstring message;
4365 std::wstring name = L"unknown";
4366 Player *player = m_env.getPlayer(c.peer_id);
4368 name = narrow_to_wide(player->getName());
4372 message += L" left game";
4374 message += L" (timed out)";
4379 m_env.removePlayer(c.peer_id);
4382 // Set player client disconnected
4384 Player *player = m_env.getPlayer(c.peer_id);
4386 player->peer_id = 0;
4390 delete m_clients[c.peer_id];
4391 m_clients.remove(c.peer_id);
4393 // Send player info to all remaining clients
4396 // Send leave chat message to all remaining clients
4397 BroadcastChatMessage(message);
4406 void Server::handlePeerChanges()
4408 while(m_peer_change_queue.size() > 0)
4410 PeerChange c = m_peer_change_queue.pop_front();
4412 dout_server<<"Server: Handling peer change: "
4413 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4416 handlePeerChange(c);
4420 u64 Server::getPlayerPrivs(Player *player)
4424 std::string playername = player->getName();
4425 // Local player gets all privileges regardless of
4426 // what's set on their account.
4427 if(g_settings.get("name") == playername)
4433 return getPlayerAuthPrivs(playername);
4437 void dedicated_server_loop(Server &server, bool &kill)
4439 DSTACK(__FUNCTION_NAME);
4441 dstream<<DTIME<<std::endl;
4442 dstream<<"========================"<<std::endl;
4443 dstream<<"Running dedicated server"<<std::endl;
4444 dstream<<"========================"<<std::endl;
4447 IntervalLimiter m_profiler_interval;
4451 // This is kind of a hack but can be done like this
4452 // because server.step() is very light
4454 ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4459 if(server.getShutdownRequested() || kill)
4461 dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4468 float profiler_print_interval =
4469 g_settings.getFloat("profiler_print_interval");
4470 if(profiler_print_interval != 0)
4472 if(m_profiler_interval.step(0.030, profiler_print_interval))
4474 dstream<<"Profiler:"<<std::endl;
4475 g_profiler.print(dstream);
4483 static int counter = 0;
4489 core::list<PlayerInfo> list = server.getPlayerInfo();
4490 core::list<PlayerInfo>::Iterator i;
4491 static u32 sum_old = 0;
4492 u32 sum = PIChecksum(list);
4495 dstream<<DTIME<<"Player info:"<<std::endl;
4496 for(i=list.begin(); i!=list.end(); i++)
4498 i->PrintLine(&dstream);