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 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 if(m_banmanager.isModified())
1841 m_banmanager.save();
1844 JMutexAutoLock lock(m_env_mutex);
1846 /*// Unload unused data (delete from memory)
1847 m_env.getMap().unloadUnusedData(
1848 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1850 /*u32 deleted_count = m_env.getMap().unloadUnusedData(
1851 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1854 // Save only changed parts
1855 m_env.getMap().save(true);
1857 /*if(deleted_count > 0)
1859 dout_server<<"Server: Unloaded "<<deleted_count
1860 <<" blocks from memory"<<std::endl;
1864 m_env.serializePlayers(m_mapsavedir);
1866 // Save environment metadata
1867 m_env.saveMeta(m_mapsavedir);
1872 void Server::Receive()
1874 DSTACK(__FUNCTION_NAME);
1875 u32 data_maxsize = 10000;
1876 Buffer<u8> data(data_maxsize);
1881 JMutexAutoLock conlock(m_con_mutex);
1882 datasize = m_con.Receive(peer_id, *data, data_maxsize);
1885 // This has to be called so that the client list gets synced
1886 // with the peer list of the connection
1887 handlePeerChanges();
1889 ProcessData(*data, datasize, peer_id);
1891 catch(con::InvalidIncomingDataException &e)
1893 derr_server<<"Server::Receive(): "
1894 "InvalidIncomingDataException: what()="
1895 <<e.what()<<std::endl;
1897 catch(con::PeerNotFoundException &e)
1899 //NOTE: This is not needed anymore
1901 // The peer has been disconnected.
1902 // Find the associated player and remove it.
1904 /*JMutexAutoLock envlock(m_env_mutex);
1906 dout_server<<"ServerThread: peer_id="<<peer_id
1907 <<" has apparently closed connection. "
1908 <<"Removing player."<<std::endl;
1910 m_env.removePlayer(peer_id);*/
1914 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1916 DSTACK(__FUNCTION_NAME);
1917 // Environment is locked first.
1918 JMutexAutoLock envlock(m_env_mutex);
1919 JMutexAutoLock conlock(m_con_mutex);
1923 peer = m_con.GetPeer(peer_id);
1925 catch(con::PeerNotFoundException &e)
1927 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1928 <<peer_id<<" not found"<<std::endl;
1932 // drop player if is ip is banned
1933 if(m_banmanager.isIpBanned(peer->address.serializeString())){
1934 SendAccessDenied(m_con, peer_id,
1935 L"Your ip is banned. Banned name was "
1936 +narrow_to_wide(m_banmanager.getBanName(
1937 peer->address.serializeString())));
1938 m_con.deletePeer(peer_id, false);
1942 u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1950 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1952 if(command == TOSERVER_INIT)
1954 // [0] u16 TOSERVER_INIT
1955 // [2] u8 SER_FMT_VER_HIGHEST
1956 // [3] u8[20] player_name
1957 // [23] u8[28] password <--- can be sent without this, from old versions
1959 if(datasize < 2+1+PLAYERNAME_SIZE)
1962 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1963 <<peer->id<<std::endl;
1965 // First byte after command is maximum supported
1966 // serialization version
1967 u8 client_max = data[2];
1968 u8 our_max = SER_FMT_VER_HIGHEST;
1969 // Use the highest version supported by both
1970 u8 deployed = core::min_(client_max, our_max);
1971 // If it's lower than the lowest supported, give up.
1972 if(deployed < SER_FMT_VER_LOWEST)
1973 deployed = SER_FMT_VER_INVALID;
1975 //peer->serialization_version = deployed;
1976 getClient(peer->id)->pending_serialization_version = deployed;
1978 if(deployed == SER_FMT_VER_INVALID)
1980 derr_server<<DTIME<<"Server: Cannot negotiate "
1981 "serialization version with peer "
1982 <<peer_id<<std::endl;
1983 SendAccessDenied(m_con, peer_id,
1984 L"Your client is too old (map format)");
1989 Read and check network protocol version
1992 u16 net_proto_version = 0;
1993 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1995 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1998 getClient(peer->id)->net_proto_version = net_proto_version;
2000 if(net_proto_version == 0)
2002 SendAccessDenied(m_con, peer_id,
2003 L"Your client is too old. Please upgrade.");
2012 char playername[PLAYERNAME_SIZE];
2013 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2015 playername[i] = data[3+i];
2017 playername[PLAYERNAME_SIZE-1] = 0;
2019 if(playername[0]=='\0')
2021 derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
2022 SendAccessDenied(m_con, peer_id,
2027 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2029 derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
2030 SendAccessDenied(m_con, peer_id,
2031 L"Name contains unallowed characters");
2036 char password[PASSWORD_SIZE];
2037 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2039 // old version - assume blank password
2044 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2046 password[i] = data[23+i];
2048 password[PASSWORD_SIZE-1] = 0;
2051 std::string checkpwd;
2052 if(m_authmanager.exists(playername))
2054 checkpwd = m_authmanager.getPassword(playername);
2058 checkpwd = g_settings.get("default_password");
2061 /*dstream<<"Server: Client gave password '"<<password
2062 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2064 if(password != checkpwd && m_authmanager.exists(playername))
2066 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2067 <<": supplied invalid password for "
2068 <<playername<<std::endl;
2069 SendAccessDenied(m_con, peer_id, L"Invalid password");
2073 // Add player to auth manager
2074 if(m_authmanager.exists(playername) == false)
2076 derr_server<<DTIME<<"Server: adding player "<<playername
2077 <<" to auth manager"<<std::endl;
2078 m_authmanager.add(playername);
2079 m_authmanager.setPassword(playername, checkpwd);
2080 m_authmanager.setPrivs(playername,
2081 stringToPrivs(g_settings.get("default_privs")));
2082 m_authmanager.save();
2086 Player *player = emergePlayer(playername, password, peer_id);
2090 // DEBUG: Test serialization
2091 std::ostringstream test_os;
2092 player->serialize(test_os);
2093 dstream<<"Player serialization test: \""<<test_os.str()
2095 std::istringstream test_is(test_os.str());
2096 player->deSerialize(test_is);
2099 // If failed, cancel
2102 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2103 <<": failed to emerge player"<<std::endl;
2108 // If a client is already connected to the player, cancel
2109 if(player->peer_id != 0)
2111 derr_server<<DTIME<<"Server: peer_id="<<peer_id
2112 <<" tried to connect to "
2113 "an already connected player (peer_id="
2114 <<player->peer_id<<")"<<std::endl;
2117 // Set client of player
2118 player->peer_id = peer_id;
2121 // Check if player doesn't exist
2123 throw con::InvalidIncomingDataException
2124 ("Server::ProcessData(): INIT: Player doesn't exist");
2126 /*// update name if it was supplied
2127 if(datasize >= 20+3)
2130 player->updateName((const char*)&data[3]);
2134 Answer with a TOCLIENT_INIT
2137 SharedBuffer<u8> reply(2+1+6+8);
2138 writeU16(&reply[0], TOCLIENT_INIT);
2139 writeU8(&reply[2], deployed);
2140 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2141 writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2144 m_con.Send(peer_id, 0, reply, true);
2148 Send complete position information
2150 SendMovePlayer(player);
2155 if(command == TOSERVER_INIT2)
2157 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2158 <<peer->id<<std::endl;
2161 getClient(peer->id)->serialization_version
2162 = getClient(peer->id)->pending_serialization_version;
2165 Send some initialization data
2168 // Send player info to all players
2171 // Send inventory to player
2172 UpdateCrafting(peer->id);
2173 SendInventory(peer->id);
2175 // Send player items to all players
2180 Player *player = m_env.getPlayer(peer_id);
2181 SendPlayerHP(player);
2186 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2187 m_env.getTimeOfDay());
2188 m_con.Send(peer->id, 0, data, true);
2191 // Send information about server to player in chat
2192 SendChatMessage(peer_id, getStatusString());
2194 // Send information about joining in chat
2196 std::wstring name = L"unknown";
2197 Player *player = m_env.getPlayer(peer_id);
2199 name = narrow_to_wide(player->getName());
2201 std::wstring message;
2204 message += L" joined game";
2205 BroadcastChatMessage(message);
2208 // Warnings about protocol version can be issued here
2209 /*if(getClient(peer->id)->net_proto_version == 0)
2211 SendChatMessage(peer_id, L"# Server: NOTE: YOUR CLIENT IS OLD AND DOES NOT WORK PROPERLY WITH THIS SERVER");
2217 if(peer_ser_ver == SER_FMT_VER_INVALID)
2219 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2220 " serialization format invalid or not initialized."
2221 " Skipping incoming command="<<command<<std::endl;
2225 Player *player = m_env.getPlayer(peer_id);
2228 derr_server<<"Server::ProcessData(): Cancelling: "
2229 "No player for peer_id="<<peer_id
2233 if(command == TOSERVER_PLAYERPOS)
2235 if(datasize < 2+12+12+4+4)
2239 v3s32 ps = readV3S32(&data[start+2]);
2240 v3s32 ss = readV3S32(&data[start+2+12]);
2241 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2242 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2243 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2244 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2245 pitch = wrapDegrees(pitch);
2246 yaw = wrapDegrees(yaw);
2247 player->setPosition(position);
2248 player->setSpeed(speed);
2249 player->setPitch(pitch);
2250 player->setYaw(yaw);
2252 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2253 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2254 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2256 else if(command == TOSERVER_GOTBLOCKS)
2269 u16 count = data[2];
2270 for(u16 i=0; i<count; i++)
2272 if((s16)datasize < 2+1+(i+1)*6)
2273 throw con::InvalidIncomingDataException
2274 ("GOTBLOCKS length is too short");
2275 v3s16 p = readV3S16(&data[2+1+i*6]);
2276 /*dstream<<"Server: GOTBLOCKS ("
2277 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2278 RemoteClient *client = getClient(peer_id);
2279 client->GotBlock(p);
2282 else if(command == TOSERVER_DELETEDBLOCKS)
2295 u16 count = data[2];
2296 for(u16 i=0; i<count; i++)
2298 if((s16)datasize < 2+1+(i+1)*6)
2299 throw con::InvalidIncomingDataException
2300 ("DELETEDBLOCKS length is too short");
2301 v3s16 p = readV3S16(&data[2+1+i*6]);
2302 /*dstream<<"Server: DELETEDBLOCKS ("
2303 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2304 RemoteClient *client = getClient(peer_id);
2305 client->SetBlockNotSent(p);
2308 else if(command == TOSERVER_CLICK_OBJECT)
2313 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2318 [2] u8 button (0=left, 1=right)
2323 u8 button = readU8(&data[2]);
2325 p.X = readS16(&data[3]);
2326 p.Y = readS16(&data[5]);
2327 p.Z = readS16(&data[7]);
2328 s16 id = readS16(&data[9]);
2329 //u16 item_i = readU16(&data[11]);
2331 MapBlock *block = NULL;
2334 block = m_env.getMap().getBlockNoCreate(p);
2336 catch(InvalidPositionException &e)
2338 derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2342 MapBlockObject *obj = block->getObject(id);
2346 derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2350 //TODO: Check that object is reasonably close
2355 InventoryList *ilist = player->inventory.getList("main");
2356 if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2359 // Skip if inventory has no free space
2360 if(ilist->getUsedSlots() == ilist->getSize())
2362 dout_server<<"Player inventory has no free space"<<std::endl;
2367 Create the inventory item
2369 InventoryItem *item = NULL;
2370 // If it is an item-object, take the item from it
2371 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2373 item = ((ItemObject*)obj)->createInventoryItem();
2375 // Else create an item of the object
2378 item = new MapBlockObjectItem
2379 (obj->getInventoryString());
2382 // Add to inventory and send inventory
2383 ilist->addItem(item);
2384 UpdateCrafting(player->peer_id);
2385 SendInventory(player->peer_id);
2388 // Remove from block
2389 block->removeObject(id);
2392 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2397 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2403 [2] u8 button (0=left, 1=right)
2407 u8 button = readU8(&data[2]);
2408 u16 id = readS16(&data[3]);
2409 u16 item_i = readU16(&data[11]);
2411 ServerActiveObject *obj = m_env.getActiveObject(id);
2415 derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2420 // Skip if object has been removed
2424 //TODO: Check that object is reasonably close
2426 // Left click, pick object up (usually)
2430 Try creating inventory item
2432 InventoryItem *item = obj->createPickedUpItem();
2436 InventoryList *ilist = player->inventory.getList("main");
2439 if(g_settings.getBool("creative_mode") == false)
2441 // Skip if inventory has no free space
2442 if(ilist->getUsedSlots() == ilist->getSize())
2444 dout_server<<"Player inventory has no free space"<<std::endl;
2448 // Add to inventory and send inventory
2449 ilist->addItem(item);
2450 UpdateCrafting(player->peer_id);
2451 SendInventory(player->peer_id);
2454 // Remove object from environment
2455 obj->m_removed = true;
2461 Item cannot be picked up. Punch it instead.
2464 ToolItem *titem = NULL;
2465 std::string toolname = "";
2467 InventoryList *mlist = player->inventory.getList("main");
2470 InventoryItem *item = mlist->getItem(item_i);
2471 if(item && (std::string)item->getName() == "ToolItem")
2473 titem = (ToolItem*)item;
2474 toolname = titem->getToolName();
2478 v3f playerpos = player->getPosition();
2479 v3f objpos = obj->getBasePosition();
2480 v3f dir = (objpos - playerpos).normalize();
2482 u16 wear = obj->punch(toolname, dir);
2486 bool weared_out = titem->addWear(wear);
2488 mlist->deleteItem(item_i);
2489 SendInventory(player->peer_id);
2493 // Right click, do something with object
2496 // Track hp changes super-crappily
2497 u16 oldhp = player->hp;
2500 obj->rightClick(player);
2503 if(player->hp != oldhp)
2505 SendPlayerHP(player);
2509 else if(command == TOSERVER_GROUND_ACTION)
2517 [3] v3s16 nodepos_undersurface
2518 [9] v3s16 nodepos_abovesurface
2523 2: stop digging (all parameters ignored)
2524 3: digging completed
2526 u8 action = readU8(&data[2]);
2528 p_under.X = readS16(&data[3]);
2529 p_under.Y = readS16(&data[5]);
2530 p_under.Z = readS16(&data[7]);
2532 p_over.X = readS16(&data[9]);
2533 p_over.Y = readS16(&data[11]);
2534 p_over.Z = readS16(&data[13]);
2535 u16 item_i = readU16(&data[15]);
2537 //TODO: Check that target is reasonably close
2545 NOTE: This can be used in the future to check if
2546 somebody is cheating, by checking the timing.
2553 else if(action == 2)
2556 RemoteClient *client = getClient(peer->id);
2557 JMutexAutoLock digmutex(client->m_dig_mutex);
2558 client->m_dig_tool_item = -1;
2563 3: Digging completed
2565 else if(action == 3)
2567 // Mandatory parameter; actually used for nothing
2568 core::map<v3s16, MapBlock*> modified_blocks;
2570 content_t material = CONTENT_IGNORE;
2571 u8 mineral = MINERAL_NONE;
2573 bool cannot_remove_node = false;
2577 MapNode n = m_env.getMap().getNode(p_under);
2579 mineral = n.getMineral();
2580 // Get material at position
2581 material = n.getContent();
2582 // If not yet cancelled
2583 if(cannot_remove_node == false)
2585 // If it's not diggable, do nothing
2586 if(content_diggable(material) == false)
2588 derr_server<<"Server: Not finishing digging: "
2589 <<"Node not diggable"
2591 cannot_remove_node = true;
2594 // If not yet cancelled
2595 if(cannot_remove_node == false)
2597 // Get node metadata
2598 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2599 if(meta && meta->nodeRemovalDisabled() == true)
2601 derr_server<<"Server: Not finishing digging: "
2602 <<"Node metadata disables removal"
2604 cannot_remove_node = true;
2608 catch(InvalidPositionException &e)
2610 derr_server<<"Server: Not finishing digging: Node not found."
2611 <<" Adding block to emerge queue."
2613 m_emerge_queue.addBlock(peer_id,
2614 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2615 cannot_remove_node = true;
2618 // Make sure the player is allowed to do it
2619 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2621 dstream<<"Player "<<player->getName()<<" cannot remove node"
2622 <<" because privileges are "<<getPlayerPrivs(player)
2624 cannot_remove_node = true;
2628 If node can't be removed, set block to be re-sent to
2631 if(cannot_remove_node)
2633 derr_server<<"Server: Not finishing digging."<<std::endl;
2635 // Client probably has wrong data.
2636 // Set block not sent, so that client will get
2638 dstream<<"Client "<<peer_id<<" tried to dig "
2639 <<"node; but node cannot be removed."
2640 <<" setting MapBlock not sent."<<std::endl;
2641 RemoteClient *client = getClient(peer_id);
2642 v3s16 blockpos = getNodeBlockPos(p_under);
2643 client->SetBlockNotSent(blockpos);
2649 Send the removal to all close-by players.
2650 - If other player is close, send REMOVENODE
2651 - Otherwise set blocks not sent
2653 core::list<u16> far_players;
2654 sendRemoveNode(p_under, peer_id, &far_players, 30);
2657 Update and send inventory
2660 if(g_settings.getBool("creative_mode") == false)
2665 InventoryList *mlist = player->inventory.getList("main");
2668 InventoryItem *item = mlist->getItem(item_i);
2669 if(item && (std::string)item->getName() == "ToolItem")
2671 ToolItem *titem = (ToolItem*)item;
2672 std::string toolname = titem->getToolName();
2674 // Get digging properties for material and tool
2675 DiggingProperties prop =
2676 getDiggingProperties(material, toolname);
2678 if(prop.diggable == false)
2680 derr_server<<"Server: WARNING: Player digged"
2681 <<" with impossible material + tool"
2682 <<" combination"<<std::endl;
2685 bool weared_out = titem->addWear(prop.wear);
2689 mlist->deleteItem(item_i);
2695 Add dug item to inventory
2698 InventoryItem *item = NULL;
2700 if(mineral != MINERAL_NONE)
2701 item = getDiggedMineralItem(mineral);
2706 std::string &dug_s = content_features(material).dug_item;
2709 std::istringstream is(dug_s, std::ios::binary);
2710 item = InventoryItem::deSerialize(is);
2716 // Add a item to inventory
2717 player->inventory.addItem("main", item);
2720 UpdateCrafting(player->peer_id);
2721 SendInventory(player->peer_id);
2727 (this takes some time so it is done after the quick stuff)
2730 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2732 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2735 Set blocks not sent to far players
2737 for(core::list<u16>::Iterator
2738 i = far_players.begin();
2739 i != far_players.end(); i++)
2742 RemoteClient *client = getClient(peer_id);
2745 client->SetBlocksNotSent(modified_blocks);
2752 else if(action == 1)
2755 InventoryList *ilist = player->inventory.getList("main");
2760 InventoryItem *item = ilist->getItem(item_i);
2762 // If there is no item, it is not possible to add it anywhere
2767 Handle material items
2769 if(std::string("MaterialItem") == item->getName())
2772 // Don't add a node if this is not a free space
2773 MapNode n2 = m_env.getMap().getNode(p_over);
2774 bool no_enough_privs =
2775 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2777 dstream<<"Player "<<player->getName()<<" cannot add node"
2778 <<" because privileges are "<<getPlayerPrivs(player)
2781 if(content_features(n2).buildable_to == false
2784 // Client probably has wrong data.
2785 // Set block not sent, so that client will get
2787 dstream<<"Client "<<peer_id<<" tried to place"
2788 <<" node in invalid position; setting"
2789 <<" MapBlock not sent."<<std::endl;
2790 RemoteClient *client = getClient(peer_id);
2791 v3s16 blockpos = getNodeBlockPos(p_over);
2792 client->SetBlockNotSent(blockpos);
2796 catch(InvalidPositionException &e)
2798 derr_server<<"Server: Ignoring ADDNODE: Node not found"
2799 <<" Adding block to emerge queue."
2801 m_emerge_queue.addBlock(peer_id,
2802 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2806 // Reset build time counter
2807 getClient(peer->id)->m_time_from_building = 0.0;
2810 MaterialItem *mitem = (MaterialItem*)item;
2812 n.setContent(mitem->getMaterial());
2814 // Calculate direction for wall mounted stuff
2815 if(content_features(n).wall_mounted)
2816 n.param2 = packDir(p_under - p_over);
2818 // Calculate the direction for furnaces and chests and stuff
2819 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2821 v3f playerpos = player->getPosition();
2822 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2823 blockpos = blockpos.normalize();
2825 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2839 Send to all close-by players
2841 core::list<u16> far_players;
2842 sendAddNode(p_over, n, 0, &far_players, 30);
2847 InventoryList *ilist = player->inventory.getList("main");
2848 if(g_settings.getBool("creative_mode") == false && ilist)
2850 // Remove from inventory and send inventory
2851 if(mitem->getCount() == 1)
2852 ilist->deleteItem(item_i);
2856 UpdateCrafting(peer_id);
2857 SendInventory(peer_id);
2863 This takes some time so it is done after the quick stuff
2865 core::map<v3s16, MapBlock*> modified_blocks;
2867 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2869 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2872 Set blocks not sent to far players
2874 for(core::list<u16>::Iterator
2875 i = far_players.begin();
2876 i != far_players.end(); i++)
2879 RemoteClient *client = getClient(peer_id);
2882 client->SetBlocksNotSent(modified_blocks);
2886 Calculate special events
2889 /*if(n.d == CONTENT_MESE)
2892 for(s16 z=-1; z<=1; z++)
2893 for(s16 y=-1; y<=1; y++)
2894 for(s16 x=-1; x<=1; x++)
2901 Place other item (not a block)
2905 v3s16 blockpos = getNodeBlockPos(p_over);
2908 Check that the block is loaded so that the item
2909 can properly be added to the static list too
2911 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2914 derr_server<<"Error while placing object: "
2915 "block not found"<<std::endl;
2919 dout_server<<"Placing a miscellaneous item on map"
2922 // Calculate a position for it
2923 v3f pos = intToFloat(p_over, BS);
2925 pos.Y -= BS*0.25; // let it drop a bit
2927 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2928 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2933 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2937 derr_server<<"WARNING: item resulted in NULL object, "
2938 <<"not placing onto map"
2943 // Add the object to the environment
2944 m_env.addActiveObject(obj);
2946 dout_server<<"Placed object"<<std::endl;
2948 if(g_settings.getBool("creative_mode") == false)
2950 // Delete the right amount of items from the slot
2951 u16 dropcount = item->getDropCount();
2953 // Delete item if all gone
2954 if(item->getCount() <= dropcount)
2956 if(item->getCount() < dropcount)
2957 dstream<<"WARNING: Server: dropped more items"
2958 <<" than the slot contains"<<std::endl;
2960 InventoryList *ilist = player->inventory.getList("main");
2962 // Remove from inventory and send inventory
2963 ilist->deleteItem(item_i);
2965 // Else decrement it
2967 item->remove(dropcount);
2970 UpdateCrafting(peer_id);
2971 SendInventory(peer_id);
2979 Catch invalid actions
2983 derr_server<<"WARNING: Server: Invalid action "
2984 <<action<<std::endl;
2988 else if(command == TOSERVER_RELEASE)
2997 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
3000 else if(command == TOSERVER_SIGNTEXT)
3002 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3011 std::string datastring((char*)&data[2], datasize-2);
3012 std::istringstream is(datastring, std::ios_base::binary);
3015 is.read((char*)buf, 6);
3016 v3s16 blockpos = readV3S16(buf);
3017 is.read((char*)buf, 2);
3018 s16 id = readS16(buf);
3019 is.read((char*)buf, 2);
3020 u16 textlen = readU16(buf);
3022 for(u16 i=0; i<textlen; i++)
3024 is.read((char*)buf, 1);
3025 text += (char)buf[0];
3028 MapBlock *block = NULL;
3031 block = m_env.getMap().getBlockNoCreate(blockpos);
3033 catch(InvalidPositionException &e)
3035 derr_server<<"Error while setting sign text: "
3036 "block not found"<<std::endl;
3040 MapBlockObject *obj = block->getObject(id);
3043 derr_server<<"Error while setting sign text: "
3044 "object not found"<<std::endl;
3048 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
3050 derr_server<<"Error while setting sign text: "
3051 "object is not a sign"<<std::endl;
3055 ((SignObject*)obj)->setText(text);
3057 obj->getBlock()->setChangedFlag();
3059 else if(command == TOSERVER_SIGNNODETEXT)
3061 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3069 std::string datastring((char*)&data[2], datasize-2);
3070 std::istringstream is(datastring, std::ios_base::binary);
3073 is.read((char*)buf, 6);
3074 v3s16 p = readV3S16(buf);
3075 is.read((char*)buf, 2);
3076 u16 textlen = readU16(buf);
3078 for(u16 i=0; i<textlen; i++)
3080 is.read((char*)buf, 1);
3081 text += (char)buf[0];
3084 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3087 if(meta->typeId() != CONTENT_SIGN_WALL)
3089 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3090 signmeta->setText(text);
3092 v3s16 blockpos = getNodeBlockPos(p);
3093 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
3096 block->setChangedFlag();
3099 for(core::map<u16, RemoteClient*>::Iterator
3100 i = m_clients.getIterator();
3101 i.atEnd()==false; i++)
3103 RemoteClient *client = i.getNode()->getValue();
3104 client->SetBlockNotSent(blockpos);
3107 else if(command == TOSERVER_INVENTORY_ACTION)
3109 /*// Ignore inventory changes if in creative mode
3110 if(g_settings.getBool("creative_mode") == true)
3112 dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3116 // Strip command and create a stream
3117 std::string datastring((char*)&data[2], datasize-2);
3118 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3119 std::istringstream is(datastring, std::ios_base::binary);
3121 InventoryAction *a = InventoryAction::deSerialize(is);
3126 c.current_player = player;
3129 Handle craftresult specially if not in creative mode
3131 bool disable_action = false;
3132 if(a->getType() == IACTION_MOVE
3133 && g_settings.getBool("creative_mode") == false)
3135 IMoveAction *ma = (IMoveAction*)a;
3136 if(ma->to_inv == "current_player" &&
3137 ma->from_inv == "current_player")
3139 InventoryList *rlist = player->inventory.getList("craftresult");
3141 InventoryList *clist = player->inventory.getList("craft");
3143 InventoryList *mlist = player->inventory.getList("main");
3146 Craftresult is no longer preview if something
3149 if(ma->to_list == "craftresult"
3150 && ma->from_list != "craftresult")
3152 // If it currently is a preview, remove
3154 if(player->craftresult_is_preview)
3156 rlist->deleteItem(0);
3158 player->craftresult_is_preview = false;
3161 Crafting takes place if this condition is true.
3163 if(player->craftresult_is_preview &&
3164 ma->from_list == "craftresult")
3166 player->craftresult_is_preview = false;
3167 clist->decrementMaterials(1);
3170 If the craftresult is placed on itself, move it to
3171 main inventory instead of doing the action
3173 if(ma->to_list == "craftresult"
3174 && ma->from_list == "craftresult")
3176 disable_action = true;
3178 InventoryItem *item1 = rlist->changeItem(0, NULL);
3179 mlist->addItem(item1);
3184 if(disable_action == false)
3186 // Feed action to player inventory
3194 UpdateCrafting(player->peer_id);
3195 SendInventory(player->peer_id);
3200 dstream<<"TOSERVER_INVENTORY_ACTION: "
3201 <<"InventoryAction::deSerialize() returned NULL"
3205 else if(command == TOSERVER_CHAT_MESSAGE)
3213 std::string datastring((char*)&data[2], datasize-2);
3214 std::istringstream is(datastring, std::ios_base::binary);
3217 is.read((char*)buf, 2);
3218 u16 len = readU16(buf);
3220 std::wstring message;
3221 for(u16 i=0; i<len; i++)
3223 is.read((char*)buf, 2);
3224 message += (wchar_t)readU16(buf);
3227 // Get player name of this client
3228 std::wstring name = narrow_to_wide(player->getName());
3230 // Line to send to players
3232 // Whether to send to the player that sent the line
3233 bool send_to_sender = false;
3234 // Whether to send to other players
3235 bool send_to_others = false;
3237 // Local player gets all privileges regardless of
3238 // what's set on their account.
3239 u64 privs = getPlayerPrivs(player);
3242 std::wstring commandprefix = L"/#";
3243 if(message.substr(0, commandprefix.size()) == commandprefix)
3245 line += L"Server: ";
3247 message = message.substr(commandprefix.size());
3249 WStrfnd f1(message);
3250 f1.next(L" "); // Skip over /#whatever
3251 std::wstring paramstring = f1.next(L"");
3253 ServerCommandContext *ctx = new ServerCommandContext(
3254 str_split(message, L' '),
3261 line += processServerCommand(ctx);
3262 send_to_sender = ctx->flags & 1;
3263 send_to_others = ctx->flags & 2;
3269 if(privs & PRIV_SHOUT)
3275 send_to_others = true;
3279 line += L"Server: You are not allowed to shout";
3280 send_to_sender = true;
3286 dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3289 Send the message to clients
3291 for(core::map<u16, RemoteClient*>::Iterator
3292 i = m_clients.getIterator();
3293 i.atEnd() == false; i++)
3295 // Get client and check that it is valid
3296 RemoteClient *client = i.getNode()->getValue();
3297 assert(client->peer_id == i.getNode()->getKey());
3298 if(client->serialization_version == SER_FMT_VER_INVALID)
3302 bool sender_selected = (peer_id == client->peer_id);
3303 if(sender_selected == true && send_to_sender == false)
3305 if(sender_selected == false && send_to_others == false)
3308 SendChatMessage(client->peer_id, line);
3312 else if(command == TOSERVER_DAMAGE)
3314 if(g_settings.getBool("enable_damage"))
3316 std::string datastring((char*)&data[2], datasize-2);
3317 std::istringstream is(datastring, std::ios_base::binary);
3318 u8 damage = readU8(is);
3319 if(player->hp > damage)
3321 player->hp -= damage;
3327 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3330 v3f pos = findSpawnPos(m_env.getServerMap());
3331 player->setPosition(pos);
3333 SendMovePlayer(player);
3334 SendPlayerHP(player);
3336 //TODO: Throw items around
3340 SendPlayerHP(player);
3342 else if(command == TOSERVER_PASSWORD)
3345 [0] u16 TOSERVER_PASSWORD
3346 [2] u8[28] old password
3347 [30] u8[28] new password
3350 if(datasize != 2+PASSWORD_SIZE*2)
3352 /*char password[PASSWORD_SIZE];
3353 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3354 password[i] = data[2+i];
3355 password[PASSWORD_SIZE-1] = 0;*/
3357 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3365 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3367 char c = data[2+PASSWORD_SIZE+i];
3373 dstream<<"Server: Client requests a password change from "
3374 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3376 std::string playername = player->getName();
3378 if(m_authmanager.exists(playername) == false)
3380 dstream<<"Server: playername not found in authmanager"<<std::endl;
3381 // Wrong old password supplied!!
3382 SendChatMessage(peer_id, L"playername not found in authmanager");
3386 std::string checkpwd = m_authmanager.getPassword(playername);
3388 if(oldpwd != checkpwd)
3390 dstream<<"Server: invalid old password"<<std::endl;
3391 // Wrong old password supplied!!
3392 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3396 m_authmanager.setPassword(playername, newpwd);
3398 dstream<<"Server: password change successful for "<<playername
3400 SendChatMessage(peer_id, L"Password change successful");
3402 else if (command == TOSERVER_PLAYERITEM)
3407 u16 item = readU16(&data[2]);
3408 player->wieldItem(item);
3409 SendWieldedItem(player);
3413 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3414 "unknown command "<<command<<std::endl;
3418 catch(SendFailedException &e)
3420 derr_server<<"Server::ProcessData(): SendFailedException: "
3426 void Server::onMapEditEvent(MapEditEvent *event)
3428 //dstream<<"Server::onMapEditEvent()"<<std::endl;
3429 if(m_ignore_map_edit_events)
3431 MapEditEvent *e = event->clone();
3432 m_unsent_map_edit_queue.push_back(e);
3435 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3437 if(id == "current_player")
3439 assert(c->current_player);
3440 return &(c->current_player->inventory);
3444 std::string id0 = fn.next(":");
3446 if(id0 == "nodemeta")
3449 p.X = stoi(fn.next(","));
3450 p.Y = stoi(fn.next(","));
3451 p.Z = stoi(fn.next(","));
3452 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3454 return meta->getInventory();
3455 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3456 <<"no metadata found"<<std::endl;
3460 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3463 void Server::inventoryModified(InventoryContext *c, std::string id)
3465 if(id == "current_player")
3467 assert(c->current_player);
3469 UpdateCrafting(c->current_player->peer_id);
3470 SendInventory(c->current_player->peer_id);
3475 std::string id0 = fn.next(":");
3477 if(id0 == "nodemeta")
3480 p.X = stoi(fn.next(","));
3481 p.Y = stoi(fn.next(","));
3482 p.Z = stoi(fn.next(","));
3483 v3s16 blockpos = getNodeBlockPos(p);
3485 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3487 meta->inventoryModified();
3489 for(core::map<u16, RemoteClient*>::Iterator
3490 i = m_clients.getIterator();
3491 i.atEnd()==false; i++)
3493 RemoteClient *client = i.getNode()->getValue();
3494 client->SetBlockNotSent(blockpos);
3500 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3503 core::list<PlayerInfo> Server::getPlayerInfo()
3505 DSTACK(__FUNCTION_NAME);
3506 JMutexAutoLock envlock(m_env_mutex);
3507 JMutexAutoLock conlock(m_con_mutex);
3509 core::list<PlayerInfo> list;
3511 core::list<Player*> players = m_env.getPlayers();
3513 core::list<Player*>::Iterator i;
3514 for(i = players.begin();
3515 i != players.end(); i++)
3519 Player *player = *i;
3522 con::Peer *peer = m_con.GetPeer(player->peer_id);
3523 // Copy info from peer to info struct
3525 info.address = peer->address;
3526 info.avg_rtt = peer->avg_rtt;
3528 catch(con::PeerNotFoundException &e)
3530 // Set dummy peer info
3532 info.address = Address(0,0,0,0,0);
3536 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3537 info.position = player->getPosition();
3539 list.push_back(info);
3546 void Server::peerAdded(con::Peer *peer)
3548 DSTACK(__FUNCTION_NAME);
3549 dout_server<<"Server::peerAdded(): peer->id="
3550 <<peer->id<<std::endl;
3553 c.type = PEER_ADDED;
3554 c.peer_id = peer->id;
3556 m_peer_change_queue.push_back(c);
3559 void Server::deletingPeer(con::Peer *peer, bool timeout)
3561 DSTACK(__FUNCTION_NAME);
3562 dout_server<<"Server::deletingPeer(): peer->id="
3563 <<peer->id<<", timeout="<<timeout<<std::endl;
3566 c.type = PEER_REMOVED;
3567 c.peer_id = peer->id;
3568 c.timeout = timeout;
3569 m_peer_change_queue.push_back(c);
3576 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3578 DSTACK(__FUNCTION_NAME);
3579 std::ostringstream os(std::ios_base::binary);
3581 writeU16(os, TOCLIENT_HP);
3585 std::string s = os.str();
3586 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3588 con.Send(peer_id, 0, data, true);
3591 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3592 const std::wstring &reason)
3594 DSTACK(__FUNCTION_NAME);
3595 std::ostringstream os(std::ios_base::binary);
3597 writeU16(os, TOCLIENT_ACCESS_DENIED);
3598 os<<serializeWideString(reason);
3601 std::string s = os.str();
3602 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3604 con.Send(peer_id, 0, data, true);
3608 Non-static send methods
3611 void Server::SendObjectData(float dtime)
3613 DSTACK(__FUNCTION_NAME);
3615 core::map<v3s16, bool> stepped_blocks;
3617 for(core::map<u16, RemoteClient*>::Iterator
3618 i = m_clients.getIterator();
3619 i.atEnd() == false; i++)
3621 u16 peer_id = i.getNode()->getKey();
3622 RemoteClient *client = i.getNode()->getValue();
3623 assert(client->peer_id == peer_id);
3625 if(client->serialization_version == SER_FMT_VER_INVALID)
3628 client->SendObjectData(this, dtime, stepped_blocks);
3632 void Server::SendPlayerInfos()
3634 DSTACK(__FUNCTION_NAME);
3636 //JMutexAutoLock envlock(m_env_mutex);
3638 // Get connected players
3639 core::list<Player*> players = m_env.getPlayers(true);
3641 u32 player_count = players.getSize();
3642 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3644 SharedBuffer<u8> data(datasize);
3645 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3648 core::list<Player*>::Iterator i;
3649 for(i = players.begin();
3650 i != players.end(); i++)
3652 Player *player = *i;
3654 /*dstream<<"Server sending player info for player with "
3655 "peer_id="<<player->peer_id<<std::endl;*/
3657 writeU16(&data[start], player->peer_id);
3658 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3659 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3660 start += 2+PLAYERNAME_SIZE;
3663 //JMutexAutoLock conlock(m_con_mutex);
3666 m_con.SendToAll(0, data, true);
3669 void Server::SendInventory(u16 peer_id)
3671 DSTACK(__FUNCTION_NAME);
3673 Player* player = m_env.getPlayer(peer_id);
3680 std::ostringstream os;
3681 //os.imbue(std::locale("C"));
3683 player->inventory.serialize(os);
3685 std::string s = os.str();
3687 SharedBuffer<u8> data(s.size()+2);
3688 writeU16(&data[0], TOCLIENT_INVENTORY);
3689 memcpy(&data[2], s.c_str(), s.size());
3692 m_con.Send(peer_id, 0, data, true);
3695 std::string getWieldedItemString(const Player *player)
3697 const InventoryItem *item = player->getWieldItem();
3699 return std::string("");
3700 std::ostringstream os(std::ios_base::binary);
3701 item->serialize(os);
3705 void Server::SendWieldedItem(const Player* player)
3707 DSTACK(__FUNCTION_NAME);
3711 std::ostringstream os(std::ios_base::binary);
3713 writeU16(os, TOCLIENT_PLAYERITEM);
3715 writeU16(os, player->peer_id);
3716 os<<serializeString(getWieldedItemString(player));
3719 std::string s = os.str();
3720 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3722 m_con.SendToAll(0, data, true);
3725 void Server::SendPlayerItems()
3727 DSTACK(__FUNCTION_NAME);
3729 std::ostringstream os(std::ios_base::binary);
3730 core::list<Player *> players = m_env.getPlayers(true);
3732 writeU16(os, TOCLIENT_PLAYERITEM);
3733 writeU16(os, players.size());
3734 core::list<Player *>::Iterator i;
3735 for(i = players.begin(); i != players.end(); ++i)
3738 writeU16(os, p->peer_id);
3739 os<<serializeString(getWieldedItemString(p));
3743 std::string s = os.str();
3744 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3746 m_con.SendToAll(0, data, true);
3749 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3751 DSTACK(__FUNCTION_NAME);
3753 std::ostringstream os(std::ios_base::binary);
3757 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3758 os.write((char*)buf, 2);
3761 writeU16(buf, message.size());
3762 os.write((char*)buf, 2);
3765 for(u32 i=0; i<message.size(); i++)
3769 os.write((char*)buf, 2);
3773 std::string s = os.str();
3774 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3776 m_con.Send(peer_id, 0, data, true);
3779 void Server::BroadcastChatMessage(const std::wstring &message)
3781 for(core::map<u16, RemoteClient*>::Iterator
3782 i = m_clients.getIterator();
3783 i.atEnd() == false; i++)
3785 // Get client and check that it is valid
3786 RemoteClient *client = i.getNode()->getValue();
3787 assert(client->peer_id == i.getNode()->getKey());
3788 if(client->serialization_version == SER_FMT_VER_INVALID)
3791 SendChatMessage(client->peer_id, message);
3795 void Server::SendPlayerHP(Player *player)
3797 SendHP(m_con, player->peer_id, player->hp);
3800 void Server::SendMovePlayer(Player *player)
3802 DSTACK(__FUNCTION_NAME);
3803 std::ostringstream os(std::ios_base::binary);
3805 writeU16(os, TOCLIENT_MOVE_PLAYER);
3806 writeV3F1000(os, player->getPosition());
3807 writeF1000(os, player->getPitch());
3808 writeF1000(os, player->getYaw());
3811 v3f pos = player->getPosition();
3812 f32 pitch = player->getPitch();
3813 f32 yaw = player->getYaw();
3814 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3815 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3822 std::string s = os.str();
3823 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3825 m_con.Send(player->peer_id, 0, data, true);
3828 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3829 core::list<u16> *far_players, float far_d_nodes)
3831 float maxd = far_d_nodes*BS;
3832 v3f p_f = intToFloat(p, BS);
3836 SharedBuffer<u8> reply(replysize);
3837 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3838 writeS16(&reply[2], p.X);
3839 writeS16(&reply[4], p.Y);
3840 writeS16(&reply[6], p.Z);
3842 for(core::map<u16, RemoteClient*>::Iterator
3843 i = m_clients.getIterator();
3844 i.atEnd() == false; i++)
3846 // Get client and check that it is valid
3847 RemoteClient *client = i.getNode()->getValue();
3848 assert(client->peer_id == i.getNode()->getKey());
3849 if(client->serialization_version == SER_FMT_VER_INVALID)
3852 // Don't send if it's the same one
3853 if(client->peer_id == ignore_id)
3859 Player *player = m_env.getPlayer(client->peer_id);
3862 // If player is far away, only set modified blocks not sent
3863 v3f player_pos = player->getPosition();
3864 if(player_pos.getDistanceFrom(p_f) > maxd)
3866 far_players->push_back(client->peer_id);
3873 m_con.Send(client->peer_id, 0, reply, true);
3877 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3878 core::list<u16> *far_players, float far_d_nodes)
3880 float maxd = far_d_nodes*BS;
3881 v3f p_f = intToFloat(p, BS);
3883 for(core::map<u16, RemoteClient*>::Iterator
3884 i = m_clients.getIterator();
3885 i.atEnd() == false; i++)
3887 // Get client and check that it is valid
3888 RemoteClient *client = i.getNode()->getValue();
3889 assert(client->peer_id == i.getNode()->getKey());
3890 if(client->serialization_version == SER_FMT_VER_INVALID)
3893 // Don't send if it's the same one
3894 if(client->peer_id == ignore_id)
3900 Player *player = m_env.getPlayer(client->peer_id);
3903 // If player is far away, only set modified blocks not sent
3904 v3f player_pos = player->getPosition();
3905 if(player_pos.getDistanceFrom(p_f) > maxd)
3907 far_players->push_back(client->peer_id);
3914 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3915 SharedBuffer<u8> reply(replysize);
3916 writeU16(&reply[0], TOCLIENT_ADDNODE);
3917 writeS16(&reply[2], p.X);
3918 writeS16(&reply[4], p.Y);
3919 writeS16(&reply[6], p.Z);
3920 n.serialize(&reply[8], client->serialization_version);
3923 m_con.Send(client->peer_id, 0, reply, true);
3927 void Server::setBlockNotSent(v3s16 p)
3929 for(core::map<u16, RemoteClient*>::Iterator
3930 i = m_clients.getIterator();
3931 i.atEnd()==false; i++)
3933 RemoteClient *client = i.getNode()->getValue();
3934 client->SetBlockNotSent(p);
3938 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3940 DSTACK(__FUNCTION_NAME);
3942 v3s16 p = block->getPos();
3946 bool completely_air = true;
3947 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3948 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3949 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3951 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3953 completely_air = false;
3954 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3959 dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3961 dstream<<"[completely air] ";
3966 Create a packet with the block in the right format
3969 std::ostringstream os(std::ios_base::binary);
3970 block->serialize(os, ver);
3971 std::string s = os.str();
3972 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3974 u32 replysize = 8 + blockdata.getSize();
3975 SharedBuffer<u8> reply(replysize);
3976 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3977 writeS16(&reply[2], p.X);
3978 writeS16(&reply[4], p.Y);
3979 writeS16(&reply[6], p.Z);
3980 memcpy(&reply[8], *blockdata, blockdata.getSize());
3982 /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3983 <<": \tpacket size: "<<replysize<<std::endl;*/
3988 m_con.Send(peer_id, 1, reply, true);
3991 void Server::SendBlocks(float dtime)
3993 DSTACK(__FUNCTION_NAME);
3995 JMutexAutoLock envlock(m_env_mutex);
3996 JMutexAutoLock conlock(m_con_mutex);
3998 //TimeTaker timer("Server::SendBlocks");
4000 core::array<PrioritySortedBlockTransfer> queue;
4002 s32 total_sending = 0;
4005 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
4007 for(core::map<u16, RemoteClient*>::Iterator
4008 i = m_clients.getIterator();
4009 i.atEnd() == false; i++)
4011 RemoteClient *client = i.getNode()->getValue();
4012 assert(client->peer_id == i.getNode()->getKey());
4014 total_sending += client->SendingCount();
4016 if(client->serialization_version == SER_FMT_VER_INVALID)
4019 client->GetNextBlocks(this, dtime, queue);
4024 // Lowest priority number comes first.
4025 // Lowest is most important.
4028 for(u32 i=0; i<queue.size(); i++)
4030 //TODO: Calculate limit dynamically
4031 if(total_sending >= g_settings.getS32
4032 ("max_simultaneous_block_sends_server_total"))
4035 PrioritySortedBlockTransfer q = queue[i];
4037 MapBlock *block = NULL;
4040 block = m_env.getMap().getBlockNoCreate(q.pos);
4042 catch(InvalidPositionException &e)
4047 RemoteClient *client = getClient(q.peer_id);
4049 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4051 client->SentBlock(q.pos);
4061 void Server::UpdateCrafting(u16 peer_id)
4063 DSTACK(__FUNCTION_NAME);
4065 Player* player = m_env.getPlayer(peer_id);
4069 Calculate crafting stuff
4071 if(g_settings.getBool("creative_mode") == false)
4073 InventoryList *clist = player->inventory.getList("craft");
4074 InventoryList *rlist = player->inventory.getList("craftresult");
4076 if(rlist->getUsedSlots() == 0)
4077 player->craftresult_is_preview = true;
4079 if(rlist && player->craftresult_is_preview)
4081 rlist->clearItems();
4083 if(clist && rlist && player->craftresult_is_preview)
4085 InventoryItem *items[9];
4086 for(u16 i=0; i<9; i++)
4088 items[i] = clist->getItem(i);
4091 // Get result of crafting grid
4092 InventoryItem *result = craft_get_result(items);
4094 rlist->addItem(result);
4097 } // if creative_mode == false
4100 RemoteClient* Server::getClient(u16 peer_id)
4102 DSTACK(__FUNCTION_NAME);
4103 //JMutexAutoLock lock(m_con_mutex);
4104 core::map<u16, RemoteClient*>::Node *n;
4105 n = m_clients.find(peer_id);
4106 // A client should exist for all peers
4108 return n->getValue();
4111 std::wstring Server::getStatusString()
4113 std::wostringstream os(std::ios_base::binary);
4116 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4118 os<<L", uptime="<<m_uptime.get();
4119 // Information about clients
4121 for(core::map<u16, RemoteClient*>::Iterator
4122 i = m_clients.getIterator();
4123 i.atEnd() == false; i++)
4125 // Get client and check that it is valid
4126 RemoteClient *client = i.getNode()->getValue();
4127 assert(client->peer_id == i.getNode()->getKey());
4128 if(client->serialization_version == SER_FMT_VER_INVALID)
4131 Player *player = m_env.getPlayer(client->peer_id);
4132 // Get name of player
4133 std::wstring name = L"unknown";
4135 name = narrow_to_wide(player->getName());
4136 // Add name to information string
4140 if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
4141 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4142 if(g_settings.get("motd") != "")
4143 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings.get("motd"));
4147 v3f findSpawnPos(ServerMap &map)
4149 //return v3f(50,50,50)*BS;
4152 s16 groundheight = 0;
4155 nodepos = v2s16(0,0);
4160 // Try to find a good place a few times
4161 for(s32 i=0; i<1000; i++)
4164 // We're going to try to throw the player to this position
4165 nodepos = v2s16(-range + (myrand()%(range*2)),
4166 -range + (myrand()%(range*2)));
4167 v2s16 sectorpos = getNodeSectorPos(nodepos);
4168 // Get sector (NOTE: Don't get because it's slow)
4169 //m_env.getMap().emergeSector(sectorpos);
4170 // Get ground height at point (fallbacks to heightmap function)
4171 groundheight = map.findGroundLevel(nodepos);
4172 // Don't go underwater
4173 if(groundheight < WATER_LEVEL)
4175 //dstream<<"-> Underwater"<<std::endl;
4178 // Don't go to high places
4179 if(groundheight > WATER_LEVEL + 4)
4181 //dstream<<"-> Underwater"<<std::endl;
4185 // Found a good place
4186 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4191 // If no suitable place was not found, go above water at least.
4192 if(groundheight < WATER_LEVEL)
4193 groundheight = WATER_LEVEL;
4195 return intToFloat(v3s16(
4202 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4205 Try to get an existing player
4207 Player *player = m_env.getPlayer(name);
4210 // If player is already connected, cancel
4211 if(player->peer_id != 0)
4213 dstream<<"emergePlayer(): Player already connected"<<std::endl;
4218 player->peer_id = peer_id;
4220 // Reset inventory to creative if in creative mode
4221 if(g_settings.getBool("creative_mode"))
4223 // Warning: double code below
4224 // Backup actual inventory
4225 player->inventory_backup = new Inventory();
4226 *(player->inventory_backup) = player->inventory;
4227 // Set creative inventory
4228 craft_set_creative_inventory(player);
4235 If player with the wanted peer_id already exists, cancel.
4237 if(m_env.getPlayer(peer_id) != NULL)
4239 dstream<<"emergePlayer(): Player with wrong name but same"
4240 " peer_id already exists"<<std::endl;
4248 player = new ServerRemotePlayer();
4249 //player->peer_id = c.peer_id;
4250 //player->peer_id = PEER_ID_INEXISTENT;
4251 player->peer_id = peer_id;
4252 player->updateName(name);
4253 m_authmanager.add(name);
4254 m_authmanager.setPassword(name, password);
4255 m_authmanager.setPrivs(name,
4256 stringToPrivs(g_settings.get("default_privs")));
4262 dstream<<"Server: Finding spawn place for player \""
4263 <<player->getName()<<"\""<<std::endl;
4265 v3f pos = findSpawnPos(m_env.getServerMap());
4267 player->setPosition(pos);
4270 Add player to environment
4273 m_env.addPlayer(player);
4276 Add stuff to inventory
4279 if(g_settings.getBool("creative_mode"))
4281 // Warning: double code above
4282 // Backup actual inventory
4283 player->inventory_backup = new Inventory();
4284 *(player->inventory_backup) = player->inventory;
4285 // Set creative inventory
4286 craft_set_creative_inventory(player);
4288 else if(g_settings.getBool("give_initial_stuff"))
4290 craft_give_initial_stuff(player);
4295 } // create new player
4298 void Server::handlePeerChange(PeerChange &c)
4300 JMutexAutoLock envlock(m_env_mutex);
4301 JMutexAutoLock conlock(m_con_mutex);
4303 if(c.type == PEER_ADDED)
4310 core::map<u16, RemoteClient*>::Node *n;
4311 n = m_clients.find(c.peer_id);
4312 // The client shouldn't already exist
4316 RemoteClient *client = new RemoteClient();
4317 client->peer_id = c.peer_id;
4318 m_clients.insert(client->peer_id, client);
4321 else if(c.type == PEER_REMOVED)
4328 core::map<u16, RemoteClient*>::Node *n;
4329 n = m_clients.find(c.peer_id);
4330 // The client should exist
4334 Mark objects to be not known by the client
4336 RemoteClient *client = n->getValue();
4338 for(core::map<u16, bool>::Iterator
4339 i = client->m_known_objects.getIterator();
4340 i.atEnd()==false; i++)
4343 u16 id = i.getNode()->getKey();
4344 ServerActiveObject* obj = m_env.getActiveObject(id);
4346 if(obj && obj->m_known_by_count > 0)
4347 obj->m_known_by_count--;
4350 // Collect information about leaving in chat
4351 std::wstring message;
4353 std::wstring name = L"unknown";
4354 Player *player = m_env.getPlayer(c.peer_id);
4356 name = narrow_to_wide(player->getName());
4360 message += L" left game";
4362 message += L" (timed out)";
4367 m_env.removePlayer(c.peer_id);
4370 // Set player client disconnected
4372 Player *player = m_env.getPlayer(c.peer_id);
4374 player->peer_id = 0;
4378 delete m_clients[c.peer_id];
4379 m_clients.remove(c.peer_id);
4381 // Send player info to all remaining clients
4384 // Send leave chat message to all remaining clients
4385 BroadcastChatMessage(message);
4394 void Server::handlePeerChanges()
4396 while(m_peer_change_queue.size() > 0)
4398 PeerChange c = m_peer_change_queue.pop_front();
4400 dout_server<<"Server: Handling peer change: "
4401 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4404 handlePeerChange(c);
4408 u64 Server::getPlayerPrivs(Player *player)
4412 std::string playername = player->getName();
4413 // Local player gets all privileges regardless of
4414 // what's set on their account.
4415 if(g_settings.get("name") == playername)
4421 return getPlayerAuthPrivs(playername);
4425 void dedicated_server_loop(Server &server, bool &kill)
4427 DSTACK(__FUNCTION_NAME);
4429 dstream<<DTIME<<std::endl;
4430 dstream<<"========================"<<std::endl;
4431 dstream<<"Running dedicated server"<<std::endl;
4432 dstream<<"========================"<<std::endl;
4435 IntervalLimiter m_profiler_interval;
4439 // This is kind of a hack but can be done like this
4440 // because server.step() is very light
4442 ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4447 if(server.getShutdownRequested() || kill)
4449 dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4456 float profiler_print_interval =
4457 g_settings.getFloat("profiler_print_interval");
4458 if(profiler_print_interval != 0)
4460 if(m_profiler_interval.step(0.030, profiler_print_interval))
4462 dstream<<"Profiler:"<<std::endl;
4463 g_profiler.print(dstream);
4471 static int counter = 0;
4477 core::list<PlayerInfo> list = server.getPlayerInfo();
4478 core::list<PlayerInfo>::Iterator i;
4479 static u32 sum_old = 0;
4480 u32 sum = PIChecksum(list);
4483 dstream<<DTIME<<"Player info:"<<std::endl;
4484 for(i=list.begin(); i!=list.end(); i++)
4486 i->PrintLine(&dstream);