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"
43 #include "scriptapi.h"
45 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
47 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
49 class MapEditEventIgnorer
52 MapEditEventIgnorer(bool *flag):
61 ~MapEditEventIgnorer()
74 void * ServerThread::Thread()
78 log_register_thread("ServerThread");
80 DSTACK(__FUNCTION_NAME);
82 BEGIN_DEBUG_EXCEPTION_HANDLER
87 //TimeTaker timer("AsyncRunStep() + Receive()");
90 //TimeTaker timer("AsyncRunStep()");
91 m_server->AsyncRunStep();
94 //infostream<<"Running m_server->Receive()"<<std::endl;
97 catch(con::NoIncomingDataException &e)
100 catch(con::PeerNotFoundException &e)
102 infostream<<"Server: PeerNotFoundException"<<std::endl;
106 END_DEBUG_EXCEPTION_HANDLER(errorstream)
111 void * EmergeThread::Thread()
115 log_register_thread("EmergeThread");
117 DSTACK(__FUNCTION_NAME);
119 BEGIN_DEBUG_EXCEPTION_HANDLER
121 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
124 Get block info from queue, emerge them and send them
127 After queue is empty, exit.
131 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
135 SharedPtr<QueuedBlockEmerge> q(qptr);
141 Do not generate over-limit
143 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
144 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
145 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
146 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
147 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
148 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
151 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
153 //TimeTaker timer("block emerge");
156 Try to emerge it from somewhere.
158 If it is only wanted as optional, only loading from disk
163 Check if any peer wants it as non-optional. In that case it
166 Also decrement the emerge queue count in clients.
169 bool only_from_disk = true;
172 core::map<u16, u8>::Iterator i;
173 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
175 //u16 peer_id = i.getNode()->getKey();
178 u8 flags = i.getNode()->getValue();
179 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
180 only_from_disk = false;
185 if(enable_mapgen_debug_info)
186 infostream<<"EmergeThread: p="
187 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
188 <<"only_from_disk="<<only_from_disk<<std::endl;
190 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
192 //core::map<v3s16, MapBlock*> changed_blocks;
193 //core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
195 MapBlock *block = NULL;
196 bool got_block = true;
197 core::map<v3s16, MapBlock*> modified_blocks;
200 Fetch block from map or generate a single block
203 JMutexAutoLock envlock(m_server->m_env_mutex);
205 // Load sector if it isn't loaded
206 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
207 //map.loadSectorFull(p2d);
208 map.loadSectorMeta(p2d);
210 block = map.getBlockNoCreateNoEx(p);
211 if(!block || block->isDummy() || !block->isGenerated())
213 if(enable_mapgen_debug_info)
214 infostream<<"EmergeThread: not in memory, loading"<<std::endl;
216 // Get, load or create sector
217 /*ServerMapSector *sector =
218 (ServerMapSector*)map.createSector(p2d);*/
220 // Load/generate block
222 /*block = map.emergeBlock(p, sector, changed_blocks,
223 lighting_invalidated_blocks);*/
225 block = map.loadBlock(p);
227 if(only_from_disk == false)
229 if(block == NULL || block->isGenerated() == false)
231 if(enable_mapgen_debug_info)
232 infostream<<"EmergeThread: generating"<<std::endl;
233 block = map.generateBlock(p, modified_blocks);
237 if(enable_mapgen_debug_info)
238 infostream<<"EmergeThread: ended up with: "
239 <<analyze_block(block)<<std::endl;
248 Ignore map edit events, they will not need to be
249 sent to anybody because the block hasn't been sent
252 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
254 // Activate objects and stuff
255 m_server->m_env->activateBlock(block, 3600);
260 /*if(block->getLightingExpired()){
261 lighting_invalidated_blocks[block->getPos()] = block;
265 // TODO: Some additional checking and lighting updating,
270 JMutexAutoLock envlock(m_server->m_env_mutex);
275 Collect a list of blocks that have been modified in
276 addition to the fetched one.
280 if(lighting_invalidated_blocks.size() > 0)
282 /*infostream<<"lighting "<<lighting_invalidated_blocks.size()
283 <<" blocks"<<std::endl;*/
285 // 50-100ms for single block generation
286 //TimeTaker timer("** EmergeThread updateLighting");
288 // Update lighting without locking the environment mutex,
289 // add modified blocks to changed blocks
290 map.updateLighting(lighting_invalidated_blocks, modified_blocks);
293 // Add all from changed_blocks to modified_blocks
294 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
295 i.atEnd() == false; i++)
297 MapBlock *block = i.getNode()->getValue();
298 modified_blocks.insert(block->getPos(), block);
302 // If we got no block, there should be no invalidated blocks
305 //assert(lighting_invalidated_blocks.size() == 0);
311 Set sent status of modified blocks on clients
314 // NOTE: Server's clients are also behind the connection mutex
315 JMutexAutoLock lock(m_server->m_con_mutex);
318 Add the originally fetched block to the modified list
322 modified_blocks.insert(p, block);
326 Set the modified blocks unsent for all the clients
329 for(core::map<u16, RemoteClient*>::Iterator
330 i = m_server->m_clients.getIterator();
331 i.atEnd() == false; i++)
333 RemoteClient *client = i.getNode()->getValue();
335 if(modified_blocks.size() > 0)
337 // Remove block from sent history
338 client->SetBlocksNotSent(modified_blocks);
344 END_DEBUG_EXCEPTION_HANDLER(errorstream)
349 void RemoteClient::GetNextBlocks(Server *server, float dtime,
350 core::array<PrioritySortedBlockTransfer> &dest)
352 DSTACK(__FUNCTION_NAME);
355 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
358 m_nothing_to_send_pause_timer -= dtime;
359 m_nearest_unsent_reset_timer += dtime;
361 if(m_nothing_to_send_pause_timer >= 0)
366 // Won't send anything if already sending
367 if(m_blocks_sending.size() >= g_settings->getU16
368 ("max_simultaneous_block_sends_per_client"))
370 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
374 //TimeTaker timer("RemoteClient::GetNextBlocks");
376 Player *player = server->m_env->getPlayer(peer_id);
378 assert(player != NULL);
380 v3f playerpos = player->getPosition();
381 v3f playerspeed = player->getSpeed();
382 v3f playerspeeddir(0,0,0);
383 if(playerspeed.getLength() > 1.0*BS)
384 playerspeeddir = playerspeed / playerspeed.getLength();
385 // Predict to next block
386 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
388 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
390 v3s16 center = getNodeBlockPos(center_nodepos);
392 // Camera position and direction
393 v3f camera_pos = player->getEyePosition();
394 v3f camera_dir = v3f(0,0,1);
395 camera_dir.rotateYZBy(player->getPitch());
396 camera_dir.rotateXZBy(player->getYaw());
398 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
399 <<camera_dir.Z<<")"<<std::endl;*/
402 Get the starting value of the block finder radius.
405 if(m_last_center != center)
407 m_nearest_unsent_d = 0;
408 m_last_center = center;
411 /*infostream<<"m_nearest_unsent_reset_timer="
412 <<m_nearest_unsent_reset_timer<<std::endl;*/
414 // Reset periodically to workaround for some bugs or stuff
415 if(m_nearest_unsent_reset_timer > 20.0)
417 m_nearest_unsent_reset_timer = 0;
418 m_nearest_unsent_d = 0;
419 //infostream<<"Resetting m_nearest_unsent_d for "
420 // <<server->getPlayerName(peer_id)<<std::endl;
423 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
424 s16 d_start = m_nearest_unsent_d;
426 //infostream<<"d_start="<<d_start<<std::endl;
428 u16 max_simul_sends_setting = g_settings->getU16
429 ("max_simultaneous_block_sends_per_client");
430 u16 max_simul_sends_usually = max_simul_sends_setting;
433 Check the time from last addNode/removeNode.
435 Decrease send rate if player is building stuff.
437 m_time_from_building += dtime;
438 if(m_time_from_building < g_settings->getFloat(
439 "full_block_send_enable_min_time_from_building"))
441 max_simul_sends_usually
442 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
446 Number of blocks sending + number of blocks selected for sending
448 u32 num_blocks_selected = m_blocks_sending.size();
451 next time d will be continued from the d from which the nearest
452 unsent block was found this time.
454 This is because not necessarily any of the blocks found this
455 time are actually sent.
457 s32 new_nearest_unsent_d = -1;
459 s16 d_max = g_settings->getS16("max_block_send_distance");
460 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
462 // Don't loop very much at a time
463 s16 max_d_increment_at_time = 2;
464 if(d_max > d_start + max_d_increment_at_time)
465 d_max = d_start + max_d_increment_at_time;
466 /*if(d_max_gen > d_start+2)
467 d_max_gen = d_start+2;*/
469 //infostream<<"Starting from "<<d_start<<std::endl;
471 s32 nearest_emerged_d = -1;
472 s32 nearest_emergefull_d = -1;
473 s32 nearest_sent_d = -1;
474 bool queue_is_full = false;
477 for(d = d_start; d <= d_max; d++)
479 /*errorstream<<"checking d="<<d<<" for "
480 <<server->getPlayerName(peer_id)<<std::endl;*/
481 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
484 If m_nearest_unsent_d was changed by the EmergeThread
485 (it can change it to 0 through SetBlockNotSent),
487 Else update m_nearest_unsent_d
489 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
491 d = m_nearest_unsent_d;
492 last_nearest_unsent_d = m_nearest_unsent_d;
496 Get the border/face dot coordinates of a "d-radiused"
499 core::list<v3s16> list;
500 getFacePositions(list, d);
502 core::list<v3s16>::Iterator li;
503 for(li=list.begin(); li!=list.end(); li++)
505 v3s16 p = *li + center;
509 - Don't allow too many simultaneous transfers
510 - EXCEPT when the blocks are very close
512 Also, don't send blocks that are already flying.
515 // Start with the usual maximum
516 u16 max_simul_dynamic = max_simul_sends_usually;
518 // If block is very close, allow full maximum
519 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
520 max_simul_dynamic = max_simul_sends_setting;
522 // Don't select too many blocks for sending
523 if(num_blocks_selected >= max_simul_dynamic)
525 queue_is_full = true;
526 goto queue_full_break;
529 // Don't send blocks that are currently being transferred
530 if(m_blocks_sending.find(p) != NULL)
536 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
537 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
538 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
539 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
540 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
541 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
544 // If this is true, inexistent block will be made from scratch
545 bool generate = d <= d_max_gen;
548 /*// Limit the generating area vertically to 2/3
549 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
552 // Limit the send area vertically to 1/2
553 if(abs(p.Y - center.Y) > d_max / 2)
559 If block is far away, don't generate it unless it is
565 // Block center y in nodes
566 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
567 // Don't generate if it's very high or very low
568 if(y < -64 || y > 64)
572 v2s16 p2d_nodes_center(
576 // Get ground height in nodes
577 s16 gh = server->m_env->getServerMap().findGroundLevel(
580 // If differs a lot, don't generate
581 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
583 // Actually, don't even send it
589 //infostream<<"d="<<d<<std::endl;
592 Don't generate or send if not in sight
593 FIXME This only works if the client uses a small enough
594 FOV setting. The default of 72 degrees is fine.
597 float camera_fov = (72.0*PI/180) * 4./3.;
598 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
604 Don't send already sent blocks
607 if(m_blocks_sent.find(p) != NULL)
614 Check if map has this block
616 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
618 bool surely_not_found_on_disk = false;
619 bool block_is_invalid = false;
622 // Reset usage timer, this block will be of use in the future.
623 block->resetUsageTimer();
625 // Block is dummy if data doesn't exist.
626 // It means it has been not found from disk and not generated
629 surely_not_found_on_disk = true;
632 // Block is valid if lighting is up-to-date and data exists
633 if(block->isValid() == false)
635 block_is_invalid = true;
638 /*if(block->isFullyGenerated() == false)
640 block_is_invalid = true;
645 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
646 v2s16 chunkpos = map->sector_to_chunk(p2d);
647 if(map->chunkNonVolatile(chunkpos) == false)
648 block_is_invalid = true;
650 if(block->isGenerated() == false)
651 block_is_invalid = true;
654 If block is not close, don't send it unless it is near
657 Block is near ground level if night-time mesh
658 differs from day-time mesh.
662 if(block->dayNightDiffed() == false)
669 If block has been marked to not exist on disk (dummy)
670 and generating new ones is not wanted, skip block.
672 if(generate == false && surely_not_found_on_disk == true)
679 Add inexistent block to emerge queue.
681 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
683 //TODO: Get value from somewhere
684 // Allow only one block in emerge queue
685 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
686 // Allow two blocks in queue per client
687 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
688 if(server->m_emerge_queue.peerItemCount(peer_id) < 25)
690 //infostream<<"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();
701 if(nearest_emerged_d == -1)
702 nearest_emerged_d = d;
704 if(nearest_emergefull_d == -1)
705 nearest_emergefull_d = d;
712 if(nearest_sent_d == -1)
716 Add block to send queue
719 /*errorstream<<"sending from d="<<d<<" to "
720 <<server->getPlayerName(peer_id)<<std::endl;*/
722 PrioritySortedBlockTransfer q((float)d, p, peer_id);
726 num_blocks_selected += 1;
731 //infostream<<"Stopped at "<<d<<std::endl;
733 // If nothing was found for sending and nothing was queued for
734 // emerging, continue next time browsing from here
735 if(nearest_emerged_d != -1){
736 new_nearest_unsent_d = nearest_emerged_d;
737 } else if(nearest_emergefull_d != -1){
738 new_nearest_unsent_d = nearest_emergefull_d;
740 if(d > g_settings->getS16("max_block_send_distance")){
741 new_nearest_unsent_d = 0;
742 m_nothing_to_send_pause_timer = 2.0;
743 /*infostream<<"GetNextBlocks(): d wrapped around for "
744 <<server->getPlayerName(peer_id)
745 <<"; setting to 0 and pausing"<<std::endl;*/
747 if(nearest_sent_d != -1)
748 new_nearest_unsent_d = nearest_sent_d;
750 new_nearest_unsent_d = d;
754 if(new_nearest_unsent_d != -1)
755 m_nearest_unsent_d = new_nearest_unsent_d;
757 /*timer_result = timer.stop(true);
758 if(timer_result != 0)
759 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
762 void RemoteClient::SendObjectData(
765 core::map<v3s16, bool> &stepped_blocks
768 DSTACK(__FUNCTION_NAME);
770 // Can't send anything without knowing version
771 if(serialization_version == SER_FMT_VER_INVALID)
773 infostream<<"RemoteClient::SendObjectData(): Not sending, no version."
779 Send a TOCLIENT_OBJECTDATA packet.
783 u16 number of player positions
795 std::ostringstream os(std::ios_base::binary);
799 writeU16(buf, TOCLIENT_OBJECTDATA);
800 os.write((char*)buf, 2);
803 Get and write player data
806 // Get connected players
807 core::list<Player*> players = server->m_env->getPlayers(true);
809 // Write player count
810 u16 playercount = players.size();
811 writeU16(buf, playercount);
812 os.write((char*)buf, 2);
814 core::list<Player*>::Iterator i;
815 for(i = players.begin();
816 i != players.end(); i++)
820 v3f pf = player->getPosition();
821 v3f sf = player->getSpeed();
823 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
824 v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
825 s32 pitch_i (player->getPitch() * 100);
826 s32 yaw_i (player->getYaw() * 100);
828 writeU16(buf, player->peer_id);
829 os.write((char*)buf, 2);
830 writeV3S32(buf, position_i);
831 os.write((char*)buf, 12);
832 writeV3S32(buf, speed_i);
833 os.write((char*)buf, 12);
834 writeS32(buf, pitch_i);
835 os.write((char*)buf, 4);
836 writeS32(buf, yaw_i);
837 os.write((char*)buf, 4);
841 Get and write object data (dummy, for compatibility)
846 os.write((char*)buf, 2);
852 //infostream<<"Server: Sending object data to "<<peer_id<<std::endl;
855 std::string s = os.str();
856 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
857 // Send as unreliable
858 server->m_con.Send(peer_id, 0, data, false);
861 void RemoteClient::GotBlock(v3s16 p)
863 if(m_blocks_sending.find(p) != NULL)
864 m_blocks_sending.remove(p);
867 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
868 " m_blocks_sending"<<std::endl;*/
869 m_excess_gotblocks++;
871 m_blocks_sent.insert(p, true);
874 void RemoteClient::SentBlock(v3s16 p)
876 if(m_blocks_sending.find(p) == NULL)
877 m_blocks_sending.insert(p, 0.0);
879 infostream<<"RemoteClient::SentBlock(): Sent block"
880 " already in m_blocks_sending"<<std::endl;
883 void RemoteClient::SetBlockNotSent(v3s16 p)
885 m_nearest_unsent_d = 0;
887 if(m_blocks_sending.find(p) != NULL)
888 m_blocks_sending.remove(p);
889 if(m_blocks_sent.find(p) != NULL)
890 m_blocks_sent.remove(p);
893 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
895 m_nearest_unsent_d = 0;
897 for(core::map<v3s16, MapBlock*>::Iterator
898 i = blocks.getIterator();
899 i.atEnd()==false; i++)
901 v3s16 p = i.getNode()->getKey();
903 if(m_blocks_sending.find(p) != NULL)
904 m_blocks_sending.remove(p);
905 if(m_blocks_sent.find(p) != NULL)
906 m_blocks_sent.remove(p);
914 PlayerInfo::PlayerInfo()
920 void PlayerInfo::PrintLine(std::ostream *s)
923 (*s)<<"\""<<name<<"\" ("
924 <<(position.X/10)<<","<<(position.Y/10)
925 <<","<<(position.Z/10)<<") ";
927 (*s)<<" avg_rtt="<<avg_rtt;
931 u32 PIChecksum(core::list<PlayerInfo> &l)
933 core::list<PlayerInfo>::Iterator i;
936 for(i=l.begin(); i!=l.end(); i++)
938 checksum += a * (i->id+1);
939 checksum ^= 0x435aafcd;
950 std::string mapsavedir,
951 std::string configpath
954 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
955 m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"),
956 m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"),
960 m_emergethread(this),
962 m_time_of_day_send_timer(0),
964 m_mapsavedir(mapsavedir),
965 m_configpath(configpath),
966 m_shutdown_requested(false),
967 m_ignore_map_edit_events(false),
968 m_ignore_map_edit_events_peer_id(0)
970 m_liquid_transform_timer = 0.0;
971 m_print_info_timer = 0.0;
972 m_objectdata_timer = 0.0;
973 m_emergethread_trigger_timer = 0.0;
974 m_savemap_timer = 0.0;
978 m_step_dtime_mutex.Init();
981 JMutexAutoLock envlock(m_env_mutex);
982 JMutexAutoLock conlock(m_con_mutex);
984 // Initialize scripting
986 infostream<<"Server: Initializing scripting"<<std::endl;
987 m_lua = script_init();
990 scriptapi_export(m_lua, this);
991 // Load and run scripts
992 script_load(m_lua, (porting::path_data + DIR_DELIM + "scripts"
993 + DIR_DELIM + "default.lua").c_str());
995 // Initialize Environment
997 m_env = new ServerEnvironment(new ServerMap(mapsavedir), m_lua);
999 // Register us to receive map edit events
1000 m_env->getMap().addEventReceiver(this);
1002 // If file exists, load environment metadata
1003 if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt"))
1005 infostream<<"Server: Loading environment metadata"<<std::endl;
1006 m_env->loadMeta(m_mapsavedir);
1010 infostream<<"Server: Loading players"<<std::endl;
1011 m_env->deSerializePlayers(m_mapsavedir);
1016 infostream<<"Server::~Server()"<<std::endl;
1019 Send shutdown message
1022 JMutexAutoLock conlock(m_con_mutex);
1024 std::wstring line = L"*** Server shutting down";
1027 Send the message to clients
1029 for(core::map<u16, RemoteClient*>::Iterator
1030 i = m_clients.getIterator();
1031 i.atEnd() == false; i++)
1033 // Get client and check that it is valid
1034 RemoteClient *client = i.getNode()->getValue();
1035 assert(client->peer_id == i.getNode()->getKey());
1036 if(client->serialization_version == SER_FMT_VER_INVALID)
1040 SendChatMessage(client->peer_id, line);
1042 catch(con::PeerNotFoundException &e)
1048 JMutexAutoLock envlock(m_env_mutex);
1053 infostream<<"Server: Saving players"<<std::endl;
1054 m_env->serializePlayers(m_mapsavedir);
1057 Save environment metadata
1059 infostream<<"Server: Saving environment metadata"<<std::endl;
1060 m_env->saveMeta(m_mapsavedir);
1072 JMutexAutoLock clientslock(m_con_mutex);
1074 for(core::map<u16, RemoteClient*>::Iterator
1075 i = m_clients.getIterator();
1076 i.atEnd() == false; i++)
1079 // NOTE: These are removed by env destructor
1081 u16 peer_id = i.getNode()->getKey();
1082 JMutexAutoLock envlock(m_env_mutex);
1083 m_env->removePlayer(peer_id);
1087 delete i.getNode()->getValue();
1091 // Delete Environment
1094 // Deinitialize scripting
1095 infostream<<"Server: Deinitializing scripting"<<std::endl;
1096 script_deinit(m_lua);
1099 void Server::start(unsigned short port)
1101 DSTACK(__FUNCTION_NAME);
1102 // Stop thread if already running
1105 // Initialize connection
1106 m_con.SetTimeoutMs(30);
1110 m_thread.setRun(true);
1113 infostream<<"Server: Started on port "<<port<<std::endl;
1118 DSTACK(__FUNCTION_NAME);
1120 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1122 // Stop threads (set run=false first so both start stopping)
1123 m_thread.setRun(false);
1124 m_emergethread.setRun(false);
1126 m_emergethread.stop();
1128 infostream<<"Server: Threads stopped"<<std::endl;
1131 void Server::step(float dtime)
1133 DSTACK(__FUNCTION_NAME);
1138 JMutexAutoLock lock(m_step_dtime_mutex);
1139 m_step_dtime += dtime;
1143 void Server::AsyncRunStep()
1145 DSTACK(__FUNCTION_NAME);
1147 g_profiler->add("Server::AsyncRunStep (num)", 1);
1151 JMutexAutoLock lock1(m_step_dtime_mutex);
1152 dtime = m_step_dtime;
1156 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
1157 // Send blocks to clients
1164 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1166 //infostream<<"Server steps "<<dtime<<std::endl;
1167 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1170 JMutexAutoLock lock1(m_step_dtime_mutex);
1171 m_step_dtime -= dtime;
1178 m_uptime.set(m_uptime.get() + dtime);
1182 // Process connection's timeouts
1183 JMutexAutoLock lock2(m_con_mutex);
1184 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1185 m_con.RunTimeouts(dtime);
1189 // This has to be called so that the client list gets synced
1190 // with the peer list of the connection
1191 handlePeerChanges();
1195 Update m_time_of_day and overall game time
1198 JMutexAutoLock envlock(m_env_mutex);
1200 m_time_counter += dtime;
1201 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1202 u32 units = (u32)(m_time_counter*speed);
1203 m_time_counter -= (f32)units / speed;
1205 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1207 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1210 Send to clients at constant intervals
1213 m_time_of_day_send_timer -= dtime;
1214 if(m_time_of_day_send_timer < 0.0)
1216 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1218 //JMutexAutoLock envlock(m_env_mutex);
1219 JMutexAutoLock conlock(m_con_mutex);
1221 for(core::map<u16, RemoteClient*>::Iterator
1222 i = m_clients.getIterator();
1223 i.atEnd() == false; i++)
1225 RemoteClient *client = i.getNode()->getValue();
1226 //Player *player = m_env->getPlayer(client->peer_id);
1228 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1229 m_env->getTimeOfDay());
1231 m_con.Send(client->peer_id, 0, data, true);
1237 JMutexAutoLock lock(m_env_mutex);
1239 ScopeProfiler sp(g_profiler, "SEnv step");
1240 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1244 const float map_timer_and_unload_dtime = 5.15;
1245 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1247 JMutexAutoLock lock(m_env_mutex);
1248 // Run Map's timers and unload unused data
1249 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1250 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1251 g_settings->getFloat("server_unload_unused_data_timeout"));
1261 m_liquid_transform_timer += dtime;
1262 if(m_liquid_transform_timer >= 1.00)
1264 m_liquid_transform_timer -= 1.00;
1266 JMutexAutoLock lock(m_env_mutex);
1268 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1270 core::map<v3s16, MapBlock*> modified_blocks;
1271 m_env->getMap().transformLiquids(modified_blocks);
1276 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1277 ServerMap &map = ((ServerMap&)m_env->getMap());
1278 map.updateLighting(modified_blocks, lighting_modified_blocks);
1280 // Add blocks modified by lighting to modified_blocks
1281 for(core::map<v3s16, MapBlock*>::Iterator
1282 i = lighting_modified_blocks.getIterator();
1283 i.atEnd() == false; i++)
1285 MapBlock *block = i.getNode()->getValue();
1286 modified_blocks.insert(block->getPos(), block);
1290 Set the modified blocks unsent for all the clients
1293 JMutexAutoLock lock2(m_con_mutex);
1295 for(core::map<u16, RemoteClient*>::Iterator
1296 i = m_clients.getIterator();
1297 i.atEnd() == false; i++)
1299 RemoteClient *client = i.getNode()->getValue();
1301 if(modified_blocks.size() > 0)
1303 // Remove block from sent history
1304 client->SetBlocksNotSent(modified_blocks);
1309 // Periodically print some info
1311 float &counter = m_print_info_timer;
1317 JMutexAutoLock lock2(m_con_mutex);
1319 if(m_clients.size() != 0)
1320 infostream<<"Players:"<<std::endl;
1321 for(core::map<u16, RemoteClient*>::Iterator
1322 i = m_clients.getIterator();
1323 i.atEnd() == false; i++)
1325 //u16 peer_id = i.getNode()->getKey();
1326 RemoteClient *client = i.getNode()->getValue();
1327 Player *player = m_env->getPlayer(client->peer_id);
1330 infostream<<"* "<<player->getName()<<"\t";
1331 client->PrintInfo(infostream);
1336 //if(g_settings->getBool("enable_experimental"))
1340 Check added and deleted active objects
1343 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1344 JMutexAutoLock envlock(m_env_mutex);
1345 JMutexAutoLock conlock(m_con_mutex);
1347 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1349 // Radius inside which objects are active
1350 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1351 radius *= MAP_BLOCKSIZE;
1353 for(core::map<u16, RemoteClient*>::Iterator
1354 i = m_clients.getIterator();
1355 i.atEnd() == false; i++)
1357 RemoteClient *client = i.getNode()->getValue();
1358 Player *player = m_env->getPlayer(client->peer_id);
1361 // This can happen if the client timeouts somehow
1362 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1364 <<" has no associated player"<<std::endl;*/
1367 v3s16 pos = floatToInt(player->getPosition(), BS);
1369 core::map<u16, bool> removed_objects;
1370 core::map<u16, bool> added_objects;
1371 m_env->getRemovedActiveObjects(pos, radius,
1372 client->m_known_objects, removed_objects);
1373 m_env->getAddedActiveObjects(pos, radius,
1374 client->m_known_objects, added_objects);
1376 // Ignore if nothing happened
1377 if(removed_objects.size() == 0 && added_objects.size() == 0)
1379 //infostream<<"active objects: none changed"<<std::endl;
1383 std::string data_buffer;
1387 // Handle removed objects
1388 writeU16((u8*)buf, removed_objects.size());
1389 data_buffer.append(buf, 2);
1390 for(core::map<u16, bool>::Iterator
1391 i = removed_objects.getIterator();
1392 i.atEnd()==false; i++)
1395 u16 id = i.getNode()->getKey();
1396 ServerActiveObject* obj = m_env->getActiveObject(id);
1398 // Add to data buffer for sending
1399 writeU16((u8*)buf, i.getNode()->getKey());
1400 data_buffer.append(buf, 2);
1402 // Remove from known objects
1403 client->m_known_objects.remove(i.getNode()->getKey());
1405 if(obj && obj->m_known_by_count > 0)
1406 obj->m_known_by_count--;
1409 // Handle added objects
1410 writeU16((u8*)buf, added_objects.size());
1411 data_buffer.append(buf, 2);
1412 for(core::map<u16, bool>::Iterator
1413 i = added_objects.getIterator();
1414 i.atEnd()==false; i++)
1417 u16 id = i.getNode()->getKey();
1418 ServerActiveObject* obj = m_env->getActiveObject(id);
1421 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1423 infostream<<"WARNING: "<<__FUNCTION_NAME
1424 <<": NULL object"<<std::endl;
1426 type = obj->getType();
1428 // Add to data buffer for sending
1429 writeU16((u8*)buf, id);
1430 data_buffer.append(buf, 2);
1431 writeU8((u8*)buf, type);
1432 data_buffer.append(buf, 1);
1435 data_buffer.append(serializeLongString(
1436 obj->getClientInitializationData()));
1438 data_buffer.append(serializeLongString(""));
1440 // Add to known objects
1441 client->m_known_objects.insert(i.getNode()->getKey(), false);
1444 obj->m_known_by_count++;
1448 SharedBuffer<u8> reply(2 + data_buffer.size());
1449 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1450 memcpy((char*)&reply[2], data_buffer.c_str(),
1451 data_buffer.size());
1453 m_con.Send(client->peer_id, 0, reply, true);
1455 infostream<<"Server: Sent object remove/add: "
1456 <<removed_objects.size()<<" removed, "
1457 <<added_objects.size()<<" added, "
1458 <<"packet size is "<<reply.getSize()<<std::endl;
1463 Collect a list of all the objects known by the clients
1464 and report it back to the environment.
1467 core::map<u16, bool> all_known_objects;
1469 for(core::map<u16, RemoteClient*>::Iterator
1470 i = m_clients.getIterator();
1471 i.atEnd() == false; i++)
1473 RemoteClient *client = i.getNode()->getValue();
1474 // Go through all known objects of client
1475 for(core::map<u16, bool>::Iterator
1476 i = client->m_known_objects.getIterator();
1477 i.atEnd()==false; i++)
1479 u16 id = i.getNode()->getKey();
1480 all_known_objects[id] = true;
1484 m_env->setKnownActiveObjects(whatever);
1490 Send object messages
1493 JMutexAutoLock envlock(m_env_mutex);
1494 JMutexAutoLock conlock(m_con_mutex);
1496 //ScopeProfiler sp(g_profiler, "Server: sending object messages");
1499 // Value = data sent by object
1500 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1502 // Get active object messages from environment
1505 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1509 core::list<ActiveObjectMessage>* message_list = NULL;
1510 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1511 n = buffered_messages.find(aom.id);
1514 message_list = new core::list<ActiveObjectMessage>;
1515 buffered_messages.insert(aom.id, message_list);
1519 message_list = n->getValue();
1521 message_list->push_back(aom);
1524 // Route data to every client
1525 for(core::map<u16, RemoteClient*>::Iterator
1526 i = m_clients.getIterator();
1527 i.atEnd()==false; i++)
1529 RemoteClient *client = i.getNode()->getValue();
1530 std::string reliable_data;
1531 std::string unreliable_data;
1532 // Go through all objects in message buffer
1533 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1534 j = buffered_messages.getIterator();
1535 j.atEnd()==false; j++)
1537 // If object is not known by client, skip it
1538 u16 id = j.getNode()->getKey();
1539 if(client->m_known_objects.find(id) == NULL)
1541 // Get message list of object
1542 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1543 // Go through every message
1544 for(core::list<ActiveObjectMessage>::Iterator
1545 k = list->begin(); k != list->end(); k++)
1547 // Compose the full new data with header
1548 ActiveObjectMessage aom = *k;
1549 std::string new_data;
1552 writeU16((u8*)&buf[0], aom.id);
1553 new_data.append(buf, 2);
1555 new_data += serializeString(aom.datastring);
1556 // Add data to buffer
1558 reliable_data += new_data;
1560 unreliable_data += new_data;
1564 reliable_data and unreliable_data are now ready.
1567 if(reliable_data.size() > 0)
1569 SharedBuffer<u8> reply(2 + reliable_data.size());
1570 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1571 memcpy((char*)&reply[2], reliable_data.c_str(),
1572 reliable_data.size());
1574 m_con.Send(client->peer_id, 0, reply, true);
1576 if(unreliable_data.size() > 0)
1578 SharedBuffer<u8> reply(2 + unreliable_data.size());
1579 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1580 memcpy((char*)&reply[2], unreliable_data.c_str(),
1581 unreliable_data.size());
1582 // Send as unreliable
1583 m_con.Send(client->peer_id, 0, reply, false);
1586 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1588 infostream<<"Server: Size of object message data: "
1589 <<"reliable: "<<reliable_data.size()
1590 <<", unreliable: "<<unreliable_data.size()
1595 // Clear buffered_messages
1596 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1597 i = buffered_messages.getIterator();
1598 i.atEnd()==false; i++)
1600 delete i.getNode()->getValue();
1604 } // enable_experimental
1607 Send queued-for-sending map edit events.
1610 // Don't send too many at a time
1613 // Single change sending is disabled if queue size is not small
1614 bool disable_single_change_sending = false;
1615 if(m_unsent_map_edit_queue.size() >= 4)
1616 disable_single_change_sending = true;
1618 bool got_any_events = false;
1620 // We'll log the amount of each
1623 while(m_unsent_map_edit_queue.size() != 0)
1625 got_any_events = true;
1627 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1629 // Players far away from the change are stored here.
1630 // Instead of sending the changes, MapBlocks are set not sent
1632 core::list<u16> far_players;
1634 if(event->type == MEET_ADDNODE)
1636 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1637 prof.add("MEET_ADDNODE", 1);
1638 if(disable_single_change_sending)
1639 sendAddNode(event->p, event->n, event->already_known_by_peer,
1642 sendAddNode(event->p, event->n, event->already_known_by_peer,
1645 else if(event->type == MEET_REMOVENODE)
1647 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1648 prof.add("MEET_REMOVENODE", 1);
1649 if(disable_single_change_sending)
1650 sendRemoveNode(event->p, event->already_known_by_peer,
1653 sendRemoveNode(event->p, event->already_known_by_peer,
1656 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1658 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1659 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1660 setBlockNotSent(event->p);
1662 else if(event->type == MEET_OTHER)
1664 infostream<<"Server: MEET_OTHER"<<std::endl;
1665 prof.add("MEET_OTHER", 1);
1666 for(core::map<v3s16, bool>::Iterator
1667 i = event->modified_blocks.getIterator();
1668 i.atEnd()==false; i++)
1670 v3s16 p = i.getNode()->getKey();
1676 prof.add("unknown", 1);
1677 infostream<<"WARNING: Server: Unknown MapEditEvent "
1678 <<((u32)event->type)<<std::endl;
1682 Set blocks not sent to far players
1684 if(far_players.size() > 0)
1686 // Convert list format to that wanted by SetBlocksNotSent
1687 core::map<v3s16, MapBlock*> modified_blocks2;
1688 for(core::map<v3s16, bool>::Iterator
1689 i = event->modified_blocks.getIterator();
1690 i.atEnd()==false; i++)
1692 v3s16 p = i.getNode()->getKey();
1693 modified_blocks2.insert(p,
1694 m_env->getMap().getBlockNoCreateNoEx(p));
1696 // Set blocks not sent
1697 for(core::list<u16>::Iterator
1698 i = far_players.begin();
1699 i != far_players.end(); i++)
1702 RemoteClient *client = getClient(peer_id);
1705 client->SetBlocksNotSent(modified_blocks2);
1711 /*// Don't send too many at a time
1713 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1719 infostream<<"Server: MapEditEvents:"<<std::endl;
1720 prof.print(infostream);
1726 Send object positions
1729 float &counter = m_objectdata_timer;
1731 if(counter >= g_settings->getFloat("objectdata_interval"))
1733 JMutexAutoLock lock1(m_env_mutex);
1734 JMutexAutoLock lock2(m_con_mutex);
1736 //ScopeProfiler sp(g_profiler, "Server: sending player positions");
1738 SendObjectData(counter);
1745 Trigger emergethread (it somehow gets to a non-triggered but
1746 bysy state sometimes)
1749 float &counter = m_emergethread_trigger_timer;
1755 m_emergethread.trigger();
1759 // Save map, players and auth stuff
1761 float &counter = m_savemap_timer;
1763 if(counter >= g_settings->getFloat("server_map_save_interval"))
1767 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1770 if(m_authmanager.isModified())
1771 m_authmanager.save();
1774 if(m_banmanager.isModified())
1775 m_banmanager.save();
1778 JMutexAutoLock lock(m_env_mutex);
1780 /*// Unload unused data (delete from memory)
1781 m_env->getMap().unloadUnusedData(
1782 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1784 /*u32 deleted_count = m_env->getMap().unloadUnusedData(
1785 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1788 // Save only changed parts
1789 m_env->getMap().save(true);
1791 /*if(deleted_count > 0)
1793 infostream<<"Server: Unloaded "<<deleted_count
1794 <<" blocks from memory"<<std::endl;
1798 m_env->serializePlayers(m_mapsavedir);
1800 // Save environment metadata
1801 m_env->saveMeta(m_mapsavedir);
1806 void Server::Receive()
1808 DSTACK(__FUNCTION_NAME);
1809 SharedBuffer<u8> data;
1814 JMutexAutoLock conlock(m_con_mutex);
1815 datasize = m_con.Receive(peer_id, data);
1818 // This has to be called so that the client list gets synced
1819 // with the peer list of the connection
1820 handlePeerChanges();
1822 ProcessData(*data, datasize, peer_id);
1824 catch(con::InvalidIncomingDataException &e)
1826 infostream<<"Server::Receive(): "
1827 "InvalidIncomingDataException: what()="
1828 <<e.what()<<std::endl;
1830 catch(con::PeerNotFoundException &e)
1832 //NOTE: This is not needed anymore
1834 // The peer has been disconnected.
1835 // Find the associated player and remove it.
1837 /*JMutexAutoLock envlock(m_env_mutex);
1839 infostream<<"ServerThread: peer_id="<<peer_id
1840 <<" has apparently closed connection. "
1841 <<"Removing player."<<std::endl;
1843 m_env->removePlayer(peer_id);*/
1847 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1849 DSTACK(__FUNCTION_NAME);
1850 // Environment is locked first.
1851 JMutexAutoLock envlock(m_env_mutex);
1852 JMutexAutoLock conlock(m_con_mutex);
1855 Address address = m_con.GetPeerAddress(peer_id);
1857 // drop player if is ip is banned
1858 if(m_banmanager.isIpBanned(address.serializeString())){
1859 SendAccessDenied(m_con, peer_id,
1860 L"Your ip is banned. Banned name was "
1861 +narrow_to_wide(m_banmanager.getBanName(
1862 address.serializeString())));
1863 m_con.DeletePeer(peer_id);
1867 catch(con::PeerNotFoundException &e)
1869 infostream<<"Server::ProcessData(): Cancelling: peer "
1870 <<peer_id<<" not found"<<std::endl;
1874 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1882 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1884 if(command == TOSERVER_INIT)
1886 // [0] u16 TOSERVER_INIT
1887 // [2] u8 SER_FMT_VER_HIGHEST
1888 // [3] u8[20] player_name
1889 // [23] u8[28] password <--- can be sent without this, from old versions
1891 if(datasize < 2+1+PLAYERNAME_SIZE)
1894 infostream<<"Server: Got TOSERVER_INIT from "
1895 <<peer_id<<std::endl;
1897 // First byte after command is maximum supported
1898 // serialization version
1899 u8 client_max = data[2];
1900 u8 our_max = SER_FMT_VER_HIGHEST;
1901 // Use the highest version supported by both
1902 u8 deployed = core::min_(client_max, our_max);
1903 // If it's lower than the lowest supported, give up.
1904 if(deployed < SER_FMT_VER_LOWEST)
1905 deployed = SER_FMT_VER_INVALID;
1907 //peer->serialization_version = deployed;
1908 getClient(peer_id)->pending_serialization_version = deployed;
1910 if(deployed == SER_FMT_VER_INVALID)
1912 infostream<<"Server: Cannot negotiate "
1913 "serialization version with peer "
1914 <<peer_id<<std::endl;
1915 SendAccessDenied(m_con, peer_id,
1916 L"Your client is too old (map format)");
1921 Read and check network protocol version
1924 u16 net_proto_version = 0;
1925 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1927 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1930 getClient(peer_id)->net_proto_version = net_proto_version;
1932 if(net_proto_version == 0)
1934 SendAccessDenied(m_con, peer_id,
1935 L"Your client is too old. Please upgrade.");
1939 /* Uhh... this should actually be a warning but let's do it like this */
1940 if(g_settings->getBool("strict_protocol_version_checking"))
1942 if(net_proto_version < PROTOCOL_VERSION)
1944 SendAccessDenied(m_con, peer_id,
1945 L"Your client is too old. Please upgrade.");
1955 char playername[PLAYERNAME_SIZE];
1956 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1958 playername[i] = data[3+i];
1960 playername[PLAYERNAME_SIZE-1] = 0;
1962 if(playername[0]=='\0')
1964 infostream<<"Server: Player has empty name"<<std::endl;
1965 SendAccessDenied(m_con, peer_id,
1970 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1972 infostream<<"Server: Player has invalid name"<<std::endl;
1973 SendAccessDenied(m_con, peer_id,
1974 L"Name contains unallowed characters");
1979 char password[PASSWORD_SIZE];
1980 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1982 // old version - assume blank password
1987 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1989 password[i] = data[23+i];
1991 password[PASSWORD_SIZE-1] = 0;
1994 std::string checkpwd;
1995 if(m_authmanager.exists(playername))
1997 checkpwd = m_authmanager.getPassword(playername);
2001 checkpwd = g_settings->get("default_password");
2004 /*infostream<<"Server: Client gave password '"<<password
2005 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2007 if(password != checkpwd && m_authmanager.exists(playername))
2009 infostream<<"Server: peer_id="<<peer_id
2010 <<": supplied invalid password for "
2011 <<playername<<std::endl;
2012 SendAccessDenied(m_con, peer_id, L"Invalid password");
2016 // Add player to auth manager
2017 if(m_authmanager.exists(playername) == false)
2019 infostream<<"Server: adding player "<<playername
2020 <<" to auth manager"<<std::endl;
2021 m_authmanager.add(playername);
2022 m_authmanager.setPassword(playername, checkpwd);
2023 m_authmanager.setPrivs(playername,
2024 stringToPrivs(g_settings->get("default_privs")));
2025 m_authmanager.save();
2028 // Enforce user limit.
2029 // Don't enforce for users that have some admin right
2030 if(m_clients.size() >= g_settings->getU16("max_users") &&
2031 (m_authmanager.getPrivs(playername)
2032 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 &&
2033 playername != g_settings->get("name"))
2035 SendAccessDenied(m_con, peer_id, L"Too many users.");
2040 Player *player = emergePlayer(playername, password, peer_id);
2042 // If failed, cancel
2045 infostream<<"Server: peer_id="<<peer_id
2046 <<": failed to emerge player"<<std::endl;
2051 Answer with a TOCLIENT_INIT
2054 SharedBuffer<u8> reply(2+1+6+8);
2055 writeU16(&reply[0], TOCLIENT_INIT);
2056 writeU8(&reply[2], deployed);
2057 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2058 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2061 m_con.Send(peer_id, 0, reply, true);
2065 Send complete position information
2067 SendMovePlayer(player);
2072 if(command == TOSERVER_INIT2)
2074 infostream<<"Server: Got TOSERVER_INIT2 from "
2075 <<peer_id<<std::endl;
2078 getClient(peer_id)->serialization_version
2079 = getClient(peer_id)->pending_serialization_version;
2082 Send some initialization data
2085 // Send player info to all players
2088 // Send inventory to player
2089 UpdateCrafting(peer_id);
2090 SendInventory(peer_id);
2092 // Send player items to all players
2095 Player *player = m_env->getPlayer(peer_id);
2098 SendPlayerHP(player);
2102 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2103 m_env->getTimeOfDay());
2104 m_con.Send(peer_id, 0, data, true);
2107 // Send information about server to player in chat
2108 SendChatMessage(peer_id, getStatusString());
2110 // Send information about joining in chat
2112 std::wstring name = L"unknown";
2113 Player *player = m_env->getPlayer(peer_id);
2115 name = narrow_to_wide(player->getName());
2117 std::wstring message;
2120 message += L" joined game";
2121 BroadcastChatMessage(message);
2124 // Warnings about protocol version can be issued here
2125 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2127 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2131 Check HP, respawn if necessary
2133 HandlePlayerHP(player, 0);
2139 std::ostringstream os(std::ios_base::binary);
2140 for(core::map<u16, RemoteClient*>::Iterator
2141 i = m_clients.getIterator();
2142 i.atEnd() == false; i++)
2144 RemoteClient *client = i.getNode()->getValue();
2145 assert(client->peer_id == i.getNode()->getKey());
2146 if(client->serialization_version == SER_FMT_VER_INVALID)
2149 Player *player = m_env->getPlayer(client->peer_id);
2152 // Get name of player
2153 os<<player->getName()<<" ";
2156 actionstream<<player->getName()<<" joins game. List of players: "
2157 <<os.str()<<std::endl;
2163 if(peer_ser_ver == SER_FMT_VER_INVALID)
2165 infostream<<"Server::ProcessData(): Cancelling: Peer"
2166 " serialization format invalid or not initialized."
2167 " Skipping incoming command="<<command<<std::endl;
2171 Player *player = m_env->getPlayer(peer_id);
2174 infostream<<"Server::ProcessData(): Cancelling: "
2175 "No player for peer_id="<<peer_id
2179 if(command == TOSERVER_PLAYERPOS)
2181 if(datasize < 2+12+12+4+4)
2185 v3s32 ps = readV3S32(&data[start+2]);
2186 v3s32 ss = readV3S32(&data[start+2+12]);
2187 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2188 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2189 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2190 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2191 pitch = wrapDegrees(pitch);
2192 yaw = wrapDegrees(yaw);
2194 player->setPosition(position);
2195 player->setSpeed(speed);
2196 player->setPitch(pitch);
2197 player->setYaw(yaw);
2199 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2200 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2201 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2203 else if(command == TOSERVER_GOTBLOCKS)
2216 u16 count = data[2];
2217 for(u16 i=0; i<count; i++)
2219 if((s16)datasize < 2+1+(i+1)*6)
2220 throw con::InvalidIncomingDataException
2221 ("GOTBLOCKS length is too short");
2222 v3s16 p = readV3S16(&data[2+1+i*6]);
2223 /*infostream<<"Server: GOTBLOCKS ("
2224 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2225 RemoteClient *client = getClient(peer_id);
2226 client->GotBlock(p);
2229 else if(command == TOSERVER_DELETEDBLOCKS)
2242 u16 count = data[2];
2243 for(u16 i=0; i<count; i++)
2245 if((s16)datasize < 2+1+(i+1)*6)
2246 throw con::InvalidIncomingDataException
2247 ("DELETEDBLOCKS length is too short");
2248 v3s16 p = readV3S16(&data[2+1+i*6]);
2249 /*infostream<<"Server: DELETEDBLOCKS ("
2250 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2251 RemoteClient *client = getClient(peer_id);
2252 client->SetBlockNotSent(p);
2255 else if(command == TOSERVER_CLICK_OBJECT)
2257 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2260 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2265 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2271 [2] u8 button (0=left, 1=right)
2275 u8 button = readU8(&data[2]);
2276 u16 id = readS16(&data[3]);
2277 u16 item_i = readU16(&data[5]);
2279 ServerActiveObject *obj = m_env->getActiveObject(id);
2283 infostream<<"Server: CLICK_ACTIVEOBJECT: object not found"
2288 // Skip if object has been removed
2292 //TODO: Check that object is reasonably close
2294 // Left click, pick object up (usually)
2298 Try creating inventory item
2300 InventoryItem *item = obj->createPickedUpItem();
2304 InventoryList *ilist = player->inventory.getList("main");
2307 actionstream<<player->getName()<<" picked up "
2308 <<item->getName()<<std::endl;
2309 if(g_settings->getBool("creative_mode") == false)
2311 // Skip if inventory has no free space
2312 if(ilist->roomForItem(item) == false)
2314 infostream<<"Player inventory has no free space"<<std::endl;
2318 // Add to inventory and send inventory
2319 ilist->addItem(item);
2320 UpdateCrafting(player->peer_id);
2321 SendInventory(player->peer_id);
2324 // Remove object from environment
2325 obj->m_removed = true;
2331 Item cannot be picked up. Punch it instead.
2334 actionstream<<player->getName()<<" punches object "
2335 <<obj->getId()<<std::endl;
2337 ToolItem *titem = NULL;
2338 std::string toolname = "";
2340 InventoryList *mlist = player->inventory.getList("main");
2343 InventoryItem *item = mlist->getItem(item_i);
2344 if(item && (std::string)item->getName() == "ToolItem")
2346 titem = (ToolItem*)item;
2347 toolname = titem->getToolName();
2351 v3f playerpos = player->getPosition();
2352 v3f objpos = obj->getBasePosition();
2353 v3f dir = (objpos - playerpos).normalize();
2355 u16 wear = obj->punch(toolname, dir, player->getName());
2359 bool weared_out = titem->addWear(wear);
2361 mlist->deleteItem(item_i);
2362 SendInventory(player->peer_id);
2366 // Right click, do something with object
2369 actionstream<<player->getName()<<" right clicks object "
2370 <<obj->getId()<<std::endl;
2372 // Track hp changes super-crappily
2373 u16 oldhp = player->hp;
2376 obj->rightClick(player);
2379 if(player->hp != oldhp)
2381 SendPlayerHP(player);
2385 else if(command == TOSERVER_GROUND_ACTION)
2393 [3] v3s16 nodepos_undersurface
2394 [9] v3s16 nodepos_abovesurface
2399 2: stop digging (all parameters ignored)
2400 3: digging completed
2402 u8 action = readU8(&data[2]);
2404 p_under.X = readS16(&data[3]);
2405 p_under.Y = readS16(&data[5]);
2406 p_under.Z = readS16(&data[7]);
2408 p_over.X = readS16(&data[9]);
2409 p_over.Y = readS16(&data[11]);
2410 p_over.Z = readS16(&data[13]);
2411 u16 item_i = readU16(&data[15]);
2413 //TODO: Check that target is reasonably close
2421 NOTE: This can be used in the future to check if
2422 somebody is cheating, by checking the timing.
2429 else if(action == 2)
2432 RemoteClient *client = getClient(peer_id);
2433 JMutexAutoLock digmutex(client->m_dig_mutex);
2434 client->m_dig_tool_item = -1;
2439 3: Digging completed
2441 else if(action == 3)
2443 // Mandatory parameter; actually used for nothing
2444 core::map<v3s16, MapBlock*> modified_blocks;
2446 content_t material = CONTENT_IGNORE;
2447 u8 mineral = MINERAL_NONE;
2449 bool cannot_remove_node = false;
2453 MapNode n = m_env->getMap().getNode(p_under);
2455 mineral = n.getMineral();
2456 // Get material at position
2457 material = n.getContent();
2458 // If not yet cancelled
2459 if(cannot_remove_node == false)
2461 // If it's not diggable, do nothing
2462 if(content_diggable(material) == false)
2464 infostream<<"Server: Not finishing digging: "
2465 <<"Node not diggable"
2467 cannot_remove_node = true;
2470 // If not yet cancelled
2471 if(cannot_remove_node == false)
2473 // Get node metadata
2474 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
2475 if(meta && meta->nodeRemovalDisabled() == true)
2477 infostream<<"Server: Not finishing digging: "
2478 <<"Node metadata disables removal"
2480 cannot_remove_node = true;
2484 catch(InvalidPositionException &e)
2486 infostream<<"Server: Not finishing digging: Node not found."
2487 <<" Adding block to emerge queue."
2489 m_emerge_queue.addBlock(peer_id,
2490 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2491 cannot_remove_node = true;
2494 // Make sure the player is allowed to do it
2495 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2497 infostream<<"Player "<<player->getName()<<" cannot remove node"
2498 <<" because privileges are "<<getPlayerPrivs(player)
2500 cannot_remove_node = true;
2504 If node can't be removed, set block to be re-sent to
2507 if(cannot_remove_node)
2509 infostream<<"Server: Not finishing digging."<<std::endl;
2511 // Client probably has wrong data.
2512 // Set block not sent, so that client will get
2514 infostream<<"Client "<<peer_id<<" tried to dig "
2515 <<"node; but node cannot be removed."
2516 <<" setting MapBlock not sent."<<std::endl;
2517 RemoteClient *client = getClient(peer_id);
2518 v3s16 blockpos = getNodeBlockPos(p_under);
2519 client->SetBlockNotSent(blockpos);
2524 actionstream<<player->getName()<<" digs "<<PP(p_under)
2525 <<", gets material "<<(int)material<<", mineral "
2526 <<(int)mineral<<std::endl;
2529 Send the removal to all close-by players.
2530 - If other player is close, send REMOVENODE
2531 - Otherwise set blocks not sent
2533 core::list<u16> far_players;
2534 sendRemoveNode(p_under, peer_id, &far_players, 30);
2537 Update and send inventory
2540 if(g_settings->getBool("creative_mode") == false)
2545 InventoryList *mlist = player->inventory.getList("main");
2548 InventoryItem *item = mlist->getItem(item_i);
2549 if(item && (std::string)item->getName() == "ToolItem")
2551 ToolItem *titem = (ToolItem*)item;
2552 std::string toolname = titem->getToolName();
2554 // Get digging properties for material and tool
2555 DiggingProperties prop =
2556 getDiggingProperties(material, toolname);
2558 if(prop.diggable == false)
2560 infostream<<"Server: WARNING: Player digged"
2561 <<" with impossible material + tool"
2562 <<" combination"<<std::endl;
2565 bool weared_out = titem->addWear(prop.wear);
2569 mlist->deleteItem(item_i);
2575 Add dug item to inventory
2578 InventoryItem *item = NULL;
2580 if(mineral != MINERAL_NONE)
2581 item = getDiggedMineralItem(mineral);
2586 std::string &dug_s = content_features(material).dug_item;
2589 std::istringstream is(dug_s, std::ios::binary);
2590 item = InventoryItem::deSerialize(is);
2596 // Add a item to inventory
2597 player->inventory.addItem("main", item);
2600 UpdateCrafting(player->peer_id);
2601 SendInventory(player->peer_id);
2606 if(mineral != MINERAL_NONE)
2607 item = getDiggedMineralItem(mineral);
2612 std::string &extra_dug_s = content_features(material).extra_dug_item;
2613 s32 extra_rarity = content_features(material).extra_dug_item_rarity;
2614 if(extra_dug_s != "" && extra_rarity != 0
2615 && myrand() % extra_rarity == 0)
2617 std::istringstream is(extra_dug_s, std::ios::binary);
2618 item = InventoryItem::deSerialize(is);
2624 // Add a item to inventory
2625 player->inventory.addItem("main", item);
2628 UpdateCrafting(player->peer_id);
2629 SendInventory(player->peer_id);
2635 (this takes some time so it is done after the quick stuff)
2638 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2640 m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
2643 Set blocks not sent to far players
2645 for(core::list<u16>::Iterator
2646 i = far_players.begin();
2647 i != far_players.end(); i++)
2650 RemoteClient *client = getClient(peer_id);
2653 client->SetBlocksNotSent(modified_blocks);
2660 else if(action == 1)
2663 InventoryList *ilist = player->inventory.getList("main");
2668 InventoryItem *item = ilist->getItem(item_i);
2670 // If there is no item, it is not possible to add it anywhere
2675 Handle material items
2677 if(std::string("MaterialItem") == item->getName())
2680 // Don't add a node if this is not a free space
2681 MapNode n2 = m_env->getMap().getNode(p_over);
2682 bool no_enough_privs =
2683 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2685 infostream<<"Player "<<player->getName()<<" cannot add node"
2686 <<" because privileges are "<<getPlayerPrivs(player)
2689 if(content_features(n2).buildable_to == false
2692 // Client probably has wrong data.
2693 // Set block not sent, so that client will get
2695 infostream<<"Client "<<peer_id<<" tried to place"
2696 <<" node in invalid position; setting"
2697 <<" MapBlock not sent."<<std::endl;
2698 RemoteClient *client = getClient(peer_id);
2699 v3s16 blockpos = getNodeBlockPos(p_over);
2700 client->SetBlockNotSent(blockpos);
2704 catch(InvalidPositionException &e)
2706 infostream<<"Server: Ignoring ADDNODE: Node not found"
2707 <<" Adding block to emerge queue."
2709 m_emerge_queue.addBlock(peer_id,
2710 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2714 // Reset build time counter
2715 getClient(peer_id)->m_time_from_building = 0.0;
2718 MaterialItem *mitem = (MaterialItem*)item;
2720 n.setContent(mitem->getMaterial());
2722 actionstream<<player->getName()<<" places material "
2723 <<(int)mitem->getMaterial()
2724 <<" at "<<PP(p_under)<<std::endl;
2726 // Calculate direction for wall mounted stuff
2727 if(content_features(n).wall_mounted)
2728 n.param2 = packDir(p_under - p_over);
2730 // Calculate the direction for furnaces and chests and stuff
2731 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2733 v3f playerpos = player->getPosition();
2734 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2735 blockpos = blockpos.normalize();
2737 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2751 Send to all close-by players
2753 core::list<u16> far_players;
2754 sendAddNode(p_over, n, 0, &far_players, 30);
2759 InventoryList *ilist = player->inventory.getList("main");
2760 if(g_settings->getBool("creative_mode") == false && ilist)
2762 // Remove from inventory and send inventory
2763 if(mitem->getCount() == 1)
2764 ilist->deleteItem(item_i);
2768 UpdateCrafting(peer_id);
2769 SendInventory(peer_id);
2775 This takes some time so it is done after the quick stuff
2777 core::map<v3s16, MapBlock*> modified_blocks;
2779 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2781 std::string p_name = std::string(player->getName());
2782 m_env->getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
2785 Set blocks not sent to far players
2787 for(core::list<u16>::Iterator
2788 i = far_players.begin();
2789 i != far_players.end(); i++)
2792 RemoteClient *client = getClient(peer_id);
2795 client->SetBlocksNotSent(modified_blocks);
2799 Calculate special events
2802 /*if(n.d == CONTENT_MESE)
2805 for(s16 z=-1; z<=1; z++)
2806 for(s16 y=-1; y<=1; y++)
2807 for(s16 x=-1; x<=1; x++)
2814 Place other item (not a block)
2818 v3s16 blockpos = getNodeBlockPos(p_over);
2821 Check that the block is loaded so that the item
2822 can properly be added to the static list too
2824 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2827 infostream<<"Error while placing object: "
2828 "block not found"<<std::endl;
2833 If in creative mode, item dropping is disabled unless
2834 player has build privileges
2836 if(g_settings->getBool("creative_mode") &&
2837 (getPlayerPrivs(player) & PRIV_BUILD) == 0)
2839 infostream<<"Not allowing player to drop item: "
2840 "creative mode and no build privs"<<std::endl;
2844 // Calculate a position for it
2845 v3f pos = intToFloat(p_over, BS);
2847 pos.Y -= BS*0.25; // let it drop a bit
2849 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2850 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2855 ServerActiveObject *obj = item->createSAO(m_env, 0, pos);
2859 infostream<<"WARNING: item resulted in NULL object, "
2860 <<"not placing onto map"
2865 actionstream<<player->getName()<<" places "<<item->getName()
2866 <<" at "<<PP(p_over)<<std::endl;
2868 // Add the object to the environment
2869 m_env->addActiveObject(obj);
2871 infostream<<"Placed object"<<std::endl;
2873 if(g_settings->getBool("creative_mode") == false)
2875 // Delete the right amount of items from the slot
2876 u16 dropcount = item->getDropCount();
2878 // Delete item if all gone
2879 if(item->getCount() <= dropcount)
2881 if(item->getCount() < dropcount)
2882 infostream<<"WARNING: Server: dropped more items"
2883 <<" than the slot contains"<<std::endl;
2885 InventoryList *ilist = player->inventory.getList("main");
2887 // Remove from inventory and send inventory
2888 ilist->deleteItem(item_i);
2890 // Else decrement it
2892 item->remove(dropcount);
2895 UpdateCrafting(peer_id);
2896 SendInventory(peer_id);
2904 Catch invalid actions
2908 infostream<<"WARNING: Server: Invalid action "
2909 <<action<<std::endl;
2913 else if(command == TOSERVER_RELEASE)
2922 infostream<<"TOSERVER_RELEASE ignored"<<std::endl;
2925 else if(command == TOSERVER_SIGNTEXT)
2927 infostream<<"Server: TOSERVER_SIGNTEXT not supported anymore"
2931 else if(command == TOSERVER_SIGNNODETEXT)
2933 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2941 std::string datastring((char*)&data[2], datasize-2);
2942 std::istringstream is(datastring, std::ios_base::binary);
2945 is.read((char*)buf, 6);
2946 v3s16 p = readV3S16(buf);
2947 is.read((char*)buf, 2);
2948 u16 textlen = readU16(buf);
2950 for(u16 i=0; i<textlen; i++)
2952 is.read((char*)buf, 1);
2953 text += (char)buf[0];
2956 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2959 if(meta->typeId() != CONTENT_SIGN_WALL)
2961 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2962 signmeta->setText(text);
2964 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign "
2965 <<" at "<<PP(p)<<std::endl;
2967 v3s16 blockpos = getNodeBlockPos(p);
2968 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2971 block->setChangedFlag();
2974 for(core::map<u16, RemoteClient*>::Iterator
2975 i = m_clients.getIterator();
2976 i.atEnd()==false; i++)
2978 RemoteClient *client = i.getNode()->getValue();
2979 client->SetBlockNotSent(blockpos);
2982 else if(command == TOSERVER_INVENTORY_ACTION)
2984 /*// Ignore inventory changes if in creative mode
2985 if(g_settings->getBool("creative_mode") == true)
2987 infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
2991 // Strip command and create a stream
2992 std::string datastring((char*)&data[2], datasize-2);
2993 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2994 std::istringstream is(datastring, std::ios_base::binary);
2996 InventoryAction *a = InventoryAction::deSerialize(is);
3001 c.current_player = player;
3004 Handle craftresult specially if not in creative mode
3006 bool disable_action = false;
3007 if(a->getType() == IACTION_MOVE
3008 && g_settings->getBool("creative_mode") == false)
3010 IMoveAction *ma = (IMoveAction*)a;
3011 if(ma->to_inv == "current_player" &&
3012 ma->from_inv == "current_player")
3014 InventoryList *rlist = player->inventory.getList("craftresult");
3016 InventoryList *clist = player->inventory.getList("craft");
3018 InventoryList *mlist = player->inventory.getList("main");
3021 Craftresult is no longer preview if something
3024 if(ma->to_list == "craftresult"
3025 && ma->from_list != "craftresult")
3027 // If it currently is a preview, remove
3029 if(player->craftresult_is_preview)
3031 rlist->deleteItem(0);
3033 player->craftresult_is_preview = false;
3036 Crafting takes place if this condition is true.
3038 if(player->craftresult_is_preview &&
3039 ma->from_list == "craftresult")
3041 player->craftresult_is_preview = false;
3042 clist->decrementMaterials(1);
3044 /* Print out action */
3045 InventoryList *list =
3046 player->inventory.getList("craftresult");
3048 InventoryItem *item = list->getItem(0);
3049 std::string itemname = "NULL";
3051 itemname = item->getName();
3052 actionstream<<player->getName()<<" crafts "
3053 <<itemname<<std::endl;
3056 If the craftresult is placed on itself, move it to
3057 main inventory instead of doing the action
3059 if(ma->to_list == "craftresult"
3060 && ma->from_list == "craftresult")
3062 disable_action = true;
3064 InventoryItem *item1 = rlist->changeItem(0, NULL);
3065 mlist->addItem(item1);
3068 // Disallow moving items if not allowed to build
3069 else if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3073 // if it's a locking chest, only allow the owner or server admins to move items
3074 else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3076 Strfnd fn(ma->from_inv);
3077 std::string id0 = fn.next(":");
3078 if(id0 == "nodemeta")
3081 p.X = stoi(fn.next(","));
3082 p.Y = stoi(fn.next(","));
3083 p.Z = stoi(fn.next(","));
3084 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3085 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3086 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3087 if (lcm->getOwner() != player->getName())
3092 else if (ma->to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3094 Strfnd fn(ma->to_inv);
3095 std::string id0 = fn.next(":");
3096 if(id0 == "nodemeta")
3099 p.X = stoi(fn.next(","));
3100 p.Y = stoi(fn.next(","));
3101 p.Z = stoi(fn.next(","));
3102 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3103 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3104 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3105 if (lcm->getOwner() != player->getName())
3112 if(disable_action == false)
3114 // Feed action to player inventory
3122 UpdateCrafting(player->peer_id);
3123 SendInventory(player->peer_id);
3128 infostream<<"TOSERVER_INVENTORY_ACTION: "
3129 <<"InventoryAction::deSerialize() returned NULL"
3133 else if(command == TOSERVER_CHAT_MESSAGE)
3141 std::string datastring((char*)&data[2], datasize-2);
3142 std::istringstream is(datastring, std::ios_base::binary);
3145 is.read((char*)buf, 2);
3146 u16 len = readU16(buf);
3148 std::wstring message;
3149 for(u16 i=0; i<len; i++)
3151 is.read((char*)buf, 2);
3152 message += (wchar_t)readU16(buf);
3155 // Get player name of this client
3156 std::wstring name = narrow_to_wide(player->getName());
3158 // Line to send to players
3160 // Whether to send to the player that sent the line
3161 bool send_to_sender = false;
3162 // Whether to send to other players
3163 bool send_to_others = false;
3165 // Local player gets all privileges regardless of
3166 // what's set on their account.
3167 u64 privs = getPlayerPrivs(player);
3170 if(message[0] == L'/')
3172 size_t strip_size = 1;
3173 if (message[1] == L'#') // support old-style commans
3175 message = message.substr(strip_size);
3177 WStrfnd f1(message);
3178 f1.next(L" "); // Skip over /#whatever
3179 std::wstring paramstring = f1.next(L"");
3181 ServerCommandContext *ctx = new ServerCommandContext(
3182 str_split(message, L' '),
3189 std::wstring reply(processServerCommand(ctx));
3190 send_to_sender = ctx->flags & SEND_TO_SENDER;
3191 send_to_others = ctx->flags & SEND_TO_OTHERS;
3193 if (ctx->flags & SEND_NO_PREFIX)
3196 line += L"Server: " + reply;
3203 if(privs & PRIV_SHOUT)
3209 send_to_others = true;
3213 line += L"Server: You are not allowed to shout";
3214 send_to_sender = true;
3221 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3224 Send the message to clients
3226 for(core::map<u16, RemoteClient*>::Iterator
3227 i = m_clients.getIterator();
3228 i.atEnd() == false; i++)
3230 // Get client and check that it is valid
3231 RemoteClient *client = i.getNode()->getValue();
3232 assert(client->peer_id == i.getNode()->getKey());
3233 if(client->serialization_version == SER_FMT_VER_INVALID)
3237 bool sender_selected = (peer_id == client->peer_id);
3238 if(sender_selected == true && send_to_sender == false)
3240 if(sender_selected == false && send_to_others == false)
3243 SendChatMessage(client->peer_id, line);
3247 else if(command == TOSERVER_DAMAGE)
3249 std::string datastring((char*)&data[2], datasize-2);
3250 std::istringstream is(datastring, std::ios_base::binary);
3251 u8 damage = readU8(is);
3253 if(g_settings->getBool("enable_damage"))
3255 actionstream<<player->getName()<<" damaged by "
3256 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
3259 HandlePlayerHP(player, damage);
3263 SendPlayerHP(player);
3266 else if(command == TOSERVER_PASSWORD)
3269 [0] u16 TOSERVER_PASSWORD
3270 [2] u8[28] old password
3271 [30] u8[28] new password
3274 if(datasize != 2+PASSWORD_SIZE*2)
3276 /*char password[PASSWORD_SIZE];
3277 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3278 password[i] = data[2+i];
3279 password[PASSWORD_SIZE-1] = 0;*/
3281 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3289 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3291 char c = data[2+PASSWORD_SIZE+i];
3297 infostream<<"Server: Client requests a password change from "
3298 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3300 std::string playername = player->getName();
3302 if(m_authmanager.exists(playername) == false)
3304 infostream<<"Server: playername not found in authmanager"<<std::endl;
3305 // Wrong old password supplied!!
3306 SendChatMessage(peer_id, L"playername not found in authmanager");
3310 std::string checkpwd = m_authmanager.getPassword(playername);
3312 if(oldpwd != checkpwd)
3314 infostream<<"Server: invalid old password"<<std::endl;
3315 // Wrong old password supplied!!
3316 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3320 actionstream<<player->getName()<<" changes password"<<std::endl;
3322 m_authmanager.setPassword(playername, newpwd);
3324 infostream<<"Server: password change successful for "<<playername
3326 SendChatMessage(peer_id, L"Password change successful");
3328 else if(command == TOSERVER_PLAYERITEM)
3333 u16 item = readU16(&data[2]);
3334 player->wieldItem(item);
3335 SendWieldedItem(player);
3337 else if(command == TOSERVER_RESPAWN)
3342 RespawnPlayer(player);
3344 actionstream<<player->getName()<<" respawns at "
3345 <<PP(player->getPosition()/BS)<<std::endl;
3349 infostream<<"Server::ProcessData(): Ignoring "
3350 "unknown command "<<command<<std::endl;
3354 catch(SendFailedException &e)
3356 errorstream<<"Server::ProcessData(): SendFailedException: "
3362 void Server::onMapEditEvent(MapEditEvent *event)
3364 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3365 if(m_ignore_map_edit_events)
3367 MapEditEvent *e = event->clone();
3368 m_unsent_map_edit_queue.push_back(e);
3371 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3373 if(id == "current_player")
3375 assert(c->current_player);
3376 return &(c->current_player->inventory);
3380 std::string id0 = fn.next(":");
3382 if(id0 == "nodemeta")
3385 p.X = stoi(fn.next(","));
3386 p.Y = stoi(fn.next(","));
3387 p.Z = stoi(fn.next(","));
3388 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3390 return meta->getInventory();
3391 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3392 <<"no metadata found"<<std::endl;
3396 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3399 void Server::inventoryModified(InventoryContext *c, std::string id)
3401 if(id == "current_player")
3403 assert(c->current_player);
3405 UpdateCrafting(c->current_player->peer_id);
3406 SendInventory(c->current_player->peer_id);
3411 std::string id0 = fn.next(":");
3413 if(id0 == "nodemeta")
3416 p.X = stoi(fn.next(","));
3417 p.Y = stoi(fn.next(","));
3418 p.Z = stoi(fn.next(","));
3419 v3s16 blockpos = getNodeBlockPos(p);
3421 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3423 meta->inventoryModified();
3425 for(core::map<u16, RemoteClient*>::Iterator
3426 i = m_clients.getIterator();
3427 i.atEnd()==false; i++)
3429 RemoteClient *client = i.getNode()->getValue();
3430 client->SetBlockNotSent(blockpos);
3436 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3439 core::list<PlayerInfo> Server::getPlayerInfo()
3441 DSTACK(__FUNCTION_NAME);
3442 JMutexAutoLock envlock(m_env_mutex);
3443 JMutexAutoLock conlock(m_con_mutex);
3445 core::list<PlayerInfo> list;
3447 core::list<Player*> players = m_env->getPlayers();
3449 core::list<Player*>::Iterator i;
3450 for(i = players.begin();
3451 i != players.end(); i++)
3455 Player *player = *i;
3458 // Copy info from connection to info struct
3459 info.id = player->peer_id;
3460 info.address = m_con.GetPeerAddress(player->peer_id);
3461 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3463 catch(con::PeerNotFoundException &e)
3465 // Set dummy peer info
3467 info.address = Address(0,0,0,0,0);
3471 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3472 info.position = player->getPosition();
3474 list.push_back(info);
3481 void Server::peerAdded(con::Peer *peer)
3483 DSTACK(__FUNCTION_NAME);
3484 infostream<<"Server::peerAdded(): peer->id="
3485 <<peer->id<<std::endl;
3488 c.type = PEER_ADDED;
3489 c.peer_id = peer->id;
3491 m_peer_change_queue.push_back(c);
3494 void Server::deletingPeer(con::Peer *peer, bool timeout)
3496 DSTACK(__FUNCTION_NAME);
3497 infostream<<"Server::deletingPeer(): peer->id="
3498 <<peer->id<<", timeout="<<timeout<<std::endl;
3501 c.type = PEER_REMOVED;
3502 c.peer_id = peer->id;
3503 c.timeout = timeout;
3504 m_peer_change_queue.push_back(c);
3511 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3513 DSTACK(__FUNCTION_NAME);
3514 std::ostringstream os(std::ios_base::binary);
3516 writeU16(os, TOCLIENT_HP);
3520 std::string s = os.str();
3521 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3523 con.Send(peer_id, 0, data, true);
3526 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3527 const std::wstring &reason)
3529 DSTACK(__FUNCTION_NAME);
3530 std::ostringstream os(std::ios_base::binary);
3532 writeU16(os, TOCLIENT_ACCESS_DENIED);
3533 os<<serializeWideString(reason);
3536 std::string s = os.str();
3537 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3539 con.Send(peer_id, 0, data, true);
3542 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3543 bool set_camera_point_target, v3f camera_point_target)
3545 DSTACK(__FUNCTION_NAME);
3546 std::ostringstream os(std::ios_base::binary);
3548 writeU16(os, TOCLIENT_DEATHSCREEN);
3549 writeU8(os, set_camera_point_target);
3550 writeV3F1000(os, camera_point_target);
3553 std::string s = os.str();
3554 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3556 con.Send(peer_id, 0, data, true);
3560 Non-static send methods
3563 void Server::SendObjectData(float dtime)
3565 DSTACK(__FUNCTION_NAME);
3567 core::map<v3s16, bool> stepped_blocks;
3569 for(core::map<u16, RemoteClient*>::Iterator
3570 i = m_clients.getIterator();
3571 i.atEnd() == false; i++)
3573 u16 peer_id = i.getNode()->getKey();
3574 RemoteClient *client = i.getNode()->getValue();
3575 assert(client->peer_id == peer_id);
3577 if(client->serialization_version == SER_FMT_VER_INVALID)
3580 client->SendObjectData(this, dtime, stepped_blocks);
3584 void Server::SendPlayerInfos()
3586 DSTACK(__FUNCTION_NAME);
3588 //JMutexAutoLock envlock(m_env_mutex);
3590 // Get connected players
3591 core::list<Player*> players = m_env->getPlayers(true);
3593 u32 player_count = players.getSize();
3594 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3596 SharedBuffer<u8> data(datasize);
3597 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3600 core::list<Player*>::Iterator i;
3601 for(i = players.begin();
3602 i != players.end(); i++)
3604 Player *player = *i;
3606 /*infostream<<"Server sending player info for player with "
3607 "peer_id="<<player->peer_id<<std::endl;*/
3609 writeU16(&data[start], player->peer_id);
3610 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3611 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3612 start += 2+PLAYERNAME_SIZE;
3615 //JMutexAutoLock conlock(m_con_mutex);
3618 m_con.SendToAll(0, data, true);
3621 void Server::SendInventory(u16 peer_id)
3623 DSTACK(__FUNCTION_NAME);
3625 Player* player = m_env->getPlayer(peer_id);
3632 std::ostringstream os;
3633 //os.imbue(std::locale("C"));
3635 player->inventory.serialize(os);
3637 std::string s = os.str();
3639 SharedBuffer<u8> data(s.size()+2);
3640 writeU16(&data[0], TOCLIENT_INVENTORY);
3641 memcpy(&data[2], s.c_str(), s.size());
3644 m_con.Send(peer_id, 0, data, true);
3647 std::string getWieldedItemString(const Player *player)
3649 const InventoryItem *item = player->getWieldItem();
3651 return std::string("");
3652 std::ostringstream os(std::ios_base::binary);
3653 item->serialize(os);
3657 void Server::SendWieldedItem(const Player* player)
3659 DSTACK(__FUNCTION_NAME);
3663 std::ostringstream os(std::ios_base::binary);
3665 writeU16(os, TOCLIENT_PLAYERITEM);
3667 writeU16(os, player->peer_id);
3668 os<<serializeString(getWieldedItemString(player));
3671 std::string s = os.str();
3672 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3674 m_con.SendToAll(0, data, true);
3677 void Server::SendPlayerItems()
3679 DSTACK(__FUNCTION_NAME);
3681 std::ostringstream os(std::ios_base::binary);
3682 core::list<Player *> players = m_env->getPlayers(true);
3684 writeU16(os, TOCLIENT_PLAYERITEM);
3685 writeU16(os, players.size());
3686 core::list<Player *>::Iterator i;
3687 for(i = players.begin(); i != players.end(); ++i)
3690 writeU16(os, p->peer_id);
3691 os<<serializeString(getWieldedItemString(p));
3695 std::string s = os.str();
3696 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3698 m_con.SendToAll(0, data, true);
3701 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3703 DSTACK(__FUNCTION_NAME);
3705 std::ostringstream os(std::ios_base::binary);
3709 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3710 os.write((char*)buf, 2);
3713 writeU16(buf, message.size());
3714 os.write((char*)buf, 2);
3717 for(u32 i=0; i<message.size(); i++)
3721 os.write((char*)buf, 2);
3725 std::string s = os.str();
3726 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3728 m_con.Send(peer_id, 0, data, true);
3731 void Server::BroadcastChatMessage(const std::wstring &message)
3733 for(core::map<u16, RemoteClient*>::Iterator
3734 i = m_clients.getIterator();
3735 i.atEnd() == false; i++)
3737 // Get client and check that it is valid
3738 RemoteClient *client = i.getNode()->getValue();
3739 assert(client->peer_id == i.getNode()->getKey());
3740 if(client->serialization_version == SER_FMT_VER_INVALID)
3743 SendChatMessage(client->peer_id, message);
3747 void Server::SendPlayerHP(Player *player)
3749 SendHP(m_con, player->peer_id, player->hp);
3752 void Server::SendMovePlayer(Player *player)
3754 DSTACK(__FUNCTION_NAME);
3755 std::ostringstream os(std::ios_base::binary);
3757 writeU16(os, TOCLIENT_MOVE_PLAYER);
3758 writeV3F1000(os, player->getPosition());
3759 writeF1000(os, player->getPitch());
3760 writeF1000(os, player->getYaw());
3763 v3f pos = player->getPosition();
3764 f32 pitch = player->getPitch();
3765 f32 yaw = player->getYaw();
3766 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
3767 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3774 std::string s = os.str();
3775 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3777 m_con.Send(player->peer_id, 0, data, true);
3780 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3781 core::list<u16> *far_players, float far_d_nodes)
3783 float maxd = far_d_nodes*BS;
3784 v3f p_f = intToFloat(p, BS);
3788 SharedBuffer<u8> reply(replysize);
3789 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3790 writeS16(&reply[2], p.X);
3791 writeS16(&reply[4], p.Y);
3792 writeS16(&reply[6], p.Z);
3794 for(core::map<u16, RemoteClient*>::Iterator
3795 i = m_clients.getIterator();
3796 i.atEnd() == false; i++)
3798 // Get client and check that it is valid
3799 RemoteClient *client = i.getNode()->getValue();
3800 assert(client->peer_id == i.getNode()->getKey());
3801 if(client->serialization_version == SER_FMT_VER_INVALID)
3804 // Don't send if it's the same one
3805 if(client->peer_id == ignore_id)
3811 Player *player = m_env->getPlayer(client->peer_id);
3814 // If player is far away, only set modified blocks not sent
3815 v3f player_pos = player->getPosition();
3816 if(player_pos.getDistanceFrom(p_f) > maxd)
3818 far_players->push_back(client->peer_id);
3825 m_con.Send(client->peer_id, 0, reply, true);
3829 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3830 core::list<u16> *far_players, float far_d_nodes)
3832 float maxd = far_d_nodes*BS;
3833 v3f p_f = intToFloat(p, BS);
3835 for(core::map<u16, RemoteClient*>::Iterator
3836 i = m_clients.getIterator();
3837 i.atEnd() == false; i++)
3839 // Get client and check that it is valid
3840 RemoteClient *client = i.getNode()->getValue();
3841 assert(client->peer_id == i.getNode()->getKey());
3842 if(client->serialization_version == SER_FMT_VER_INVALID)
3845 // Don't send if it's the same one
3846 if(client->peer_id == ignore_id)
3852 Player *player = m_env->getPlayer(client->peer_id);
3855 // If player is far away, only set modified blocks not sent
3856 v3f player_pos = player->getPosition();
3857 if(player_pos.getDistanceFrom(p_f) > maxd)
3859 far_players->push_back(client->peer_id);
3866 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3867 SharedBuffer<u8> reply(replysize);
3868 writeU16(&reply[0], TOCLIENT_ADDNODE);
3869 writeS16(&reply[2], p.X);
3870 writeS16(&reply[4], p.Y);
3871 writeS16(&reply[6], p.Z);
3872 n.serialize(&reply[8], client->serialization_version);
3875 m_con.Send(client->peer_id, 0, reply, true);
3879 void Server::setBlockNotSent(v3s16 p)
3881 for(core::map<u16, RemoteClient*>::Iterator
3882 i = m_clients.getIterator();
3883 i.atEnd()==false; i++)
3885 RemoteClient *client = i.getNode()->getValue();
3886 client->SetBlockNotSent(p);
3890 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3892 DSTACK(__FUNCTION_NAME);
3894 v3s16 p = block->getPos();
3898 bool completely_air = true;
3899 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3900 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3901 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3903 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3905 completely_air = false;
3906 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3911 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3913 infostream<<"[completely air] ";
3914 infostream<<std::endl;
3918 Create a packet with the block in the right format
3921 std::ostringstream os(std::ios_base::binary);
3922 block->serialize(os, ver);
3923 std::string s = os.str();
3924 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3926 u32 replysize = 8 + blockdata.getSize();
3927 SharedBuffer<u8> reply(replysize);
3928 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3929 writeS16(&reply[2], p.X);
3930 writeS16(&reply[4], p.Y);
3931 writeS16(&reply[6], p.Z);
3932 memcpy(&reply[8], *blockdata, blockdata.getSize());
3934 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3935 <<": \tpacket size: "<<replysize<<std::endl;*/
3940 m_con.Send(peer_id, 1, reply, true);
3943 void Server::SendBlocks(float dtime)
3945 DSTACK(__FUNCTION_NAME);
3947 JMutexAutoLock envlock(m_env_mutex);
3948 JMutexAutoLock conlock(m_con_mutex);
3950 //TimeTaker timer("Server::SendBlocks");
3952 core::array<PrioritySortedBlockTransfer> queue;
3954 s32 total_sending = 0;
3957 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3959 for(core::map<u16, RemoteClient*>::Iterator
3960 i = m_clients.getIterator();
3961 i.atEnd() == false; i++)
3963 RemoteClient *client = i.getNode()->getValue();
3964 assert(client->peer_id == i.getNode()->getKey());
3966 total_sending += client->SendingCount();
3968 if(client->serialization_version == SER_FMT_VER_INVALID)
3971 client->GetNextBlocks(this, dtime, queue);
3976 // Lowest priority number comes first.
3977 // Lowest is most important.
3980 for(u32 i=0; i<queue.size(); i++)
3982 //TODO: Calculate limit dynamically
3983 if(total_sending >= g_settings->getS32
3984 ("max_simultaneous_block_sends_server_total"))
3987 PrioritySortedBlockTransfer q = queue[i];
3989 MapBlock *block = NULL;
3992 block = m_env->getMap().getBlockNoCreate(q.pos);
3994 catch(InvalidPositionException &e)
3999 RemoteClient *client = getClient(q.peer_id);
4001 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4003 client->SentBlock(q.pos);
4013 void Server::HandlePlayerHP(Player *player, s16 damage)
4015 if(player->hp > damage)
4017 player->hp -= damage;
4018 SendPlayerHP(player);
4022 infostream<<"Server::HandlePlayerHP(): Player "
4023 <<player->getName()<<" dies"<<std::endl;
4027 //TODO: Throw items around
4029 // Handle players that are not connected
4030 if(player->peer_id == PEER_ID_INEXISTENT){
4031 RespawnPlayer(player);
4035 SendPlayerHP(player);
4037 RemoteClient *client = getClient(player->peer_id);
4038 if(client->net_proto_version >= 3)
4040 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4044 RespawnPlayer(player);
4049 void Server::RespawnPlayer(Player *player)
4051 v3f pos = findSpawnPos(m_env->getServerMap());
4052 player->setPosition(pos);
4054 SendMovePlayer(player);
4055 SendPlayerHP(player);
4058 void Server::UpdateCrafting(u16 peer_id)
4060 DSTACK(__FUNCTION_NAME);
4062 Player* player = m_env->getPlayer(peer_id);
4066 Calculate crafting stuff
4068 if(g_settings->getBool("creative_mode") == false)
4070 InventoryList *clist = player->inventory.getList("craft");
4071 InventoryList *rlist = player->inventory.getList("craftresult");
4073 if(rlist && rlist->getUsedSlots() == 0)
4074 player->craftresult_is_preview = true;
4076 if(rlist && player->craftresult_is_preview)
4078 rlist->clearItems();
4080 if(clist && rlist && player->craftresult_is_preview)
4082 InventoryItem *items[9];
4083 for(u16 i=0; i<9; i++)
4085 items[i] = clist->getItem(i);
4088 // Get result of crafting grid
4089 InventoryItem *result = craft_get_result(items);
4091 rlist->addItem(result);
4094 } // if creative_mode == false
4097 RemoteClient* Server::getClient(u16 peer_id)
4099 DSTACK(__FUNCTION_NAME);
4100 //JMutexAutoLock lock(m_con_mutex);
4101 core::map<u16, RemoteClient*>::Node *n;
4102 n = m_clients.find(peer_id);
4103 // A client should exist for all peers
4105 return n->getValue();
4108 std::wstring Server::getStatusString()
4110 std::wostringstream os(std::ios_base::binary);
4113 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4115 os<<L", uptime="<<m_uptime.get();
4116 // Information about clients
4118 for(core::map<u16, RemoteClient*>::Iterator
4119 i = m_clients.getIterator();
4120 i.atEnd() == false; i++)
4122 // Get client and check that it is valid
4123 RemoteClient *client = i.getNode()->getValue();
4124 assert(client->peer_id == i.getNode()->getKey());
4125 if(client->serialization_version == SER_FMT_VER_INVALID)
4128 Player *player = m_env->getPlayer(client->peer_id);
4129 // Get name of player
4130 std::wstring name = L"unknown";
4132 name = narrow_to_wide(player->getName());
4133 // Add name to information string
4137 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4138 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4139 if(g_settings->get("motd") != "")
4140 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4144 // Saves g_settings to configpath given at initialization
4145 void Server::saveConfig()
4147 if(m_configpath != "")
4148 g_settings->updateConfigFile(m_configpath.c_str());
4151 void Server::notifyPlayer(const char *name, const std::wstring msg)
4153 Player *player = m_env->getPlayer(name);
4156 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4159 void Server::notifyPlayers(const std::wstring msg)
4161 BroadcastChatMessage(msg);
4164 v3f findSpawnPos(ServerMap &map)
4166 //return v3f(50,50,50)*BS;
4171 nodepos = v2s16(0,0);
4176 // Try to find a good place a few times
4177 for(s32 i=0; i<1000; i++)
4180 // We're going to try to throw the player to this position
4181 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4182 -range + (myrand()%(range*2)));
4183 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4184 // Get ground height at point (fallbacks to heightmap function)
4185 s16 groundheight = map.findGroundLevel(nodepos2d);
4186 // Don't go underwater
4187 if(groundheight < WATER_LEVEL)
4189 //infostream<<"-> Underwater"<<std::endl;
4192 // Don't go to high places
4193 if(groundheight > WATER_LEVEL + 4)
4195 //infostream<<"-> Underwater"<<std::endl;
4199 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4200 bool is_good = false;
4202 for(s32 i=0; i<10; i++){
4203 v3s16 blockpos = getNodeBlockPos(nodepos);
4204 map.emergeBlock(blockpos, true);
4205 MapNode n = map.getNodeNoEx(nodepos);
4206 if(n.getContent() == CONTENT_AIR){
4217 // Found a good place
4218 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4224 return intToFloat(nodepos, BS);
4227 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4230 Try to get an existing player
4232 Player *player = m_env->getPlayer(name);
4235 // If player is already connected, cancel
4236 if(player->peer_id != 0)
4238 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4243 player->peer_id = peer_id;
4245 // Reset inventory to creative if in creative mode
4246 if(g_settings->getBool("creative_mode"))
4248 // Warning: double code below
4249 // Backup actual inventory
4250 player->inventory_backup = new Inventory();
4251 *(player->inventory_backup) = player->inventory;
4252 // Set creative inventory
4253 craft_set_creative_inventory(player);
4260 If player with the wanted peer_id already exists, cancel.
4262 if(m_env->getPlayer(peer_id) != NULL)
4264 infostream<<"emergePlayer(): Player with wrong name but same"
4265 " peer_id already exists"<<std::endl;
4273 player = new ServerRemotePlayer();
4274 //player->peer_id = c.peer_id;
4275 //player->peer_id = PEER_ID_INEXISTENT;
4276 player->peer_id = peer_id;
4277 player->updateName(name);
4278 m_authmanager.add(name);
4279 m_authmanager.setPassword(name, password);
4280 m_authmanager.setPrivs(name,
4281 stringToPrivs(g_settings->get("default_privs")));
4287 infostream<<"Server: Finding spawn place for player \""
4288 <<player->getName()<<"\""<<std::endl;
4290 v3f pos = findSpawnPos(m_env->getServerMap());
4292 player->setPosition(pos);
4295 Add player to environment
4298 m_env->addPlayer(player);
4301 Add stuff to inventory
4304 if(g_settings->getBool("creative_mode"))
4306 // Warning: double code above
4307 // Backup actual inventory
4308 player->inventory_backup = new Inventory();
4309 *(player->inventory_backup) = player->inventory;
4310 // Set creative inventory
4311 craft_set_creative_inventory(player);
4313 else if(g_settings->getBool("give_initial_stuff"))
4315 craft_give_initial_stuff(player);
4320 } // create new player
4323 void Server::handlePeerChange(PeerChange &c)
4325 JMutexAutoLock envlock(m_env_mutex);
4326 JMutexAutoLock conlock(m_con_mutex);
4328 if(c.type == PEER_ADDED)
4335 core::map<u16, RemoteClient*>::Node *n;
4336 n = m_clients.find(c.peer_id);
4337 // The client shouldn't already exist
4341 RemoteClient *client = new RemoteClient();
4342 client->peer_id = c.peer_id;
4343 m_clients.insert(client->peer_id, client);
4346 else if(c.type == PEER_REMOVED)
4353 core::map<u16, RemoteClient*>::Node *n;
4354 n = m_clients.find(c.peer_id);
4355 // The client should exist
4359 Mark objects to be not known by the client
4361 RemoteClient *client = n->getValue();
4363 for(core::map<u16, bool>::Iterator
4364 i = client->m_known_objects.getIterator();
4365 i.atEnd()==false; i++)
4368 u16 id = i.getNode()->getKey();
4369 ServerActiveObject* obj = m_env->getActiveObject(id);
4371 if(obj && obj->m_known_by_count > 0)
4372 obj->m_known_by_count--;
4375 // Collect information about leaving in chat
4376 std::wstring message;
4378 Player *player = m_env->getPlayer(c.peer_id);
4381 std::wstring name = narrow_to_wide(player->getName());
4384 message += L" left game";
4386 message += L" (timed out)";
4392 m_env->removePlayer(c.peer_id);
4395 // Set player client disconnected
4397 Player *player = m_env->getPlayer(c.peer_id);
4399 player->peer_id = 0;
4406 std::ostringstream os(std::ios_base::binary);
4407 for(core::map<u16, RemoteClient*>::Iterator
4408 i = m_clients.getIterator();
4409 i.atEnd() == false; i++)
4411 RemoteClient *client = i.getNode()->getValue();
4412 assert(client->peer_id == i.getNode()->getKey());
4413 if(client->serialization_version == SER_FMT_VER_INVALID)
4416 Player *player = m_env->getPlayer(client->peer_id);
4419 // Get name of player
4420 os<<player->getName()<<" ";
4423 actionstream<<player->getName()<<" "
4424 <<(c.timeout?"times out.":"leaves game.")
4425 <<" List of players: "
4426 <<os.str()<<std::endl;
4431 delete m_clients[c.peer_id];
4432 m_clients.remove(c.peer_id);
4434 // Send player info to all remaining clients
4437 // Send leave chat message to all remaining clients
4438 BroadcastChatMessage(message);
4447 void Server::handlePeerChanges()
4449 while(m_peer_change_queue.size() > 0)
4451 PeerChange c = m_peer_change_queue.pop_front();
4453 infostream<<"Server: Handling peer change: "
4454 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4457 handlePeerChange(c);
4461 u64 Server::getPlayerPrivs(Player *player)
4465 std::string playername = player->getName();
4466 // Local player gets all privileges regardless of
4467 // what's set on their account.
4468 if(g_settings->get("name") == playername)
4474 return getPlayerAuthPrivs(playername);
4478 void dedicated_server_loop(Server &server, bool &kill)
4480 DSTACK(__FUNCTION_NAME);
4482 infostream<<DTIME<<std::endl;
4483 infostream<<"========================"<<std::endl;
4484 infostream<<"Running dedicated server"<<std::endl;
4485 infostream<<"========================"<<std::endl;
4486 infostream<<std::endl;
4488 IntervalLimiter m_profiler_interval;
4492 // This is kind of a hack but can be done like this
4493 // because server.step() is very light
4495 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4500 if(server.getShutdownRequested() || kill)
4502 infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4509 float profiler_print_interval =
4510 g_settings->getFloat("profiler_print_interval");
4511 if(profiler_print_interval != 0)
4513 if(m_profiler_interval.step(0.030, profiler_print_interval))
4515 infostream<<"Profiler:"<<std::endl;
4516 g_profiler->print(infostream);
4517 g_profiler->clear();
4524 static int counter = 0;
4530 core::list<PlayerInfo> list = server.getPlayerInfo();
4531 core::list<PlayerInfo>::Iterator i;
4532 static u32 sum_old = 0;
4533 u32 sum = PIChecksum(list);
4536 infostream<<DTIME<<"Player info:"<<std::endl;
4537 for(i=list.begin(); i!=list.end(); i++)
4539 i->PrintLine(&infostream);