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"
47 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
49 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
51 class MapEditEventIgnorer
54 MapEditEventIgnorer(bool *flag):
63 ~MapEditEventIgnorer()
76 void * ServerThread::Thread()
80 log_register_thread("ServerThread");
82 DSTACK(__FUNCTION_NAME);
84 BEGIN_DEBUG_EXCEPTION_HANDLER
89 //TimeTaker timer("AsyncRunStep() + Receive()");
92 //TimeTaker timer("AsyncRunStep()");
93 m_server->AsyncRunStep();
96 //infostream<<"Running m_server->Receive()"<<std::endl;
99 catch(con::NoIncomingDataException &e)
102 catch(con::PeerNotFoundException &e)
104 infostream<<"Server: PeerNotFoundException"<<std::endl;
108 END_DEBUG_EXCEPTION_HANDLER(errorstream)
113 void * EmergeThread::Thread()
117 log_register_thread("EmergeThread");
119 DSTACK(__FUNCTION_NAME);
121 BEGIN_DEBUG_EXCEPTION_HANDLER
123 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
126 Get block info from queue, emerge them and send them
129 After queue is empty, exit.
133 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
137 SharedPtr<QueuedBlockEmerge> q(qptr);
143 Do not generate over-limit
145 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
146 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
147 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
148 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
149 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
150 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
153 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
155 //TimeTaker timer("block emerge");
158 Try to emerge it from somewhere.
160 If it is only wanted as optional, only loading from disk
165 Check if any peer wants it as non-optional. In that case it
168 Also decrement the emerge queue count in clients.
171 bool only_from_disk = true;
174 core::map<u16, u8>::Iterator i;
175 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
177 //u16 peer_id = i.getNode()->getKey();
180 u8 flags = i.getNode()->getValue();
181 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
182 only_from_disk = false;
187 if(enable_mapgen_debug_info)
188 infostream<<"EmergeThread: p="
189 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
190 <<"only_from_disk="<<only_from_disk<<std::endl;
192 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
194 //core::map<v3s16, MapBlock*> changed_blocks;
195 //core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
197 MapBlock *block = NULL;
198 bool got_block = true;
199 core::map<v3s16, MapBlock*> modified_blocks;
202 Fetch block from map or generate a single block
205 JMutexAutoLock envlock(m_server->m_env_mutex);
207 // Load sector if it isn't loaded
208 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
209 //map.loadSectorFull(p2d);
210 map.loadSectorMeta(p2d);
212 block = map.getBlockNoCreateNoEx(p);
213 if(!block || block->isDummy() || !block->isGenerated())
215 if(enable_mapgen_debug_info)
216 infostream<<"EmergeThread: not in memory, loading"<<std::endl;
218 // Get, load or create sector
219 /*ServerMapSector *sector =
220 (ServerMapSector*)map.createSector(p2d);*/
222 // Load/generate block
224 /*block = map.emergeBlock(p, sector, changed_blocks,
225 lighting_invalidated_blocks);*/
227 block = map.loadBlock(p);
229 if(only_from_disk == false)
231 if(block == NULL || block->isGenerated() == false)
233 if(enable_mapgen_debug_info)
234 infostream<<"EmergeThread: generating"<<std::endl;
235 block = map.generateBlock(p, modified_blocks);
239 if(enable_mapgen_debug_info)
240 infostream<<"EmergeThread: ended up with: "
241 <<analyze_block(block)<<std::endl;
250 Ignore map edit events, they will not need to be
251 sent to anybody because the block hasn't been sent
254 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
256 // Activate objects and stuff
257 m_server->m_env->activateBlock(block, 3600);
262 /*if(block->getLightingExpired()){
263 lighting_invalidated_blocks[block->getPos()] = block;
267 // TODO: Some additional checking and lighting updating,
272 JMutexAutoLock envlock(m_server->m_env_mutex);
277 Collect a list of blocks that have been modified in
278 addition to the fetched one.
282 if(lighting_invalidated_blocks.size() > 0)
284 /*infostream<<"lighting "<<lighting_invalidated_blocks.size()
285 <<" blocks"<<std::endl;*/
287 // 50-100ms for single block generation
288 //TimeTaker timer("** EmergeThread updateLighting");
290 // Update lighting without locking the environment mutex,
291 // add modified blocks to changed blocks
292 map.updateLighting(lighting_invalidated_blocks, modified_blocks);
295 // Add all from changed_blocks to modified_blocks
296 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
297 i.atEnd() == false; i++)
299 MapBlock *block = i.getNode()->getValue();
300 modified_blocks.insert(block->getPos(), block);
304 // If we got no block, there should be no invalidated blocks
307 //assert(lighting_invalidated_blocks.size() == 0);
313 Set sent status of modified blocks on clients
316 // NOTE: Server's clients are also behind the connection mutex
317 JMutexAutoLock lock(m_server->m_con_mutex);
320 Add the originally fetched block to the modified list
324 modified_blocks.insert(p, block);
328 Set the modified blocks unsent for all the clients
331 for(core::map<u16, RemoteClient*>::Iterator
332 i = m_server->m_clients.getIterator();
333 i.atEnd() == false; i++)
335 RemoteClient *client = i.getNode()->getValue();
337 if(modified_blocks.size() > 0)
339 // Remove block from sent history
340 client->SetBlocksNotSent(modified_blocks);
346 END_DEBUG_EXCEPTION_HANDLER(errorstream)
351 void RemoteClient::GetNextBlocks(Server *server, float dtime,
352 core::array<PrioritySortedBlockTransfer> &dest)
354 DSTACK(__FUNCTION_NAME);
357 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
360 m_nothing_to_send_pause_timer -= dtime;
361 m_nearest_unsent_reset_timer += dtime;
363 if(m_nothing_to_send_pause_timer >= 0)
368 // Won't send anything if already sending
369 if(m_blocks_sending.size() >= g_settings->getU16
370 ("max_simultaneous_block_sends_per_client"))
372 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
376 //TimeTaker timer("RemoteClient::GetNextBlocks");
378 Player *player = server->m_env->getPlayer(peer_id);
380 assert(player != NULL);
382 v3f playerpos = player->getPosition();
383 v3f playerspeed = player->getSpeed();
384 v3f playerspeeddir(0,0,0);
385 if(playerspeed.getLength() > 1.0*BS)
386 playerspeeddir = playerspeed / playerspeed.getLength();
387 // Predict to next block
388 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
390 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
392 v3s16 center = getNodeBlockPos(center_nodepos);
394 // Camera position and direction
395 v3f camera_pos = player->getEyePosition();
396 v3f camera_dir = v3f(0,0,1);
397 camera_dir.rotateYZBy(player->getPitch());
398 camera_dir.rotateXZBy(player->getYaw());
400 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
401 <<camera_dir.Z<<")"<<std::endl;*/
404 Get the starting value of the block finder radius.
407 if(m_last_center != center)
409 m_nearest_unsent_d = 0;
410 m_last_center = center;
413 /*infostream<<"m_nearest_unsent_reset_timer="
414 <<m_nearest_unsent_reset_timer<<std::endl;*/
416 // Reset periodically to workaround for some bugs or stuff
417 if(m_nearest_unsent_reset_timer > 20.0)
419 m_nearest_unsent_reset_timer = 0;
420 m_nearest_unsent_d = 0;
421 //infostream<<"Resetting m_nearest_unsent_d for "
422 // <<server->getPlayerName(peer_id)<<std::endl;
425 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
426 s16 d_start = m_nearest_unsent_d;
428 //infostream<<"d_start="<<d_start<<std::endl;
430 u16 max_simul_sends_setting = g_settings->getU16
431 ("max_simultaneous_block_sends_per_client");
432 u16 max_simul_sends_usually = max_simul_sends_setting;
435 Check the time from last addNode/removeNode.
437 Decrease send rate if player is building stuff.
439 m_time_from_building += dtime;
440 if(m_time_from_building < g_settings->getFloat(
441 "full_block_send_enable_min_time_from_building"))
443 max_simul_sends_usually
444 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
448 Number of blocks sending + number of blocks selected for sending
450 u32 num_blocks_selected = m_blocks_sending.size();
453 next time d will be continued from the d from which the nearest
454 unsent block was found this time.
456 This is because not necessarily any of the blocks found this
457 time are actually sent.
459 s32 new_nearest_unsent_d = -1;
461 s16 d_max = g_settings->getS16("max_block_send_distance");
462 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
464 // Don't loop very much at a time
465 s16 max_d_increment_at_time = 2;
466 if(d_max > d_start + max_d_increment_at_time)
467 d_max = d_start + max_d_increment_at_time;
468 /*if(d_max_gen > d_start+2)
469 d_max_gen = d_start+2;*/
471 //infostream<<"Starting from "<<d_start<<std::endl;
473 s32 nearest_emerged_d = -1;
474 s32 nearest_emergefull_d = -1;
475 s32 nearest_sent_d = -1;
476 bool queue_is_full = false;
479 for(d = d_start; d <= d_max; d++)
481 /*errorstream<<"checking d="<<d<<" for "
482 <<server->getPlayerName(peer_id)<<std::endl;*/
483 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
486 If m_nearest_unsent_d was changed by the EmergeThread
487 (it can change it to 0 through SetBlockNotSent),
489 Else update m_nearest_unsent_d
491 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
493 d = m_nearest_unsent_d;
494 last_nearest_unsent_d = m_nearest_unsent_d;
498 Get the border/face dot coordinates of a "d-radiused"
501 core::list<v3s16> list;
502 getFacePositions(list, d);
504 core::list<v3s16>::Iterator li;
505 for(li=list.begin(); li!=list.end(); li++)
507 v3s16 p = *li + center;
511 - Don't allow too many simultaneous transfers
512 - EXCEPT when the blocks are very close
514 Also, don't send blocks that are already flying.
517 // Start with the usual maximum
518 u16 max_simul_dynamic = max_simul_sends_usually;
520 // If block is very close, allow full maximum
521 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
522 max_simul_dynamic = max_simul_sends_setting;
524 // Don't select too many blocks for sending
525 if(num_blocks_selected >= max_simul_dynamic)
527 queue_is_full = true;
528 goto queue_full_break;
531 // Don't send blocks that are currently being transferred
532 if(m_blocks_sending.find(p) != NULL)
538 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
539 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
540 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
541 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
542 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
543 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
546 // If this is true, inexistent block will be made from scratch
547 bool generate = d <= d_max_gen;
550 /*// Limit the generating area vertically to 2/3
551 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
554 // Limit the send area vertically to 1/2
555 if(abs(p.Y - center.Y) > d_max / 2)
561 If block is far away, don't generate it unless it is
567 // Block center y in nodes
568 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
569 // Don't generate if it's very high or very low
570 if(y < -64 || y > 64)
574 v2s16 p2d_nodes_center(
578 // Get ground height in nodes
579 s16 gh = server->m_env->getServerMap().findGroundLevel(
582 // If differs a lot, don't generate
583 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
585 // Actually, don't even send it
591 //infostream<<"d="<<d<<std::endl;
594 Don't generate or send if not in sight
595 FIXME This only works if the client uses a small enough
596 FOV setting. The default of 72 degrees is fine.
599 float camera_fov = (72.0*PI/180) * 4./3.;
600 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
606 Don't send already sent blocks
609 if(m_blocks_sent.find(p) != NULL)
616 Check if map has this block
618 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
620 bool surely_not_found_on_disk = false;
621 bool block_is_invalid = false;
624 // Reset usage timer, this block will be of use in the future.
625 block->resetUsageTimer();
627 // Block is dummy if data doesn't exist.
628 // It means it has been not found from disk and not generated
631 surely_not_found_on_disk = true;
634 // Block is valid if lighting is up-to-date and data exists
635 if(block->isValid() == false)
637 block_is_invalid = true;
640 /*if(block->isFullyGenerated() == false)
642 block_is_invalid = true;
647 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
648 v2s16 chunkpos = map->sector_to_chunk(p2d);
649 if(map->chunkNonVolatile(chunkpos) == false)
650 block_is_invalid = true;
652 if(block->isGenerated() == false)
653 block_is_invalid = true;
656 If block is not close, don't send it unless it is near
659 Block is near ground level if night-time mesh
660 differs from day-time mesh.
664 if(block->dayNightDiffed() == false)
671 If block has been marked to not exist on disk (dummy)
672 and generating new ones is not wanted, skip block.
674 if(generate == false && surely_not_found_on_disk == true)
681 Add inexistent block to emerge queue.
683 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
685 //TODO: Get value from somewhere
686 // Allow only one block in emerge queue
687 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
688 // Allow two blocks in queue per client
689 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
690 if(server->m_emerge_queue.peerItemCount(peer_id) < 25)
692 //infostream<<"Adding block to emerge queue"<<std::endl;
694 // Add it to the emerge queue and trigger the thread
697 if(generate == false)
698 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
700 server->m_emerge_queue.addBlock(peer_id, p, flags);
701 server->m_emergethread.trigger();
703 if(nearest_emerged_d == -1)
704 nearest_emerged_d = d;
706 if(nearest_emergefull_d == -1)
707 nearest_emergefull_d = d;
714 if(nearest_sent_d == -1)
718 Add block to send queue
721 /*errorstream<<"sending from d="<<d<<" to "
722 <<server->getPlayerName(peer_id)<<std::endl;*/
724 PrioritySortedBlockTransfer q((float)d, p, peer_id);
728 num_blocks_selected += 1;
733 //infostream<<"Stopped at "<<d<<std::endl;
735 // If nothing was found for sending and nothing was queued for
736 // emerging, continue next time browsing from here
737 if(nearest_emerged_d != -1){
738 new_nearest_unsent_d = nearest_emerged_d;
739 } else if(nearest_emergefull_d != -1){
740 new_nearest_unsent_d = nearest_emergefull_d;
742 if(d > g_settings->getS16("max_block_send_distance")){
743 new_nearest_unsent_d = 0;
744 m_nothing_to_send_pause_timer = 2.0;
745 /*infostream<<"GetNextBlocks(): d wrapped around for "
746 <<server->getPlayerName(peer_id)
747 <<"; setting to 0 and pausing"<<std::endl;*/
749 if(nearest_sent_d != -1)
750 new_nearest_unsent_d = nearest_sent_d;
752 new_nearest_unsent_d = d;
756 if(new_nearest_unsent_d != -1)
757 m_nearest_unsent_d = new_nearest_unsent_d;
759 /*timer_result = timer.stop(true);
760 if(timer_result != 0)
761 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
764 void RemoteClient::SendObjectData(
767 core::map<v3s16, bool> &stepped_blocks
770 DSTACK(__FUNCTION_NAME);
772 // Can't send anything without knowing version
773 if(serialization_version == SER_FMT_VER_INVALID)
775 infostream<<"RemoteClient::SendObjectData(): Not sending, no version."
781 Send a TOCLIENT_OBJECTDATA packet.
785 u16 number of player positions
797 std::ostringstream os(std::ios_base::binary);
801 writeU16(buf, TOCLIENT_OBJECTDATA);
802 os.write((char*)buf, 2);
805 Get and write player data
808 // Get connected players
809 core::list<Player*> players = server->m_env->getPlayers(true);
811 // Write player count
812 u16 playercount = players.size();
813 writeU16(buf, playercount);
814 os.write((char*)buf, 2);
816 core::list<Player*>::Iterator i;
817 for(i = players.begin();
818 i != players.end(); i++)
822 v3f pf = player->getPosition();
823 v3f sf = player->getSpeed();
825 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
826 v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
827 s32 pitch_i (player->getPitch() * 100);
828 s32 yaw_i (player->getYaw() * 100);
830 writeU16(buf, player->peer_id);
831 os.write((char*)buf, 2);
832 writeV3S32(buf, position_i);
833 os.write((char*)buf, 12);
834 writeV3S32(buf, speed_i);
835 os.write((char*)buf, 12);
836 writeS32(buf, pitch_i);
837 os.write((char*)buf, 4);
838 writeS32(buf, yaw_i);
839 os.write((char*)buf, 4);
843 Get and write object data (dummy, for compatibility)
848 os.write((char*)buf, 2);
854 //infostream<<"Server: Sending object data to "<<peer_id<<std::endl;
857 std::string s = os.str();
858 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
859 // Send as unreliable
860 server->m_con.Send(peer_id, 0, data, false);
863 void RemoteClient::GotBlock(v3s16 p)
865 if(m_blocks_sending.find(p) != NULL)
866 m_blocks_sending.remove(p);
869 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
870 " m_blocks_sending"<<std::endl;*/
871 m_excess_gotblocks++;
873 m_blocks_sent.insert(p, true);
876 void RemoteClient::SentBlock(v3s16 p)
878 if(m_blocks_sending.find(p) == NULL)
879 m_blocks_sending.insert(p, 0.0);
881 infostream<<"RemoteClient::SentBlock(): Sent block"
882 " already in m_blocks_sending"<<std::endl;
885 void RemoteClient::SetBlockNotSent(v3s16 p)
887 m_nearest_unsent_d = 0;
889 if(m_blocks_sending.find(p) != NULL)
890 m_blocks_sending.remove(p);
891 if(m_blocks_sent.find(p) != NULL)
892 m_blocks_sent.remove(p);
895 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
897 m_nearest_unsent_d = 0;
899 for(core::map<v3s16, MapBlock*>::Iterator
900 i = blocks.getIterator();
901 i.atEnd()==false; i++)
903 v3s16 p = i.getNode()->getKey();
905 if(m_blocks_sending.find(p) != NULL)
906 m_blocks_sending.remove(p);
907 if(m_blocks_sent.find(p) != NULL)
908 m_blocks_sent.remove(p);
916 PlayerInfo::PlayerInfo()
922 void PlayerInfo::PrintLine(std::ostream *s)
925 (*s)<<"\""<<name<<"\" ("
926 <<(position.X/10)<<","<<(position.Y/10)
927 <<","<<(position.Z/10)<<") ";
929 (*s)<<" avg_rtt="<<avg_rtt;
933 u32 PIChecksum(core::list<PlayerInfo> &l)
935 core::list<PlayerInfo>::Iterator i;
938 for(i=l.begin(); i!=l.end(); i++)
940 checksum += a * (i->id+1);
941 checksum ^= 0x435aafcd;
952 ModSpec(const std::string &name_="", const std::string path_=""):
958 static core::list<ModSpec> getMods(core::list<std::string> &modspaths)
960 core::list<ModSpec> mods;
961 for(core::list<std::string>::Iterator i = modspaths.begin();
962 i != modspaths.end(); i++){
963 std::string modspath = *i;
964 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(modspath);
965 for(u32 j=0; j<dirlist.size(); j++){
968 std::string modname = dirlist[j].name;
969 std::string modpath = modspath + DIR_DELIM + modname;
970 mods.push_back(ModSpec(modname, modpath));
981 std::string mapsavedir,
982 std::string configpath
985 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
986 m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"),
987 m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"),
989 m_toolmgr(createToolDefManager()),
990 m_nodemgr(createNodeDefManager()),
992 m_emergethread(this),
994 m_time_of_day_send_timer(0),
996 m_mapsavedir(mapsavedir),
997 m_configpath(configpath),
998 m_shutdown_requested(false),
999 m_ignore_map_edit_events(false),
1000 m_ignore_map_edit_events_peer_id(0)
1002 m_liquid_transform_timer = 0.0;
1003 m_print_info_timer = 0.0;
1004 m_objectdata_timer = 0.0;
1005 m_emergethread_trigger_timer = 0.0;
1006 m_savemap_timer = 0.0;
1010 m_step_dtime_mutex.Init();
1013 JMutexAutoLock envlock(m_env_mutex);
1014 JMutexAutoLock conlock(m_con_mutex);
1016 infostream<<"m_nodemgr="<<m_nodemgr<<std::endl;
1018 // Initialize default node definitions
1019 content_mapnode_init(NULL, m_nodemgr);
1021 // Add default global mod path
1022 m_modspaths.push_back(porting::path_data + DIR_DELIM + "mods");
1024 // Initialize scripting
1026 infostream<<"Server: Initializing scripting"<<std::endl;
1027 m_lua = script_init();
1030 scriptapi_export(m_lua, this);
1031 // Load and run scripts
1032 core::list<ModSpec> mods = getMods(m_modspaths);
1033 for(core::list<ModSpec>::Iterator i = mods.begin();
1034 i != mods.end(); i++){
1036 infostream<<"Server: Loading mod \""<<mod.name<<"\""<<std::endl;
1037 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1038 bool success = script_load(m_lua, scriptpath.c_str());
1040 errorstream<<"Server: Failed to load and run "
1041 <<scriptpath<<std::endl;
1046 // Initialize Environment
1048 m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua, this);
1050 // Give environment reference to scripting api
1051 scriptapi_add_environment(m_lua, m_env);
1053 // Register us to receive map edit events
1054 m_env->getMap().addEventReceiver(this);
1056 // If file exists, load environment metadata
1057 if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt"))
1059 infostream<<"Server: Loading environment metadata"<<std::endl;
1060 m_env->loadMeta(m_mapsavedir);
1064 infostream<<"Server: Loading players"<<std::endl;
1065 m_env->deSerializePlayers(m_mapsavedir);
1070 infostream<<"Server::~Server()"<<std::endl;
1073 Send shutdown message
1076 JMutexAutoLock conlock(m_con_mutex);
1078 std::wstring line = L"*** Server shutting down";
1081 Send the message to clients
1083 for(core::map<u16, RemoteClient*>::Iterator
1084 i = m_clients.getIterator();
1085 i.atEnd() == false; i++)
1087 // Get client and check that it is valid
1088 RemoteClient *client = i.getNode()->getValue();
1089 assert(client->peer_id == i.getNode()->getKey());
1090 if(client->serialization_version == SER_FMT_VER_INVALID)
1094 SendChatMessage(client->peer_id, line);
1096 catch(con::PeerNotFoundException &e)
1102 JMutexAutoLock envlock(m_env_mutex);
1107 infostream<<"Server: Saving players"<<std::endl;
1108 m_env->serializePlayers(m_mapsavedir);
1111 Save environment metadata
1113 infostream<<"Server: Saving environment metadata"<<std::endl;
1114 m_env->saveMeta(m_mapsavedir);
1126 JMutexAutoLock clientslock(m_con_mutex);
1128 for(core::map<u16, RemoteClient*>::Iterator
1129 i = m_clients.getIterator();
1130 i.atEnd() == false; i++)
1133 // NOTE: These are removed by env destructor
1135 u16 peer_id = i.getNode()->getKey();
1136 JMutexAutoLock envlock(m_env_mutex);
1137 m_env->removePlayer(peer_id);
1141 delete i.getNode()->getValue();
1145 // Delete Environment
1151 // Deinitialize scripting
1152 infostream<<"Server: Deinitializing scripting"<<std::endl;
1153 script_deinit(m_lua);
1156 void Server::start(unsigned short port)
1158 DSTACK(__FUNCTION_NAME);
1159 // Stop thread if already running
1162 // Initialize connection
1163 m_con.SetTimeoutMs(30);
1167 m_thread.setRun(true);
1170 infostream<<"Server: Started on port "<<port<<std::endl;
1175 DSTACK(__FUNCTION_NAME);
1177 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1179 // Stop threads (set run=false first so both start stopping)
1180 m_thread.setRun(false);
1181 m_emergethread.setRun(false);
1183 m_emergethread.stop();
1185 infostream<<"Server: Threads stopped"<<std::endl;
1188 void Server::step(float dtime)
1190 DSTACK(__FUNCTION_NAME);
1195 JMutexAutoLock lock(m_step_dtime_mutex);
1196 m_step_dtime += dtime;
1200 void Server::AsyncRunStep()
1202 DSTACK(__FUNCTION_NAME);
1204 g_profiler->add("Server::AsyncRunStep (num)", 1);
1208 JMutexAutoLock lock1(m_step_dtime_mutex);
1209 dtime = m_step_dtime;
1213 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
1214 // Send blocks to clients
1221 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1223 //infostream<<"Server steps "<<dtime<<std::endl;
1224 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1227 JMutexAutoLock lock1(m_step_dtime_mutex);
1228 m_step_dtime -= dtime;
1235 m_uptime.set(m_uptime.get() + dtime);
1239 // Process connection's timeouts
1240 JMutexAutoLock lock2(m_con_mutex);
1241 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1242 m_con.RunTimeouts(dtime);
1246 // This has to be called so that the client list gets synced
1247 // with the peer list of the connection
1248 handlePeerChanges();
1252 Update m_time_of_day and overall game time
1255 JMutexAutoLock envlock(m_env_mutex);
1257 m_time_counter += dtime;
1258 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1259 u32 units = (u32)(m_time_counter*speed);
1260 m_time_counter -= (f32)units / speed;
1262 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1264 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1267 Send to clients at constant intervals
1270 m_time_of_day_send_timer -= dtime;
1271 if(m_time_of_day_send_timer < 0.0)
1273 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1275 //JMutexAutoLock envlock(m_env_mutex);
1276 JMutexAutoLock conlock(m_con_mutex);
1278 for(core::map<u16, RemoteClient*>::Iterator
1279 i = m_clients.getIterator();
1280 i.atEnd() == false; i++)
1282 RemoteClient *client = i.getNode()->getValue();
1283 //Player *player = m_env->getPlayer(client->peer_id);
1285 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1286 m_env->getTimeOfDay());
1288 m_con.Send(client->peer_id, 0, data, true);
1294 JMutexAutoLock lock(m_env_mutex);
1296 ScopeProfiler sp(g_profiler, "SEnv step");
1297 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1301 const float map_timer_and_unload_dtime = 5.15;
1302 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1304 JMutexAutoLock lock(m_env_mutex);
1305 // Run Map's timers and unload unused data
1306 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1307 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1308 g_settings->getFloat("server_unload_unused_data_timeout"));
1318 m_liquid_transform_timer += dtime;
1319 if(m_liquid_transform_timer >= 1.00)
1321 m_liquid_transform_timer -= 1.00;
1323 JMutexAutoLock lock(m_env_mutex);
1325 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1327 core::map<v3s16, MapBlock*> modified_blocks;
1328 m_env->getMap().transformLiquids(modified_blocks);
1333 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1334 ServerMap &map = ((ServerMap&)m_env->getMap());
1335 map.updateLighting(modified_blocks, lighting_modified_blocks);
1337 // Add blocks modified by lighting to modified_blocks
1338 for(core::map<v3s16, MapBlock*>::Iterator
1339 i = lighting_modified_blocks.getIterator();
1340 i.atEnd() == false; i++)
1342 MapBlock *block = i.getNode()->getValue();
1343 modified_blocks.insert(block->getPos(), block);
1347 Set the modified blocks unsent for all the clients
1350 JMutexAutoLock lock2(m_con_mutex);
1352 for(core::map<u16, RemoteClient*>::Iterator
1353 i = m_clients.getIterator();
1354 i.atEnd() == false; i++)
1356 RemoteClient *client = i.getNode()->getValue();
1358 if(modified_blocks.size() > 0)
1360 // Remove block from sent history
1361 client->SetBlocksNotSent(modified_blocks);
1366 // Periodically print some info
1368 float &counter = m_print_info_timer;
1374 JMutexAutoLock lock2(m_con_mutex);
1376 if(m_clients.size() != 0)
1377 infostream<<"Players:"<<std::endl;
1378 for(core::map<u16, RemoteClient*>::Iterator
1379 i = m_clients.getIterator();
1380 i.atEnd() == false; i++)
1382 //u16 peer_id = i.getNode()->getKey();
1383 RemoteClient *client = i.getNode()->getValue();
1384 Player *player = m_env->getPlayer(client->peer_id);
1387 infostream<<"* "<<player->getName()<<"\t";
1388 client->PrintInfo(infostream);
1393 //if(g_settings->getBool("enable_experimental"))
1397 Check added and deleted active objects
1400 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1401 JMutexAutoLock envlock(m_env_mutex);
1402 JMutexAutoLock conlock(m_con_mutex);
1404 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1406 // Radius inside which objects are active
1407 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1408 radius *= MAP_BLOCKSIZE;
1410 for(core::map<u16, RemoteClient*>::Iterator
1411 i = m_clients.getIterator();
1412 i.atEnd() == false; i++)
1414 RemoteClient *client = i.getNode()->getValue();
1415 Player *player = m_env->getPlayer(client->peer_id);
1418 // This can happen if the client timeouts somehow
1419 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1421 <<" has no associated player"<<std::endl;*/
1424 v3s16 pos = floatToInt(player->getPosition(), BS);
1426 core::map<u16, bool> removed_objects;
1427 core::map<u16, bool> added_objects;
1428 m_env->getRemovedActiveObjects(pos, radius,
1429 client->m_known_objects, removed_objects);
1430 m_env->getAddedActiveObjects(pos, radius,
1431 client->m_known_objects, added_objects);
1433 // Ignore if nothing happened
1434 if(removed_objects.size() == 0 && added_objects.size() == 0)
1436 //infostream<<"active objects: none changed"<<std::endl;
1440 std::string data_buffer;
1444 // Handle removed objects
1445 writeU16((u8*)buf, removed_objects.size());
1446 data_buffer.append(buf, 2);
1447 for(core::map<u16, bool>::Iterator
1448 i = removed_objects.getIterator();
1449 i.atEnd()==false; i++)
1452 u16 id = i.getNode()->getKey();
1453 ServerActiveObject* obj = m_env->getActiveObject(id);
1455 // Add to data buffer for sending
1456 writeU16((u8*)buf, i.getNode()->getKey());
1457 data_buffer.append(buf, 2);
1459 // Remove from known objects
1460 client->m_known_objects.remove(i.getNode()->getKey());
1462 if(obj && obj->m_known_by_count > 0)
1463 obj->m_known_by_count--;
1466 // Handle added objects
1467 writeU16((u8*)buf, added_objects.size());
1468 data_buffer.append(buf, 2);
1469 for(core::map<u16, bool>::Iterator
1470 i = added_objects.getIterator();
1471 i.atEnd()==false; i++)
1474 u16 id = i.getNode()->getKey();
1475 ServerActiveObject* obj = m_env->getActiveObject(id);
1478 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1480 infostream<<"WARNING: "<<__FUNCTION_NAME
1481 <<": NULL object"<<std::endl;
1483 type = obj->getType();
1485 // Add to data buffer for sending
1486 writeU16((u8*)buf, id);
1487 data_buffer.append(buf, 2);
1488 writeU8((u8*)buf, type);
1489 data_buffer.append(buf, 1);
1492 data_buffer.append(serializeLongString(
1493 obj->getClientInitializationData()));
1495 data_buffer.append(serializeLongString(""));
1497 // Add to known objects
1498 client->m_known_objects.insert(i.getNode()->getKey(), false);
1501 obj->m_known_by_count++;
1505 SharedBuffer<u8> reply(2 + data_buffer.size());
1506 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1507 memcpy((char*)&reply[2], data_buffer.c_str(),
1508 data_buffer.size());
1510 m_con.Send(client->peer_id, 0, reply, true);
1512 infostream<<"Server: Sent object remove/add: "
1513 <<removed_objects.size()<<" removed, "
1514 <<added_objects.size()<<" added, "
1515 <<"packet size is "<<reply.getSize()<<std::endl;
1520 Collect a list of all the objects known by the clients
1521 and report it back to the environment.
1524 core::map<u16, bool> all_known_objects;
1526 for(core::map<u16, RemoteClient*>::Iterator
1527 i = m_clients.getIterator();
1528 i.atEnd() == false; i++)
1530 RemoteClient *client = i.getNode()->getValue();
1531 // Go through all known objects of client
1532 for(core::map<u16, bool>::Iterator
1533 i = client->m_known_objects.getIterator();
1534 i.atEnd()==false; i++)
1536 u16 id = i.getNode()->getKey();
1537 all_known_objects[id] = true;
1541 m_env->setKnownActiveObjects(whatever);
1547 Send object messages
1550 JMutexAutoLock envlock(m_env_mutex);
1551 JMutexAutoLock conlock(m_con_mutex);
1553 //ScopeProfiler sp(g_profiler, "Server: sending object messages");
1556 // Value = data sent by object
1557 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1559 // Get active object messages from environment
1562 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1566 core::list<ActiveObjectMessage>* message_list = NULL;
1567 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1568 n = buffered_messages.find(aom.id);
1571 message_list = new core::list<ActiveObjectMessage>;
1572 buffered_messages.insert(aom.id, message_list);
1576 message_list = n->getValue();
1578 message_list->push_back(aom);
1581 // Route data to every client
1582 for(core::map<u16, RemoteClient*>::Iterator
1583 i = m_clients.getIterator();
1584 i.atEnd()==false; i++)
1586 RemoteClient *client = i.getNode()->getValue();
1587 std::string reliable_data;
1588 std::string unreliable_data;
1589 // Go through all objects in message buffer
1590 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1591 j = buffered_messages.getIterator();
1592 j.atEnd()==false; j++)
1594 // If object is not known by client, skip it
1595 u16 id = j.getNode()->getKey();
1596 if(client->m_known_objects.find(id) == NULL)
1598 // Get message list of object
1599 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1600 // Go through every message
1601 for(core::list<ActiveObjectMessage>::Iterator
1602 k = list->begin(); k != list->end(); k++)
1604 // Compose the full new data with header
1605 ActiveObjectMessage aom = *k;
1606 std::string new_data;
1609 writeU16((u8*)&buf[0], aom.id);
1610 new_data.append(buf, 2);
1612 new_data += serializeString(aom.datastring);
1613 // Add data to buffer
1615 reliable_data += new_data;
1617 unreliable_data += new_data;
1621 reliable_data and unreliable_data are now ready.
1624 if(reliable_data.size() > 0)
1626 SharedBuffer<u8> reply(2 + reliable_data.size());
1627 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1628 memcpy((char*)&reply[2], reliable_data.c_str(),
1629 reliable_data.size());
1631 m_con.Send(client->peer_id, 0, reply, true);
1633 if(unreliable_data.size() > 0)
1635 SharedBuffer<u8> reply(2 + unreliable_data.size());
1636 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1637 memcpy((char*)&reply[2], unreliable_data.c_str(),
1638 unreliable_data.size());
1639 // Send as unreliable
1640 m_con.Send(client->peer_id, 0, reply, false);
1643 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1645 infostream<<"Server: Size of object message data: "
1646 <<"reliable: "<<reliable_data.size()
1647 <<", unreliable: "<<unreliable_data.size()
1652 // Clear buffered_messages
1653 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1654 i = buffered_messages.getIterator();
1655 i.atEnd()==false; i++)
1657 delete i.getNode()->getValue();
1661 } // enable_experimental
1664 Send queued-for-sending map edit events.
1667 // Don't send too many at a time
1670 // Single change sending is disabled if queue size is not small
1671 bool disable_single_change_sending = false;
1672 if(m_unsent_map_edit_queue.size() >= 4)
1673 disable_single_change_sending = true;
1675 bool got_any_events = false;
1677 // We'll log the amount of each
1680 while(m_unsent_map_edit_queue.size() != 0)
1682 got_any_events = true;
1684 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1686 // Players far away from the change are stored here.
1687 // Instead of sending the changes, MapBlocks are set not sent
1689 core::list<u16> far_players;
1691 if(event->type == MEET_ADDNODE)
1693 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1694 prof.add("MEET_ADDNODE", 1);
1695 if(disable_single_change_sending)
1696 sendAddNode(event->p, event->n, event->already_known_by_peer,
1699 sendAddNode(event->p, event->n, event->already_known_by_peer,
1702 else if(event->type == MEET_REMOVENODE)
1704 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1705 prof.add("MEET_REMOVENODE", 1);
1706 if(disable_single_change_sending)
1707 sendRemoveNode(event->p, event->already_known_by_peer,
1710 sendRemoveNode(event->p, event->already_known_by_peer,
1713 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1715 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1716 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1717 setBlockNotSent(event->p);
1719 else if(event->type == MEET_OTHER)
1721 infostream<<"Server: MEET_OTHER"<<std::endl;
1722 prof.add("MEET_OTHER", 1);
1723 for(core::map<v3s16, bool>::Iterator
1724 i = event->modified_blocks.getIterator();
1725 i.atEnd()==false; i++)
1727 v3s16 p = i.getNode()->getKey();
1733 prof.add("unknown", 1);
1734 infostream<<"WARNING: Server: Unknown MapEditEvent "
1735 <<((u32)event->type)<<std::endl;
1739 Set blocks not sent to far players
1741 if(far_players.size() > 0)
1743 // Convert list format to that wanted by SetBlocksNotSent
1744 core::map<v3s16, MapBlock*> modified_blocks2;
1745 for(core::map<v3s16, bool>::Iterator
1746 i = event->modified_blocks.getIterator();
1747 i.atEnd()==false; i++)
1749 v3s16 p = i.getNode()->getKey();
1750 modified_blocks2.insert(p,
1751 m_env->getMap().getBlockNoCreateNoEx(p));
1753 // Set blocks not sent
1754 for(core::list<u16>::Iterator
1755 i = far_players.begin();
1756 i != far_players.end(); i++)
1759 RemoteClient *client = getClient(peer_id);
1762 client->SetBlocksNotSent(modified_blocks2);
1768 /*// Don't send too many at a time
1770 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1776 infostream<<"Server: MapEditEvents:"<<std::endl;
1777 prof.print(infostream);
1783 Send object positions
1786 float &counter = m_objectdata_timer;
1788 if(counter >= g_settings->getFloat("objectdata_interval"))
1790 JMutexAutoLock lock1(m_env_mutex);
1791 JMutexAutoLock lock2(m_con_mutex);
1793 //ScopeProfiler sp(g_profiler, "Server: sending player positions");
1795 SendObjectData(counter);
1802 Trigger emergethread (it somehow gets to a non-triggered but
1803 bysy state sometimes)
1806 float &counter = m_emergethread_trigger_timer;
1812 m_emergethread.trigger();
1816 // Save map, players and auth stuff
1818 float &counter = m_savemap_timer;
1820 if(counter >= g_settings->getFloat("server_map_save_interval"))
1824 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1827 if(m_authmanager.isModified())
1828 m_authmanager.save();
1831 if(m_banmanager.isModified())
1832 m_banmanager.save();
1835 JMutexAutoLock lock(m_env_mutex);
1837 /*// Unload unused data (delete from memory)
1838 m_env->getMap().unloadUnusedData(
1839 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1841 /*u32 deleted_count = m_env->getMap().unloadUnusedData(
1842 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1845 // Save only changed parts
1846 m_env->getMap().save(true);
1848 /*if(deleted_count > 0)
1850 infostream<<"Server: Unloaded "<<deleted_count
1851 <<" blocks from memory"<<std::endl;
1855 m_env->serializePlayers(m_mapsavedir);
1857 // Save environment metadata
1858 m_env->saveMeta(m_mapsavedir);
1863 void Server::Receive()
1865 DSTACK(__FUNCTION_NAME);
1866 SharedBuffer<u8> data;
1871 JMutexAutoLock conlock(m_con_mutex);
1872 datasize = m_con.Receive(peer_id, data);
1875 // This has to be called so that the client list gets synced
1876 // with the peer list of the connection
1877 handlePeerChanges();
1879 ProcessData(*data, datasize, peer_id);
1881 catch(con::InvalidIncomingDataException &e)
1883 infostream<<"Server::Receive(): "
1884 "InvalidIncomingDataException: what()="
1885 <<e.what()<<std::endl;
1887 catch(con::PeerNotFoundException &e)
1889 //NOTE: This is not needed anymore
1891 // The peer has been disconnected.
1892 // Find the associated player and remove it.
1894 /*JMutexAutoLock envlock(m_env_mutex);
1896 infostream<<"ServerThread: peer_id="<<peer_id
1897 <<" has apparently closed connection. "
1898 <<"Removing player."<<std::endl;
1900 m_env->removePlayer(peer_id);*/
1904 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1906 DSTACK(__FUNCTION_NAME);
1907 // Environment is locked first.
1908 JMutexAutoLock envlock(m_env_mutex);
1909 JMutexAutoLock conlock(m_con_mutex);
1912 Address address = m_con.GetPeerAddress(peer_id);
1914 // drop player if is ip is banned
1915 if(m_banmanager.isIpBanned(address.serializeString())){
1916 SendAccessDenied(m_con, peer_id,
1917 L"Your ip is banned. Banned name was "
1918 +narrow_to_wide(m_banmanager.getBanName(
1919 address.serializeString())));
1920 m_con.DeletePeer(peer_id);
1924 catch(con::PeerNotFoundException &e)
1926 infostream<<"Server::ProcessData(): Cancelling: peer "
1927 <<peer_id<<" not found"<<std::endl;
1931 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1939 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1941 if(command == TOSERVER_INIT)
1943 // [0] u16 TOSERVER_INIT
1944 // [2] u8 SER_FMT_VER_HIGHEST
1945 // [3] u8[20] player_name
1946 // [23] u8[28] password <--- can be sent without this, from old versions
1948 if(datasize < 2+1+PLAYERNAME_SIZE)
1951 infostream<<"Server: Got TOSERVER_INIT from "
1952 <<peer_id<<std::endl;
1954 // First byte after command is maximum supported
1955 // serialization version
1956 u8 client_max = data[2];
1957 u8 our_max = SER_FMT_VER_HIGHEST;
1958 // Use the highest version supported by both
1959 u8 deployed = core::min_(client_max, our_max);
1960 // If it's lower than the lowest supported, give up.
1961 if(deployed < SER_FMT_VER_LOWEST)
1962 deployed = SER_FMT_VER_INVALID;
1964 //peer->serialization_version = deployed;
1965 getClient(peer_id)->pending_serialization_version = deployed;
1967 if(deployed == SER_FMT_VER_INVALID)
1969 infostream<<"Server: Cannot negotiate "
1970 "serialization version with peer "
1971 <<peer_id<<std::endl;
1972 SendAccessDenied(m_con, peer_id,
1973 L"Your client is too old (map format)");
1978 Read and check network protocol version
1981 u16 net_proto_version = 0;
1982 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1984 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1987 getClient(peer_id)->net_proto_version = net_proto_version;
1989 if(net_proto_version == 0)
1991 SendAccessDenied(m_con, peer_id,
1992 L"Your client is too old. Please upgrade.");
1996 /* Uhh... this should actually be a warning but let's do it like this */
1997 if(g_settings->getBool("strict_protocol_version_checking"))
1999 if(net_proto_version < PROTOCOL_VERSION)
2001 SendAccessDenied(m_con, peer_id,
2002 L"Your client is too old. Please upgrade.");
2012 char playername[PLAYERNAME_SIZE];
2013 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2015 playername[i] = data[3+i];
2017 playername[PLAYERNAME_SIZE-1] = 0;
2019 if(playername[0]=='\0')
2021 infostream<<"Server: Player has empty name"<<std::endl;
2022 SendAccessDenied(m_con, peer_id,
2027 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2029 infostream<<"Server: Player has invalid name"<<std::endl;
2030 SendAccessDenied(m_con, peer_id,
2031 L"Name contains unallowed characters");
2036 char password[PASSWORD_SIZE];
2037 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2039 // old version - assume blank password
2044 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2046 password[i] = data[23+i];
2048 password[PASSWORD_SIZE-1] = 0;
2051 std::string checkpwd;
2052 if(m_authmanager.exists(playername))
2054 checkpwd = m_authmanager.getPassword(playername);
2058 checkpwd = g_settings->get("default_password");
2061 /*infostream<<"Server: Client gave password '"<<password
2062 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2064 if(password != checkpwd && m_authmanager.exists(playername))
2066 infostream<<"Server: peer_id="<<peer_id
2067 <<": supplied invalid password for "
2068 <<playername<<std::endl;
2069 SendAccessDenied(m_con, peer_id, L"Invalid password");
2073 // Add player to auth manager
2074 if(m_authmanager.exists(playername) == false)
2076 infostream<<"Server: adding player "<<playername
2077 <<" to auth manager"<<std::endl;
2078 m_authmanager.add(playername);
2079 m_authmanager.setPassword(playername, checkpwd);
2080 m_authmanager.setPrivs(playername,
2081 stringToPrivs(g_settings->get("default_privs")));
2082 m_authmanager.save();
2085 // Enforce user limit.
2086 // Don't enforce for users that have some admin right
2087 if(m_clients.size() >= g_settings->getU16("max_users") &&
2088 (m_authmanager.getPrivs(playername)
2089 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 &&
2090 playername != g_settings->get("name"))
2092 SendAccessDenied(m_con, peer_id, L"Too many users.");
2097 Player *player = emergePlayer(playername, password, peer_id);
2099 // If failed, cancel
2102 infostream<<"Server: peer_id="<<peer_id
2103 <<": failed to emerge player"<<std::endl;
2108 Answer with a TOCLIENT_INIT
2111 SharedBuffer<u8> reply(2+1+6+8);
2112 writeU16(&reply[0], TOCLIENT_INIT);
2113 writeU8(&reply[2], deployed);
2114 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2115 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2118 m_con.Send(peer_id, 0, reply, true);
2122 Send complete position information
2124 SendMovePlayer(player);
2129 if(command == TOSERVER_INIT2)
2131 infostream<<"Server: Got TOSERVER_INIT2 from "
2132 <<peer_id<<std::endl;
2135 getClient(peer_id)->serialization_version
2136 = getClient(peer_id)->pending_serialization_version;
2139 Send some initialization data
2143 SendTextures(peer_id);
2145 // Send tool definitions
2146 SendToolDef(m_con, peer_id, m_toolmgr);
2148 // Send player info to all players
2151 // Send inventory to player
2152 UpdateCrafting(peer_id);
2153 SendInventory(peer_id);
2155 // Send player items to all players
2158 Player *player = m_env->getPlayer(peer_id);
2161 SendPlayerHP(player);
2165 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2166 m_env->getTimeOfDay());
2167 m_con.Send(peer_id, 0, data, true);
2170 // Send information about server to player in chat
2171 SendChatMessage(peer_id, getStatusString());
2173 // Send information about joining in chat
2175 std::wstring name = L"unknown";
2176 Player *player = m_env->getPlayer(peer_id);
2178 name = narrow_to_wide(player->getName());
2180 std::wstring message;
2183 message += L" joined game";
2184 BroadcastChatMessage(message);
2187 // Warnings about protocol version can be issued here
2188 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2190 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2194 Check HP, respawn if necessary
2196 HandlePlayerHP(player, 0);
2202 std::ostringstream os(std::ios_base::binary);
2203 for(core::map<u16, RemoteClient*>::Iterator
2204 i = m_clients.getIterator();
2205 i.atEnd() == false; i++)
2207 RemoteClient *client = i.getNode()->getValue();
2208 assert(client->peer_id == i.getNode()->getKey());
2209 if(client->serialization_version == SER_FMT_VER_INVALID)
2212 Player *player = m_env->getPlayer(client->peer_id);
2215 // Get name of player
2216 os<<player->getName()<<" ";
2219 actionstream<<player->getName()<<" joins game. List of players: "
2220 <<os.str()<<std::endl;
2226 if(peer_ser_ver == SER_FMT_VER_INVALID)
2228 infostream<<"Server::ProcessData(): Cancelling: Peer"
2229 " serialization format invalid or not initialized."
2230 " Skipping incoming command="<<command<<std::endl;
2234 Player *player = m_env->getPlayer(peer_id);
2237 infostream<<"Server::ProcessData(): Cancelling: "
2238 "No player for peer_id="<<peer_id
2242 if(command == TOSERVER_PLAYERPOS)
2244 if(datasize < 2+12+12+4+4)
2248 v3s32 ps = readV3S32(&data[start+2]);
2249 v3s32 ss = readV3S32(&data[start+2+12]);
2250 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2251 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2252 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2253 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2254 pitch = wrapDegrees(pitch);
2255 yaw = wrapDegrees(yaw);
2257 player->setPosition(position);
2258 player->setSpeed(speed);
2259 player->setPitch(pitch);
2260 player->setYaw(yaw);
2262 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2263 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2264 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2266 else if(command == TOSERVER_GOTBLOCKS)
2279 u16 count = data[2];
2280 for(u16 i=0; i<count; i++)
2282 if((s16)datasize < 2+1+(i+1)*6)
2283 throw con::InvalidIncomingDataException
2284 ("GOTBLOCKS length is too short");
2285 v3s16 p = readV3S16(&data[2+1+i*6]);
2286 /*infostream<<"Server: GOTBLOCKS ("
2287 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2288 RemoteClient *client = getClient(peer_id);
2289 client->GotBlock(p);
2292 else if(command == TOSERVER_DELETEDBLOCKS)
2305 u16 count = data[2];
2306 for(u16 i=0; i<count; i++)
2308 if((s16)datasize < 2+1+(i+1)*6)
2309 throw con::InvalidIncomingDataException
2310 ("DELETEDBLOCKS length is too short");
2311 v3s16 p = readV3S16(&data[2+1+i*6]);
2312 /*infostream<<"Server: DELETEDBLOCKS ("
2313 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2314 RemoteClient *client = getClient(peer_id);
2315 client->SetBlockNotSent(p);
2318 else if(command == TOSERVER_CLICK_OBJECT)
2320 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2323 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2328 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2334 [2] u8 button (0=left, 1=right)
2338 u8 button = readU8(&data[2]);
2339 u16 id = readS16(&data[3]);
2340 u16 item_i = readU16(&data[5]);
2342 ServerActiveObject *obj = m_env->getActiveObject(id);
2346 infostream<<"Server: CLICK_ACTIVEOBJECT: object not found"
2351 // Skip if object has been removed
2355 //TODO: Check that object is reasonably close
2357 // Get ServerRemotePlayer
2358 ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
2360 // Update wielded item
2361 srp->wieldItem(item_i);
2363 // Left click, pick/punch
2366 actionstream<<player->getName()<<" punches object "
2367 <<obj->getId()<<std::endl;
2374 Try creating inventory item
2376 InventoryItem *item = obj->createPickedUpItem();
2380 InventoryList *ilist = player->inventory.getList("main");
2383 actionstream<<player->getName()<<" picked up "
2384 <<item->getName()<<std::endl;
2385 if(g_settings->getBool("creative_mode") == false)
2387 // Skip if inventory has no free space
2388 if(ilist->roomForItem(item) == false)
2390 infostream<<"Player inventory has no free space"<<std::endl;
2394 // Add to inventory and send inventory
2395 ilist->addItem(item);
2396 UpdateCrafting(player->peer_id);
2397 SendInventory(player->peer_id);
2400 // Remove object from environment
2401 obj->m_removed = true;
2407 Item cannot be picked up. Punch it instead.
2410 actionstream<<player->getName()<<" punches object "
2411 <<obj->getId()<<std::endl;
2413 ToolItem *titem = NULL;
2414 std::string toolname = "";
2416 InventoryList *mlist = player->inventory.getList("main");
2419 InventoryItem *item = mlist->getItem(item_i);
2420 if(item && (std::string)item->getName() == "ToolItem")
2422 titem = (ToolItem*)item;
2423 toolname = titem->getToolName();
2427 v3f playerpos = player->getPosition();
2428 v3f objpos = obj->getBasePosition();
2429 v3f dir = (objpos - playerpos).normalize();
2431 u16 wear = obj->punch(toolname, dir, player->getName());
2435 bool weared_out = titem->addWear(wear);
2437 mlist->deleteItem(item_i);
2438 SendInventory(player->peer_id);
2443 // Right click, do something with object
2446 actionstream<<player->getName()<<" right clicks object "
2447 <<obj->getId()<<std::endl;
2450 obj->rightClick(srp);
2454 Update player state to client
2456 SendPlayerHP(player);
2457 UpdateCrafting(player->peer_id);
2458 SendInventory(player->peer_id);
2460 else if(command == TOSERVER_GROUND_ACTION)
2468 [3] v3s16 nodepos_undersurface
2469 [9] v3s16 nodepos_abovesurface
2474 2: stop digging (all parameters ignored)
2475 3: digging completed
2477 u8 action = readU8(&data[2]);
2479 p_under.X = readS16(&data[3]);
2480 p_under.Y = readS16(&data[5]);
2481 p_under.Z = readS16(&data[7]);
2483 p_over.X = readS16(&data[9]);
2484 p_over.Y = readS16(&data[11]);
2485 p_over.Z = readS16(&data[13]);
2486 u16 item_i = readU16(&data[15]);
2488 //TODO: Check that target is reasonably close
2496 NOTE: This can be used in the future to check if
2497 somebody is cheating, by checking the timing.
2504 else if(action == 2)
2507 RemoteClient *client = getClient(peer_id);
2508 JMutexAutoLock digmutex(client->m_dig_mutex);
2509 client->m_dig_tool_item = -1;
2514 3: Digging completed
2516 else if(action == 3)
2518 // Mandatory parameter; actually used for nothing
2519 core::map<v3s16, MapBlock*> modified_blocks;
2521 content_t material = CONTENT_IGNORE;
2522 u8 mineral = MINERAL_NONE;
2524 bool cannot_remove_node = false;
2528 MapNode n = m_env->getMap().getNode(p_under);
2530 mineral = n.getMineral(m_nodemgr);
2531 // Get material at position
2532 material = n.getContent();
2533 // If not yet cancelled
2534 if(cannot_remove_node == false)
2536 // If it's not diggable, do nothing
2537 if(m_nodemgr->get(material).diggable == false)
2539 infostream<<"Server: Not finishing digging: "
2540 <<"Node not diggable"
2542 cannot_remove_node = true;
2545 // If not yet cancelled
2546 if(cannot_remove_node == false)
2548 // Get node metadata
2549 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
2550 if(meta && meta->nodeRemovalDisabled() == true)
2552 infostream<<"Server: Not finishing digging: "
2553 <<"Node metadata disables removal"
2555 cannot_remove_node = true;
2559 catch(InvalidPositionException &e)
2561 infostream<<"Server: Not finishing digging: Node not found."
2562 <<" Adding block to emerge queue."
2564 m_emerge_queue.addBlock(peer_id,
2565 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2566 cannot_remove_node = true;
2569 // Make sure the player is allowed to do it
2570 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2572 infostream<<"Player "<<player->getName()<<" cannot remove node"
2573 <<" because privileges are "<<getPlayerPrivs(player)
2575 cannot_remove_node = true;
2579 If node can't be removed, set block to be re-sent to
2582 if(cannot_remove_node)
2584 infostream<<"Server: Not finishing digging."<<std::endl;
2586 // Client probably has wrong data.
2587 // Set block not sent, so that client will get
2589 infostream<<"Client "<<peer_id<<" tried to dig "
2590 <<"node; but node cannot be removed."
2591 <<" setting MapBlock not sent."<<std::endl;
2592 RemoteClient *client = getClient(peer_id);
2593 v3s16 blockpos = getNodeBlockPos(p_under);
2594 client->SetBlockNotSent(blockpos);
2599 actionstream<<player->getName()<<" digs "<<PP(p_under)
2600 <<", gets material "<<(int)material<<", mineral "
2601 <<(int)mineral<<std::endl;
2604 Send the removal to all close-by players.
2605 - If other player is close, send REMOVENODE
2606 - Otherwise set blocks not sent
2608 core::list<u16> far_players;
2609 sendRemoveNode(p_under, peer_id, &far_players, 30);
2612 Update and send inventory
2615 if(g_settings->getBool("creative_mode") == false)
2620 InventoryList *mlist = player->inventory.getList("main");
2623 InventoryItem *item = mlist->getItem(item_i);
2624 if(item && (std::string)item->getName() == "ToolItem")
2626 ToolItem *titem = (ToolItem*)item;
2627 std::string toolname = titem->getToolName();
2629 // Get digging properties for material and tool
2630 ToolDiggingProperties tp =
2631 m_toolmgr->getDiggingProperties(toolname);
2632 DiggingProperties prop =
2633 getDiggingProperties(material, &tp, m_nodemgr);
2635 if(prop.diggable == false)
2637 infostream<<"Server: WARNING: Player digged"
2638 <<" with impossible material + tool"
2639 <<" combination"<<std::endl;
2642 bool weared_out = titem->addWear(prop.wear);
2646 mlist->deleteItem(item_i);
2652 Add dug item to inventory
2655 InventoryItem *item = NULL;
2657 if(mineral != MINERAL_NONE)
2658 item = getDiggedMineralItem(mineral, this);
2663 const std::string &dug_s = m_nodemgr->get(material).dug_item;
2666 std::istringstream is(dug_s, std::ios::binary);
2667 item = InventoryItem::deSerialize(is, this);
2673 // Add a item to inventory
2674 player->inventory.addItem("main", item);
2677 UpdateCrafting(player->peer_id);
2678 SendInventory(player->peer_id);
2683 if(mineral != MINERAL_NONE)
2684 item = getDiggedMineralItem(mineral, this);
2689 const std::string &extra_dug_s = m_nodemgr->get(material).extra_dug_item;
2690 s32 extra_rarity = m_nodemgr->get(material).extra_dug_item_rarity;
2691 if(extra_dug_s != "" && extra_rarity != 0
2692 && myrand() % extra_rarity == 0)
2694 std::istringstream is(extra_dug_s, std::ios::binary);
2695 item = InventoryItem::deSerialize(is, this);
2701 // Add a item to inventory
2702 player->inventory.addItem("main", item);
2705 UpdateCrafting(player->peer_id);
2706 SendInventory(player->peer_id);
2712 (this takes some time so it is done after the quick stuff)
2715 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2717 m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
2720 Set blocks not sent to far players
2722 for(core::list<u16>::Iterator
2723 i = far_players.begin();
2724 i != far_players.end(); i++)
2727 RemoteClient *client = getClient(peer_id);
2730 client->SetBlocksNotSent(modified_blocks);
2737 else if(action == 1)
2740 InventoryList *ilist = player->inventory.getList("main");
2745 InventoryItem *item = ilist->getItem(item_i);
2747 // If there is no item, it is not possible to add it anywhere
2752 Handle material items
2754 if(std::string("MaterialItem") == item->getName())
2757 // Don't add a node if this is not a free space
2758 MapNode n2 = m_env->getMap().getNode(p_over);
2759 bool no_enough_privs =
2760 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2762 infostream<<"Player "<<player->getName()<<" cannot add node"
2763 <<" because privileges are "<<getPlayerPrivs(player)
2766 if(m_nodemgr->get(n2).buildable_to == false
2769 // Client probably has wrong data.
2770 // Set block not sent, so that client will get
2772 infostream<<"Client "<<peer_id<<" tried to place"
2773 <<" node in invalid position; setting"
2774 <<" MapBlock not sent."<<std::endl;
2775 RemoteClient *client = getClient(peer_id);
2776 v3s16 blockpos = getNodeBlockPos(p_over);
2777 client->SetBlockNotSent(blockpos);
2781 catch(InvalidPositionException &e)
2783 infostream<<"Server: Ignoring ADDNODE: Node not found"
2784 <<" Adding block to emerge queue."
2786 m_emerge_queue.addBlock(peer_id,
2787 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2791 // Reset build time counter
2792 getClient(peer_id)->m_time_from_building = 0.0;
2795 MaterialItem *mitem = (MaterialItem*)item;
2797 n.setContent(mitem->getMaterial());
2799 actionstream<<player->getName()<<" places material "
2800 <<(int)mitem->getMaterial()
2801 <<" at "<<PP(p_under)<<std::endl;
2803 // Calculate direction for wall mounted stuff
2804 if(m_nodemgr->get(n).wall_mounted)
2805 n.param2 = packDir(p_under - p_over);
2807 // Calculate the direction for furnaces and chests and stuff
2808 if(m_nodemgr->get(n).param_type == CPT_FACEDIR_SIMPLE)
2810 v3f playerpos = player->getPosition();
2811 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2812 blockpos = blockpos.normalize();
2814 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2828 Send to all close-by players
2830 core::list<u16> far_players;
2831 sendAddNode(p_over, n, 0, &far_players, 30);
2836 InventoryList *ilist = player->inventory.getList("main");
2837 if(g_settings->getBool("creative_mode") == false && ilist)
2839 // Remove from inventory and send inventory
2840 if(mitem->getCount() == 1)
2841 ilist->deleteItem(item_i);
2845 UpdateCrafting(peer_id);
2846 SendInventory(peer_id);
2852 This takes some time so it is done after the quick stuff
2854 core::map<v3s16, MapBlock*> modified_blocks;
2856 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2858 std::string p_name = std::string(player->getName());
2859 m_env->getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
2862 Set blocks not sent to far players
2864 for(core::list<u16>::Iterator
2865 i = far_players.begin();
2866 i != far_players.end(); i++)
2869 RemoteClient *client = getClient(peer_id);
2872 client->SetBlocksNotSent(modified_blocks);
2876 Calculate special events
2879 /*if(n.d == CONTENT_MESE)
2882 for(s16 z=-1; z<=1; z++)
2883 for(s16 y=-1; y<=1; y++)
2884 for(s16 x=-1; x<=1; x++)
2891 Place other item (not a block)
2895 v3s16 blockpos = getNodeBlockPos(p_over);
2898 Check that the block is loaded so that the item
2899 can properly be added to the static list too
2901 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2904 infostream<<"Error while placing object: "
2905 "block not found"<<std::endl;
2910 If in creative mode, item dropping is disabled unless
2911 player has build privileges
2913 if(g_settings->getBool("creative_mode") &&
2914 (getPlayerPrivs(player) & PRIV_BUILD) == 0)
2916 infostream<<"Not allowing player to drop item: "
2917 "creative mode and no build privs"<<std::endl;
2921 // Calculate a position for it
2922 v3f pos = intToFloat(p_over, BS);
2924 /*pos.Y -= BS*0.25; // let it drop a bit
2926 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2927 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;*/
2932 ServerActiveObject *obj = item->createSAO(m_env, 0, pos);
2936 infostream<<"WARNING: item resulted in NULL object, "
2937 <<"not placing onto map"
2942 actionstream<<player->getName()<<" places "<<item->getName()
2943 <<" at "<<PP(p_over)<<std::endl;
2945 // Add the object to the environment
2946 m_env->addActiveObject(obj);
2948 infostream<<"Placed object"<<std::endl;
2950 if(g_settings->getBool("creative_mode") == false)
2952 // Delete the right amount of items from the slot
2953 u16 dropcount = item->getDropCount();
2955 // Delete item if all gone
2956 if(item->getCount() <= dropcount)
2958 if(item->getCount() < dropcount)
2959 infostream<<"WARNING: Server: dropped more items"
2960 <<" than the slot contains"<<std::endl;
2962 InventoryList *ilist = player->inventory.getList("main");
2964 // Remove from inventory and send inventory
2965 ilist->deleteItem(item_i);
2967 // Else decrement it
2969 item->remove(dropcount);
2972 UpdateCrafting(peer_id);
2973 SendInventory(peer_id);
2981 Catch invalid actions
2985 infostream<<"WARNING: Server: Invalid action "
2986 <<action<<std::endl;
2990 else if(command == TOSERVER_RELEASE)
2999 infostream<<"TOSERVER_RELEASE ignored"<<std::endl;
3002 else if(command == TOSERVER_SIGNTEXT)
3004 infostream<<"Server: TOSERVER_SIGNTEXT not supported anymore"
3008 else if(command == TOSERVER_SIGNNODETEXT)
3010 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3018 std::string datastring((char*)&data[2], datasize-2);
3019 std::istringstream is(datastring, std::ios_base::binary);
3022 is.read((char*)buf, 6);
3023 v3s16 p = readV3S16(buf);
3024 is.read((char*)buf, 2);
3025 u16 textlen = readU16(buf);
3027 for(u16 i=0; i<textlen; i++)
3029 is.read((char*)buf, 1);
3030 text += (char)buf[0];
3033 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3036 if(meta->typeId() != CONTENT_SIGN_WALL)
3038 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3039 signmeta->setText(text);
3041 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign "
3042 <<" at "<<PP(p)<<std::endl;
3044 v3s16 blockpos = getNodeBlockPos(p);
3045 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3048 block->setChangedFlag();
3051 for(core::map<u16, RemoteClient*>::Iterator
3052 i = m_clients.getIterator();
3053 i.atEnd()==false; i++)
3055 RemoteClient *client = i.getNode()->getValue();
3056 client->SetBlockNotSent(blockpos);
3059 else if(command == TOSERVER_INVENTORY_ACTION)
3061 /*// Ignore inventory changes if in creative mode
3062 if(g_settings->getBool("creative_mode") == true)
3064 infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3068 // Strip command and create a stream
3069 std::string datastring((char*)&data[2], datasize-2);
3070 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3071 std::istringstream is(datastring, std::ios_base::binary);
3073 InventoryAction *a = InventoryAction::deSerialize(is);
3078 c.current_player = player;
3081 Handle craftresult specially if not in creative mode
3083 bool disable_action = false;
3084 if(a->getType() == IACTION_MOVE
3085 && g_settings->getBool("creative_mode") == false)
3087 IMoveAction *ma = (IMoveAction*)a;
3088 if(ma->to_inv == "current_player" &&
3089 ma->from_inv == "current_player")
3091 InventoryList *rlist = player->inventory.getList("craftresult");
3093 InventoryList *clist = player->inventory.getList("craft");
3095 InventoryList *mlist = player->inventory.getList("main");
3098 Craftresult is no longer preview if something
3101 if(ma->to_list == "craftresult"
3102 && ma->from_list != "craftresult")
3104 // If it currently is a preview, remove
3106 if(player->craftresult_is_preview)
3108 rlist->deleteItem(0);
3110 player->craftresult_is_preview = false;
3113 Crafting takes place if this condition is true.
3115 if(player->craftresult_is_preview &&
3116 ma->from_list == "craftresult")
3118 player->craftresult_is_preview = false;
3119 clist->decrementMaterials(1);
3121 /* Print out action */
3122 InventoryList *list =
3123 player->inventory.getList("craftresult");
3125 InventoryItem *item = list->getItem(0);
3126 std::string itemname = "NULL";
3128 itemname = item->getName();
3129 actionstream<<player->getName()<<" crafts "
3130 <<itemname<<std::endl;
3133 If the craftresult is placed on itself, move it to
3134 main inventory instead of doing the action
3136 if(ma->to_list == "craftresult"
3137 && ma->from_list == "craftresult")
3139 disable_action = true;
3141 InventoryItem *item1 = rlist->changeItem(0, NULL);
3142 mlist->addItem(item1);
3145 // Disallow moving items if not allowed to build
3146 else if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3150 // if it's a locking chest, only allow the owner or server admins to move items
3151 else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3153 Strfnd fn(ma->from_inv);
3154 std::string id0 = fn.next(":");
3155 if(id0 == "nodemeta")
3158 p.X = stoi(fn.next(","));
3159 p.Y = stoi(fn.next(","));
3160 p.Z = stoi(fn.next(","));
3161 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3162 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3163 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3164 if (lcm->getOwner() != player->getName())
3169 else if (ma->to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3171 Strfnd fn(ma->to_inv);
3172 std::string id0 = fn.next(":");
3173 if(id0 == "nodemeta")
3176 p.X = stoi(fn.next(","));
3177 p.Y = stoi(fn.next(","));
3178 p.Z = stoi(fn.next(","));
3179 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3180 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3181 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3182 if (lcm->getOwner() != player->getName())
3189 if(disable_action == false)
3191 // Feed action to player inventory
3199 UpdateCrafting(player->peer_id);
3200 SendInventory(player->peer_id);
3205 infostream<<"TOSERVER_INVENTORY_ACTION: "
3206 <<"InventoryAction::deSerialize() returned NULL"
3210 else if(command == TOSERVER_CHAT_MESSAGE)
3218 std::string datastring((char*)&data[2], datasize-2);
3219 std::istringstream is(datastring, std::ios_base::binary);
3222 is.read((char*)buf, 2);
3223 u16 len = readU16(buf);
3225 std::wstring message;
3226 for(u16 i=0; i<len; i++)
3228 is.read((char*)buf, 2);
3229 message += (wchar_t)readU16(buf);
3232 // Get player name of this client
3233 std::wstring name = narrow_to_wide(player->getName());
3235 // Line to send to players
3237 // Whether to send to the player that sent the line
3238 bool send_to_sender = false;
3239 // Whether to send to other players
3240 bool send_to_others = false;
3242 // Local player gets all privileges regardless of
3243 // what's set on their account.
3244 u64 privs = getPlayerPrivs(player);
3247 if(message[0] == L'/')
3249 size_t strip_size = 1;
3250 if (message[1] == L'#') // support old-style commans
3252 message = message.substr(strip_size);
3254 WStrfnd f1(message);
3255 f1.next(L" "); // Skip over /#whatever
3256 std::wstring paramstring = f1.next(L"");
3258 ServerCommandContext *ctx = new ServerCommandContext(
3259 str_split(message, L' '),
3266 std::wstring reply(processServerCommand(ctx));
3267 send_to_sender = ctx->flags & SEND_TO_SENDER;
3268 send_to_others = ctx->flags & SEND_TO_OTHERS;
3270 if (ctx->flags & SEND_NO_PREFIX)
3273 line += L"Server: " + reply;
3280 if(privs & PRIV_SHOUT)
3286 send_to_others = true;
3290 line += L"Server: You are not allowed to shout";
3291 send_to_sender = true;
3298 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3301 Send the message to clients
3303 for(core::map<u16, RemoteClient*>::Iterator
3304 i = m_clients.getIterator();
3305 i.atEnd() == false; i++)
3307 // Get client and check that it is valid
3308 RemoteClient *client = i.getNode()->getValue();
3309 assert(client->peer_id == i.getNode()->getKey());
3310 if(client->serialization_version == SER_FMT_VER_INVALID)
3314 bool sender_selected = (peer_id == client->peer_id);
3315 if(sender_selected == true && send_to_sender == false)
3317 if(sender_selected == false && send_to_others == false)
3320 SendChatMessage(client->peer_id, line);
3324 else if(command == TOSERVER_DAMAGE)
3326 std::string datastring((char*)&data[2], datasize-2);
3327 std::istringstream is(datastring, std::ios_base::binary);
3328 u8 damage = readU8(is);
3330 if(g_settings->getBool("enable_damage"))
3332 actionstream<<player->getName()<<" damaged by "
3333 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
3336 HandlePlayerHP(player, damage);
3340 SendPlayerHP(player);
3343 else if(command == TOSERVER_PASSWORD)
3346 [0] u16 TOSERVER_PASSWORD
3347 [2] u8[28] old password
3348 [30] u8[28] new password
3351 if(datasize != 2+PASSWORD_SIZE*2)
3353 /*char password[PASSWORD_SIZE];
3354 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3355 password[i] = data[2+i];
3356 password[PASSWORD_SIZE-1] = 0;*/
3358 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3366 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3368 char c = data[2+PASSWORD_SIZE+i];
3374 infostream<<"Server: Client requests a password change from "
3375 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3377 std::string playername = player->getName();
3379 if(m_authmanager.exists(playername) == false)
3381 infostream<<"Server: playername not found in authmanager"<<std::endl;
3382 // Wrong old password supplied!!
3383 SendChatMessage(peer_id, L"playername not found in authmanager");
3387 std::string checkpwd = m_authmanager.getPassword(playername);
3389 if(oldpwd != checkpwd)
3391 infostream<<"Server: invalid old password"<<std::endl;
3392 // Wrong old password supplied!!
3393 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3397 actionstream<<player->getName()<<" changes password"<<std::endl;
3399 m_authmanager.setPassword(playername, newpwd);
3401 infostream<<"Server: password change successful for "<<playername
3403 SendChatMessage(peer_id, L"Password change successful");
3405 else if(command == TOSERVER_PLAYERITEM)
3410 u16 item = readU16(&data[2]);
3411 player->wieldItem(item);
3412 SendWieldedItem(player);
3414 else if(command == TOSERVER_RESPAWN)
3419 RespawnPlayer(player);
3421 actionstream<<player->getName()<<" respawns at "
3422 <<PP(player->getPosition()/BS)<<std::endl;
3426 infostream<<"Server::ProcessData(): Ignoring "
3427 "unknown command "<<command<<std::endl;
3431 catch(SendFailedException &e)
3433 errorstream<<"Server::ProcessData(): SendFailedException: "
3439 void Server::onMapEditEvent(MapEditEvent *event)
3441 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3442 if(m_ignore_map_edit_events)
3444 MapEditEvent *e = event->clone();
3445 m_unsent_map_edit_queue.push_back(e);
3448 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3450 if(id == "current_player")
3452 assert(c->current_player);
3453 return &(c->current_player->inventory);
3457 std::string id0 = fn.next(":");
3459 if(id0 == "nodemeta")
3462 p.X = stoi(fn.next(","));
3463 p.Y = stoi(fn.next(","));
3464 p.Z = stoi(fn.next(","));
3465 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3467 return meta->getInventory();
3468 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3469 <<"no metadata found"<<std::endl;
3473 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3476 void Server::inventoryModified(InventoryContext *c, std::string id)
3478 if(id == "current_player")
3480 assert(c->current_player);
3482 UpdateCrafting(c->current_player->peer_id);
3483 SendInventory(c->current_player->peer_id);
3488 std::string id0 = fn.next(":");
3490 if(id0 == "nodemeta")
3493 p.X = stoi(fn.next(","));
3494 p.Y = stoi(fn.next(","));
3495 p.Z = stoi(fn.next(","));
3496 v3s16 blockpos = getNodeBlockPos(p);
3498 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3500 meta->inventoryModified();
3502 for(core::map<u16, RemoteClient*>::Iterator
3503 i = m_clients.getIterator();
3504 i.atEnd()==false; i++)
3506 RemoteClient *client = i.getNode()->getValue();
3507 client->SetBlockNotSent(blockpos);
3513 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3516 core::list<PlayerInfo> Server::getPlayerInfo()
3518 DSTACK(__FUNCTION_NAME);
3519 JMutexAutoLock envlock(m_env_mutex);
3520 JMutexAutoLock conlock(m_con_mutex);
3522 core::list<PlayerInfo> list;
3524 core::list<Player*> players = m_env->getPlayers();
3526 core::list<Player*>::Iterator i;
3527 for(i = players.begin();
3528 i != players.end(); i++)
3532 Player *player = *i;
3535 // Copy info from connection to info struct
3536 info.id = player->peer_id;
3537 info.address = m_con.GetPeerAddress(player->peer_id);
3538 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3540 catch(con::PeerNotFoundException &e)
3542 // Set dummy peer info
3544 info.address = Address(0,0,0,0,0);
3548 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3549 info.position = player->getPosition();
3551 list.push_back(info);
3558 void Server::peerAdded(con::Peer *peer)
3560 DSTACK(__FUNCTION_NAME);
3561 infostream<<"Server::peerAdded(): peer->id="
3562 <<peer->id<<std::endl;
3565 c.type = PEER_ADDED;
3566 c.peer_id = peer->id;
3568 m_peer_change_queue.push_back(c);
3571 void Server::deletingPeer(con::Peer *peer, bool timeout)
3573 DSTACK(__FUNCTION_NAME);
3574 infostream<<"Server::deletingPeer(): peer->id="
3575 <<peer->id<<", timeout="<<timeout<<std::endl;
3578 c.type = PEER_REMOVED;
3579 c.peer_id = peer->id;
3580 c.timeout = timeout;
3581 m_peer_change_queue.push_back(c);
3588 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3590 DSTACK(__FUNCTION_NAME);
3591 std::ostringstream os(std::ios_base::binary);
3593 writeU16(os, TOCLIENT_HP);
3597 std::string s = os.str();
3598 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3600 con.Send(peer_id, 0, data, true);
3603 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3604 const std::wstring &reason)
3606 DSTACK(__FUNCTION_NAME);
3607 std::ostringstream os(std::ios_base::binary);
3609 writeU16(os, TOCLIENT_ACCESS_DENIED);
3610 os<<serializeWideString(reason);
3613 std::string s = os.str();
3614 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3616 con.Send(peer_id, 0, data, true);
3619 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3620 bool set_camera_point_target, v3f camera_point_target)
3622 DSTACK(__FUNCTION_NAME);
3623 std::ostringstream os(std::ios_base::binary);
3625 writeU16(os, TOCLIENT_DEATHSCREEN);
3626 writeU8(os, set_camera_point_target);
3627 writeV3F1000(os, camera_point_target);
3630 std::string s = os.str();
3631 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3633 con.Send(peer_id, 0, data, true);
3636 void Server::SendToolDef(con::Connection &con, u16 peer_id,
3637 IToolDefManager *tooldef)
3639 DSTACK(__FUNCTION_NAME);
3640 std::ostringstream os(std::ios_base::binary);
3644 u32 length of the next item
3645 serialized ToolDefManager
3647 writeU16(os, TOCLIENT_TOOLDEF);
3648 std::ostringstream tmp_os(std::ios::binary);
3649 tooldef->serialize(tmp_os);
3650 os<<serializeLongString(tmp_os.str());
3653 std::string s = os.str();
3654 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3656 con.Send(peer_id, 0, data, true);
3660 Non-static send methods
3663 void Server::SendObjectData(float dtime)
3665 DSTACK(__FUNCTION_NAME);
3667 core::map<v3s16, bool> stepped_blocks;
3669 for(core::map<u16, RemoteClient*>::Iterator
3670 i = m_clients.getIterator();
3671 i.atEnd() == false; i++)
3673 u16 peer_id = i.getNode()->getKey();
3674 RemoteClient *client = i.getNode()->getValue();
3675 assert(client->peer_id == peer_id);
3677 if(client->serialization_version == SER_FMT_VER_INVALID)
3680 client->SendObjectData(this, dtime, stepped_blocks);
3684 void Server::SendPlayerInfos()
3686 DSTACK(__FUNCTION_NAME);
3688 //JMutexAutoLock envlock(m_env_mutex);
3690 // Get connected players
3691 core::list<Player*> players = m_env->getPlayers(true);
3693 u32 player_count = players.getSize();
3694 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3696 SharedBuffer<u8> data(datasize);
3697 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3700 core::list<Player*>::Iterator i;
3701 for(i = players.begin();
3702 i != players.end(); i++)
3704 Player *player = *i;
3706 /*infostream<<"Server sending player info for player with "
3707 "peer_id="<<player->peer_id<<std::endl;*/
3709 writeU16(&data[start], player->peer_id);
3710 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3711 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3712 start += 2+PLAYERNAME_SIZE;
3715 //JMutexAutoLock conlock(m_con_mutex);
3718 m_con.SendToAll(0, data, true);
3721 void Server::SendInventory(u16 peer_id)
3723 DSTACK(__FUNCTION_NAME);
3725 Player* player = m_env->getPlayer(peer_id);
3732 std::ostringstream os;
3733 //os.imbue(std::locale("C"));
3735 player->inventory.serialize(os);
3737 std::string s = os.str();
3739 SharedBuffer<u8> data(s.size()+2);
3740 writeU16(&data[0], TOCLIENT_INVENTORY);
3741 memcpy(&data[2], s.c_str(), s.size());
3744 m_con.Send(peer_id, 0, data, true);
3747 std::string getWieldedItemString(const Player *player)
3749 const InventoryItem *item = player->getWieldItem();
3751 return std::string("");
3752 std::ostringstream os(std::ios_base::binary);
3753 item->serialize(os);
3757 void Server::SendWieldedItem(const Player* player)
3759 DSTACK(__FUNCTION_NAME);
3763 std::ostringstream os(std::ios_base::binary);
3765 writeU16(os, TOCLIENT_PLAYERITEM);
3767 writeU16(os, player->peer_id);
3768 os<<serializeString(getWieldedItemString(player));
3771 std::string s = os.str();
3772 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3774 m_con.SendToAll(0, data, true);
3777 void Server::SendPlayerItems()
3779 DSTACK(__FUNCTION_NAME);
3781 std::ostringstream os(std::ios_base::binary);
3782 core::list<Player *> players = m_env->getPlayers(true);
3784 writeU16(os, TOCLIENT_PLAYERITEM);
3785 writeU16(os, players.size());
3786 core::list<Player *>::Iterator i;
3787 for(i = players.begin(); i != players.end(); ++i)
3790 writeU16(os, p->peer_id);
3791 os<<serializeString(getWieldedItemString(p));
3795 std::string s = os.str();
3796 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3798 m_con.SendToAll(0, data, true);
3801 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3803 DSTACK(__FUNCTION_NAME);
3805 std::ostringstream os(std::ios_base::binary);
3809 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3810 os.write((char*)buf, 2);
3813 writeU16(buf, message.size());
3814 os.write((char*)buf, 2);
3817 for(u32 i=0; i<message.size(); i++)
3821 os.write((char*)buf, 2);
3825 std::string s = os.str();
3826 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3828 m_con.Send(peer_id, 0, data, true);
3831 void Server::BroadcastChatMessage(const std::wstring &message)
3833 for(core::map<u16, RemoteClient*>::Iterator
3834 i = m_clients.getIterator();
3835 i.atEnd() == false; i++)
3837 // Get client and check that it is valid
3838 RemoteClient *client = i.getNode()->getValue();
3839 assert(client->peer_id == i.getNode()->getKey());
3840 if(client->serialization_version == SER_FMT_VER_INVALID)
3843 SendChatMessage(client->peer_id, message);
3847 void Server::SendPlayerHP(Player *player)
3849 SendHP(m_con, player->peer_id, player->hp);
3852 void Server::SendMovePlayer(Player *player)
3854 DSTACK(__FUNCTION_NAME);
3855 std::ostringstream os(std::ios_base::binary);
3857 writeU16(os, TOCLIENT_MOVE_PLAYER);
3858 writeV3F1000(os, player->getPosition());
3859 writeF1000(os, player->getPitch());
3860 writeF1000(os, player->getYaw());
3863 v3f pos = player->getPosition();
3864 f32 pitch = player->getPitch();
3865 f32 yaw = player->getYaw();
3866 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
3867 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3874 std::string s = os.str();
3875 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3877 m_con.Send(player->peer_id, 0, data, true);
3880 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3881 core::list<u16> *far_players, float far_d_nodes)
3883 float maxd = far_d_nodes*BS;
3884 v3f p_f = intToFloat(p, BS);
3888 SharedBuffer<u8> reply(replysize);
3889 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3890 writeS16(&reply[2], p.X);
3891 writeS16(&reply[4], p.Y);
3892 writeS16(&reply[6], p.Z);
3894 for(core::map<u16, RemoteClient*>::Iterator
3895 i = m_clients.getIterator();
3896 i.atEnd() == false; i++)
3898 // Get client and check that it is valid
3899 RemoteClient *client = i.getNode()->getValue();
3900 assert(client->peer_id == i.getNode()->getKey());
3901 if(client->serialization_version == SER_FMT_VER_INVALID)
3904 // Don't send if it's the same one
3905 if(client->peer_id == ignore_id)
3911 Player *player = m_env->getPlayer(client->peer_id);
3914 // If player is far away, only set modified blocks not sent
3915 v3f player_pos = player->getPosition();
3916 if(player_pos.getDistanceFrom(p_f) > maxd)
3918 far_players->push_back(client->peer_id);
3925 m_con.Send(client->peer_id, 0, reply, true);
3929 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3930 core::list<u16> *far_players, float far_d_nodes)
3932 float maxd = far_d_nodes*BS;
3933 v3f p_f = intToFloat(p, BS);
3935 for(core::map<u16, RemoteClient*>::Iterator
3936 i = m_clients.getIterator();
3937 i.atEnd() == false; i++)
3939 // Get client and check that it is valid
3940 RemoteClient *client = i.getNode()->getValue();
3941 assert(client->peer_id == i.getNode()->getKey());
3942 if(client->serialization_version == SER_FMT_VER_INVALID)
3945 // Don't send if it's the same one
3946 if(client->peer_id == ignore_id)
3952 Player *player = m_env->getPlayer(client->peer_id);
3955 // If player is far away, only set modified blocks not sent
3956 v3f player_pos = player->getPosition();
3957 if(player_pos.getDistanceFrom(p_f) > maxd)
3959 far_players->push_back(client->peer_id);
3966 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3967 SharedBuffer<u8> reply(replysize);
3968 writeU16(&reply[0], TOCLIENT_ADDNODE);
3969 writeS16(&reply[2], p.X);
3970 writeS16(&reply[4], p.Y);
3971 writeS16(&reply[6], p.Z);
3972 n.serialize(&reply[8], client->serialization_version);
3975 m_con.Send(client->peer_id, 0, reply, true);
3979 void Server::setBlockNotSent(v3s16 p)
3981 for(core::map<u16, RemoteClient*>::Iterator
3982 i = m_clients.getIterator();
3983 i.atEnd()==false; i++)
3985 RemoteClient *client = i.getNode()->getValue();
3986 client->SetBlockNotSent(p);
3990 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3992 DSTACK(__FUNCTION_NAME);
3994 v3s16 p = block->getPos();
3998 bool completely_air = true;
3999 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4000 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4001 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4003 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4005 completely_air = false;
4006 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4011 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4013 infostream<<"[completely air] ";
4014 infostream<<std::endl;
4018 Create a packet with the block in the right format
4021 std::ostringstream os(std::ios_base::binary);
4022 block->serialize(os, ver);
4023 std::string s = os.str();
4024 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4026 u32 replysize = 8 + blockdata.getSize();
4027 SharedBuffer<u8> reply(replysize);
4028 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4029 writeS16(&reply[2], p.X);
4030 writeS16(&reply[4], p.Y);
4031 writeS16(&reply[6], p.Z);
4032 memcpy(&reply[8], *blockdata, blockdata.getSize());
4034 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4035 <<": \tpacket size: "<<replysize<<std::endl;*/
4040 m_con.Send(peer_id, 1, reply, true);
4043 void Server::SendBlocks(float dtime)
4045 DSTACK(__FUNCTION_NAME);
4047 JMutexAutoLock envlock(m_env_mutex);
4048 JMutexAutoLock conlock(m_con_mutex);
4050 //TimeTaker timer("Server::SendBlocks");
4052 core::array<PrioritySortedBlockTransfer> queue;
4054 s32 total_sending = 0;
4057 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4059 for(core::map<u16, RemoteClient*>::Iterator
4060 i = m_clients.getIterator();
4061 i.atEnd() == false; i++)
4063 RemoteClient *client = i.getNode()->getValue();
4064 assert(client->peer_id == i.getNode()->getKey());
4066 total_sending += client->SendingCount();
4068 if(client->serialization_version == SER_FMT_VER_INVALID)
4071 client->GetNextBlocks(this, dtime, queue);
4076 // Lowest priority number comes first.
4077 // Lowest is most important.
4080 for(u32 i=0; i<queue.size(); i++)
4082 //TODO: Calculate limit dynamically
4083 if(total_sending >= g_settings->getS32
4084 ("max_simultaneous_block_sends_server_total"))
4087 PrioritySortedBlockTransfer q = queue[i];
4089 MapBlock *block = NULL;
4092 block = m_env->getMap().getBlockNoCreate(q.pos);
4094 catch(InvalidPositionException &e)
4099 RemoteClient *client = getClient(q.peer_id);
4101 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4103 client->SentBlock(q.pos);
4109 struct SendableTexture
4115 SendableTexture(const std::string &name_="", const std::string path_="",
4116 const std::string &data_=""):
4123 void Server::SendTextures(u16 peer_id)
4125 DSTACK(__FUNCTION_NAME);
4127 infostream<<"Server::SendTextures(): Sending textures to client"<<std::endl;
4131 core::list<SendableTexture> textures;
4132 core::list<ModSpec> mods = getMods(m_modspaths);
4133 for(core::list<ModSpec>::Iterator i = mods.begin();
4134 i != mods.end(); i++){
4136 std::string texturepath = mod.path + DIR_DELIM + "textures";
4137 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
4138 for(u32 j=0; j<dirlist.size(); j++){
4139 if(dirlist[j].dir) // Ignode dirs
4141 std::string tname = dirlist[j].name;
4142 std::string tpath = texturepath + DIR_DELIM + tname;
4144 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4145 if(fis.good() == false){
4146 errorstream<<"Server::SendTextures(): Could not open \""
4147 <<tname<<"\" for reading"<<std::endl;
4150 std::ostringstream tmp_os(std::ios_base::binary);
4154 fis.read(buf, 1024);
4155 std::streamsize len = fis.gcount();
4156 tmp_os.write(buf, len);
4165 errorstream<<"Server::SendTextures(): Failed to read \""
4166 <<tname<<"\""<<std::endl;
4169 errorstream<<"Server::SendTextures(): Loaded \""
4170 <<tname<<"\""<<std::endl;
4172 textures.push_back(SendableTexture(tname, tpath, tmp_os.str()));
4176 /* Create and send packet */
4180 u32 number of textures
4188 std::ostringstream os(std::ios_base::binary);
4190 writeU16(os, TOCLIENT_TEXTURES);
4191 writeU32(os, textures.size());
4193 for(core::list<SendableTexture>::Iterator i = textures.begin();
4194 i != textures.end(); i++){
4195 os<<serializeString(i->name);
4196 os<<serializeLongString(i->data);
4200 std::string s = os.str();
4201 infostream<<"Server::SendTextures(): number of textures: "
4202 <<textures.size()<<", data size: "<<s.size()<<std::endl;
4203 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4205 m_con.Send(peer_id, 0, data, true);
4212 void Server::HandlePlayerHP(Player *player, s16 damage)
4214 if(player->hp > damage)
4216 player->hp -= damage;
4217 SendPlayerHP(player);
4221 infostream<<"Server::HandlePlayerHP(): Player "
4222 <<player->getName()<<" dies"<<std::endl;
4226 //TODO: Throw items around
4228 // Handle players that are not connected
4229 if(player->peer_id == PEER_ID_INEXISTENT){
4230 RespawnPlayer(player);
4234 SendPlayerHP(player);
4236 RemoteClient *client = getClient(player->peer_id);
4237 if(client->net_proto_version >= 3)
4239 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4243 RespawnPlayer(player);
4248 void Server::RespawnPlayer(Player *player)
4250 v3f pos = findSpawnPos(m_env->getServerMap());
4251 player->setPosition(pos);
4253 SendMovePlayer(player);
4254 SendPlayerHP(player);
4257 void Server::UpdateCrafting(u16 peer_id)
4259 DSTACK(__FUNCTION_NAME);
4261 Player* player = m_env->getPlayer(peer_id);
4265 Calculate crafting stuff
4267 if(g_settings->getBool("creative_mode") == false)
4269 InventoryList *clist = player->inventory.getList("craft");
4270 InventoryList *rlist = player->inventory.getList("craftresult");
4272 if(rlist && rlist->getUsedSlots() == 0)
4273 player->craftresult_is_preview = true;
4275 if(rlist && player->craftresult_is_preview)
4277 rlist->clearItems();
4279 if(clist && rlist && player->craftresult_is_preview)
4281 InventoryItem *items[9];
4282 for(u16 i=0; i<9; i++)
4284 items[i] = clist->getItem(i);
4287 // Get result of crafting grid
4288 InventoryItem *result = craft_get_result(items, this);
4290 rlist->addItem(result);
4293 } // if creative_mode == false
4296 RemoteClient* Server::getClient(u16 peer_id)
4298 DSTACK(__FUNCTION_NAME);
4299 //JMutexAutoLock lock(m_con_mutex);
4300 core::map<u16, RemoteClient*>::Node *n;
4301 n = m_clients.find(peer_id);
4302 // A client should exist for all peers
4304 return n->getValue();
4307 std::wstring Server::getStatusString()
4309 std::wostringstream os(std::ios_base::binary);
4312 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4314 os<<L", uptime="<<m_uptime.get();
4315 // Information about clients
4317 for(core::map<u16, RemoteClient*>::Iterator
4318 i = m_clients.getIterator();
4319 i.atEnd() == false; i++)
4321 // Get client and check that it is valid
4322 RemoteClient *client = i.getNode()->getValue();
4323 assert(client->peer_id == i.getNode()->getKey());
4324 if(client->serialization_version == SER_FMT_VER_INVALID)
4327 Player *player = m_env->getPlayer(client->peer_id);
4328 // Get name of player
4329 std::wstring name = L"unknown";
4331 name = narrow_to_wide(player->getName());
4332 // Add name to information string
4336 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4337 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4338 if(g_settings->get("motd") != "")
4339 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4343 // Saves g_settings to configpath given at initialization
4344 void Server::saveConfig()
4346 if(m_configpath != "")
4347 g_settings->updateConfigFile(m_configpath.c_str());
4350 void Server::notifyPlayer(const char *name, const std::wstring msg)
4352 Player *player = m_env->getPlayer(name);
4355 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4358 void Server::notifyPlayers(const std::wstring msg)
4360 BroadcastChatMessage(msg);
4363 // IGameDef interface
4365 IToolDefManager* Server::getToolDefManager()
4369 INodeDefManager* Server::getNodeDefManager()
4373 ITextureSource* Server::getTextureSource()
4378 IWritableToolDefManager* Server::getWritableToolDefManager()
4382 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4387 v3f findSpawnPos(ServerMap &map)
4389 //return v3f(50,50,50)*BS;
4394 nodepos = v2s16(0,0);
4399 // Try to find a good place a few times
4400 for(s32 i=0; i<1000; i++)
4403 // We're going to try to throw the player to this position
4404 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4405 -range + (myrand()%(range*2)));
4406 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4407 // Get ground height at point (fallbacks to heightmap function)
4408 s16 groundheight = map.findGroundLevel(nodepos2d);
4409 // Don't go underwater
4410 if(groundheight < WATER_LEVEL)
4412 //infostream<<"-> Underwater"<<std::endl;
4415 // Don't go to high places
4416 if(groundheight > WATER_LEVEL + 4)
4418 //infostream<<"-> Underwater"<<std::endl;
4422 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4423 bool is_good = false;
4425 for(s32 i=0; i<10; i++){
4426 v3s16 blockpos = getNodeBlockPos(nodepos);
4427 map.emergeBlock(blockpos, true);
4428 MapNode n = map.getNodeNoEx(nodepos);
4429 if(n.getContent() == CONTENT_AIR){
4440 // Found a good place
4441 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4447 return intToFloat(nodepos, BS);
4450 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4453 Try to get an existing player
4455 Player *player = m_env->getPlayer(name);
4458 // If player is already connected, cancel
4459 if(player->peer_id != 0)
4461 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4466 player->peer_id = peer_id;
4468 // Reset inventory to creative if in creative mode
4469 if(g_settings->getBool("creative_mode"))
4471 // Warning: double code below
4472 // Backup actual inventory
4473 player->inventory_backup = new Inventory();
4474 *(player->inventory_backup) = player->inventory;
4475 // Set creative inventory
4476 craft_set_creative_inventory(player, this);
4483 If player with the wanted peer_id already exists, cancel.
4485 if(m_env->getPlayer(peer_id) != NULL)
4487 infostream<<"emergePlayer(): Player with wrong name but same"
4488 " peer_id already exists"<<std::endl;
4496 // Add authentication stuff
4497 m_authmanager.add(name);
4498 m_authmanager.setPassword(name, password);
4499 m_authmanager.setPrivs(name,
4500 stringToPrivs(g_settings->get("default_privs")));
4506 infostream<<"Server: Finding spawn place for player \""
4507 <<name<<"\""<<std::endl;
4509 v3f pos = findSpawnPos(m_env->getServerMap());
4511 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4514 Add player to environment
4517 m_env->addPlayer(player);
4520 Add stuff to inventory
4523 if(g_settings->getBool("creative_mode"))
4525 // Warning: double code above
4526 // Backup actual inventory
4527 player->inventory_backup = new Inventory();
4528 *(player->inventory_backup) = player->inventory;
4529 // Set creative inventory
4530 craft_set_creative_inventory(player, this);
4532 else if(g_settings->getBool("give_initial_stuff"))
4534 craft_give_initial_stuff(player, this);
4539 } // create new player
4542 void Server::handlePeerChange(PeerChange &c)
4544 JMutexAutoLock envlock(m_env_mutex);
4545 JMutexAutoLock conlock(m_con_mutex);
4547 if(c.type == PEER_ADDED)
4554 core::map<u16, RemoteClient*>::Node *n;
4555 n = m_clients.find(c.peer_id);
4556 // The client shouldn't already exist
4560 RemoteClient *client = new RemoteClient();
4561 client->peer_id = c.peer_id;
4562 m_clients.insert(client->peer_id, client);
4565 else if(c.type == PEER_REMOVED)
4572 core::map<u16, RemoteClient*>::Node *n;
4573 n = m_clients.find(c.peer_id);
4574 // The client should exist
4578 Mark objects to be not known by the client
4580 RemoteClient *client = n->getValue();
4582 for(core::map<u16, bool>::Iterator
4583 i = client->m_known_objects.getIterator();
4584 i.atEnd()==false; i++)
4587 u16 id = i.getNode()->getKey();
4588 ServerActiveObject* obj = m_env->getActiveObject(id);
4590 if(obj && obj->m_known_by_count > 0)
4591 obj->m_known_by_count--;
4594 // Collect information about leaving in chat
4595 std::wstring message;
4597 Player *player = m_env->getPlayer(c.peer_id);
4600 std::wstring name = narrow_to_wide(player->getName());
4603 message += L" left game";
4605 message += L" (timed out)";
4611 m_env->removePlayer(c.peer_id);
4614 // Set player client disconnected
4616 Player *player = m_env->getPlayer(c.peer_id);
4618 player->peer_id = 0;
4625 std::ostringstream os(std::ios_base::binary);
4626 for(core::map<u16, RemoteClient*>::Iterator
4627 i = m_clients.getIterator();
4628 i.atEnd() == false; i++)
4630 RemoteClient *client = i.getNode()->getValue();
4631 assert(client->peer_id == i.getNode()->getKey());
4632 if(client->serialization_version == SER_FMT_VER_INVALID)
4635 Player *player = m_env->getPlayer(client->peer_id);
4638 // Get name of player
4639 os<<player->getName()<<" ";
4642 actionstream<<player->getName()<<" "
4643 <<(c.timeout?"times out.":"leaves game.")
4644 <<" List of players: "
4645 <<os.str()<<std::endl;
4650 delete m_clients[c.peer_id];
4651 m_clients.remove(c.peer_id);
4653 // Send player info to all remaining clients
4656 // Send leave chat message to all remaining clients
4657 BroadcastChatMessage(message);
4666 void Server::handlePeerChanges()
4668 while(m_peer_change_queue.size() > 0)
4670 PeerChange c = m_peer_change_queue.pop_front();
4672 infostream<<"Server: Handling peer change: "
4673 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4676 handlePeerChange(c);
4680 u64 Server::getPlayerPrivs(Player *player)
4684 std::string playername = player->getName();
4685 // Local player gets all privileges regardless of
4686 // what's set on their account.
4687 if(g_settings->get("name") == playername)
4693 return getPlayerAuthPrivs(playername);
4697 void dedicated_server_loop(Server &server, bool &kill)
4699 DSTACK(__FUNCTION_NAME);
4701 infostream<<DTIME<<std::endl;
4702 infostream<<"========================"<<std::endl;
4703 infostream<<"Running dedicated server"<<std::endl;
4704 infostream<<"========================"<<std::endl;
4705 infostream<<std::endl;
4707 IntervalLimiter m_profiler_interval;
4711 // This is kind of a hack but can be done like this
4712 // because server.step() is very light
4714 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4719 if(server.getShutdownRequested() || kill)
4721 infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4728 float profiler_print_interval =
4729 g_settings->getFloat("profiler_print_interval");
4730 if(profiler_print_interval != 0)
4732 if(m_profiler_interval.step(0.030, profiler_print_interval))
4734 infostream<<"Profiler:"<<std::endl;
4735 g_profiler->print(infostream);
4736 g_profiler->clear();
4743 static int counter = 0;
4749 core::list<PlayerInfo> list = server.getPlayerInfo();
4750 core::list<PlayerInfo>::Iterator i;
4751 static u32 sum_old = 0;
4752 u32 sum = PIChecksum(list);
4755 infostream<<DTIME<<"Player info:"<<std::endl;
4756 for(i=list.begin(); i!=list.end(); i++)
4758 i->PrintLine(&infostream);