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 std::string defaultscript = porting::path_data + DIR_DELIM
993 + "scripts" + DIR_DELIM + "default.lua";
994 bool success = script_load(m_lua, defaultscript.c_str());
996 errorstream<<"Server: Failed to load and run "
997 <<defaultscript<<std::endl;
1001 // Initialize Environment
1003 m_env = new ServerEnvironment(new ServerMap(mapsavedir), m_lua);
1005 // Give environment reference to scripting api
1006 scriptapi_add_environment(m_lua, m_env);
1008 // Register us to receive map edit events
1009 m_env->getMap().addEventReceiver(this);
1011 // If file exists, load environment metadata
1012 if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt"))
1014 infostream<<"Server: Loading environment metadata"<<std::endl;
1015 m_env->loadMeta(m_mapsavedir);
1019 infostream<<"Server: Loading players"<<std::endl;
1020 m_env->deSerializePlayers(m_mapsavedir);
1025 infostream<<"Server::~Server()"<<std::endl;
1028 Send shutdown message
1031 JMutexAutoLock conlock(m_con_mutex);
1033 std::wstring line = L"*** Server shutting down";
1036 Send the message to clients
1038 for(core::map<u16, RemoteClient*>::Iterator
1039 i = m_clients.getIterator();
1040 i.atEnd() == false; i++)
1042 // Get client and check that it is valid
1043 RemoteClient *client = i.getNode()->getValue();
1044 assert(client->peer_id == i.getNode()->getKey());
1045 if(client->serialization_version == SER_FMT_VER_INVALID)
1049 SendChatMessage(client->peer_id, line);
1051 catch(con::PeerNotFoundException &e)
1057 JMutexAutoLock envlock(m_env_mutex);
1062 infostream<<"Server: Saving players"<<std::endl;
1063 m_env->serializePlayers(m_mapsavedir);
1066 Save environment metadata
1068 infostream<<"Server: Saving environment metadata"<<std::endl;
1069 m_env->saveMeta(m_mapsavedir);
1081 JMutexAutoLock clientslock(m_con_mutex);
1083 for(core::map<u16, RemoteClient*>::Iterator
1084 i = m_clients.getIterator();
1085 i.atEnd() == false; i++)
1088 // NOTE: These are removed by env destructor
1090 u16 peer_id = i.getNode()->getKey();
1091 JMutexAutoLock envlock(m_env_mutex);
1092 m_env->removePlayer(peer_id);
1096 delete i.getNode()->getValue();
1100 // Delete Environment
1103 // Deinitialize scripting
1104 infostream<<"Server: Deinitializing scripting"<<std::endl;
1105 script_deinit(m_lua);
1108 void Server::start(unsigned short port)
1110 DSTACK(__FUNCTION_NAME);
1111 // Stop thread if already running
1114 // Initialize connection
1115 m_con.SetTimeoutMs(30);
1119 m_thread.setRun(true);
1122 infostream<<"Server: Started on port "<<port<<std::endl;
1127 DSTACK(__FUNCTION_NAME);
1129 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1131 // Stop threads (set run=false first so both start stopping)
1132 m_thread.setRun(false);
1133 m_emergethread.setRun(false);
1135 m_emergethread.stop();
1137 infostream<<"Server: Threads stopped"<<std::endl;
1140 void Server::step(float dtime)
1142 DSTACK(__FUNCTION_NAME);
1147 JMutexAutoLock lock(m_step_dtime_mutex);
1148 m_step_dtime += dtime;
1152 void Server::AsyncRunStep()
1154 DSTACK(__FUNCTION_NAME);
1156 g_profiler->add("Server::AsyncRunStep (num)", 1);
1160 JMutexAutoLock lock1(m_step_dtime_mutex);
1161 dtime = m_step_dtime;
1165 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
1166 // Send blocks to clients
1173 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1175 //infostream<<"Server steps "<<dtime<<std::endl;
1176 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1179 JMutexAutoLock lock1(m_step_dtime_mutex);
1180 m_step_dtime -= dtime;
1187 m_uptime.set(m_uptime.get() + dtime);
1191 // Process connection's timeouts
1192 JMutexAutoLock lock2(m_con_mutex);
1193 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1194 m_con.RunTimeouts(dtime);
1198 // This has to be called so that the client list gets synced
1199 // with the peer list of the connection
1200 handlePeerChanges();
1204 Update m_time_of_day and overall game time
1207 JMutexAutoLock envlock(m_env_mutex);
1209 m_time_counter += dtime;
1210 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1211 u32 units = (u32)(m_time_counter*speed);
1212 m_time_counter -= (f32)units / speed;
1214 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1216 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1219 Send to clients at constant intervals
1222 m_time_of_day_send_timer -= dtime;
1223 if(m_time_of_day_send_timer < 0.0)
1225 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1227 //JMutexAutoLock envlock(m_env_mutex);
1228 JMutexAutoLock conlock(m_con_mutex);
1230 for(core::map<u16, RemoteClient*>::Iterator
1231 i = m_clients.getIterator();
1232 i.atEnd() == false; i++)
1234 RemoteClient *client = i.getNode()->getValue();
1235 //Player *player = m_env->getPlayer(client->peer_id);
1237 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1238 m_env->getTimeOfDay());
1240 m_con.Send(client->peer_id, 0, data, true);
1246 JMutexAutoLock lock(m_env_mutex);
1248 ScopeProfiler sp(g_profiler, "SEnv step");
1249 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1253 const float map_timer_and_unload_dtime = 5.15;
1254 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1256 JMutexAutoLock lock(m_env_mutex);
1257 // Run Map's timers and unload unused data
1258 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1259 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1260 g_settings->getFloat("server_unload_unused_data_timeout"));
1270 m_liquid_transform_timer += dtime;
1271 if(m_liquid_transform_timer >= 1.00)
1273 m_liquid_transform_timer -= 1.00;
1275 JMutexAutoLock lock(m_env_mutex);
1277 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1279 core::map<v3s16, MapBlock*> modified_blocks;
1280 m_env->getMap().transformLiquids(modified_blocks);
1285 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1286 ServerMap &map = ((ServerMap&)m_env->getMap());
1287 map.updateLighting(modified_blocks, lighting_modified_blocks);
1289 // Add blocks modified by lighting to modified_blocks
1290 for(core::map<v3s16, MapBlock*>::Iterator
1291 i = lighting_modified_blocks.getIterator();
1292 i.atEnd() == false; i++)
1294 MapBlock *block = i.getNode()->getValue();
1295 modified_blocks.insert(block->getPos(), block);
1299 Set the modified blocks unsent for all the clients
1302 JMutexAutoLock lock2(m_con_mutex);
1304 for(core::map<u16, RemoteClient*>::Iterator
1305 i = m_clients.getIterator();
1306 i.atEnd() == false; i++)
1308 RemoteClient *client = i.getNode()->getValue();
1310 if(modified_blocks.size() > 0)
1312 // Remove block from sent history
1313 client->SetBlocksNotSent(modified_blocks);
1318 // Periodically print some info
1320 float &counter = m_print_info_timer;
1326 JMutexAutoLock lock2(m_con_mutex);
1328 if(m_clients.size() != 0)
1329 infostream<<"Players:"<<std::endl;
1330 for(core::map<u16, RemoteClient*>::Iterator
1331 i = m_clients.getIterator();
1332 i.atEnd() == false; i++)
1334 //u16 peer_id = i.getNode()->getKey();
1335 RemoteClient *client = i.getNode()->getValue();
1336 Player *player = m_env->getPlayer(client->peer_id);
1339 infostream<<"* "<<player->getName()<<"\t";
1340 client->PrintInfo(infostream);
1345 //if(g_settings->getBool("enable_experimental"))
1349 Check added and deleted active objects
1352 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1353 JMutexAutoLock envlock(m_env_mutex);
1354 JMutexAutoLock conlock(m_con_mutex);
1356 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1358 // Radius inside which objects are active
1359 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1360 radius *= MAP_BLOCKSIZE;
1362 for(core::map<u16, RemoteClient*>::Iterator
1363 i = m_clients.getIterator();
1364 i.atEnd() == false; i++)
1366 RemoteClient *client = i.getNode()->getValue();
1367 Player *player = m_env->getPlayer(client->peer_id);
1370 // This can happen if the client timeouts somehow
1371 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1373 <<" has no associated player"<<std::endl;*/
1376 v3s16 pos = floatToInt(player->getPosition(), BS);
1378 core::map<u16, bool> removed_objects;
1379 core::map<u16, bool> added_objects;
1380 m_env->getRemovedActiveObjects(pos, radius,
1381 client->m_known_objects, removed_objects);
1382 m_env->getAddedActiveObjects(pos, radius,
1383 client->m_known_objects, added_objects);
1385 // Ignore if nothing happened
1386 if(removed_objects.size() == 0 && added_objects.size() == 0)
1388 //infostream<<"active objects: none changed"<<std::endl;
1392 std::string data_buffer;
1396 // Handle removed objects
1397 writeU16((u8*)buf, removed_objects.size());
1398 data_buffer.append(buf, 2);
1399 for(core::map<u16, bool>::Iterator
1400 i = removed_objects.getIterator();
1401 i.atEnd()==false; i++)
1404 u16 id = i.getNode()->getKey();
1405 ServerActiveObject* obj = m_env->getActiveObject(id);
1407 // Add to data buffer for sending
1408 writeU16((u8*)buf, i.getNode()->getKey());
1409 data_buffer.append(buf, 2);
1411 // Remove from known objects
1412 client->m_known_objects.remove(i.getNode()->getKey());
1414 if(obj && obj->m_known_by_count > 0)
1415 obj->m_known_by_count--;
1418 // Handle added objects
1419 writeU16((u8*)buf, added_objects.size());
1420 data_buffer.append(buf, 2);
1421 for(core::map<u16, bool>::Iterator
1422 i = added_objects.getIterator();
1423 i.atEnd()==false; i++)
1426 u16 id = i.getNode()->getKey();
1427 ServerActiveObject* obj = m_env->getActiveObject(id);
1430 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1432 infostream<<"WARNING: "<<__FUNCTION_NAME
1433 <<": NULL object"<<std::endl;
1435 type = obj->getType();
1437 // Add to data buffer for sending
1438 writeU16((u8*)buf, id);
1439 data_buffer.append(buf, 2);
1440 writeU8((u8*)buf, type);
1441 data_buffer.append(buf, 1);
1444 data_buffer.append(serializeLongString(
1445 obj->getClientInitializationData()));
1447 data_buffer.append(serializeLongString(""));
1449 // Add to known objects
1450 client->m_known_objects.insert(i.getNode()->getKey(), false);
1453 obj->m_known_by_count++;
1457 SharedBuffer<u8> reply(2 + data_buffer.size());
1458 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1459 memcpy((char*)&reply[2], data_buffer.c_str(),
1460 data_buffer.size());
1462 m_con.Send(client->peer_id, 0, reply, true);
1464 infostream<<"Server: Sent object remove/add: "
1465 <<removed_objects.size()<<" removed, "
1466 <<added_objects.size()<<" added, "
1467 <<"packet size is "<<reply.getSize()<<std::endl;
1472 Collect a list of all the objects known by the clients
1473 and report it back to the environment.
1476 core::map<u16, bool> all_known_objects;
1478 for(core::map<u16, RemoteClient*>::Iterator
1479 i = m_clients.getIterator();
1480 i.atEnd() == false; i++)
1482 RemoteClient *client = i.getNode()->getValue();
1483 // Go through all known objects of client
1484 for(core::map<u16, bool>::Iterator
1485 i = client->m_known_objects.getIterator();
1486 i.atEnd()==false; i++)
1488 u16 id = i.getNode()->getKey();
1489 all_known_objects[id] = true;
1493 m_env->setKnownActiveObjects(whatever);
1499 Send object messages
1502 JMutexAutoLock envlock(m_env_mutex);
1503 JMutexAutoLock conlock(m_con_mutex);
1505 //ScopeProfiler sp(g_profiler, "Server: sending object messages");
1508 // Value = data sent by object
1509 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1511 // Get active object messages from environment
1514 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1518 core::list<ActiveObjectMessage>* message_list = NULL;
1519 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1520 n = buffered_messages.find(aom.id);
1523 message_list = new core::list<ActiveObjectMessage>;
1524 buffered_messages.insert(aom.id, message_list);
1528 message_list = n->getValue();
1530 message_list->push_back(aom);
1533 // Route data to every client
1534 for(core::map<u16, RemoteClient*>::Iterator
1535 i = m_clients.getIterator();
1536 i.atEnd()==false; i++)
1538 RemoteClient *client = i.getNode()->getValue();
1539 std::string reliable_data;
1540 std::string unreliable_data;
1541 // Go through all objects in message buffer
1542 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1543 j = buffered_messages.getIterator();
1544 j.atEnd()==false; j++)
1546 // If object is not known by client, skip it
1547 u16 id = j.getNode()->getKey();
1548 if(client->m_known_objects.find(id) == NULL)
1550 // Get message list of object
1551 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1552 // Go through every message
1553 for(core::list<ActiveObjectMessage>::Iterator
1554 k = list->begin(); k != list->end(); k++)
1556 // Compose the full new data with header
1557 ActiveObjectMessage aom = *k;
1558 std::string new_data;
1561 writeU16((u8*)&buf[0], aom.id);
1562 new_data.append(buf, 2);
1564 new_data += serializeString(aom.datastring);
1565 // Add data to buffer
1567 reliable_data += new_data;
1569 unreliable_data += new_data;
1573 reliable_data and unreliable_data are now ready.
1576 if(reliable_data.size() > 0)
1578 SharedBuffer<u8> reply(2 + reliable_data.size());
1579 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1580 memcpy((char*)&reply[2], reliable_data.c_str(),
1581 reliable_data.size());
1583 m_con.Send(client->peer_id, 0, reply, true);
1585 if(unreliable_data.size() > 0)
1587 SharedBuffer<u8> reply(2 + unreliable_data.size());
1588 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1589 memcpy((char*)&reply[2], unreliable_data.c_str(),
1590 unreliable_data.size());
1591 // Send as unreliable
1592 m_con.Send(client->peer_id, 0, reply, false);
1595 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1597 infostream<<"Server: Size of object message data: "
1598 <<"reliable: "<<reliable_data.size()
1599 <<", unreliable: "<<unreliable_data.size()
1604 // Clear buffered_messages
1605 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1606 i = buffered_messages.getIterator();
1607 i.atEnd()==false; i++)
1609 delete i.getNode()->getValue();
1613 } // enable_experimental
1616 Send queued-for-sending map edit events.
1619 // Don't send too many at a time
1622 // Single change sending is disabled if queue size is not small
1623 bool disable_single_change_sending = false;
1624 if(m_unsent_map_edit_queue.size() >= 4)
1625 disable_single_change_sending = true;
1627 bool got_any_events = false;
1629 // We'll log the amount of each
1632 while(m_unsent_map_edit_queue.size() != 0)
1634 got_any_events = true;
1636 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1638 // Players far away from the change are stored here.
1639 // Instead of sending the changes, MapBlocks are set not sent
1641 core::list<u16> far_players;
1643 if(event->type == MEET_ADDNODE)
1645 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1646 prof.add("MEET_ADDNODE", 1);
1647 if(disable_single_change_sending)
1648 sendAddNode(event->p, event->n, event->already_known_by_peer,
1651 sendAddNode(event->p, event->n, event->already_known_by_peer,
1654 else if(event->type == MEET_REMOVENODE)
1656 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1657 prof.add("MEET_REMOVENODE", 1);
1658 if(disable_single_change_sending)
1659 sendRemoveNode(event->p, event->already_known_by_peer,
1662 sendRemoveNode(event->p, event->already_known_by_peer,
1665 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1667 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1668 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1669 setBlockNotSent(event->p);
1671 else if(event->type == MEET_OTHER)
1673 infostream<<"Server: MEET_OTHER"<<std::endl;
1674 prof.add("MEET_OTHER", 1);
1675 for(core::map<v3s16, bool>::Iterator
1676 i = event->modified_blocks.getIterator();
1677 i.atEnd()==false; i++)
1679 v3s16 p = i.getNode()->getKey();
1685 prof.add("unknown", 1);
1686 infostream<<"WARNING: Server: Unknown MapEditEvent "
1687 <<((u32)event->type)<<std::endl;
1691 Set blocks not sent to far players
1693 if(far_players.size() > 0)
1695 // Convert list format to that wanted by SetBlocksNotSent
1696 core::map<v3s16, MapBlock*> modified_blocks2;
1697 for(core::map<v3s16, bool>::Iterator
1698 i = event->modified_blocks.getIterator();
1699 i.atEnd()==false; i++)
1701 v3s16 p = i.getNode()->getKey();
1702 modified_blocks2.insert(p,
1703 m_env->getMap().getBlockNoCreateNoEx(p));
1705 // Set blocks not sent
1706 for(core::list<u16>::Iterator
1707 i = far_players.begin();
1708 i != far_players.end(); i++)
1711 RemoteClient *client = getClient(peer_id);
1714 client->SetBlocksNotSent(modified_blocks2);
1720 /*// Don't send too many at a time
1722 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1728 infostream<<"Server: MapEditEvents:"<<std::endl;
1729 prof.print(infostream);
1735 Send object positions
1738 float &counter = m_objectdata_timer;
1740 if(counter >= g_settings->getFloat("objectdata_interval"))
1742 JMutexAutoLock lock1(m_env_mutex);
1743 JMutexAutoLock lock2(m_con_mutex);
1745 //ScopeProfiler sp(g_profiler, "Server: sending player positions");
1747 SendObjectData(counter);
1754 Trigger emergethread (it somehow gets to a non-triggered but
1755 bysy state sometimes)
1758 float &counter = m_emergethread_trigger_timer;
1764 m_emergethread.trigger();
1768 // Save map, players and auth stuff
1770 float &counter = m_savemap_timer;
1772 if(counter >= g_settings->getFloat("server_map_save_interval"))
1776 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1779 if(m_authmanager.isModified())
1780 m_authmanager.save();
1783 if(m_banmanager.isModified())
1784 m_banmanager.save();
1787 JMutexAutoLock lock(m_env_mutex);
1789 /*// Unload unused data (delete from memory)
1790 m_env->getMap().unloadUnusedData(
1791 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1793 /*u32 deleted_count = m_env->getMap().unloadUnusedData(
1794 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1797 // Save only changed parts
1798 m_env->getMap().save(true);
1800 /*if(deleted_count > 0)
1802 infostream<<"Server: Unloaded "<<deleted_count
1803 <<" blocks from memory"<<std::endl;
1807 m_env->serializePlayers(m_mapsavedir);
1809 // Save environment metadata
1810 m_env->saveMeta(m_mapsavedir);
1815 void Server::Receive()
1817 DSTACK(__FUNCTION_NAME);
1818 SharedBuffer<u8> data;
1823 JMutexAutoLock conlock(m_con_mutex);
1824 datasize = m_con.Receive(peer_id, data);
1827 // This has to be called so that the client list gets synced
1828 // with the peer list of the connection
1829 handlePeerChanges();
1831 ProcessData(*data, datasize, peer_id);
1833 catch(con::InvalidIncomingDataException &e)
1835 infostream<<"Server::Receive(): "
1836 "InvalidIncomingDataException: what()="
1837 <<e.what()<<std::endl;
1839 catch(con::PeerNotFoundException &e)
1841 //NOTE: This is not needed anymore
1843 // The peer has been disconnected.
1844 // Find the associated player and remove it.
1846 /*JMutexAutoLock envlock(m_env_mutex);
1848 infostream<<"ServerThread: peer_id="<<peer_id
1849 <<" has apparently closed connection. "
1850 <<"Removing player."<<std::endl;
1852 m_env->removePlayer(peer_id);*/
1856 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1858 DSTACK(__FUNCTION_NAME);
1859 // Environment is locked first.
1860 JMutexAutoLock envlock(m_env_mutex);
1861 JMutexAutoLock conlock(m_con_mutex);
1864 Address address = m_con.GetPeerAddress(peer_id);
1866 // drop player if is ip is banned
1867 if(m_banmanager.isIpBanned(address.serializeString())){
1868 SendAccessDenied(m_con, peer_id,
1869 L"Your ip is banned. Banned name was "
1870 +narrow_to_wide(m_banmanager.getBanName(
1871 address.serializeString())));
1872 m_con.DeletePeer(peer_id);
1876 catch(con::PeerNotFoundException &e)
1878 infostream<<"Server::ProcessData(): Cancelling: peer "
1879 <<peer_id<<" not found"<<std::endl;
1883 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1891 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1893 if(command == TOSERVER_INIT)
1895 // [0] u16 TOSERVER_INIT
1896 // [2] u8 SER_FMT_VER_HIGHEST
1897 // [3] u8[20] player_name
1898 // [23] u8[28] password <--- can be sent without this, from old versions
1900 if(datasize < 2+1+PLAYERNAME_SIZE)
1903 infostream<<"Server: Got TOSERVER_INIT from "
1904 <<peer_id<<std::endl;
1906 // First byte after command is maximum supported
1907 // serialization version
1908 u8 client_max = data[2];
1909 u8 our_max = SER_FMT_VER_HIGHEST;
1910 // Use the highest version supported by both
1911 u8 deployed = core::min_(client_max, our_max);
1912 // If it's lower than the lowest supported, give up.
1913 if(deployed < SER_FMT_VER_LOWEST)
1914 deployed = SER_FMT_VER_INVALID;
1916 //peer->serialization_version = deployed;
1917 getClient(peer_id)->pending_serialization_version = deployed;
1919 if(deployed == SER_FMT_VER_INVALID)
1921 infostream<<"Server: Cannot negotiate "
1922 "serialization version with peer "
1923 <<peer_id<<std::endl;
1924 SendAccessDenied(m_con, peer_id,
1925 L"Your client is too old (map format)");
1930 Read and check network protocol version
1933 u16 net_proto_version = 0;
1934 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1936 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1939 getClient(peer_id)->net_proto_version = net_proto_version;
1941 if(net_proto_version == 0)
1943 SendAccessDenied(m_con, peer_id,
1944 L"Your client is too old. Please upgrade.");
1948 /* Uhh... this should actually be a warning but let's do it like this */
1949 if(g_settings->getBool("strict_protocol_version_checking"))
1951 if(net_proto_version < PROTOCOL_VERSION)
1953 SendAccessDenied(m_con, peer_id,
1954 L"Your client is too old. Please upgrade.");
1964 char playername[PLAYERNAME_SIZE];
1965 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1967 playername[i] = data[3+i];
1969 playername[PLAYERNAME_SIZE-1] = 0;
1971 if(playername[0]=='\0')
1973 infostream<<"Server: Player has empty name"<<std::endl;
1974 SendAccessDenied(m_con, peer_id,
1979 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1981 infostream<<"Server: Player has invalid name"<<std::endl;
1982 SendAccessDenied(m_con, peer_id,
1983 L"Name contains unallowed characters");
1988 char password[PASSWORD_SIZE];
1989 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1991 // old version - assume blank password
1996 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1998 password[i] = data[23+i];
2000 password[PASSWORD_SIZE-1] = 0;
2003 std::string checkpwd;
2004 if(m_authmanager.exists(playername))
2006 checkpwd = m_authmanager.getPassword(playername);
2010 checkpwd = g_settings->get("default_password");
2013 /*infostream<<"Server: Client gave password '"<<password
2014 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2016 if(password != checkpwd && m_authmanager.exists(playername))
2018 infostream<<"Server: peer_id="<<peer_id
2019 <<": supplied invalid password for "
2020 <<playername<<std::endl;
2021 SendAccessDenied(m_con, peer_id, L"Invalid password");
2025 // Add player to auth manager
2026 if(m_authmanager.exists(playername) == false)
2028 infostream<<"Server: adding player "<<playername
2029 <<" to auth manager"<<std::endl;
2030 m_authmanager.add(playername);
2031 m_authmanager.setPassword(playername, checkpwd);
2032 m_authmanager.setPrivs(playername,
2033 stringToPrivs(g_settings->get("default_privs")));
2034 m_authmanager.save();
2037 // Enforce user limit.
2038 // Don't enforce for users that have some admin right
2039 if(m_clients.size() >= g_settings->getU16("max_users") &&
2040 (m_authmanager.getPrivs(playername)
2041 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 &&
2042 playername != g_settings->get("name"))
2044 SendAccessDenied(m_con, peer_id, L"Too many users.");
2049 Player *player = emergePlayer(playername, password, peer_id);
2051 // If failed, cancel
2054 infostream<<"Server: peer_id="<<peer_id
2055 <<": failed to emerge player"<<std::endl;
2060 Answer with a TOCLIENT_INIT
2063 SharedBuffer<u8> reply(2+1+6+8);
2064 writeU16(&reply[0], TOCLIENT_INIT);
2065 writeU8(&reply[2], deployed);
2066 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2067 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2070 m_con.Send(peer_id, 0, reply, true);
2074 Send complete position information
2076 SendMovePlayer(player);
2081 if(command == TOSERVER_INIT2)
2083 infostream<<"Server: Got TOSERVER_INIT2 from "
2084 <<peer_id<<std::endl;
2087 getClient(peer_id)->serialization_version
2088 = getClient(peer_id)->pending_serialization_version;
2091 Send some initialization data
2094 // Send player info to all players
2097 // Send inventory to player
2098 UpdateCrafting(peer_id);
2099 SendInventory(peer_id);
2101 // Send player items to all players
2104 Player *player = m_env->getPlayer(peer_id);
2107 SendPlayerHP(player);
2111 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2112 m_env->getTimeOfDay());
2113 m_con.Send(peer_id, 0, data, true);
2116 // Send information about server to player in chat
2117 SendChatMessage(peer_id, getStatusString());
2119 // Send information about joining in chat
2121 std::wstring name = L"unknown";
2122 Player *player = m_env->getPlayer(peer_id);
2124 name = narrow_to_wide(player->getName());
2126 std::wstring message;
2129 message += L" joined game";
2130 BroadcastChatMessage(message);
2133 // Warnings about protocol version can be issued here
2134 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2136 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2140 Check HP, respawn if necessary
2142 HandlePlayerHP(player, 0);
2148 std::ostringstream os(std::ios_base::binary);
2149 for(core::map<u16, RemoteClient*>::Iterator
2150 i = m_clients.getIterator();
2151 i.atEnd() == false; i++)
2153 RemoteClient *client = i.getNode()->getValue();
2154 assert(client->peer_id == i.getNode()->getKey());
2155 if(client->serialization_version == SER_FMT_VER_INVALID)
2158 Player *player = m_env->getPlayer(client->peer_id);
2161 // Get name of player
2162 os<<player->getName()<<" ";
2165 actionstream<<player->getName()<<" joins game. List of players: "
2166 <<os.str()<<std::endl;
2172 if(peer_ser_ver == SER_FMT_VER_INVALID)
2174 infostream<<"Server::ProcessData(): Cancelling: Peer"
2175 " serialization format invalid or not initialized."
2176 " Skipping incoming command="<<command<<std::endl;
2180 Player *player = m_env->getPlayer(peer_id);
2183 infostream<<"Server::ProcessData(): Cancelling: "
2184 "No player for peer_id="<<peer_id
2188 if(command == TOSERVER_PLAYERPOS)
2190 if(datasize < 2+12+12+4+4)
2194 v3s32 ps = readV3S32(&data[start+2]);
2195 v3s32 ss = readV3S32(&data[start+2+12]);
2196 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2197 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2198 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2199 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2200 pitch = wrapDegrees(pitch);
2201 yaw = wrapDegrees(yaw);
2203 player->setPosition(position);
2204 player->setSpeed(speed);
2205 player->setPitch(pitch);
2206 player->setYaw(yaw);
2208 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2209 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2210 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2212 else if(command == TOSERVER_GOTBLOCKS)
2225 u16 count = data[2];
2226 for(u16 i=0; i<count; i++)
2228 if((s16)datasize < 2+1+(i+1)*6)
2229 throw con::InvalidIncomingDataException
2230 ("GOTBLOCKS length is too short");
2231 v3s16 p = readV3S16(&data[2+1+i*6]);
2232 /*infostream<<"Server: GOTBLOCKS ("
2233 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2234 RemoteClient *client = getClient(peer_id);
2235 client->GotBlock(p);
2238 else if(command == TOSERVER_DELETEDBLOCKS)
2251 u16 count = data[2];
2252 for(u16 i=0; i<count; i++)
2254 if((s16)datasize < 2+1+(i+1)*6)
2255 throw con::InvalidIncomingDataException
2256 ("DELETEDBLOCKS length is too short");
2257 v3s16 p = readV3S16(&data[2+1+i*6]);
2258 /*infostream<<"Server: DELETEDBLOCKS ("
2259 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2260 RemoteClient *client = getClient(peer_id);
2261 client->SetBlockNotSent(p);
2264 else if(command == TOSERVER_CLICK_OBJECT)
2266 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2269 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2274 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2280 [2] u8 button (0=left, 1=right)
2284 u8 button = readU8(&data[2]);
2285 u16 id = readS16(&data[3]);
2286 u16 item_i = readU16(&data[5]);
2288 ServerActiveObject *obj = m_env->getActiveObject(id);
2292 infostream<<"Server: CLICK_ACTIVEOBJECT: object not found"
2297 // Skip if object has been removed
2301 //TODO: Check that object is reasonably close
2303 // Get ServerRemotePlayer
2304 ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
2306 // Update wielded item
2307 srp->wieldItem(item_i);
2309 // Left click, pick/punch
2312 actionstream<<player->getName()<<" punches object "
2313 <<obj->getId()<<std::endl;
2320 Try creating inventory item
2322 InventoryItem *item = obj->createPickedUpItem();
2326 InventoryList *ilist = player->inventory.getList("main");
2329 actionstream<<player->getName()<<" picked up "
2330 <<item->getName()<<std::endl;
2331 if(g_settings->getBool("creative_mode") == false)
2333 // Skip if inventory has no free space
2334 if(ilist->roomForItem(item) == false)
2336 infostream<<"Player inventory has no free space"<<std::endl;
2340 // Add to inventory and send inventory
2341 ilist->addItem(item);
2342 UpdateCrafting(player->peer_id);
2343 SendInventory(player->peer_id);
2346 // Remove object from environment
2347 obj->m_removed = true;
2353 Item cannot be picked up. Punch it instead.
2356 actionstream<<player->getName()<<" punches object "
2357 <<obj->getId()<<std::endl;
2359 ToolItem *titem = NULL;
2360 std::string toolname = "";
2362 InventoryList *mlist = player->inventory.getList("main");
2365 InventoryItem *item = mlist->getItem(item_i);
2366 if(item && (std::string)item->getName() == "ToolItem")
2368 titem = (ToolItem*)item;
2369 toolname = titem->getToolName();
2373 v3f playerpos = player->getPosition();
2374 v3f objpos = obj->getBasePosition();
2375 v3f dir = (objpos - playerpos).normalize();
2377 u16 wear = obj->punch(toolname, dir, player->getName());
2381 bool weared_out = titem->addWear(wear);
2383 mlist->deleteItem(item_i);
2384 SendInventory(player->peer_id);
2389 // Right click, do something with object
2392 actionstream<<player->getName()<<" right clicks object "
2393 <<obj->getId()<<std::endl;
2396 obj->rightClick(srp);
2400 Update player state to client
2402 SendPlayerHP(player);
2403 UpdateCrafting(player->peer_id);
2404 SendInventory(player->peer_id);
2406 else if(command == TOSERVER_GROUND_ACTION)
2414 [3] v3s16 nodepos_undersurface
2415 [9] v3s16 nodepos_abovesurface
2420 2: stop digging (all parameters ignored)
2421 3: digging completed
2423 u8 action = readU8(&data[2]);
2425 p_under.X = readS16(&data[3]);
2426 p_under.Y = readS16(&data[5]);
2427 p_under.Z = readS16(&data[7]);
2429 p_over.X = readS16(&data[9]);
2430 p_over.Y = readS16(&data[11]);
2431 p_over.Z = readS16(&data[13]);
2432 u16 item_i = readU16(&data[15]);
2434 //TODO: Check that target is reasonably close
2442 NOTE: This can be used in the future to check if
2443 somebody is cheating, by checking the timing.
2450 else if(action == 2)
2453 RemoteClient *client = getClient(peer_id);
2454 JMutexAutoLock digmutex(client->m_dig_mutex);
2455 client->m_dig_tool_item = -1;
2460 3: Digging completed
2462 else if(action == 3)
2464 // Mandatory parameter; actually used for nothing
2465 core::map<v3s16, MapBlock*> modified_blocks;
2467 content_t material = CONTENT_IGNORE;
2468 u8 mineral = MINERAL_NONE;
2470 bool cannot_remove_node = false;
2474 MapNode n = m_env->getMap().getNode(p_under);
2476 mineral = n.getMineral();
2477 // Get material at position
2478 material = n.getContent();
2479 // If not yet cancelled
2480 if(cannot_remove_node == false)
2482 // If it's not diggable, do nothing
2483 if(content_diggable(material) == false)
2485 infostream<<"Server: Not finishing digging: "
2486 <<"Node not diggable"
2488 cannot_remove_node = true;
2491 // If not yet cancelled
2492 if(cannot_remove_node == false)
2494 // Get node metadata
2495 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
2496 if(meta && meta->nodeRemovalDisabled() == true)
2498 infostream<<"Server: Not finishing digging: "
2499 <<"Node metadata disables removal"
2501 cannot_remove_node = true;
2505 catch(InvalidPositionException &e)
2507 infostream<<"Server: Not finishing digging: Node not found."
2508 <<" Adding block to emerge queue."
2510 m_emerge_queue.addBlock(peer_id,
2511 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2512 cannot_remove_node = true;
2515 // Make sure the player is allowed to do it
2516 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2518 infostream<<"Player "<<player->getName()<<" cannot remove node"
2519 <<" because privileges are "<<getPlayerPrivs(player)
2521 cannot_remove_node = true;
2525 If node can't be removed, set block to be re-sent to
2528 if(cannot_remove_node)
2530 infostream<<"Server: Not finishing digging."<<std::endl;
2532 // Client probably has wrong data.
2533 // Set block not sent, so that client will get
2535 infostream<<"Client "<<peer_id<<" tried to dig "
2536 <<"node; but node cannot be removed."
2537 <<" setting MapBlock not sent."<<std::endl;
2538 RemoteClient *client = getClient(peer_id);
2539 v3s16 blockpos = getNodeBlockPos(p_under);
2540 client->SetBlockNotSent(blockpos);
2545 actionstream<<player->getName()<<" digs "<<PP(p_under)
2546 <<", gets material "<<(int)material<<", mineral "
2547 <<(int)mineral<<std::endl;
2550 Send the removal to all close-by players.
2551 - If other player is close, send REMOVENODE
2552 - Otherwise set blocks not sent
2554 core::list<u16> far_players;
2555 sendRemoveNode(p_under, peer_id, &far_players, 30);
2558 Update and send inventory
2561 if(g_settings->getBool("creative_mode") == false)
2566 InventoryList *mlist = player->inventory.getList("main");
2569 InventoryItem *item = mlist->getItem(item_i);
2570 if(item && (std::string)item->getName() == "ToolItem")
2572 ToolItem *titem = (ToolItem*)item;
2573 std::string toolname = titem->getToolName();
2575 // Get digging properties for material and tool
2576 DiggingProperties prop =
2577 getDiggingProperties(material, toolname);
2579 if(prop.diggable == false)
2581 infostream<<"Server: WARNING: Player digged"
2582 <<" with impossible material + tool"
2583 <<" combination"<<std::endl;
2586 bool weared_out = titem->addWear(prop.wear);
2590 mlist->deleteItem(item_i);
2596 Add dug item to inventory
2599 InventoryItem *item = NULL;
2601 if(mineral != MINERAL_NONE)
2602 item = getDiggedMineralItem(mineral);
2607 std::string &dug_s = content_features(material).dug_item;
2610 std::istringstream is(dug_s, std::ios::binary);
2611 item = InventoryItem::deSerialize(is);
2617 // Add a item to inventory
2618 player->inventory.addItem("main", item);
2621 UpdateCrafting(player->peer_id);
2622 SendInventory(player->peer_id);
2627 if(mineral != MINERAL_NONE)
2628 item = getDiggedMineralItem(mineral);
2633 std::string &extra_dug_s = content_features(material).extra_dug_item;
2634 s32 extra_rarity = content_features(material).extra_dug_item_rarity;
2635 if(extra_dug_s != "" && extra_rarity != 0
2636 && myrand() % extra_rarity == 0)
2638 std::istringstream is(extra_dug_s, std::ios::binary);
2639 item = InventoryItem::deSerialize(is);
2645 // Add a item to inventory
2646 player->inventory.addItem("main", item);
2649 UpdateCrafting(player->peer_id);
2650 SendInventory(player->peer_id);
2656 (this takes some time so it is done after the quick stuff)
2659 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2661 m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
2664 Set blocks not sent to far players
2666 for(core::list<u16>::Iterator
2667 i = far_players.begin();
2668 i != far_players.end(); i++)
2671 RemoteClient *client = getClient(peer_id);
2674 client->SetBlocksNotSent(modified_blocks);
2681 else if(action == 1)
2684 InventoryList *ilist = player->inventory.getList("main");
2689 InventoryItem *item = ilist->getItem(item_i);
2691 // If there is no item, it is not possible to add it anywhere
2696 Handle material items
2698 if(std::string("MaterialItem") == item->getName())
2701 // Don't add a node if this is not a free space
2702 MapNode n2 = m_env->getMap().getNode(p_over);
2703 bool no_enough_privs =
2704 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2706 infostream<<"Player "<<player->getName()<<" cannot add node"
2707 <<" because privileges are "<<getPlayerPrivs(player)
2710 if(content_features(n2).buildable_to == false
2713 // Client probably has wrong data.
2714 // Set block not sent, so that client will get
2716 infostream<<"Client "<<peer_id<<" tried to place"
2717 <<" node in invalid position; setting"
2718 <<" MapBlock not sent."<<std::endl;
2719 RemoteClient *client = getClient(peer_id);
2720 v3s16 blockpos = getNodeBlockPos(p_over);
2721 client->SetBlockNotSent(blockpos);
2725 catch(InvalidPositionException &e)
2727 infostream<<"Server: Ignoring ADDNODE: Node not found"
2728 <<" Adding block to emerge queue."
2730 m_emerge_queue.addBlock(peer_id,
2731 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2735 // Reset build time counter
2736 getClient(peer_id)->m_time_from_building = 0.0;
2739 MaterialItem *mitem = (MaterialItem*)item;
2741 n.setContent(mitem->getMaterial());
2743 actionstream<<player->getName()<<" places material "
2744 <<(int)mitem->getMaterial()
2745 <<" at "<<PP(p_under)<<std::endl;
2747 // Calculate direction for wall mounted stuff
2748 if(content_features(n).wall_mounted)
2749 n.param2 = packDir(p_under - p_over);
2751 // Calculate the direction for furnaces and chests and stuff
2752 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2754 v3f playerpos = player->getPosition();
2755 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2756 blockpos = blockpos.normalize();
2758 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2772 Send to all close-by players
2774 core::list<u16> far_players;
2775 sendAddNode(p_over, n, 0, &far_players, 30);
2780 InventoryList *ilist = player->inventory.getList("main");
2781 if(g_settings->getBool("creative_mode") == false && ilist)
2783 // Remove from inventory and send inventory
2784 if(mitem->getCount() == 1)
2785 ilist->deleteItem(item_i);
2789 UpdateCrafting(peer_id);
2790 SendInventory(peer_id);
2796 This takes some time so it is done after the quick stuff
2798 core::map<v3s16, MapBlock*> modified_blocks;
2800 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2802 std::string p_name = std::string(player->getName());
2803 m_env->getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
2806 Set blocks not sent to far players
2808 for(core::list<u16>::Iterator
2809 i = far_players.begin();
2810 i != far_players.end(); i++)
2813 RemoteClient *client = getClient(peer_id);
2816 client->SetBlocksNotSent(modified_blocks);
2820 Calculate special events
2823 /*if(n.d == CONTENT_MESE)
2826 for(s16 z=-1; z<=1; z++)
2827 for(s16 y=-1; y<=1; y++)
2828 for(s16 x=-1; x<=1; x++)
2835 Place other item (not a block)
2839 v3s16 blockpos = getNodeBlockPos(p_over);
2842 Check that the block is loaded so that the item
2843 can properly be added to the static list too
2845 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2848 infostream<<"Error while placing object: "
2849 "block not found"<<std::endl;
2854 If in creative mode, item dropping is disabled unless
2855 player has build privileges
2857 if(g_settings->getBool("creative_mode") &&
2858 (getPlayerPrivs(player) & PRIV_BUILD) == 0)
2860 infostream<<"Not allowing player to drop item: "
2861 "creative mode and no build privs"<<std::endl;
2865 // Calculate a position for it
2866 v3f pos = intToFloat(p_over, BS);
2868 /*pos.Y -= BS*0.25; // let it drop a bit
2870 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2871 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;*/
2876 ServerActiveObject *obj = item->createSAO(m_env, 0, pos);
2880 infostream<<"WARNING: item resulted in NULL object, "
2881 <<"not placing onto map"
2886 actionstream<<player->getName()<<" places "<<item->getName()
2887 <<" at "<<PP(p_over)<<std::endl;
2889 // Add the object to the environment
2890 m_env->addActiveObject(obj);
2892 infostream<<"Placed object"<<std::endl;
2894 if(g_settings->getBool("creative_mode") == false)
2896 // Delete the right amount of items from the slot
2897 u16 dropcount = item->getDropCount();
2899 // Delete item if all gone
2900 if(item->getCount() <= dropcount)
2902 if(item->getCount() < dropcount)
2903 infostream<<"WARNING: Server: dropped more items"
2904 <<" than the slot contains"<<std::endl;
2906 InventoryList *ilist = player->inventory.getList("main");
2908 // Remove from inventory and send inventory
2909 ilist->deleteItem(item_i);
2911 // Else decrement it
2913 item->remove(dropcount);
2916 UpdateCrafting(peer_id);
2917 SendInventory(peer_id);
2925 Catch invalid actions
2929 infostream<<"WARNING: Server: Invalid action "
2930 <<action<<std::endl;
2934 else if(command == TOSERVER_RELEASE)
2943 infostream<<"TOSERVER_RELEASE ignored"<<std::endl;
2946 else if(command == TOSERVER_SIGNTEXT)
2948 infostream<<"Server: TOSERVER_SIGNTEXT not supported anymore"
2952 else if(command == TOSERVER_SIGNNODETEXT)
2954 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2962 std::string datastring((char*)&data[2], datasize-2);
2963 std::istringstream is(datastring, std::ios_base::binary);
2966 is.read((char*)buf, 6);
2967 v3s16 p = readV3S16(buf);
2968 is.read((char*)buf, 2);
2969 u16 textlen = readU16(buf);
2971 for(u16 i=0; i<textlen; i++)
2973 is.read((char*)buf, 1);
2974 text += (char)buf[0];
2977 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2980 if(meta->typeId() != CONTENT_SIGN_WALL)
2982 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2983 signmeta->setText(text);
2985 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign "
2986 <<" at "<<PP(p)<<std::endl;
2988 v3s16 blockpos = getNodeBlockPos(p);
2989 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2992 block->setChangedFlag();
2995 for(core::map<u16, RemoteClient*>::Iterator
2996 i = m_clients.getIterator();
2997 i.atEnd()==false; i++)
2999 RemoteClient *client = i.getNode()->getValue();
3000 client->SetBlockNotSent(blockpos);
3003 else if(command == TOSERVER_INVENTORY_ACTION)
3005 /*// Ignore inventory changes if in creative mode
3006 if(g_settings->getBool("creative_mode") == true)
3008 infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3012 // Strip command and create a stream
3013 std::string datastring((char*)&data[2], datasize-2);
3014 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3015 std::istringstream is(datastring, std::ios_base::binary);
3017 InventoryAction *a = InventoryAction::deSerialize(is);
3022 c.current_player = player;
3025 Handle craftresult specially if not in creative mode
3027 bool disable_action = false;
3028 if(a->getType() == IACTION_MOVE
3029 && g_settings->getBool("creative_mode") == false)
3031 IMoveAction *ma = (IMoveAction*)a;
3032 if(ma->to_inv == "current_player" &&
3033 ma->from_inv == "current_player")
3035 InventoryList *rlist = player->inventory.getList("craftresult");
3037 InventoryList *clist = player->inventory.getList("craft");
3039 InventoryList *mlist = player->inventory.getList("main");
3042 Craftresult is no longer preview if something
3045 if(ma->to_list == "craftresult"
3046 && ma->from_list != "craftresult")
3048 // If it currently is a preview, remove
3050 if(player->craftresult_is_preview)
3052 rlist->deleteItem(0);
3054 player->craftresult_is_preview = false;
3057 Crafting takes place if this condition is true.
3059 if(player->craftresult_is_preview &&
3060 ma->from_list == "craftresult")
3062 player->craftresult_is_preview = false;
3063 clist->decrementMaterials(1);
3065 /* Print out action */
3066 InventoryList *list =
3067 player->inventory.getList("craftresult");
3069 InventoryItem *item = list->getItem(0);
3070 std::string itemname = "NULL";
3072 itemname = item->getName();
3073 actionstream<<player->getName()<<" crafts "
3074 <<itemname<<std::endl;
3077 If the craftresult is placed on itself, move it to
3078 main inventory instead of doing the action
3080 if(ma->to_list == "craftresult"
3081 && ma->from_list == "craftresult")
3083 disable_action = true;
3085 InventoryItem *item1 = rlist->changeItem(0, NULL);
3086 mlist->addItem(item1);
3089 // Disallow moving items if not allowed to build
3090 else if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3094 // if it's a locking chest, only allow the owner or server admins to move items
3095 else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3097 Strfnd fn(ma->from_inv);
3098 std::string id0 = fn.next(":");
3099 if(id0 == "nodemeta")
3102 p.X = stoi(fn.next(","));
3103 p.Y = stoi(fn.next(","));
3104 p.Z = stoi(fn.next(","));
3105 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3106 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3107 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3108 if (lcm->getOwner() != player->getName())
3113 else if (ma->to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3115 Strfnd fn(ma->to_inv);
3116 std::string id0 = fn.next(":");
3117 if(id0 == "nodemeta")
3120 p.X = stoi(fn.next(","));
3121 p.Y = stoi(fn.next(","));
3122 p.Z = stoi(fn.next(","));
3123 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3124 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3125 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3126 if (lcm->getOwner() != player->getName())
3133 if(disable_action == false)
3135 // Feed action to player inventory
3143 UpdateCrafting(player->peer_id);
3144 SendInventory(player->peer_id);
3149 infostream<<"TOSERVER_INVENTORY_ACTION: "
3150 <<"InventoryAction::deSerialize() returned NULL"
3154 else if(command == TOSERVER_CHAT_MESSAGE)
3162 std::string datastring((char*)&data[2], datasize-2);
3163 std::istringstream is(datastring, std::ios_base::binary);
3166 is.read((char*)buf, 2);
3167 u16 len = readU16(buf);
3169 std::wstring message;
3170 for(u16 i=0; i<len; i++)
3172 is.read((char*)buf, 2);
3173 message += (wchar_t)readU16(buf);
3176 // Get player name of this client
3177 std::wstring name = narrow_to_wide(player->getName());
3179 // Line to send to players
3181 // Whether to send to the player that sent the line
3182 bool send_to_sender = false;
3183 // Whether to send to other players
3184 bool send_to_others = false;
3186 // Local player gets all privileges regardless of
3187 // what's set on their account.
3188 u64 privs = getPlayerPrivs(player);
3191 if(message[0] == L'/')
3193 size_t strip_size = 1;
3194 if (message[1] == L'#') // support old-style commans
3196 message = message.substr(strip_size);
3198 WStrfnd f1(message);
3199 f1.next(L" "); // Skip over /#whatever
3200 std::wstring paramstring = f1.next(L"");
3202 ServerCommandContext *ctx = new ServerCommandContext(
3203 str_split(message, L' '),
3210 std::wstring reply(processServerCommand(ctx));
3211 send_to_sender = ctx->flags & SEND_TO_SENDER;
3212 send_to_others = ctx->flags & SEND_TO_OTHERS;
3214 if (ctx->flags & SEND_NO_PREFIX)
3217 line += L"Server: " + reply;
3224 if(privs & PRIV_SHOUT)
3230 send_to_others = true;
3234 line += L"Server: You are not allowed to shout";
3235 send_to_sender = true;
3242 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3245 Send the message to clients
3247 for(core::map<u16, RemoteClient*>::Iterator
3248 i = m_clients.getIterator();
3249 i.atEnd() == false; i++)
3251 // Get client and check that it is valid
3252 RemoteClient *client = i.getNode()->getValue();
3253 assert(client->peer_id == i.getNode()->getKey());
3254 if(client->serialization_version == SER_FMT_VER_INVALID)
3258 bool sender_selected = (peer_id == client->peer_id);
3259 if(sender_selected == true && send_to_sender == false)
3261 if(sender_selected == false && send_to_others == false)
3264 SendChatMessage(client->peer_id, line);
3268 else if(command == TOSERVER_DAMAGE)
3270 std::string datastring((char*)&data[2], datasize-2);
3271 std::istringstream is(datastring, std::ios_base::binary);
3272 u8 damage = readU8(is);
3274 if(g_settings->getBool("enable_damage"))
3276 actionstream<<player->getName()<<" damaged by "
3277 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
3280 HandlePlayerHP(player, damage);
3284 SendPlayerHP(player);
3287 else if(command == TOSERVER_PASSWORD)
3290 [0] u16 TOSERVER_PASSWORD
3291 [2] u8[28] old password
3292 [30] u8[28] new password
3295 if(datasize != 2+PASSWORD_SIZE*2)
3297 /*char password[PASSWORD_SIZE];
3298 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3299 password[i] = data[2+i];
3300 password[PASSWORD_SIZE-1] = 0;*/
3302 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3310 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3312 char c = data[2+PASSWORD_SIZE+i];
3318 infostream<<"Server: Client requests a password change from "
3319 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3321 std::string playername = player->getName();
3323 if(m_authmanager.exists(playername) == false)
3325 infostream<<"Server: playername not found in authmanager"<<std::endl;
3326 // Wrong old password supplied!!
3327 SendChatMessage(peer_id, L"playername not found in authmanager");
3331 std::string checkpwd = m_authmanager.getPassword(playername);
3333 if(oldpwd != checkpwd)
3335 infostream<<"Server: invalid old password"<<std::endl;
3336 // Wrong old password supplied!!
3337 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3341 actionstream<<player->getName()<<" changes password"<<std::endl;
3343 m_authmanager.setPassword(playername, newpwd);
3345 infostream<<"Server: password change successful for "<<playername
3347 SendChatMessage(peer_id, L"Password change successful");
3349 else if(command == TOSERVER_PLAYERITEM)
3354 u16 item = readU16(&data[2]);
3355 player->wieldItem(item);
3356 SendWieldedItem(player);
3358 else if(command == TOSERVER_RESPAWN)
3363 RespawnPlayer(player);
3365 actionstream<<player->getName()<<" respawns at "
3366 <<PP(player->getPosition()/BS)<<std::endl;
3370 infostream<<"Server::ProcessData(): Ignoring "
3371 "unknown command "<<command<<std::endl;
3375 catch(SendFailedException &e)
3377 errorstream<<"Server::ProcessData(): SendFailedException: "
3383 void Server::onMapEditEvent(MapEditEvent *event)
3385 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3386 if(m_ignore_map_edit_events)
3388 MapEditEvent *e = event->clone();
3389 m_unsent_map_edit_queue.push_back(e);
3392 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3394 if(id == "current_player")
3396 assert(c->current_player);
3397 return &(c->current_player->inventory);
3401 std::string id0 = fn.next(":");
3403 if(id0 == "nodemeta")
3406 p.X = stoi(fn.next(","));
3407 p.Y = stoi(fn.next(","));
3408 p.Z = stoi(fn.next(","));
3409 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3411 return meta->getInventory();
3412 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3413 <<"no metadata found"<<std::endl;
3417 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3420 void Server::inventoryModified(InventoryContext *c, std::string id)
3422 if(id == "current_player")
3424 assert(c->current_player);
3426 UpdateCrafting(c->current_player->peer_id);
3427 SendInventory(c->current_player->peer_id);
3432 std::string id0 = fn.next(":");
3434 if(id0 == "nodemeta")
3437 p.X = stoi(fn.next(","));
3438 p.Y = stoi(fn.next(","));
3439 p.Z = stoi(fn.next(","));
3440 v3s16 blockpos = getNodeBlockPos(p);
3442 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3444 meta->inventoryModified();
3446 for(core::map<u16, RemoteClient*>::Iterator
3447 i = m_clients.getIterator();
3448 i.atEnd()==false; i++)
3450 RemoteClient *client = i.getNode()->getValue();
3451 client->SetBlockNotSent(blockpos);
3457 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3460 core::list<PlayerInfo> Server::getPlayerInfo()
3462 DSTACK(__FUNCTION_NAME);
3463 JMutexAutoLock envlock(m_env_mutex);
3464 JMutexAutoLock conlock(m_con_mutex);
3466 core::list<PlayerInfo> list;
3468 core::list<Player*> players = m_env->getPlayers();
3470 core::list<Player*>::Iterator i;
3471 for(i = players.begin();
3472 i != players.end(); i++)
3476 Player *player = *i;
3479 // Copy info from connection to info struct
3480 info.id = player->peer_id;
3481 info.address = m_con.GetPeerAddress(player->peer_id);
3482 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3484 catch(con::PeerNotFoundException &e)
3486 // Set dummy peer info
3488 info.address = Address(0,0,0,0,0);
3492 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3493 info.position = player->getPosition();
3495 list.push_back(info);
3502 void Server::peerAdded(con::Peer *peer)
3504 DSTACK(__FUNCTION_NAME);
3505 infostream<<"Server::peerAdded(): peer->id="
3506 <<peer->id<<std::endl;
3509 c.type = PEER_ADDED;
3510 c.peer_id = peer->id;
3512 m_peer_change_queue.push_back(c);
3515 void Server::deletingPeer(con::Peer *peer, bool timeout)
3517 DSTACK(__FUNCTION_NAME);
3518 infostream<<"Server::deletingPeer(): peer->id="
3519 <<peer->id<<", timeout="<<timeout<<std::endl;
3522 c.type = PEER_REMOVED;
3523 c.peer_id = peer->id;
3524 c.timeout = timeout;
3525 m_peer_change_queue.push_back(c);
3532 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3534 DSTACK(__FUNCTION_NAME);
3535 std::ostringstream os(std::ios_base::binary);
3537 writeU16(os, TOCLIENT_HP);
3541 std::string s = os.str();
3542 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3544 con.Send(peer_id, 0, data, true);
3547 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3548 const std::wstring &reason)
3550 DSTACK(__FUNCTION_NAME);
3551 std::ostringstream os(std::ios_base::binary);
3553 writeU16(os, TOCLIENT_ACCESS_DENIED);
3554 os<<serializeWideString(reason);
3557 std::string s = os.str();
3558 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3560 con.Send(peer_id, 0, data, true);
3563 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3564 bool set_camera_point_target, v3f camera_point_target)
3566 DSTACK(__FUNCTION_NAME);
3567 std::ostringstream os(std::ios_base::binary);
3569 writeU16(os, TOCLIENT_DEATHSCREEN);
3570 writeU8(os, set_camera_point_target);
3571 writeV3F1000(os, camera_point_target);
3574 std::string s = os.str();
3575 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3577 con.Send(peer_id, 0, data, true);
3581 Non-static send methods
3584 void Server::SendObjectData(float dtime)
3586 DSTACK(__FUNCTION_NAME);
3588 core::map<v3s16, bool> stepped_blocks;
3590 for(core::map<u16, RemoteClient*>::Iterator
3591 i = m_clients.getIterator();
3592 i.atEnd() == false; i++)
3594 u16 peer_id = i.getNode()->getKey();
3595 RemoteClient *client = i.getNode()->getValue();
3596 assert(client->peer_id == peer_id);
3598 if(client->serialization_version == SER_FMT_VER_INVALID)
3601 client->SendObjectData(this, dtime, stepped_blocks);
3605 void Server::SendPlayerInfos()
3607 DSTACK(__FUNCTION_NAME);
3609 //JMutexAutoLock envlock(m_env_mutex);
3611 // Get connected players
3612 core::list<Player*> players = m_env->getPlayers(true);
3614 u32 player_count = players.getSize();
3615 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3617 SharedBuffer<u8> data(datasize);
3618 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3621 core::list<Player*>::Iterator i;
3622 for(i = players.begin();
3623 i != players.end(); i++)
3625 Player *player = *i;
3627 /*infostream<<"Server sending player info for player with "
3628 "peer_id="<<player->peer_id<<std::endl;*/
3630 writeU16(&data[start], player->peer_id);
3631 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3632 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3633 start += 2+PLAYERNAME_SIZE;
3636 //JMutexAutoLock conlock(m_con_mutex);
3639 m_con.SendToAll(0, data, true);
3642 void Server::SendInventory(u16 peer_id)
3644 DSTACK(__FUNCTION_NAME);
3646 Player* player = m_env->getPlayer(peer_id);
3653 std::ostringstream os;
3654 //os.imbue(std::locale("C"));
3656 player->inventory.serialize(os);
3658 std::string s = os.str();
3660 SharedBuffer<u8> data(s.size()+2);
3661 writeU16(&data[0], TOCLIENT_INVENTORY);
3662 memcpy(&data[2], s.c_str(), s.size());
3665 m_con.Send(peer_id, 0, data, true);
3668 std::string getWieldedItemString(const Player *player)
3670 const InventoryItem *item = player->getWieldItem();
3672 return std::string("");
3673 std::ostringstream os(std::ios_base::binary);
3674 item->serialize(os);
3678 void Server::SendWieldedItem(const Player* player)
3680 DSTACK(__FUNCTION_NAME);
3684 std::ostringstream os(std::ios_base::binary);
3686 writeU16(os, TOCLIENT_PLAYERITEM);
3688 writeU16(os, player->peer_id);
3689 os<<serializeString(getWieldedItemString(player));
3692 std::string s = os.str();
3693 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3695 m_con.SendToAll(0, data, true);
3698 void Server::SendPlayerItems()
3700 DSTACK(__FUNCTION_NAME);
3702 std::ostringstream os(std::ios_base::binary);
3703 core::list<Player *> players = m_env->getPlayers(true);
3705 writeU16(os, TOCLIENT_PLAYERITEM);
3706 writeU16(os, players.size());
3707 core::list<Player *>::Iterator i;
3708 for(i = players.begin(); i != players.end(); ++i)
3711 writeU16(os, p->peer_id);
3712 os<<serializeString(getWieldedItemString(p));
3716 std::string s = os.str();
3717 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3719 m_con.SendToAll(0, data, true);
3722 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3724 DSTACK(__FUNCTION_NAME);
3726 std::ostringstream os(std::ios_base::binary);
3730 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3731 os.write((char*)buf, 2);
3734 writeU16(buf, message.size());
3735 os.write((char*)buf, 2);
3738 for(u32 i=0; i<message.size(); i++)
3742 os.write((char*)buf, 2);
3746 std::string s = os.str();
3747 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3749 m_con.Send(peer_id, 0, data, true);
3752 void Server::BroadcastChatMessage(const std::wstring &message)
3754 for(core::map<u16, RemoteClient*>::Iterator
3755 i = m_clients.getIterator();
3756 i.atEnd() == false; i++)
3758 // Get client and check that it is valid
3759 RemoteClient *client = i.getNode()->getValue();
3760 assert(client->peer_id == i.getNode()->getKey());
3761 if(client->serialization_version == SER_FMT_VER_INVALID)
3764 SendChatMessage(client->peer_id, message);
3768 void Server::SendPlayerHP(Player *player)
3770 SendHP(m_con, player->peer_id, player->hp);
3773 void Server::SendMovePlayer(Player *player)
3775 DSTACK(__FUNCTION_NAME);
3776 std::ostringstream os(std::ios_base::binary);
3778 writeU16(os, TOCLIENT_MOVE_PLAYER);
3779 writeV3F1000(os, player->getPosition());
3780 writeF1000(os, player->getPitch());
3781 writeF1000(os, player->getYaw());
3784 v3f pos = player->getPosition();
3785 f32 pitch = player->getPitch();
3786 f32 yaw = player->getYaw();
3787 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
3788 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3795 std::string s = os.str();
3796 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3798 m_con.Send(player->peer_id, 0, data, true);
3801 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3802 core::list<u16> *far_players, float far_d_nodes)
3804 float maxd = far_d_nodes*BS;
3805 v3f p_f = intToFloat(p, BS);
3809 SharedBuffer<u8> reply(replysize);
3810 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3811 writeS16(&reply[2], p.X);
3812 writeS16(&reply[4], p.Y);
3813 writeS16(&reply[6], p.Z);
3815 for(core::map<u16, RemoteClient*>::Iterator
3816 i = m_clients.getIterator();
3817 i.atEnd() == false; i++)
3819 // Get client and check that it is valid
3820 RemoteClient *client = i.getNode()->getValue();
3821 assert(client->peer_id == i.getNode()->getKey());
3822 if(client->serialization_version == SER_FMT_VER_INVALID)
3825 // Don't send if it's the same one
3826 if(client->peer_id == ignore_id)
3832 Player *player = m_env->getPlayer(client->peer_id);
3835 // If player is far away, only set modified blocks not sent
3836 v3f player_pos = player->getPosition();
3837 if(player_pos.getDistanceFrom(p_f) > maxd)
3839 far_players->push_back(client->peer_id);
3846 m_con.Send(client->peer_id, 0, reply, true);
3850 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3851 core::list<u16> *far_players, float far_d_nodes)
3853 float maxd = far_d_nodes*BS;
3854 v3f p_f = intToFloat(p, BS);
3856 for(core::map<u16, RemoteClient*>::Iterator
3857 i = m_clients.getIterator();
3858 i.atEnd() == false; i++)
3860 // Get client and check that it is valid
3861 RemoteClient *client = i.getNode()->getValue();
3862 assert(client->peer_id == i.getNode()->getKey());
3863 if(client->serialization_version == SER_FMT_VER_INVALID)
3866 // Don't send if it's the same one
3867 if(client->peer_id == ignore_id)
3873 Player *player = m_env->getPlayer(client->peer_id);
3876 // If player is far away, only set modified blocks not sent
3877 v3f player_pos = player->getPosition();
3878 if(player_pos.getDistanceFrom(p_f) > maxd)
3880 far_players->push_back(client->peer_id);
3887 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3888 SharedBuffer<u8> reply(replysize);
3889 writeU16(&reply[0], TOCLIENT_ADDNODE);
3890 writeS16(&reply[2], p.X);
3891 writeS16(&reply[4], p.Y);
3892 writeS16(&reply[6], p.Z);
3893 n.serialize(&reply[8], client->serialization_version);
3896 m_con.Send(client->peer_id, 0, reply, true);
3900 void Server::setBlockNotSent(v3s16 p)
3902 for(core::map<u16, RemoteClient*>::Iterator
3903 i = m_clients.getIterator();
3904 i.atEnd()==false; i++)
3906 RemoteClient *client = i.getNode()->getValue();
3907 client->SetBlockNotSent(p);
3911 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3913 DSTACK(__FUNCTION_NAME);
3915 v3s16 p = block->getPos();
3919 bool completely_air = true;
3920 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3921 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3922 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3924 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3926 completely_air = false;
3927 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3932 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3934 infostream<<"[completely air] ";
3935 infostream<<std::endl;
3939 Create a packet with the block in the right format
3942 std::ostringstream os(std::ios_base::binary);
3943 block->serialize(os, ver);
3944 std::string s = os.str();
3945 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3947 u32 replysize = 8 + blockdata.getSize();
3948 SharedBuffer<u8> reply(replysize);
3949 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3950 writeS16(&reply[2], p.X);
3951 writeS16(&reply[4], p.Y);
3952 writeS16(&reply[6], p.Z);
3953 memcpy(&reply[8], *blockdata, blockdata.getSize());
3955 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3956 <<": \tpacket size: "<<replysize<<std::endl;*/
3961 m_con.Send(peer_id, 1, reply, true);
3964 void Server::SendBlocks(float dtime)
3966 DSTACK(__FUNCTION_NAME);
3968 JMutexAutoLock envlock(m_env_mutex);
3969 JMutexAutoLock conlock(m_con_mutex);
3971 //TimeTaker timer("Server::SendBlocks");
3973 core::array<PrioritySortedBlockTransfer> queue;
3975 s32 total_sending = 0;
3978 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3980 for(core::map<u16, RemoteClient*>::Iterator
3981 i = m_clients.getIterator();
3982 i.atEnd() == false; i++)
3984 RemoteClient *client = i.getNode()->getValue();
3985 assert(client->peer_id == i.getNode()->getKey());
3987 total_sending += client->SendingCount();
3989 if(client->serialization_version == SER_FMT_VER_INVALID)
3992 client->GetNextBlocks(this, dtime, queue);
3997 // Lowest priority number comes first.
3998 // Lowest is most important.
4001 for(u32 i=0; i<queue.size(); i++)
4003 //TODO: Calculate limit dynamically
4004 if(total_sending >= g_settings->getS32
4005 ("max_simultaneous_block_sends_server_total"))
4008 PrioritySortedBlockTransfer q = queue[i];
4010 MapBlock *block = NULL;
4013 block = m_env->getMap().getBlockNoCreate(q.pos);
4015 catch(InvalidPositionException &e)
4020 RemoteClient *client = getClient(q.peer_id);
4022 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4024 client->SentBlock(q.pos);
4034 void Server::HandlePlayerHP(Player *player, s16 damage)
4036 if(player->hp > damage)
4038 player->hp -= damage;
4039 SendPlayerHP(player);
4043 infostream<<"Server::HandlePlayerHP(): Player "
4044 <<player->getName()<<" dies"<<std::endl;
4048 //TODO: Throw items around
4050 // Handle players that are not connected
4051 if(player->peer_id == PEER_ID_INEXISTENT){
4052 RespawnPlayer(player);
4056 SendPlayerHP(player);
4058 RemoteClient *client = getClient(player->peer_id);
4059 if(client->net_proto_version >= 3)
4061 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4065 RespawnPlayer(player);
4070 void Server::RespawnPlayer(Player *player)
4072 v3f pos = findSpawnPos(m_env->getServerMap());
4073 player->setPosition(pos);
4075 SendMovePlayer(player);
4076 SendPlayerHP(player);
4079 void Server::UpdateCrafting(u16 peer_id)
4081 DSTACK(__FUNCTION_NAME);
4083 Player* player = m_env->getPlayer(peer_id);
4087 Calculate crafting stuff
4089 if(g_settings->getBool("creative_mode") == false)
4091 InventoryList *clist = player->inventory.getList("craft");
4092 InventoryList *rlist = player->inventory.getList("craftresult");
4094 if(rlist && rlist->getUsedSlots() == 0)
4095 player->craftresult_is_preview = true;
4097 if(rlist && player->craftresult_is_preview)
4099 rlist->clearItems();
4101 if(clist && rlist && player->craftresult_is_preview)
4103 InventoryItem *items[9];
4104 for(u16 i=0; i<9; i++)
4106 items[i] = clist->getItem(i);
4109 // Get result of crafting grid
4110 InventoryItem *result = craft_get_result(items);
4112 rlist->addItem(result);
4115 } // if creative_mode == false
4118 RemoteClient* Server::getClient(u16 peer_id)
4120 DSTACK(__FUNCTION_NAME);
4121 //JMutexAutoLock lock(m_con_mutex);
4122 core::map<u16, RemoteClient*>::Node *n;
4123 n = m_clients.find(peer_id);
4124 // A client should exist for all peers
4126 return n->getValue();
4129 std::wstring Server::getStatusString()
4131 std::wostringstream os(std::ios_base::binary);
4134 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4136 os<<L", uptime="<<m_uptime.get();
4137 // Information about clients
4139 for(core::map<u16, RemoteClient*>::Iterator
4140 i = m_clients.getIterator();
4141 i.atEnd() == false; i++)
4143 // Get client and check that it is valid
4144 RemoteClient *client = i.getNode()->getValue();
4145 assert(client->peer_id == i.getNode()->getKey());
4146 if(client->serialization_version == SER_FMT_VER_INVALID)
4149 Player *player = m_env->getPlayer(client->peer_id);
4150 // Get name of player
4151 std::wstring name = L"unknown";
4153 name = narrow_to_wide(player->getName());
4154 // Add name to information string
4158 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4159 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4160 if(g_settings->get("motd") != "")
4161 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4165 // Saves g_settings to configpath given at initialization
4166 void Server::saveConfig()
4168 if(m_configpath != "")
4169 g_settings->updateConfigFile(m_configpath.c_str());
4172 void Server::notifyPlayer(const char *name, const std::wstring msg)
4174 Player *player = m_env->getPlayer(name);
4177 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4180 void Server::notifyPlayers(const std::wstring msg)
4182 BroadcastChatMessage(msg);
4185 v3f findSpawnPos(ServerMap &map)
4187 //return v3f(50,50,50)*BS;
4192 nodepos = v2s16(0,0);
4197 // Try to find a good place a few times
4198 for(s32 i=0; i<1000; i++)
4201 // We're going to try to throw the player to this position
4202 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4203 -range + (myrand()%(range*2)));
4204 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4205 // Get ground height at point (fallbacks to heightmap function)
4206 s16 groundheight = map.findGroundLevel(nodepos2d);
4207 // Don't go underwater
4208 if(groundheight < WATER_LEVEL)
4210 //infostream<<"-> Underwater"<<std::endl;
4213 // Don't go to high places
4214 if(groundheight > WATER_LEVEL + 4)
4216 //infostream<<"-> Underwater"<<std::endl;
4220 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4221 bool is_good = false;
4223 for(s32 i=0; i<10; i++){
4224 v3s16 blockpos = getNodeBlockPos(nodepos);
4225 map.emergeBlock(blockpos, true);
4226 MapNode n = map.getNodeNoEx(nodepos);
4227 if(n.getContent() == CONTENT_AIR){
4238 // Found a good place
4239 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4245 return intToFloat(nodepos, BS);
4248 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4251 Try to get an existing player
4253 Player *player = m_env->getPlayer(name);
4256 // If player is already connected, cancel
4257 if(player->peer_id != 0)
4259 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4264 player->peer_id = peer_id;
4266 // Reset inventory to creative if in creative mode
4267 if(g_settings->getBool("creative_mode"))
4269 // Warning: double code below
4270 // Backup actual inventory
4271 player->inventory_backup = new Inventory();
4272 *(player->inventory_backup) = player->inventory;
4273 // Set creative inventory
4274 craft_set_creative_inventory(player);
4281 If player with the wanted peer_id already exists, cancel.
4283 if(m_env->getPlayer(peer_id) != NULL)
4285 infostream<<"emergePlayer(): Player with wrong name but same"
4286 " peer_id already exists"<<std::endl;
4294 // Add authentication stuff
4295 m_authmanager.add(name);
4296 m_authmanager.setPassword(name, password);
4297 m_authmanager.setPrivs(name,
4298 stringToPrivs(g_settings->get("default_privs")));
4304 infostream<<"Server: Finding spawn place for player \""
4305 <<name<<"\""<<std::endl;
4307 v3f pos = findSpawnPos(m_env->getServerMap());
4309 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4312 Add player to environment
4315 m_env->addPlayer(player);
4318 Add stuff to inventory
4321 if(g_settings->getBool("creative_mode"))
4323 // Warning: double code above
4324 // Backup actual inventory
4325 player->inventory_backup = new Inventory();
4326 *(player->inventory_backup) = player->inventory;
4327 // Set creative inventory
4328 craft_set_creative_inventory(player);
4330 else if(g_settings->getBool("give_initial_stuff"))
4332 craft_give_initial_stuff(player);
4337 } // create new player
4340 void Server::handlePeerChange(PeerChange &c)
4342 JMutexAutoLock envlock(m_env_mutex);
4343 JMutexAutoLock conlock(m_con_mutex);
4345 if(c.type == PEER_ADDED)
4352 core::map<u16, RemoteClient*>::Node *n;
4353 n = m_clients.find(c.peer_id);
4354 // The client shouldn't already exist
4358 RemoteClient *client = new RemoteClient();
4359 client->peer_id = c.peer_id;
4360 m_clients.insert(client->peer_id, client);
4363 else if(c.type == PEER_REMOVED)
4370 core::map<u16, RemoteClient*>::Node *n;
4371 n = m_clients.find(c.peer_id);
4372 // The client should exist
4376 Mark objects to be not known by the client
4378 RemoteClient *client = n->getValue();
4380 for(core::map<u16, bool>::Iterator
4381 i = client->m_known_objects.getIterator();
4382 i.atEnd()==false; i++)
4385 u16 id = i.getNode()->getKey();
4386 ServerActiveObject* obj = m_env->getActiveObject(id);
4388 if(obj && obj->m_known_by_count > 0)
4389 obj->m_known_by_count--;
4392 // Collect information about leaving in chat
4393 std::wstring message;
4395 Player *player = m_env->getPlayer(c.peer_id);
4398 std::wstring name = narrow_to_wide(player->getName());
4401 message += L" left game";
4403 message += L" (timed out)";
4409 m_env->removePlayer(c.peer_id);
4412 // Set player client disconnected
4414 Player *player = m_env->getPlayer(c.peer_id);
4416 player->peer_id = 0;
4423 std::ostringstream os(std::ios_base::binary);
4424 for(core::map<u16, RemoteClient*>::Iterator
4425 i = m_clients.getIterator();
4426 i.atEnd() == false; i++)
4428 RemoteClient *client = i.getNode()->getValue();
4429 assert(client->peer_id == i.getNode()->getKey());
4430 if(client->serialization_version == SER_FMT_VER_INVALID)
4433 Player *player = m_env->getPlayer(client->peer_id);
4436 // Get name of player
4437 os<<player->getName()<<" ";
4440 actionstream<<player->getName()<<" "
4441 <<(c.timeout?"times out.":"leaves game.")
4442 <<" List of players: "
4443 <<os.str()<<std::endl;
4448 delete m_clients[c.peer_id];
4449 m_clients.remove(c.peer_id);
4451 // Send player info to all remaining clients
4454 // Send leave chat message to all remaining clients
4455 BroadcastChatMessage(message);
4464 void Server::handlePeerChanges()
4466 while(m_peer_change_queue.size() > 0)
4468 PeerChange c = m_peer_change_queue.pop_front();
4470 infostream<<"Server: Handling peer change: "
4471 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4474 handlePeerChange(c);
4478 u64 Server::getPlayerPrivs(Player *player)
4482 std::string playername = player->getName();
4483 // Local player gets all privileges regardless of
4484 // what's set on their account.
4485 if(g_settings->get("name") == playername)
4491 return getPlayerAuthPrivs(playername);
4495 void dedicated_server_loop(Server &server, bool &kill)
4497 DSTACK(__FUNCTION_NAME);
4499 infostream<<DTIME<<std::endl;
4500 infostream<<"========================"<<std::endl;
4501 infostream<<"Running dedicated server"<<std::endl;
4502 infostream<<"========================"<<std::endl;
4503 infostream<<std::endl;
4505 IntervalLimiter m_profiler_interval;
4509 // This is kind of a hack but can be done like this
4510 // because server.step() is very light
4512 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4517 if(server.getShutdownRequested() || kill)
4519 infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4526 float profiler_print_interval =
4527 g_settings->getFloat("profiler_print_interval");
4528 if(profiler_print_interval != 0)
4530 if(m_profiler_interval.step(0.030, profiler_print_interval))
4532 infostream<<"Profiler:"<<std::endl;
4533 g_profiler->print(infostream);
4534 g_profiler->clear();
4541 static int counter = 0;
4547 core::list<PlayerInfo> list = server.getPlayerInfo();
4548 core::list<PlayerInfo>::Iterator i;
4549 static u32 sum_old = 0;
4550 u32 sum = PIChecksum(list);
4553 infostream<<DTIME<<"Player info:"<<std::endl;
4554 for(i=list.begin(); i!=list.end(); i++)
4556 i->PrintLine(&infostream);