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"
44 #include "mapnode_contentfeatures.h"
46 #include "content_tool.h" // For content_tool_init
48 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
50 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
52 class MapEditEventIgnorer
55 MapEditEventIgnorer(bool *flag):
64 ~MapEditEventIgnorer()
77 void * ServerThread::Thread()
81 log_register_thread("ServerThread");
83 DSTACK(__FUNCTION_NAME);
85 BEGIN_DEBUG_EXCEPTION_HANDLER
90 //TimeTaker timer("AsyncRunStep() + Receive()");
93 //TimeTaker timer("AsyncRunStep()");
94 m_server->AsyncRunStep();
97 //infostream<<"Running m_server->Receive()"<<std::endl;
100 catch(con::NoIncomingDataException &e)
103 catch(con::PeerNotFoundException &e)
105 infostream<<"Server: PeerNotFoundException"<<std::endl;
109 END_DEBUG_EXCEPTION_HANDLER(errorstream)
114 void * EmergeThread::Thread()
118 log_register_thread("EmergeThread");
120 DSTACK(__FUNCTION_NAME);
122 BEGIN_DEBUG_EXCEPTION_HANDLER
124 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
127 Get block info from queue, emerge them and send them
130 After queue is empty, exit.
134 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
138 SharedPtr<QueuedBlockEmerge> q(qptr);
144 Do not generate over-limit
146 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
147 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
148 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
149 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
150 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
151 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
154 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
156 //TimeTaker timer("block emerge");
159 Try to emerge it from somewhere.
161 If it is only wanted as optional, only loading from disk
166 Check if any peer wants it as non-optional. In that case it
169 Also decrement the emerge queue count in clients.
172 bool only_from_disk = true;
175 core::map<u16, u8>::Iterator i;
176 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
178 //u16 peer_id = i.getNode()->getKey();
181 u8 flags = i.getNode()->getValue();
182 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
183 only_from_disk = false;
188 if(enable_mapgen_debug_info)
189 infostream<<"EmergeThread: p="
190 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
191 <<"only_from_disk="<<only_from_disk<<std::endl;
193 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
195 //core::map<v3s16, MapBlock*> changed_blocks;
196 //core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
198 MapBlock *block = NULL;
199 bool got_block = true;
200 core::map<v3s16, MapBlock*> modified_blocks;
203 Fetch block from map or generate a single block
206 JMutexAutoLock envlock(m_server->m_env_mutex);
208 // Load sector if it isn't loaded
209 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
210 //map.loadSectorFull(p2d);
211 map.loadSectorMeta(p2d);
213 block = map.getBlockNoCreateNoEx(p);
214 if(!block || block->isDummy() || !block->isGenerated())
216 if(enable_mapgen_debug_info)
217 infostream<<"EmergeThread: not in memory, loading"<<std::endl;
219 // Get, load or create sector
220 /*ServerMapSector *sector =
221 (ServerMapSector*)map.createSector(p2d);*/
223 // Load/generate block
225 /*block = map.emergeBlock(p, sector, changed_blocks,
226 lighting_invalidated_blocks);*/
228 block = map.loadBlock(p);
230 if(only_from_disk == false)
232 if(block == NULL || block->isGenerated() == false)
234 if(enable_mapgen_debug_info)
235 infostream<<"EmergeThread: generating"<<std::endl;
236 block = map.generateBlock(p, modified_blocks);
240 if(enable_mapgen_debug_info)
241 infostream<<"EmergeThread: ended up with: "
242 <<analyze_block(block)<<std::endl;
251 Ignore map edit events, they will not need to be
252 sent to anybody because the block hasn't been sent
255 MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
257 // Activate objects and stuff
258 m_server->m_env->activateBlock(block, 3600);
263 /*if(block->getLightingExpired()){
264 lighting_invalidated_blocks[block->getPos()] = block;
268 // TODO: Some additional checking and lighting updating,
273 JMutexAutoLock envlock(m_server->m_env_mutex);
278 Collect a list of blocks that have been modified in
279 addition to the fetched one.
283 if(lighting_invalidated_blocks.size() > 0)
285 /*infostream<<"lighting "<<lighting_invalidated_blocks.size()
286 <<" blocks"<<std::endl;*/
288 // 50-100ms for single block generation
289 //TimeTaker timer("** EmergeThread updateLighting");
291 // Update lighting without locking the environment mutex,
292 // add modified blocks to changed blocks
293 map.updateLighting(lighting_invalidated_blocks, modified_blocks);
296 // Add all from changed_blocks to modified_blocks
297 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
298 i.atEnd() == false; i++)
300 MapBlock *block = i.getNode()->getValue();
301 modified_blocks.insert(block->getPos(), block);
305 // If we got no block, there should be no invalidated blocks
308 //assert(lighting_invalidated_blocks.size() == 0);
314 Set sent status of modified blocks on clients
317 // NOTE: Server's clients are also behind the connection mutex
318 JMutexAutoLock lock(m_server->m_con_mutex);
321 Add the originally fetched block to the modified list
325 modified_blocks.insert(p, block);
329 Set the modified blocks unsent for all the clients
332 for(core::map<u16, RemoteClient*>::Iterator
333 i = m_server->m_clients.getIterator();
334 i.atEnd() == false; i++)
336 RemoteClient *client = i.getNode()->getValue();
338 if(modified_blocks.size() > 0)
340 // Remove block from sent history
341 client->SetBlocksNotSent(modified_blocks);
347 END_DEBUG_EXCEPTION_HANDLER(errorstream)
352 void RemoteClient::GetNextBlocks(Server *server, float dtime,
353 core::array<PrioritySortedBlockTransfer> &dest)
355 DSTACK(__FUNCTION_NAME);
358 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
361 m_nothing_to_send_pause_timer -= dtime;
362 m_nearest_unsent_reset_timer += dtime;
364 if(m_nothing_to_send_pause_timer >= 0)
369 // Won't send anything if already sending
370 if(m_blocks_sending.size() >= g_settings->getU16
371 ("max_simultaneous_block_sends_per_client"))
373 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
377 //TimeTaker timer("RemoteClient::GetNextBlocks");
379 Player *player = server->m_env->getPlayer(peer_id);
381 assert(player != NULL);
383 v3f playerpos = player->getPosition();
384 v3f playerspeed = player->getSpeed();
385 v3f playerspeeddir(0,0,0);
386 if(playerspeed.getLength() > 1.0*BS)
387 playerspeeddir = playerspeed / playerspeed.getLength();
388 // Predict to next block
389 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
391 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
393 v3s16 center = getNodeBlockPos(center_nodepos);
395 // Camera position and direction
396 v3f camera_pos = player->getEyePosition();
397 v3f camera_dir = v3f(0,0,1);
398 camera_dir.rotateYZBy(player->getPitch());
399 camera_dir.rotateXZBy(player->getYaw());
401 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
402 <<camera_dir.Z<<")"<<std::endl;*/
405 Get the starting value of the block finder radius.
408 if(m_last_center != center)
410 m_nearest_unsent_d = 0;
411 m_last_center = center;
414 /*infostream<<"m_nearest_unsent_reset_timer="
415 <<m_nearest_unsent_reset_timer<<std::endl;*/
417 // Reset periodically to workaround for some bugs or stuff
418 if(m_nearest_unsent_reset_timer > 20.0)
420 m_nearest_unsent_reset_timer = 0;
421 m_nearest_unsent_d = 0;
422 //infostream<<"Resetting m_nearest_unsent_d for "
423 // <<server->getPlayerName(peer_id)<<std::endl;
426 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
427 s16 d_start = m_nearest_unsent_d;
429 //infostream<<"d_start="<<d_start<<std::endl;
431 u16 max_simul_sends_setting = g_settings->getU16
432 ("max_simultaneous_block_sends_per_client");
433 u16 max_simul_sends_usually = max_simul_sends_setting;
436 Check the time from last addNode/removeNode.
438 Decrease send rate if player is building stuff.
440 m_time_from_building += dtime;
441 if(m_time_from_building < g_settings->getFloat(
442 "full_block_send_enable_min_time_from_building"))
444 max_simul_sends_usually
445 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
449 Number of blocks sending + number of blocks selected for sending
451 u32 num_blocks_selected = m_blocks_sending.size();
454 next time d will be continued from the d from which the nearest
455 unsent block was found this time.
457 This is because not necessarily any of the blocks found this
458 time are actually sent.
460 s32 new_nearest_unsent_d = -1;
462 s16 d_max = g_settings->getS16("max_block_send_distance");
463 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
465 // Don't loop very much at a time
466 s16 max_d_increment_at_time = 2;
467 if(d_max > d_start + max_d_increment_at_time)
468 d_max = d_start + max_d_increment_at_time;
469 /*if(d_max_gen > d_start+2)
470 d_max_gen = d_start+2;*/
472 //infostream<<"Starting from "<<d_start<<std::endl;
474 s32 nearest_emerged_d = -1;
475 s32 nearest_emergefull_d = -1;
476 s32 nearest_sent_d = -1;
477 bool queue_is_full = false;
480 for(d = d_start; d <= d_max; d++)
482 /*errorstream<<"checking d="<<d<<" for "
483 <<server->getPlayerName(peer_id)<<std::endl;*/
484 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
487 If m_nearest_unsent_d was changed by the EmergeThread
488 (it can change it to 0 through SetBlockNotSent),
490 Else update m_nearest_unsent_d
492 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
494 d = m_nearest_unsent_d;
495 last_nearest_unsent_d = m_nearest_unsent_d;
499 Get the border/face dot coordinates of a "d-radiused"
502 core::list<v3s16> list;
503 getFacePositions(list, d);
505 core::list<v3s16>::Iterator li;
506 for(li=list.begin(); li!=list.end(); li++)
508 v3s16 p = *li + center;
512 - Don't allow too many simultaneous transfers
513 - EXCEPT when the blocks are very close
515 Also, don't send blocks that are already flying.
518 // Start with the usual maximum
519 u16 max_simul_dynamic = max_simul_sends_usually;
521 // If block is very close, allow full maximum
522 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
523 max_simul_dynamic = max_simul_sends_setting;
525 // Don't select too many blocks for sending
526 if(num_blocks_selected >= max_simul_dynamic)
528 queue_is_full = true;
529 goto queue_full_break;
532 // Don't send blocks that are currently being transferred
533 if(m_blocks_sending.find(p) != NULL)
539 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
540 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
541 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
542 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
543 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
544 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
547 // If this is true, inexistent block will be made from scratch
548 bool generate = d <= d_max_gen;
551 /*// Limit the generating area vertically to 2/3
552 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
555 // Limit the send area vertically to 1/2
556 if(abs(p.Y - center.Y) > d_max / 2)
562 If block is far away, don't generate it unless it is
568 // Block center y in nodes
569 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
570 // Don't generate if it's very high or very low
571 if(y < -64 || y > 64)
575 v2s16 p2d_nodes_center(
579 // Get ground height in nodes
580 s16 gh = server->m_env->getServerMap().findGroundLevel(
583 // If differs a lot, don't generate
584 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
586 // Actually, don't even send it
592 //infostream<<"d="<<d<<std::endl;
595 Don't generate or send if not in sight
596 FIXME This only works if the client uses a small enough
597 FOV setting. The default of 72 degrees is fine.
600 float camera_fov = (72.0*PI/180) * 4./3.;
601 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
607 Don't send already sent blocks
610 if(m_blocks_sent.find(p) != NULL)
617 Check if map has this block
619 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
621 bool surely_not_found_on_disk = false;
622 bool block_is_invalid = false;
625 // Reset usage timer, this block will be of use in the future.
626 block->resetUsageTimer();
628 // Block is dummy if data doesn't exist.
629 // It means it has been not found from disk and not generated
632 surely_not_found_on_disk = true;
635 // Block is valid if lighting is up-to-date and data exists
636 if(block->isValid() == false)
638 block_is_invalid = true;
641 /*if(block->isFullyGenerated() == false)
643 block_is_invalid = true;
648 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
649 v2s16 chunkpos = map->sector_to_chunk(p2d);
650 if(map->chunkNonVolatile(chunkpos) == false)
651 block_is_invalid = true;
653 if(block->isGenerated() == false)
654 block_is_invalid = true;
657 If block is not close, don't send it unless it is near
660 Block is near ground level if night-time mesh
661 differs from day-time mesh.
665 if(block->dayNightDiffed() == false)
672 If block has been marked to not exist on disk (dummy)
673 and generating new ones is not wanted, skip block.
675 if(generate == false && surely_not_found_on_disk == true)
682 Add inexistent block to emerge queue.
684 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
686 //TODO: Get value from somewhere
687 // Allow only one block in emerge queue
688 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
689 // Allow two blocks in queue per client
690 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
691 if(server->m_emerge_queue.peerItemCount(peer_id) < 25)
693 //infostream<<"Adding block to emerge queue"<<std::endl;
695 // Add it to the emerge queue and trigger the thread
698 if(generate == false)
699 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
701 server->m_emerge_queue.addBlock(peer_id, p, flags);
702 server->m_emergethread.trigger();
704 if(nearest_emerged_d == -1)
705 nearest_emerged_d = d;
707 if(nearest_emergefull_d == -1)
708 nearest_emergefull_d = d;
715 if(nearest_sent_d == -1)
719 Add block to send queue
722 /*errorstream<<"sending from d="<<d<<" to "
723 <<server->getPlayerName(peer_id)<<std::endl;*/
725 PrioritySortedBlockTransfer q((float)d, p, peer_id);
729 num_blocks_selected += 1;
734 //infostream<<"Stopped at "<<d<<std::endl;
736 // If nothing was found for sending and nothing was queued for
737 // emerging, continue next time browsing from here
738 if(nearest_emerged_d != -1){
739 new_nearest_unsent_d = nearest_emerged_d;
740 } else if(nearest_emergefull_d != -1){
741 new_nearest_unsent_d = nearest_emergefull_d;
743 if(d > g_settings->getS16("max_block_send_distance")){
744 new_nearest_unsent_d = 0;
745 m_nothing_to_send_pause_timer = 2.0;
746 /*infostream<<"GetNextBlocks(): d wrapped around for "
747 <<server->getPlayerName(peer_id)
748 <<"; setting to 0 and pausing"<<std::endl;*/
750 if(nearest_sent_d != -1)
751 new_nearest_unsent_d = nearest_sent_d;
753 new_nearest_unsent_d = d;
757 if(new_nearest_unsent_d != -1)
758 m_nearest_unsent_d = new_nearest_unsent_d;
760 /*timer_result = timer.stop(true);
761 if(timer_result != 0)
762 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
765 void RemoteClient::SendObjectData(
768 core::map<v3s16, bool> &stepped_blocks
771 DSTACK(__FUNCTION_NAME);
773 // Can't send anything without knowing version
774 if(serialization_version == SER_FMT_VER_INVALID)
776 infostream<<"RemoteClient::SendObjectData(): Not sending, no version."
782 Send a TOCLIENT_OBJECTDATA packet.
786 u16 number of player positions
798 std::ostringstream os(std::ios_base::binary);
802 writeU16(buf, TOCLIENT_OBJECTDATA);
803 os.write((char*)buf, 2);
806 Get and write player data
809 // Get connected players
810 core::list<Player*> players = server->m_env->getPlayers(true);
812 // Write player count
813 u16 playercount = players.size();
814 writeU16(buf, playercount);
815 os.write((char*)buf, 2);
817 core::list<Player*>::Iterator i;
818 for(i = players.begin();
819 i != players.end(); i++)
823 v3f pf = player->getPosition();
824 v3f sf = player->getSpeed();
826 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
827 v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100);
828 s32 pitch_i (player->getPitch() * 100);
829 s32 yaw_i (player->getYaw() * 100);
831 writeU16(buf, player->peer_id);
832 os.write((char*)buf, 2);
833 writeV3S32(buf, position_i);
834 os.write((char*)buf, 12);
835 writeV3S32(buf, speed_i);
836 os.write((char*)buf, 12);
837 writeS32(buf, pitch_i);
838 os.write((char*)buf, 4);
839 writeS32(buf, yaw_i);
840 os.write((char*)buf, 4);
844 Get and write object data (dummy, for compatibility)
849 os.write((char*)buf, 2);
855 //infostream<<"Server: Sending object data to "<<peer_id<<std::endl;
858 std::string s = os.str();
859 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
860 // Send as unreliable
861 server->m_con.Send(peer_id, 0, data, false);
864 void RemoteClient::GotBlock(v3s16 p)
866 if(m_blocks_sending.find(p) != NULL)
867 m_blocks_sending.remove(p);
870 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
871 " m_blocks_sending"<<std::endl;*/
872 m_excess_gotblocks++;
874 m_blocks_sent.insert(p, true);
877 void RemoteClient::SentBlock(v3s16 p)
879 if(m_blocks_sending.find(p) == NULL)
880 m_blocks_sending.insert(p, 0.0);
882 infostream<<"RemoteClient::SentBlock(): Sent block"
883 " already in m_blocks_sending"<<std::endl;
886 void RemoteClient::SetBlockNotSent(v3s16 p)
888 m_nearest_unsent_d = 0;
890 if(m_blocks_sending.find(p) != NULL)
891 m_blocks_sending.remove(p);
892 if(m_blocks_sent.find(p) != NULL)
893 m_blocks_sent.remove(p);
896 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
898 m_nearest_unsent_d = 0;
900 for(core::map<v3s16, MapBlock*>::Iterator
901 i = blocks.getIterator();
902 i.atEnd()==false; i++)
904 v3s16 p = i.getNode()->getKey();
906 if(m_blocks_sending.find(p) != NULL)
907 m_blocks_sending.remove(p);
908 if(m_blocks_sent.find(p) != NULL)
909 m_blocks_sent.remove(p);
917 PlayerInfo::PlayerInfo()
923 void PlayerInfo::PrintLine(std::ostream *s)
926 (*s)<<"\""<<name<<"\" ("
927 <<(position.X/10)<<","<<(position.Y/10)
928 <<","<<(position.Z/10)<<") ";
930 (*s)<<" avg_rtt="<<avg_rtt;
934 u32 PIChecksum(core::list<PlayerInfo> &l)
936 core::list<PlayerInfo>::Iterator i;
939 for(i=l.begin(); i!=l.end(); i++)
941 checksum += a * (i->id+1);
942 checksum ^= 0x435aafcd;
953 std::string mapsavedir,
954 std::string configpath
957 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
958 m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"),
959 m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"),
961 m_toolmgr(createToolDefManager()),
963 m_emergethread(this),
965 m_time_of_day_send_timer(0),
967 m_mapsavedir(mapsavedir),
968 m_configpath(configpath),
969 m_shutdown_requested(false),
970 m_ignore_map_edit_events(false),
971 m_ignore_map_edit_events_peer_id(0)
973 m_liquid_transform_timer = 0.0;
974 m_print_info_timer = 0.0;
975 m_objectdata_timer = 0.0;
976 m_emergethread_trigger_timer = 0.0;
977 m_savemap_timer = 0.0;
981 m_step_dtime_mutex.Init();
984 JMutexAutoLock envlock(m_env_mutex);
985 JMutexAutoLock conlock(m_con_mutex);
987 // Initialize default tool definitions
988 content_tool_init(m_toolmgr);
990 // Initialize scripting
992 infostream<<"Server: Initializing scripting"<<std::endl;
993 m_lua = script_init();
996 scriptapi_export(m_lua, this);
997 // Load and run scripts
998 std::string defaultscript = porting::path_data + DIR_DELIM
999 + "scripts" + DIR_DELIM + "default.lua";
1000 bool success = script_load(m_lua, defaultscript.c_str());
1002 errorstream<<"Server: Failed to load and run "
1003 <<defaultscript<<std::endl;
1007 // Initialize Environment
1009 m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua, this);
1011 // Give environment reference to scripting api
1012 scriptapi_add_environment(m_lua, m_env);
1014 // Register us to receive map edit events
1015 m_env->getMap().addEventReceiver(this);
1017 // If file exists, load environment metadata
1018 if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt"))
1020 infostream<<"Server: Loading environment metadata"<<std::endl;
1021 m_env->loadMeta(m_mapsavedir);
1025 infostream<<"Server: Loading players"<<std::endl;
1026 m_env->deSerializePlayers(m_mapsavedir);
1031 infostream<<"Server::~Server()"<<std::endl;
1034 Send shutdown message
1037 JMutexAutoLock conlock(m_con_mutex);
1039 std::wstring line = L"*** Server shutting down";
1042 Send the message to clients
1044 for(core::map<u16, RemoteClient*>::Iterator
1045 i = m_clients.getIterator();
1046 i.atEnd() == false; i++)
1048 // Get client and check that it is valid
1049 RemoteClient *client = i.getNode()->getValue();
1050 assert(client->peer_id == i.getNode()->getKey());
1051 if(client->serialization_version == SER_FMT_VER_INVALID)
1055 SendChatMessage(client->peer_id, line);
1057 catch(con::PeerNotFoundException &e)
1063 JMutexAutoLock envlock(m_env_mutex);
1068 infostream<<"Server: Saving players"<<std::endl;
1069 m_env->serializePlayers(m_mapsavedir);
1072 Save environment metadata
1074 infostream<<"Server: Saving environment metadata"<<std::endl;
1075 m_env->saveMeta(m_mapsavedir);
1087 JMutexAutoLock clientslock(m_con_mutex);
1089 for(core::map<u16, RemoteClient*>::Iterator
1090 i = m_clients.getIterator();
1091 i.atEnd() == false; i++)
1094 // NOTE: These are removed by env destructor
1096 u16 peer_id = i.getNode()->getKey();
1097 JMutexAutoLock envlock(m_env_mutex);
1098 m_env->removePlayer(peer_id);
1102 delete i.getNode()->getValue();
1106 // Delete Environment
1111 // Deinitialize scripting
1112 infostream<<"Server: Deinitializing scripting"<<std::endl;
1113 script_deinit(m_lua);
1116 void Server::start(unsigned short port)
1118 DSTACK(__FUNCTION_NAME);
1119 // Stop thread if already running
1122 // Initialize connection
1123 m_con.SetTimeoutMs(30);
1127 m_thread.setRun(true);
1130 infostream<<"Server: Started on port "<<port<<std::endl;
1135 DSTACK(__FUNCTION_NAME);
1137 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1139 // Stop threads (set run=false first so both start stopping)
1140 m_thread.setRun(false);
1141 m_emergethread.setRun(false);
1143 m_emergethread.stop();
1145 infostream<<"Server: Threads stopped"<<std::endl;
1148 void Server::step(float dtime)
1150 DSTACK(__FUNCTION_NAME);
1155 JMutexAutoLock lock(m_step_dtime_mutex);
1156 m_step_dtime += dtime;
1160 void Server::AsyncRunStep()
1162 DSTACK(__FUNCTION_NAME);
1164 g_profiler->add("Server::AsyncRunStep (num)", 1);
1168 JMutexAutoLock lock1(m_step_dtime_mutex);
1169 dtime = m_step_dtime;
1173 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
1174 // Send blocks to clients
1181 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1183 //infostream<<"Server steps "<<dtime<<std::endl;
1184 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1187 JMutexAutoLock lock1(m_step_dtime_mutex);
1188 m_step_dtime -= dtime;
1195 m_uptime.set(m_uptime.get() + dtime);
1199 // Process connection's timeouts
1200 JMutexAutoLock lock2(m_con_mutex);
1201 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1202 m_con.RunTimeouts(dtime);
1206 // This has to be called so that the client list gets synced
1207 // with the peer list of the connection
1208 handlePeerChanges();
1212 Update m_time_of_day and overall game time
1215 JMutexAutoLock envlock(m_env_mutex);
1217 m_time_counter += dtime;
1218 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1219 u32 units = (u32)(m_time_counter*speed);
1220 m_time_counter -= (f32)units / speed;
1222 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1224 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1227 Send to clients at constant intervals
1230 m_time_of_day_send_timer -= dtime;
1231 if(m_time_of_day_send_timer < 0.0)
1233 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1235 //JMutexAutoLock envlock(m_env_mutex);
1236 JMutexAutoLock conlock(m_con_mutex);
1238 for(core::map<u16, RemoteClient*>::Iterator
1239 i = m_clients.getIterator();
1240 i.atEnd() == false; i++)
1242 RemoteClient *client = i.getNode()->getValue();
1243 //Player *player = m_env->getPlayer(client->peer_id);
1245 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1246 m_env->getTimeOfDay());
1248 m_con.Send(client->peer_id, 0, data, true);
1254 JMutexAutoLock lock(m_env_mutex);
1256 ScopeProfiler sp(g_profiler, "SEnv step");
1257 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1261 const float map_timer_and_unload_dtime = 5.15;
1262 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1264 JMutexAutoLock lock(m_env_mutex);
1265 // Run Map's timers and unload unused data
1266 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1267 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1268 g_settings->getFloat("server_unload_unused_data_timeout"));
1278 m_liquid_transform_timer += dtime;
1279 if(m_liquid_transform_timer >= 1.00)
1281 m_liquid_transform_timer -= 1.00;
1283 JMutexAutoLock lock(m_env_mutex);
1285 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1287 core::map<v3s16, MapBlock*> modified_blocks;
1288 m_env->getMap().transformLiquids(modified_blocks);
1293 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1294 ServerMap &map = ((ServerMap&)m_env->getMap());
1295 map.updateLighting(modified_blocks, lighting_modified_blocks);
1297 // Add blocks modified by lighting to modified_blocks
1298 for(core::map<v3s16, MapBlock*>::Iterator
1299 i = lighting_modified_blocks.getIterator();
1300 i.atEnd() == false; i++)
1302 MapBlock *block = i.getNode()->getValue();
1303 modified_blocks.insert(block->getPos(), block);
1307 Set the modified blocks unsent for all the clients
1310 JMutexAutoLock lock2(m_con_mutex);
1312 for(core::map<u16, RemoteClient*>::Iterator
1313 i = m_clients.getIterator();
1314 i.atEnd() == false; i++)
1316 RemoteClient *client = i.getNode()->getValue();
1318 if(modified_blocks.size() > 0)
1320 // Remove block from sent history
1321 client->SetBlocksNotSent(modified_blocks);
1326 // Periodically print some info
1328 float &counter = m_print_info_timer;
1334 JMutexAutoLock lock2(m_con_mutex);
1336 if(m_clients.size() != 0)
1337 infostream<<"Players:"<<std::endl;
1338 for(core::map<u16, RemoteClient*>::Iterator
1339 i = m_clients.getIterator();
1340 i.atEnd() == false; i++)
1342 //u16 peer_id = i.getNode()->getKey();
1343 RemoteClient *client = i.getNode()->getValue();
1344 Player *player = m_env->getPlayer(client->peer_id);
1347 infostream<<"* "<<player->getName()<<"\t";
1348 client->PrintInfo(infostream);
1353 //if(g_settings->getBool("enable_experimental"))
1357 Check added and deleted active objects
1360 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1361 JMutexAutoLock envlock(m_env_mutex);
1362 JMutexAutoLock conlock(m_con_mutex);
1364 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1366 // Radius inside which objects are active
1367 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1368 radius *= MAP_BLOCKSIZE;
1370 for(core::map<u16, RemoteClient*>::Iterator
1371 i = m_clients.getIterator();
1372 i.atEnd() == false; i++)
1374 RemoteClient *client = i.getNode()->getValue();
1375 Player *player = m_env->getPlayer(client->peer_id);
1378 // This can happen if the client timeouts somehow
1379 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1381 <<" has no associated player"<<std::endl;*/
1384 v3s16 pos = floatToInt(player->getPosition(), BS);
1386 core::map<u16, bool> removed_objects;
1387 core::map<u16, bool> added_objects;
1388 m_env->getRemovedActiveObjects(pos, radius,
1389 client->m_known_objects, removed_objects);
1390 m_env->getAddedActiveObjects(pos, radius,
1391 client->m_known_objects, added_objects);
1393 // Ignore if nothing happened
1394 if(removed_objects.size() == 0 && added_objects.size() == 0)
1396 //infostream<<"active objects: none changed"<<std::endl;
1400 std::string data_buffer;
1404 // Handle removed objects
1405 writeU16((u8*)buf, removed_objects.size());
1406 data_buffer.append(buf, 2);
1407 for(core::map<u16, bool>::Iterator
1408 i = removed_objects.getIterator();
1409 i.atEnd()==false; i++)
1412 u16 id = i.getNode()->getKey();
1413 ServerActiveObject* obj = m_env->getActiveObject(id);
1415 // Add to data buffer for sending
1416 writeU16((u8*)buf, i.getNode()->getKey());
1417 data_buffer.append(buf, 2);
1419 // Remove from known objects
1420 client->m_known_objects.remove(i.getNode()->getKey());
1422 if(obj && obj->m_known_by_count > 0)
1423 obj->m_known_by_count--;
1426 // Handle added objects
1427 writeU16((u8*)buf, added_objects.size());
1428 data_buffer.append(buf, 2);
1429 for(core::map<u16, bool>::Iterator
1430 i = added_objects.getIterator();
1431 i.atEnd()==false; i++)
1434 u16 id = i.getNode()->getKey();
1435 ServerActiveObject* obj = m_env->getActiveObject(id);
1438 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1440 infostream<<"WARNING: "<<__FUNCTION_NAME
1441 <<": NULL object"<<std::endl;
1443 type = obj->getType();
1445 // Add to data buffer for sending
1446 writeU16((u8*)buf, id);
1447 data_buffer.append(buf, 2);
1448 writeU8((u8*)buf, type);
1449 data_buffer.append(buf, 1);
1452 data_buffer.append(serializeLongString(
1453 obj->getClientInitializationData()));
1455 data_buffer.append(serializeLongString(""));
1457 // Add to known objects
1458 client->m_known_objects.insert(i.getNode()->getKey(), false);
1461 obj->m_known_by_count++;
1465 SharedBuffer<u8> reply(2 + data_buffer.size());
1466 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1467 memcpy((char*)&reply[2], data_buffer.c_str(),
1468 data_buffer.size());
1470 m_con.Send(client->peer_id, 0, reply, true);
1472 infostream<<"Server: Sent object remove/add: "
1473 <<removed_objects.size()<<" removed, "
1474 <<added_objects.size()<<" added, "
1475 <<"packet size is "<<reply.getSize()<<std::endl;
1480 Collect a list of all the objects known by the clients
1481 and report it back to the environment.
1484 core::map<u16, bool> all_known_objects;
1486 for(core::map<u16, RemoteClient*>::Iterator
1487 i = m_clients.getIterator();
1488 i.atEnd() == false; i++)
1490 RemoteClient *client = i.getNode()->getValue();
1491 // Go through all known objects of client
1492 for(core::map<u16, bool>::Iterator
1493 i = client->m_known_objects.getIterator();
1494 i.atEnd()==false; i++)
1496 u16 id = i.getNode()->getKey();
1497 all_known_objects[id] = true;
1501 m_env->setKnownActiveObjects(whatever);
1507 Send object messages
1510 JMutexAutoLock envlock(m_env_mutex);
1511 JMutexAutoLock conlock(m_con_mutex);
1513 //ScopeProfiler sp(g_profiler, "Server: sending object messages");
1516 // Value = data sent by object
1517 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1519 // Get active object messages from environment
1522 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1526 core::list<ActiveObjectMessage>* message_list = NULL;
1527 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1528 n = buffered_messages.find(aom.id);
1531 message_list = new core::list<ActiveObjectMessage>;
1532 buffered_messages.insert(aom.id, message_list);
1536 message_list = n->getValue();
1538 message_list->push_back(aom);
1541 // Route data to every client
1542 for(core::map<u16, RemoteClient*>::Iterator
1543 i = m_clients.getIterator();
1544 i.atEnd()==false; i++)
1546 RemoteClient *client = i.getNode()->getValue();
1547 std::string reliable_data;
1548 std::string unreliable_data;
1549 // Go through all objects in message buffer
1550 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1551 j = buffered_messages.getIterator();
1552 j.atEnd()==false; j++)
1554 // If object is not known by client, skip it
1555 u16 id = j.getNode()->getKey();
1556 if(client->m_known_objects.find(id) == NULL)
1558 // Get message list of object
1559 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1560 // Go through every message
1561 for(core::list<ActiveObjectMessage>::Iterator
1562 k = list->begin(); k != list->end(); k++)
1564 // Compose the full new data with header
1565 ActiveObjectMessage aom = *k;
1566 std::string new_data;
1569 writeU16((u8*)&buf[0], aom.id);
1570 new_data.append(buf, 2);
1572 new_data += serializeString(aom.datastring);
1573 // Add data to buffer
1575 reliable_data += new_data;
1577 unreliable_data += new_data;
1581 reliable_data and unreliable_data are now ready.
1584 if(reliable_data.size() > 0)
1586 SharedBuffer<u8> reply(2 + reliable_data.size());
1587 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1588 memcpy((char*)&reply[2], reliable_data.c_str(),
1589 reliable_data.size());
1591 m_con.Send(client->peer_id, 0, reply, true);
1593 if(unreliable_data.size() > 0)
1595 SharedBuffer<u8> reply(2 + unreliable_data.size());
1596 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1597 memcpy((char*)&reply[2], unreliable_data.c_str(),
1598 unreliable_data.size());
1599 // Send as unreliable
1600 m_con.Send(client->peer_id, 0, reply, false);
1603 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1605 infostream<<"Server: Size of object message data: "
1606 <<"reliable: "<<reliable_data.size()
1607 <<", unreliable: "<<unreliable_data.size()
1612 // Clear buffered_messages
1613 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1614 i = buffered_messages.getIterator();
1615 i.atEnd()==false; i++)
1617 delete i.getNode()->getValue();
1621 } // enable_experimental
1624 Send queued-for-sending map edit events.
1627 // Don't send too many at a time
1630 // Single change sending is disabled if queue size is not small
1631 bool disable_single_change_sending = false;
1632 if(m_unsent_map_edit_queue.size() >= 4)
1633 disable_single_change_sending = true;
1635 bool got_any_events = false;
1637 // We'll log the amount of each
1640 while(m_unsent_map_edit_queue.size() != 0)
1642 got_any_events = true;
1644 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1646 // Players far away from the change are stored here.
1647 // Instead of sending the changes, MapBlocks are set not sent
1649 core::list<u16> far_players;
1651 if(event->type == MEET_ADDNODE)
1653 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1654 prof.add("MEET_ADDNODE", 1);
1655 if(disable_single_change_sending)
1656 sendAddNode(event->p, event->n, event->already_known_by_peer,
1659 sendAddNode(event->p, event->n, event->already_known_by_peer,
1662 else if(event->type == MEET_REMOVENODE)
1664 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1665 prof.add("MEET_REMOVENODE", 1);
1666 if(disable_single_change_sending)
1667 sendRemoveNode(event->p, event->already_known_by_peer,
1670 sendRemoveNode(event->p, event->already_known_by_peer,
1673 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1675 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1676 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1677 setBlockNotSent(event->p);
1679 else if(event->type == MEET_OTHER)
1681 infostream<<"Server: MEET_OTHER"<<std::endl;
1682 prof.add("MEET_OTHER", 1);
1683 for(core::map<v3s16, bool>::Iterator
1684 i = event->modified_blocks.getIterator();
1685 i.atEnd()==false; i++)
1687 v3s16 p = i.getNode()->getKey();
1693 prof.add("unknown", 1);
1694 infostream<<"WARNING: Server: Unknown MapEditEvent "
1695 <<((u32)event->type)<<std::endl;
1699 Set blocks not sent to far players
1701 if(far_players.size() > 0)
1703 // Convert list format to that wanted by SetBlocksNotSent
1704 core::map<v3s16, MapBlock*> modified_blocks2;
1705 for(core::map<v3s16, bool>::Iterator
1706 i = event->modified_blocks.getIterator();
1707 i.atEnd()==false; i++)
1709 v3s16 p = i.getNode()->getKey();
1710 modified_blocks2.insert(p,
1711 m_env->getMap().getBlockNoCreateNoEx(p));
1713 // Set blocks not sent
1714 for(core::list<u16>::Iterator
1715 i = far_players.begin();
1716 i != far_players.end(); i++)
1719 RemoteClient *client = getClient(peer_id);
1722 client->SetBlocksNotSent(modified_blocks2);
1728 /*// Don't send too many at a time
1730 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1736 infostream<<"Server: MapEditEvents:"<<std::endl;
1737 prof.print(infostream);
1743 Send object positions
1746 float &counter = m_objectdata_timer;
1748 if(counter >= g_settings->getFloat("objectdata_interval"))
1750 JMutexAutoLock lock1(m_env_mutex);
1751 JMutexAutoLock lock2(m_con_mutex);
1753 //ScopeProfiler sp(g_profiler, "Server: sending player positions");
1755 SendObjectData(counter);
1762 Trigger emergethread (it somehow gets to a non-triggered but
1763 bysy state sometimes)
1766 float &counter = m_emergethread_trigger_timer;
1772 m_emergethread.trigger();
1776 // Save map, players and auth stuff
1778 float &counter = m_savemap_timer;
1780 if(counter >= g_settings->getFloat("server_map_save_interval"))
1784 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1787 if(m_authmanager.isModified())
1788 m_authmanager.save();
1791 if(m_banmanager.isModified())
1792 m_banmanager.save();
1795 JMutexAutoLock lock(m_env_mutex);
1797 /*// Unload unused data (delete from memory)
1798 m_env->getMap().unloadUnusedData(
1799 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1801 /*u32 deleted_count = m_env->getMap().unloadUnusedData(
1802 g_settings->getFloat("server_unload_unused_sectors_timeout"));
1805 // Save only changed parts
1806 m_env->getMap().save(true);
1808 /*if(deleted_count > 0)
1810 infostream<<"Server: Unloaded "<<deleted_count
1811 <<" blocks from memory"<<std::endl;
1815 m_env->serializePlayers(m_mapsavedir);
1817 // Save environment metadata
1818 m_env->saveMeta(m_mapsavedir);
1823 void Server::Receive()
1825 DSTACK(__FUNCTION_NAME);
1826 SharedBuffer<u8> data;
1831 JMutexAutoLock conlock(m_con_mutex);
1832 datasize = m_con.Receive(peer_id, data);
1835 // This has to be called so that the client list gets synced
1836 // with the peer list of the connection
1837 handlePeerChanges();
1839 ProcessData(*data, datasize, peer_id);
1841 catch(con::InvalidIncomingDataException &e)
1843 infostream<<"Server::Receive(): "
1844 "InvalidIncomingDataException: what()="
1845 <<e.what()<<std::endl;
1847 catch(con::PeerNotFoundException &e)
1849 //NOTE: This is not needed anymore
1851 // The peer has been disconnected.
1852 // Find the associated player and remove it.
1854 /*JMutexAutoLock envlock(m_env_mutex);
1856 infostream<<"ServerThread: peer_id="<<peer_id
1857 <<" has apparently closed connection. "
1858 <<"Removing player."<<std::endl;
1860 m_env->removePlayer(peer_id);*/
1864 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1866 DSTACK(__FUNCTION_NAME);
1867 // Environment is locked first.
1868 JMutexAutoLock envlock(m_env_mutex);
1869 JMutexAutoLock conlock(m_con_mutex);
1872 Address address = m_con.GetPeerAddress(peer_id);
1874 // drop player if is ip is banned
1875 if(m_banmanager.isIpBanned(address.serializeString())){
1876 SendAccessDenied(m_con, peer_id,
1877 L"Your ip is banned. Banned name was "
1878 +narrow_to_wide(m_banmanager.getBanName(
1879 address.serializeString())));
1880 m_con.DeletePeer(peer_id);
1884 catch(con::PeerNotFoundException &e)
1886 infostream<<"Server::ProcessData(): Cancelling: peer "
1887 <<peer_id<<" not found"<<std::endl;
1891 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1899 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1901 if(command == TOSERVER_INIT)
1903 // [0] u16 TOSERVER_INIT
1904 // [2] u8 SER_FMT_VER_HIGHEST
1905 // [3] u8[20] player_name
1906 // [23] u8[28] password <--- can be sent without this, from old versions
1908 if(datasize < 2+1+PLAYERNAME_SIZE)
1911 infostream<<"Server: Got TOSERVER_INIT from "
1912 <<peer_id<<std::endl;
1914 // First byte after command is maximum supported
1915 // serialization version
1916 u8 client_max = data[2];
1917 u8 our_max = SER_FMT_VER_HIGHEST;
1918 // Use the highest version supported by both
1919 u8 deployed = core::min_(client_max, our_max);
1920 // If it's lower than the lowest supported, give up.
1921 if(deployed < SER_FMT_VER_LOWEST)
1922 deployed = SER_FMT_VER_INVALID;
1924 //peer->serialization_version = deployed;
1925 getClient(peer_id)->pending_serialization_version = deployed;
1927 if(deployed == SER_FMT_VER_INVALID)
1929 infostream<<"Server: Cannot negotiate "
1930 "serialization version with peer "
1931 <<peer_id<<std::endl;
1932 SendAccessDenied(m_con, peer_id,
1933 L"Your client is too old (map format)");
1938 Read and check network protocol version
1941 u16 net_proto_version = 0;
1942 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1944 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1947 getClient(peer_id)->net_proto_version = net_proto_version;
1949 if(net_proto_version == 0)
1951 SendAccessDenied(m_con, peer_id,
1952 L"Your client is too old. Please upgrade.");
1956 /* Uhh... this should actually be a warning but let's do it like this */
1957 if(g_settings->getBool("strict_protocol_version_checking"))
1959 if(net_proto_version < PROTOCOL_VERSION)
1961 SendAccessDenied(m_con, peer_id,
1962 L"Your client is too old. Please upgrade.");
1972 char playername[PLAYERNAME_SIZE];
1973 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1975 playername[i] = data[3+i];
1977 playername[PLAYERNAME_SIZE-1] = 0;
1979 if(playername[0]=='\0')
1981 infostream<<"Server: Player has empty name"<<std::endl;
1982 SendAccessDenied(m_con, peer_id,
1987 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1989 infostream<<"Server: Player has invalid name"<<std::endl;
1990 SendAccessDenied(m_con, peer_id,
1991 L"Name contains unallowed characters");
1996 char password[PASSWORD_SIZE];
1997 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1999 // old version - assume blank password
2004 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2006 password[i] = data[23+i];
2008 password[PASSWORD_SIZE-1] = 0;
2011 std::string checkpwd;
2012 if(m_authmanager.exists(playername))
2014 checkpwd = m_authmanager.getPassword(playername);
2018 checkpwd = g_settings->get("default_password");
2021 /*infostream<<"Server: Client gave password '"<<password
2022 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2024 if(password != checkpwd && m_authmanager.exists(playername))
2026 infostream<<"Server: peer_id="<<peer_id
2027 <<": supplied invalid password for "
2028 <<playername<<std::endl;
2029 SendAccessDenied(m_con, peer_id, L"Invalid password");
2033 // Add player to auth manager
2034 if(m_authmanager.exists(playername) == false)
2036 infostream<<"Server: adding player "<<playername
2037 <<" to auth manager"<<std::endl;
2038 m_authmanager.add(playername);
2039 m_authmanager.setPassword(playername, checkpwd);
2040 m_authmanager.setPrivs(playername,
2041 stringToPrivs(g_settings->get("default_privs")));
2042 m_authmanager.save();
2045 // Enforce user limit.
2046 // Don't enforce for users that have some admin right
2047 if(m_clients.size() >= g_settings->getU16("max_users") &&
2048 (m_authmanager.getPrivs(playername)
2049 & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 &&
2050 playername != g_settings->get("name"))
2052 SendAccessDenied(m_con, peer_id, L"Too many users.");
2057 Player *player = emergePlayer(playername, password, peer_id);
2059 // If failed, cancel
2062 infostream<<"Server: peer_id="<<peer_id
2063 <<": failed to emerge player"<<std::endl;
2068 Answer with a TOCLIENT_INIT
2071 SharedBuffer<u8> reply(2+1+6+8);
2072 writeU16(&reply[0], TOCLIENT_INIT);
2073 writeU8(&reply[2], deployed);
2074 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2075 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2078 m_con.Send(peer_id, 0, reply, true);
2082 Send complete position information
2084 SendMovePlayer(player);
2089 if(command == TOSERVER_INIT2)
2091 infostream<<"Server: Got TOSERVER_INIT2 from "
2092 <<peer_id<<std::endl;
2095 getClient(peer_id)->serialization_version
2096 = getClient(peer_id)->pending_serialization_version;
2099 Send some initialization data
2102 // Send player info to all players
2105 // Send inventory to player
2106 UpdateCrafting(peer_id);
2107 SendInventory(peer_id);
2109 // Send player items to all players
2112 Player *player = m_env->getPlayer(peer_id);
2115 SendPlayerHP(player);
2119 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2120 m_env->getTimeOfDay());
2121 m_con.Send(peer_id, 0, data, true);
2124 // Send information about server to player in chat
2125 SendChatMessage(peer_id, getStatusString());
2127 // Send information about joining in chat
2129 std::wstring name = L"unknown";
2130 Player *player = m_env->getPlayer(peer_id);
2132 name = narrow_to_wide(player->getName());
2134 std::wstring message;
2137 message += L" joined game";
2138 BroadcastChatMessage(message);
2141 // Warnings about protocol version can be issued here
2142 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2144 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2148 Check HP, respawn if necessary
2150 HandlePlayerHP(player, 0);
2156 std::ostringstream os(std::ios_base::binary);
2157 for(core::map<u16, RemoteClient*>::Iterator
2158 i = m_clients.getIterator();
2159 i.atEnd() == false; i++)
2161 RemoteClient *client = i.getNode()->getValue();
2162 assert(client->peer_id == i.getNode()->getKey());
2163 if(client->serialization_version == SER_FMT_VER_INVALID)
2166 Player *player = m_env->getPlayer(client->peer_id);
2169 // Get name of player
2170 os<<player->getName()<<" ";
2173 actionstream<<player->getName()<<" joins game. List of players: "
2174 <<os.str()<<std::endl;
2180 if(peer_ser_ver == SER_FMT_VER_INVALID)
2182 infostream<<"Server::ProcessData(): Cancelling: Peer"
2183 " serialization format invalid or not initialized."
2184 " Skipping incoming command="<<command<<std::endl;
2188 Player *player = m_env->getPlayer(peer_id);
2191 infostream<<"Server::ProcessData(): Cancelling: "
2192 "No player for peer_id="<<peer_id
2196 if(command == TOSERVER_PLAYERPOS)
2198 if(datasize < 2+12+12+4+4)
2202 v3s32 ps = readV3S32(&data[start+2]);
2203 v3s32 ss = readV3S32(&data[start+2+12]);
2204 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2205 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2206 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2207 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2208 pitch = wrapDegrees(pitch);
2209 yaw = wrapDegrees(yaw);
2211 player->setPosition(position);
2212 player->setSpeed(speed);
2213 player->setPitch(pitch);
2214 player->setYaw(yaw);
2216 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2217 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2218 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2220 else if(command == TOSERVER_GOTBLOCKS)
2233 u16 count = data[2];
2234 for(u16 i=0; i<count; i++)
2236 if((s16)datasize < 2+1+(i+1)*6)
2237 throw con::InvalidIncomingDataException
2238 ("GOTBLOCKS length is too short");
2239 v3s16 p = readV3S16(&data[2+1+i*6]);
2240 /*infostream<<"Server: GOTBLOCKS ("
2241 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2242 RemoteClient *client = getClient(peer_id);
2243 client->GotBlock(p);
2246 else if(command == TOSERVER_DELETEDBLOCKS)
2259 u16 count = data[2];
2260 for(u16 i=0; i<count; i++)
2262 if((s16)datasize < 2+1+(i+1)*6)
2263 throw con::InvalidIncomingDataException
2264 ("DELETEDBLOCKS length is too short");
2265 v3s16 p = readV3S16(&data[2+1+i*6]);
2266 /*infostream<<"Server: DELETEDBLOCKS ("
2267 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2268 RemoteClient *client = getClient(peer_id);
2269 client->SetBlockNotSent(p);
2272 else if(command == TOSERVER_CLICK_OBJECT)
2274 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2277 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2282 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2288 [2] u8 button (0=left, 1=right)
2292 u8 button = readU8(&data[2]);
2293 u16 id = readS16(&data[3]);
2294 u16 item_i = readU16(&data[5]);
2296 ServerActiveObject *obj = m_env->getActiveObject(id);
2300 infostream<<"Server: CLICK_ACTIVEOBJECT: object not found"
2305 // Skip if object has been removed
2309 //TODO: Check that object is reasonably close
2311 // Get ServerRemotePlayer
2312 ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
2314 // Update wielded item
2315 srp->wieldItem(item_i);
2317 // Left click, pick/punch
2320 actionstream<<player->getName()<<" punches object "
2321 <<obj->getId()<<std::endl;
2328 Try creating inventory item
2330 InventoryItem *item = obj->createPickedUpItem();
2334 InventoryList *ilist = player->inventory.getList("main");
2337 actionstream<<player->getName()<<" picked up "
2338 <<item->getName()<<std::endl;
2339 if(g_settings->getBool("creative_mode") == false)
2341 // Skip if inventory has no free space
2342 if(ilist->roomForItem(item) == false)
2344 infostream<<"Player inventory has no free space"<<std::endl;
2348 // Add to inventory and send inventory
2349 ilist->addItem(item);
2350 UpdateCrafting(player->peer_id);
2351 SendInventory(player->peer_id);
2354 // Remove object from environment
2355 obj->m_removed = true;
2361 Item cannot be picked up. Punch it instead.
2364 actionstream<<player->getName()<<" punches object "
2365 <<obj->getId()<<std::endl;
2367 ToolItem *titem = NULL;
2368 std::string toolname = "";
2370 InventoryList *mlist = player->inventory.getList("main");
2373 InventoryItem *item = mlist->getItem(item_i);
2374 if(item && (std::string)item->getName() == "ToolItem")
2376 titem = (ToolItem*)item;
2377 toolname = titem->getToolName();
2381 v3f playerpos = player->getPosition();
2382 v3f objpos = obj->getBasePosition();
2383 v3f dir = (objpos - playerpos).normalize();
2385 u16 wear = obj->punch(toolname, dir, player->getName());
2389 bool weared_out = titem->addWear(wear);
2391 mlist->deleteItem(item_i);
2392 SendInventory(player->peer_id);
2397 // Right click, do something with object
2400 actionstream<<player->getName()<<" right clicks object "
2401 <<obj->getId()<<std::endl;
2404 obj->rightClick(srp);
2408 Update player state to client
2410 SendPlayerHP(player);
2411 UpdateCrafting(player->peer_id);
2412 SendInventory(player->peer_id);
2414 else if(command == TOSERVER_GROUND_ACTION)
2422 [3] v3s16 nodepos_undersurface
2423 [9] v3s16 nodepos_abovesurface
2428 2: stop digging (all parameters ignored)
2429 3: digging completed
2431 u8 action = readU8(&data[2]);
2433 p_under.X = readS16(&data[3]);
2434 p_under.Y = readS16(&data[5]);
2435 p_under.Z = readS16(&data[7]);
2437 p_over.X = readS16(&data[9]);
2438 p_over.Y = readS16(&data[11]);
2439 p_over.Z = readS16(&data[13]);
2440 u16 item_i = readU16(&data[15]);
2442 //TODO: Check that target is reasonably close
2450 NOTE: This can be used in the future to check if
2451 somebody is cheating, by checking the timing.
2458 else if(action == 2)
2461 RemoteClient *client = getClient(peer_id);
2462 JMutexAutoLock digmutex(client->m_dig_mutex);
2463 client->m_dig_tool_item = -1;
2468 3: Digging completed
2470 else if(action == 3)
2472 // Mandatory parameter; actually used for nothing
2473 core::map<v3s16, MapBlock*> modified_blocks;
2475 content_t material = CONTENT_IGNORE;
2476 u8 mineral = MINERAL_NONE;
2478 bool cannot_remove_node = false;
2482 MapNode n = m_env->getMap().getNode(p_under);
2484 mineral = n.getMineral();
2485 // Get material at position
2486 material = n.getContent();
2487 // If not yet cancelled
2488 if(cannot_remove_node == false)
2490 // If it's not diggable, do nothing
2491 if(content_diggable(material) == false)
2493 infostream<<"Server: Not finishing digging: "
2494 <<"Node not diggable"
2496 cannot_remove_node = true;
2499 // If not yet cancelled
2500 if(cannot_remove_node == false)
2502 // Get node metadata
2503 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
2504 if(meta && meta->nodeRemovalDisabled() == true)
2506 infostream<<"Server: Not finishing digging: "
2507 <<"Node metadata disables removal"
2509 cannot_remove_node = true;
2513 catch(InvalidPositionException &e)
2515 infostream<<"Server: Not finishing digging: Node not found."
2516 <<" Adding block to emerge queue."
2518 m_emerge_queue.addBlock(peer_id,
2519 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2520 cannot_remove_node = true;
2523 // Make sure the player is allowed to do it
2524 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2526 infostream<<"Player "<<player->getName()<<" cannot remove node"
2527 <<" because privileges are "<<getPlayerPrivs(player)
2529 cannot_remove_node = true;
2533 If node can't be removed, set block to be re-sent to
2536 if(cannot_remove_node)
2538 infostream<<"Server: Not finishing digging."<<std::endl;
2540 // Client probably has wrong data.
2541 // Set block not sent, so that client will get
2543 infostream<<"Client "<<peer_id<<" tried to dig "
2544 <<"node; but node cannot be removed."
2545 <<" setting MapBlock not sent."<<std::endl;
2546 RemoteClient *client = getClient(peer_id);
2547 v3s16 blockpos = getNodeBlockPos(p_under);
2548 client->SetBlockNotSent(blockpos);
2553 actionstream<<player->getName()<<" digs "<<PP(p_under)
2554 <<", gets material "<<(int)material<<", mineral "
2555 <<(int)mineral<<std::endl;
2558 Send the removal to all close-by players.
2559 - If other player is close, send REMOVENODE
2560 - Otherwise set blocks not sent
2562 core::list<u16> far_players;
2563 sendRemoveNode(p_under, peer_id, &far_players, 30);
2566 Update and send inventory
2569 if(g_settings->getBool("creative_mode") == false)
2574 InventoryList *mlist = player->inventory.getList("main");
2577 InventoryItem *item = mlist->getItem(item_i);
2578 if(item && (std::string)item->getName() == "ToolItem")
2580 ToolItem *titem = (ToolItem*)item;
2581 std::string toolname = titem->getToolName();
2583 // Get digging properties for material and tool
2584 ToolDiggingProperties tp =
2585 m_toolmgr->getDiggingProperties(toolname);
2586 DiggingProperties prop =
2587 getDiggingProperties(material, &tp);
2589 if(prop.diggable == false)
2591 infostream<<"Server: WARNING: Player digged"
2592 <<" with impossible material + tool"
2593 <<" combination"<<std::endl;
2596 bool weared_out = titem->addWear(prop.wear);
2600 mlist->deleteItem(item_i);
2606 Add dug item to inventory
2609 InventoryItem *item = NULL;
2611 if(mineral != MINERAL_NONE)
2612 item = getDiggedMineralItem(mineral, this);
2617 std::string &dug_s = content_features(material).dug_item;
2620 std::istringstream is(dug_s, std::ios::binary);
2621 item = InventoryItem::deSerialize(is, this);
2627 // Add a item to inventory
2628 player->inventory.addItem("main", item);
2631 UpdateCrafting(player->peer_id);
2632 SendInventory(player->peer_id);
2637 if(mineral != MINERAL_NONE)
2638 item = getDiggedMineralItem(mineral, this);
2643 std::string &extra_dug_s = content_features(material).extra_dug_item;
2644 s32 extra_rarity = content_features(material).extra_dug_item_rarity;
2645 if(extra_dug_s != "" && extra_rarity != 0
2646 && myrand() % extra_rarity == 0)
2648 std::istringstream is(extra_dug_s, std::ios::binary);
2649 item = InventoryItem::deSerialize(is, this);
2655 // Add a item to inventory
2656 player->inventory.addItem("main", item);
2659 UpdateCrafting(player->peer_id);
2660 SendInventory(player->peer_id);
2666 (this takes some time so it is done after the quick stuff)
2669 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2671 m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
2674 Set blocks not sent to far players
2676 for(core::list<u16>::Iterator
2677 i = far_players.begin();
2678 i != far_players.end(); i++)
2681 RemoteClient *client = getClient(peer_id);
2684 client->SetBlocksNotSent(modified_blocks);
2691 else if(action == 1)
2694 InventoryList *ilist = player->inventory.getList("main");
2699 InventoryItem *item = ilist->getItem(item_i);
2701 // If there is no item, it is not possible to add it anywhere
2706 Handle material items
2708 if(std::string("MaterialItem") == item->getName())
2711 // Don't add a node if this is not a free space
2712 MapNode n2 = m_env->getMap().getNode(p_over);
2713 bool no_enough_privs =
2714 ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2716 infostream<<"Player "<<player->getName()<<" cannot add node"
2717 <<" because privileges are "<<getPlayerPrivs(player)
2720 if(content_features(n2).buildable_to == false
2723 // Client probably has wrong data.
2724 // Set block not sent, so that client will get
2726 infostream<<"Client "<<peer_id<<" tried to place"
2727 <<" node in invalid position; setting"
2728 <<" MapBlock not sent."<<std::endl;
2729 RemoteClient *client = getClient(peer_id);
2730 v3s16 blockpos = getNodeBlockPos(p_over);
2731 client->SetBlockNotSent(blockpos);
2735 catch(InvalidPositionException &e)
2737 infostream<<"Server: Ignoring ADDNODE: Node not found"
2738 <<" Adding block to emerge queue."
2740 m_emerge_queue.addBlock(peer_id,
2741 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2745 // Reset build time counter
2746 getClient(peer_id)->m_time_from_building = 0.0;
2749 MaterialItem *mitem = (MaterialItem*)item;
2751 n.setContent(mitem->getMaterial());
2753 actionstream<<player->getName()<<" places material "
2754 <<(int)mitem->getMaterial()
2755 <<" at "<<PP(p_under)<<std::endl;
2757 // Calculate direction for wall mounted stuff
2758 if(content_features(n).wall_mounted)
2759 n.param2 = packDir(p_under - p_over);
2761 // Calculate the direction for furnaces and chests and stuff
2762 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2764 v3f playerpos = player->getPosition();
2765 v3f blockpos = intToFloat(p_over, BS) - playerpos;
2766 blockpos = blockpos.normalize();
2768 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2782 Send to all close-by players
2784 core::list<u16> far_players;
2785 sendAddNode(p_over, n, 0, &far_players, 30);
2790 InventoryList *ilist = player->inventory.getList("main");
2791 if(g_settings->getBool("creative_mode") == false && ilist)
2793 // Remove from inventory and send inventory
2794 if(mitem->getCount() == 1)
2795 ilist->deleteItem(item_i);
2799 UpdateCrafting(peer_id);
2800 SendInventory(peer_id);
2806 This takes some time so it is done after the quick stuff
2808 core::map<v3s16, MapBlock*> modified_blocks;
2810 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2812 std::string p_name = std::string(player->getName());
2813 m_env->getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
2816 Set blocks not sent to far players
2818 for(core::list<u16>::Iterator
2819 i = far_players.begin();
2820 i != far_players.end(); i++)
2823 RemoteClient *client = getClient(peer_id);
2826 client->SetBlocksNotSent(modified_blocks);
2830 Calculate special events
2833 /*if(n.d == CONTENT_MESE)
2836 for(s16 z=-1; z<=1; z++)
2837 for(s16 y=-1; y<=1; y++)
2838 for(s16 x=-1; x<=1; x++)
2845 Place other item (not a block)
2849 v3s16 blockpos = getNodeBlockPos(p_over);
2852 Check that the block is loaded so that the item
2853 can properly be added to the static list too
2855 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2858 infostream<<"Error while placing object: "
2859 "block not found"<<std::endl;
2864 If in creative mode, item dropping is disabled unless
2865 player has build privileges
2867 if(g_settings->getBool("creative_mode") &&
2868 (getPlayerPrivs(player) & PRIV_BUILD) == 0)
2870 infostream<<"Not allowing player to drop item: "
2871 "creative mode and no build privs"<<std::endl;
2875 // Calculate a position for it
2876 v3f pos = intToFloat(p_over, BS);
2878 /*pos.Y -= BS*0.25; // let it drop a bit
2880 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2881 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;*/
2886 ServerActiveObject *obj = item->createSAO(m_env, 0, pos);
2890 infostream<<"WARNING: item resulted in NULL object, "
2891 <<"not placing onto map"
2896 actionstream<<player->getName()<<" places "<<item->getName()
2897 <<" at "<<PP(p_over)<<std::endl;
2899 // Add the object to the environment
2900 m_env->addActiveObject(obj);
2902 infostream<<"Placed object"<<std::endl;
2904 if(g_settings->getBool("creative_mode") == false)
2906 // Delete the right amount of items from the slot
2907 u16 dropcount = item->getDropCount();
2909 // Delete item if all gone
2910 if(item->getCount() <= dropcount)
2912 if(item->getCount() < dropcount)
2913 infostream<<"WARNING: Server: dropped more items"
2914 <<" than the slot contains"<<std::endl;
2916 InventoryList *ilist = player->inventory.getList("main");
2918 // Remove from inventory and send inventory
2919 ilist->deleteItem(item_i);
2921 // Else decrement it
2923 item->remove(dropcount);
2926 UpdateCrafting(peer_id);
2927 SendInventory(peer_id);
2935 Catch invalid actions
2939 infostream<<"WARNING: Server: Invalid action "
2940 <<action<<std::endl;
2944 else if(command == TOSERVER_RELEASE)
2953 infostream<<"TOSERVER_RELEASE ignored"<<std::endl;
2956 else if(command == TOSERVER_SIGNTEXT)
2958 infostream<<"Server: TOSERVER_SIGNTEXT not supported anymore"
2962 else if(command == TOSERVER_SIGNNODETEXT)
2964 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2972 std::string datastring((char*)&data[2], datasize-2);
2973 std::istringstream is(datastring, std::ios_base::binary);
2976 is.read((char*)buf, 6);
2977 v3s16 p = readV3S16(buf);
2978 is.read((char*)buf, 2);
2979 u16 textlen = readU16(buf);
2981 for(u16 i=0; i<textlen; i++)
2983 is.read((char*)buf, 1);
2984 text += (char)buf[0];
2987 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2990 if(meta->typeId() != CONTENT_SIGN_WALL)
2992 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2993 signmeta->setText(text);
2995 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign "
2996 <<" at "<<PP(p)<<std::endl;
2998 v3s16 blockpos = getNodeBlockPos(p);
2999 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3002 block->setChangedFlag();
3005 for(core::map<u16, RemoteClient*>::Iterator
3006 i = m_clients.getIterator();
3007 i.atEnd()==false; i++)
3009 RemoteClient *client = i.getNode()->getValue();
3010 client->SetBlockNotSent(blockpos);
3013 else if(command == TOSERVER_INVENTORY_ACTION)
3015 /*// Ignore inventory changes if in creative mode
3016 if(g_settings->getBool("creative_mode") == true)
3018 infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3022 // Strip command and create a stream
3023 std::string datastring((char*)&data[2], datasize-2);
3024 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3025 std::istringstream is(datastring, std::ios_base::binary);
3027 InventoryAction *a = InventoryAction::deSerialize(is);
3032 c.current_player = player;
3035 Handle craftresult specially if not in creative mode
3037 bool disable_action = false;
3038 if(a->getType() == IACTION_MOVE
3039 && g_settings->getBool("creative_mode") == false)
3041 IMoveAction *ma = (IMoveAction*)a;
3042 if(ma->to_inv == "current_player" &&
3043 ma->from_inv == "current_player")
3045 InventoryList *rlist = player->inventory.getList("craftresult");
3047 InventoryList *clist = player->inventory.getList("craft");
3049 InventoryList *mlist = player->inventory.getList("main");
3052 Craftresult is no longer preview if something
3055 if(ma->to_list == "craftresult"
3056 && ma->from_list != "craftresult")
3058 // If it currently is a preview, remove
3060 if(player->craftresult_is_preview)
3062 rlist->deleteItem(0);
3064 player->craftresult_is_preview = false;
3067 Crafting takes place if this condition is true.
3069 if(player->craftresult_is_preview &&
3070 ma->from_list == "craftresult")
3072 player->craftresult_is_preview = false;
3073 clist->decrementMaterials(1);
3075 /* Print out action */
3076 InventoryList *list =
3077 player->inventory.getList("craftresult");
3079 InventoryItem *item = list->getItem(0);
3080 std::string itemname = "NULL";
3082 itemname = item->getName();
3083 actionstream<<player->getName()<<" crafts "
3084 <<itemname<<std::endl;
3087 If the craftresult is placed on itself, move it to
3088 main inventory instead of doing the action
3090 if(ma->to_list == "craftresult"
3091 && ma->from_list == "craftresult")
3093 disable_action = true;
3095 InventoryItem *item1 = rlist->changeItem(0, NULL);
3096 mlist->addItem(item1);
3099 // Disallow moving items if not allowed to build
3100 else if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3104 // if it's a locking chest, only allow the owner or server admins to move items
3105 else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3107 Strfnd fn(ma->from_inv);
3108 std::string id0 = fn.next(":");
3109 if(id0 == "nodemeta")
3112 p.X = stoi(fn.next(","));
3113 p.Y = stoi(fn.next(","));
3114 p.Z = stoi(fn.next(","));
3115 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3116 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3117 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3118 if (lcm->getOwner() != player->getName())
3123 else if (ma->to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3125 Strfnd fn(ma->to_inv);
3126 std::string id0 = fn.next(":");
3127 if(id0 == "nodemeta")
3130 p.X = stoi(fn.next(","));
3131 p.Y = stoi(fn.next(","));
3132 p.Z = stoi(fn.next(","));
3133 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3134 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3135 LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3136 if (lcm->getOwner() != player->getName())
3143 if(disable_action == false)
3145 // Feed action to player inventory
3153 UpdateCrafting(player->peer_id);
3154 SendInventory(player->peer_id);
3159 infostream<<"TOSERVER_INVENTORY_ACTION: "
3160 <<"InventoryAction::deSerialize() returned NULL"
3164 else if(command == TOSERVER_CHAT_MESSAGE)
3172 std::string datastring((char*)&data[2], datasize-2);
3173 std::istringstream is(datastring, std::ios_base::binary);
3176 is.read((char*)buf, 2);
3177 u16 len = readU16(buf);
3179 std::wstring message;
3180 for(u16 i=0; i<len; i++)
3182 is.read((char*)buf, 2);
3183 message += (wchar_t)readU16(buf);
3186 // Get player name of this client
3187 std::wstring name = narrow_to_wide(player->getName());
3189 // Line to send to players
3191 // Whether to send to the player that sent the line
3192 bool send_to_sender = false;
3193 // Whether to send to other players
3194 bool send_to_others = false;
3196 // Local player gets all privileges regardless of
3197 // what's set on their account.
3198 u64 privs = getPlayerPrivs(player);
3201 if(message[0] == L'/')
3203 size_t strip_size = 1;
3204 if (message[1] == L'#') // support old-style commans
3206 message = message.substr(strip_size);
3208 WStrfnd f1(message);
3209 f1.next(L" "); // Skip over /#whatever
3210 std::wstring paramstring = f1.next(L"");
3212 ServerCommandContext *ctx = new ServerCommandContext(
3213 str_split(message, L' '),
3220 std::wstring reply(processServerCommand(ctx));
3221 send_to_sender = ctx->flags & SEND_TO_SENDER;
3222 send_to_others = ctx->flags & SEND_TO_OTHERS;
3224 if (ctx->flags & SEND_NO_PREFIX)
3227 line += L"Server: " + reply;
3234 if(privs & PRIV_SHOUT)
3240 send_to_others = true;
3244 line += L"Server: You are not allowed to shout";
3245 send_to_sender = true;
3252 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3255 Send the message to clients
3257 for(core::map<u16, RemoteClient*>::Iterator
3258 i = m_clients.getIterator();
3259 i.atEnd() == false; i++)
3261 // Get client and check that it is valid
3262 RemoteClient *client = i.getNode()->getValue();
3263 assert(client->peer_id == i.getNode()->getKey());
3264 if(client->serialization_version == SER_FMT_VER_INVALID)
3268 bool sender_selected = (peer_id == client->peer_id);
3269 if(sender_selected == true && send_to_sender == false)
3271 if(sender_selected == false && send_to_others == false)
3274 SendChatMessage(client->peer_id, line);
3278 else if(command == TOSERVER_DAMAGE)
3280 std::string datastring((char*)&data[2], datasize-2);
3281 std::istringstream is(datastring, std::ios_base::binary);
3282 u8 damage = readU8(is);
3284 if(g_settings->getBool("enable_damage"))
3286 actionstream<<player->getName()<<" damaged by "
3287 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
3290 HandlePlayerHP(player, damage);
3294 SendPlayerHP(player);
3297 else if(command == TOSERVER_PASSWORD)
3300 [0] u16 TOSERVER_PASSWORD
3301 [2] u8[28] old password
3302 [30] u8[28] new password
3305 if(datasize != 2+PASSWORD_SIZE*2)
3307 /*char password[PASSWORD_SIZE];
3308 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3309 password[i] = data[2+i];
3310 password[PASSWORD_SIZE-1] = 0;*/
3312 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3320 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3322 char c = data[2+PASSWORD_SIZE+i];
3328 infostream<<"Server: Client requests a password change from "
3329 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3331 std::string playername = player->getName();
3333 if(m_authmanager.exists(playername) == false)
3335 infostream<<"Server: playername not found in authmanager"<<std::endl;
3336 // Wrong old password supplied!!
3337 SendChatMessage(peer_id, L"playername not found in authmanager");
3341 std::string checkpwd = m_authmanager.getPassword(playername);
3343 if(oldpwd != checkpwd)
3345 infostream<<"Server: invalid old password"<<std::endl;
3346 // Wrong old password supplied!!
3347 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3351 actionstream<<player->getName()<<" changes password"<<std::endl;
3353 m_authmanager.setPassword(playername, newpwd);
3355 infostream<<"Server: password change successful for "<<playername
3357 SendChatMessage(peer_id, L"Password change successful");
3359 else if(command == TOSERVER_PLAYERITEM)
3364 u16 item = readU16(&data[2]);
3365 player->wieldItem(item);
3366 SendWieldedItem(player);
3368 else if(command == TOSERVER_RESPAWN)
3373 RespawnPlayer(player);
3375 actionstream<<player->getName()<<" respawns at "
3376 <<PP(player->getPosition()/BS)<<std::endl;
3380 infostream<<"Server::ProcessData(): Ignoring "
3381 "unknown command "<<command<<std::endl;
3385 catch(SendFailedException &e)
3387 errorstream<<"Server::ProcessData(): SendFailedException: "
3393 void Server::onMapEditEvent(MapEditEvent *event)
3395 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3396 if(m_ignore_map_edit_events)
3398 MapEditEvent *e = event->clone();
3399 m_unsent_map_edit_queue.push_back(e);
3402 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3404 if(id == "current_player")
3406 assert(c->current_player);
3407 return &(c->current_player->inventory);
3411 std::string id0 = fn.next(":");
3413 if(id0 == "nodemeta")
3416 p.X = stoi(fn.next(","));
3417 p.Y = stoi(fn.next(","));
3418 p.Z = stoi(fn.next(","));
3419 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3421 return meta->getInventory();
3422 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3423 <<"no metadata found"<<std::endl;
3427 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3430 void Server::inventoryModified(InventoryContext *c, std::string id)
3432 if(id == "current_player")
3434 assert(c->current_player);
3436 UpdateCrafting(c->current_player->peer_id);
3437 SendInventory(c->current_player->peer_id);
3442 std::string id0 = fn.next(":");
3444 if(id0 == "nodemeta")
3447 p.X = stoi(fn.next(","));
3448 p.Y = stoi(fn.next(","));
3449 p.Z = stoi(fn.next(","));
3450 v3s16 blockpos = getNodeBlockPos(p);
3452 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3454 meta->inventoryModified();
3456 for(core::map<u16, RemoteClient*>::Iterator
3457 i = m_clients.getIterator();
3458 i.atEnd()==false; i++)
3460 RemoteClient *client = i.getNode()->getValue();
3461 client->SetBlockNotSent(blockpos);
3467 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3470 core::list<PlayerInfo> Server::getPlayerInfo()
3472 DSTACK(__FUNCTION_NAME);
3473 JMutexAutoLock envlock(m_env_mutex);
3474 JMutexAutoLock conlock(m_con_mutex);
3476 core::list<PlayerInfo> list;
3478 core::list<Player*> players = m_env->getPlayers();
3480 core::list<Player*>::Iterator i;
3481 for(i = players.begin();
3482 i != players.end(); i++)
3486 Player *player = *i;
3489 // Copy info from connection to info struct
3490 info.id = player->peer_id;
3491 info.address = m_con.GetPeerAddress(player->peer_id);
3492 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3494 catch(con::PeerNotFoundException &e)
3496 // Set dummy peer info
3498 info.address = Address(0,0,0,0,0);
3502 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3503 info.position = player->getPosition();
3505 list.push_back(info);
3512 void Server::peerAdded(con::Peer *peer)
3514 DSTACK(__FUNCTION_NAME);
3515 infostream<<"Server::peerAdded(): peer->id="
3516 <<peer->id<<std::endl;
3519 c.type = PEER_ADDED;
3520 c.peer_id = peer->id;
3522 m_peer_change_queue.push_back(c);
3525 void Server::deletingPeer(con::Peer *peer, bool timeout)
3527 DSTACK(__FUNCTION_NAME);
3528 infostream<<"Server::deletingPeer(): peer->id="
3529 <<peer->id<<", timeout="<<timeout<<std::endl;
3532 c.type = PEER_REMOVED;
3533 c.peer_id = peer->id;
3534 c.timeout = timeout;
3535 m_peer_change_queue.push_back(c);
3542 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3544 DSTACK(__FUNCTION_NAME);
3545 std::ostringstream os(std::ios_base::binary);
3547 writeU16(os, TOCLIENT_HP);
3551 std::string s = os.str();
3552 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3554 con.Send(peer_id, 0, data, true);
3557 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3558 const std::wstring &reason)
3560 DSTACK(__FUNCTION_NAME);
3561 std::ostringstream os(std::ios_base::binary);
3563 writeU16(os, TOCLIENT_ACCESS_DENIED);
3564 os<<serializeWideString(reason);
3567 std::string s = os.str();
3568 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3570 con.Send(peer_id, 0, data, true);
3573 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3574 bool set_camera_point_target, v3f camera_point_target)
3576 DSTACK(__FUNCTION_NAME);
3577 std::ostringstream os(std::ios_base::binary);
3579 writeU16(os, TOCLIENT_DEATHSCREEN);
3580 writeU8(os, set_camera_point_target);
3581 writeV3F1000(os, camera_point_target);
3584 std::string s = os.str();
3585 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3587 con.Send(peer_id, 0, data, true);
3591 Non-static send methods
3594 void Server::SendObjectData(float dtime)
3596 DSTACK(__FUNCTION_NAME);
3598 core::map<v3s16, bool> stepped_blocks;
3600 for(core::map<u16, RemoteClient*>::Iterator
3601 i = m_clients.getIterator();
3602 i.atEnd() == false; i++)
3604 u16 peer_id = i.getNode()->getKey();
3605 RemoteClient *client = i.getNode()->getValue();
3606 assert(client->peer_id == peer_id);
3608 if(client->serialization_version == SER_FMT_VER_INVALID)
3611 client->SendObjectData(this, dtime, stepped_blocks);
3615 void Server::SendPlayerInfos()
3617 DSTACK(__FUNCTION_NAME);
3619 //JMutexAutoLock envlock(m_env_mutex);
3621 // Get connected players
3622 core::list<Player*> players = m_env->getPlayers(true);
3624 u32 player_count = players.getSize();
3625 u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3627 SharedBuffer<u8> data(datasize);
3628 writeU16(&data[0], TOCLIENT_PLAYERINFO);
3631 core::list<Player*>::Iterator i;
3632 for(i = players.begin();
3633 i != players.end(); i++)
3635 Player *player = *i;
3637 /*infostream<<"Server sending player info for player with "
3638 "peer_id="<<player->peer_id<<std::endl;*/
3640 writeU16(&data[start], player->peer_id);
3641 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3642 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3643 start += 2+PLAYERNAME_SIZE;
3646 //JMutexAutoLock conlock(m_con_mutex);
3649 m_con.SendToAll(0, data, true);
3652 void Server::SendInventory(u16 peer_id)
3654 DSTACK(__FUNCTION_NAME);
3656 Player* player = m_env->getPlayer(peer_id);
3663 std::ostringstream os;
3664 //os.imbue(std::locale("C"));
3666 player->inventory.serialize(os);
3668 std::string s = os.str();
3670 SharedBuffer<u8> data(s.size()+2);
3671 writeU16(&data[0], TOCLIENT_INVENTORY);
3672 memcpy(&data[2], s.c_str(), s.size());
3675 m_con.Send(peer_id, 0, data, true);
3678 std::string getWieldedItemString(const Player *player)
3680 const InventoryItem *item = player->getWieldItem();
3682 return std::string("");
3683 std::ostringstream os(std::ios_base::binary);
3684 item->serialize(os);
3688 void Server::SendWieldedItem(const Player* player)
3690 DSTACK(__FUNCTION_NAME);
3694 std::ostringstream os(std::ios_base::binary);
3696 writeU16(os, TOCLIENT_PLAYERITEM);
3698 writeU16(os, player->peer_id);
3699 os<<serializeString(getWieldedItemString(player));
3702 std::string s = os.str();
3703 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3705 m_con.SendToAll(0, data, true);
3708 void Server::SendPlayerItems()
3710 DSTACK(__FUNCTION_NAME);
3712 std::ostringstream os(std::ios_base::binary);
3713 core::list<Player *> players = m_env->getPlayers(true);
3715 writeU16(os, TOCLIENT_PLAYERITEM);
3716 writeU16(os, players.size());
3717 core::list<Player *>::Iterator i;
3718 for(i = players.begin(); i != players.end(); ++i)
3721 writeU16(os, p->peer_id);
3722 os<<serializeString(getWieldedItemString(p));
3726 std::string s = os.str();
3727 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3729 m_con.SendToAll(0, data, true);
3732 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3734 DSTACK(__FUNCTION_NAME);
3736 std::ostringstream os(std::ios_base::binary);
3740 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3741 os.write((char*)buf, 2);
3744 writeU16(buf, message.size());
3745 os.write((char*)buf, 2);
3748 for(u32 i=0; i<message.size(); i++)
3752 os.write((char*)buf, 2);
3756 std::string s = os.str();
3757 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3759 m_con.Send(peer_id, 0, data, true);
3762 void Server::BroadcastChatMessage(const std::wstring &message)
3764 for(core::map<u16, RemoteClient*>::Iterator
3765 i = m_clients.getIterator();
3766 i.atEnd() == false; i++)
3768 // Get client and check that it is valid
3769 RemoteClient *client = i.getNode()->getValue();
3770 assert(client->peer_id == i.getNode()->getKey());
3771 if(client->serialization_version == SER_FMT_VER_INVALID)
3774 SendChatMessage(client->peer_id, message);
3778 void Server::SendPlayerHP(Player *player)
3780 SendHP(m_con, player->peer_id, player->hp);
3783 void Server::SendMovePlayer(Player *player)
3785 DSTACK(__FUNCTION_NAME);
3786 std::ostringstream os(std::ios_base::binary);
3788 writeU16(os, TOCLIENT_MOVE_PLAYER);
3789 writeV3F1000(os, player->getPosition());
3790 writeF1000(os, player->getPitch());
3791 writeF1000(os, player->getYaw());
3794 v3f pos = player->getPosition();
3795 f32 pitch = player->getPitch();
3796 f32 yaw = player->getYaw();
3797 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
3798 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3805 std::string s = os.str();
3806 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3808 m_con.Send(player->peer_id, 0, data, true);
3811 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3812 core::list<u16> *far_players, float far_d_nodes)
3814 float maxd = far_d_nodes*BS;
3815 v3f p_f = intToFloat(p, BS);
3819 SharedBuffer<u8> reply(replysize);
3820 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3821 writeS16(&reply[2], p.X);
3822 writeS16(&reply[4], p.Y);
3823 writeS16(&reply[6], p.Z);
3825 for(core::map<u16, RemoteClient*>::Iterator
3826 i = m_clients.getIterator();
3827 i.atEnd() == false; i++)
3829 // Get client and check that it is valid
3830 RemoteClient *client = i.getNode()->getValue();
3831 assert(client->peer_id == i.getNode()->getKey());
3832 if(client->serialization_version == SER_FMT_VER_INVALID)
3835 // Don't send if it's the same one
3836 if(client->peer_id == ignore_id)
3842 Player *player = m_env->getPlayer(client->peer_id);
3845 // If player is far away, only set modified blocks not sent
3846 v3f player_pos = player->getPosition();
3847 if(player_pos.getDistanceFrom(p_f) > maxd)
3849 far_players->push_back(client->peer_id);
3856 m_con.Send(client->peer_id, 0, reply, true);
3860 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3861 core::list<u16> *far_players, float far_d_nodes)
3863 float maxd = far_d_nodes*BS;
3864 v3f p_f = intToFloat(p, BS);
3866 for(core::map<u16, RemoteClient*>::Iterator
3867 i = m_clients.getIterator();
3868 i.atEnd() == false; i++)
3870 // Get client and check that it is valid
3871 RemoteClient *client = i.getNode()->getValue();
3872 assert(client->peer_id == i.getNode()->getKey());
3873 if(client->serialization_version == SER_FMT_VER_INVALID)
3876 // Don't send if it's the same one
3877 if(client->peer_id == ignore_id)
3883 Player *player = m_env->getPlayer(client->peer_id);
3886 // If player is far away, only set modified blocks not sent
3887 v3f player_pos = player->getPosition();
3888 if(player_pos.getDistanceFrom(p_f) > maxd)
3890 far_players->push_back(client->peer_id);
3897 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3898 SharedBuffer<u8> reply(replysize);
3899 writeU16(&reply[0], TOCLIENT_ADDNODE);
3900 writeS16(&reply[2], p.X);
3901 writeS16(&reply[4], p.Y);
3902 writeS16(&reply[6], p.Z);
3903 n.serialize(&reply[8], client->serialization_version);
3906 m_con.Send(client->peer_id, 0, reply, true);
3910 void Server::setBlockNotSent(v3s16 p)
3912 for(core::map<u16, RemoteClient*>::Iterator
3913 i = m_clients.getIterator();
3914 i.atEnd()==false; i++)
3916 RemoteClient *client = i.getNode()->getValue();
3917 client->SetBlockNotSent(p);
3921 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3923 DSTACK(__FUNCTION_NAME);
3925 v3s16 p = block->getPos();
3929 bool completely_air = true;
3930 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3931 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3932 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3934 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3936 completely_air = false;
3937 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3942 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3944 infostream<<"[completely air] ";
3945 infostream<<std::endl;
3949 Create a packet with the block in the right format
3952 std::ostringstream os(std::ios_base::binary);
3953 block->serialize(os, ver);
3954 std::string s = os.str();
3955 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3957 u32 replysize = 8 + blockdata.getSize();
3958 SharedBuffer<u8> reply(replysize);
3959 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3960 writeS16(&reply[2], p.X);
3961 writeS16(&reply[4], p.Y);
3962 writeS16(&reply[6], p.Z);
3963 memcpy(&reply[8], *blockdata, blockdata.getSize());
3965 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3966 <<": \tpacket size: "<<replysize<<std::endl;*/
3971 m_con.Send(peer_id, 1, reply, true);
3974 void Server::SendBlocks(float dtime)
3976 DSTACK(__FUNCTION_NAME);
3978 JMutexAutoLock envlock(m_env_mutex);
3979 JMutexAutoLock conlock(m_con_mutex);
3981 //TimeTaker timer("Server::SendBlocks");
3983 core::array<PrioritySortedBlockTransfer> queue;
3985 s32 total_sending = 0;
3988 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3990 for(core::map<u16, RemoteClient*>::Iterator
3991 i = m_clients.getIterator();
3992 i.atEnd() == false; i++)
3994 RemoteClient *client = i.getNode()->getValue();
3995 assert(client->peer_id == i.getNode()->getKey());
3997 total_sending += client->SendingCount();
3999 if(client->serialization_version == SER_FMT_VER_INVALID)
4002 client->GetNextBlocks(this, dtime, queue);
4007 // Lowest priority number comes first.
4008 // Lowest is most important.
4011 for(u32 i=0; i<queue.size(); i++)
4013 //TODO: Calculate limit dynamically
4014 if(total_sending >= g_settings->getS32
4015 ("max_simultaneous_block_sends_server_total"))
4018 PrioritySortedBlockTransfer q = queue[i];
4020 MapBlock *block = NULL;
4023 block = m_env->getMap().getBlockNoCreate(q.pos);
4025 catch(InvalidPositionException &e)
4030 RemoteClient *client = getClient(q.peer_id);
4032 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4034 client->SentBlock(q.pos);
4044 void Server::HandlePlayerHP(Player *player, s16 damage)
4046 if(player->hp > damage)
4048 player->hp -= damage;
4049 SendPlayerHP(player);
4053 infostream<<"Server::HandlePlayerHP(): Player "
4054 <<player->getName()<<" dies"<<std::endl;
4058 //TODO: Throw items around
4060 // Handle players that are not connected
4061 if(player->peer_id == PEER_ID_INEXISTENT){
4062 RespawnPlayer(player);
4066 SendPlayerHP(player);
4068 RemoteClient *client = getClient(player->peer_id);
4069 if(client->net_proto_version >= 3)
4071 SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4075 RespawnPlayer(player);
4080 void Server::RespawnPlayer(Player *player)
4082 v3f pos = findSpawnPos(m_env->getServerMap());
4083 player->setPosition(pos);
4085 SendMovePlayer(player);
4086 SendPlayerHP(player);
4089 void Server::UpdateCrafting(u16 peer_id)
4091 DSTACK(__FUNCTION_NAME);
4093 Player* player = m_env->getPlayer(peer_id);
4097 Calculate crafting stuff
4099 if(g_settings->getBool("creative_mode") == false)
4101 InventoryList *clist = player->inventory.getList("craft");
4102 InventoryList *rlist = player->inventory.getList("craftresult");
4104 if(rlist && rlist->getUsedSlots() == 0)
4105 player->craftresult_is_preview = true;
4107 if(rlist && player->craftresult_is_preview)
4109 rlist->clearItems();
4111 if(clist && rlist && player->craftresult_is_preview)
4113 InventoryItem *items[9];
4114 for(u16 i=0; i<9; i++)
4116 items[i] = clist->getItem(i);
4119 // Get result of crafting grid
4120 InventoryItem *result = craft_get_result(items, this);
4122 rlist->addItem(result);
4125 } // if creative_mode == false
4128 RemoteClient* Server::getClient(u16 peer_id)
4130 DSTACK(__FUNCTION_NAME);
4131 //JMutexAutoLock lock(m_con_mutex);
4132 core::map<u16, RemoteClient*>::Node *n;
4133 n = m_clients.find(peer_id);
4134 // A client should exist for all peers
4136 return n->getValue();
4139 std::wstring Server::getStatusString()
4141 std::wostringstream os(std::ios_base::binary);
4144 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4146 os<<L", uptime="<<m_uptime.get();
4147 // Information about clients
4149 for(core::map<u16, RemoteClient*>::Iterator
4150 i = m_clients.getIterator();
4151 i.atEnd() == false; i++)
4153 // Get client and check that it is valid
4154 RemoteClient *client = i.getNode()->getValue();
4155 assert(client->peer_id == i.getNode()->getKey());
4156 if(client->serialization_version == SER_FMT_VER_INVALID)
4159 Player *player = m_env->getPlayer(client->peer_id);
4160 // Get name of player
4161 std::wstring name = L"unknown";
4163 name = narrow_to_wide(player->getName());
4164 // Add name to information string
4168 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4169 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4170 if(g_settings->get("motd") != "")
4171 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4175 // Saves g_settings to configpath given at initialization
4176 void Server::saveConfig()
4178 if(m_configpath != "")
4179 g_settings->updateConfigFile(m_configpath.c_str());
4182 void Server::notifyPlayer(const char *name, const std::wstring msg)
4184 Player *player = m_env->getPlayer(name);
4187 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4190 void Server::notifyPlayers(const std::wstring msg)
4192 BroadcastChatMessage(msg);
4195 v3f findSpawnPos(ServerMap &map)
4197 //return v3f(50,50,50)*BS;
4202 nodepos = v2s16(0,0);
4207 // Try to find a good place a few times
4208 for(s32 i=0; i<1000; i++)
4211 // We're going to try to throw the player to this position
4212 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4213 -range + (myrand()%(range*2)));
4214 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4215 // Get ground height at point (fallbacks to heightmap function)
4216 s16 groundheight = map.findGroundLevel(nodepos2d);
4217 // Don't go underwater
4218 if(groundheight < WATER_LEVEL)
4220 //infostream<<"-> Underwater"<<std::endl;
4223 // Don't go to high places
4224 if(groundheight > WATER_LEVEL + 4)
4226 //infostream<<"-> Underwater"<<std::endl;
4230 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4231 bool is_good = false;
4233 for(s32 i=0; i<10; i++){
4234 v3s16 blockpos = getNodeBlockPos(nodepos);
4235 map.emergeBlock(blockpos, true);
4236 MapNode n = map.getNodeNoEx(nodepos);
4237 if(n.getContent() == CONTENT_AIR){
4248 // Found a good place
4249 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4255 return intToFloat(nodepos, BS);
4258 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4261 Try to get an existing player
4263 Player *player = m_env->getPlayer(name);
4266 // If player is already connected, cancel
4267 if(player->peer_id != 0)
4269 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4274 player->peer_id = peer_id;
4276 // Reset inventory to creative if in creative mode
4277 if(g_settings->getBool("creative_mode"))
4279 // Warning: double code below
4280 // Backup actual inventory
4281 player->inventory_backup = new Inventory();
4282 *(player->inventory_backup) = player->inventory;
4283 // Set creative inventory
4284 craft_set_creative_inventory(player, this);
4291 If player with the wanted peer_id already exists, cancel.
4293 if(m_env->getPlayer(peer_id) != NULL)
4295 infostream<<"emergePlayer(): Player with wrong name but same"
4296 " peer_id already exists"<<std::endl;
4304 // Add authentication stuff
4305 m_authmanager.add(name);
4306 m_authmanager.setPassword(name, password);
4307 m_authmanager.setPrivs(name,
4308 stringToPrivs(g_settings->get("default_privs")));
4314 infostream<<"Server: Finding spawn place for player \""
4315 <<name<<"\""<<std::endl;
4317 v3f pos = findSpawnPos(m_env->getServerMap());
4319 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4322 Add player to environment
4325 m_env->addPlayer(player);
4328 Add stuff to inventory
4331 if(g_settings->getBool("creative_mode"))
4333 // Warning: double code above
4334 // Backup actual inventory
4335 player->inventory_backup = new Inventory();
4336 *(player->inventory_backup) = player->inventory;
4337 // Set creative inventory
4338 craft_set_creative_inventory(player, this);
4340 else if(g_settings->getBool("give_initial_stuff"))
4342 craft_give_initial_stuff(player, this);
4347 } // create new player
4350 void Server::handlePeerChange(PeerChange &c)
4352 JMutexAutoLock envlock(m_env_mutex);
4353 JMutexAutoLock conlock(m_con_mutex);
4355 if(c.type == PEER_ADDED)
4362 core::map<u16, RemoteClient*>::Node *n;
4363 n = m_clients.find(c.peer_id);
4364 // The client shouldn't already exist
4368 RemoteClient *client = new RemoteClient();
4369 client->peer_id = c.peer_id;
4370 m_clients.insert(client->peer_id, client);
4373 else if(c.type == PEER_REMOVED)
4380 core::map<u16, RemoteClient*>::Node *n;
4381 n = m_clients.find(c.peer_id);
4382 // The client should exist
4386 Mark objects to be not known by the client
4388 RemoteClient *client = n->getValue();
4390 for(core::map<u16, bool>::Iterator
4391 i = client->m_known_objects.getIterator();
4392 i.atEnd()==false; i++)
4395 u16 id = i.getNode()->getKey();
4396 ServerActiveObject* obj = m_env->getActiveObject(id);
4398 if(obj && obj->m_known_by_count > 0)
4399 obj->m_known_by_count--;
4402 // Collect information about leaving in chat
4403 std::wstring message;
4405 Player *player = m_env->getPlayer(c.peer_id);
4408 std::wstring name = narrow_to_wide(player->getName());
4411 message += L" left game";
4413 message += L" (timed out)";
4419 m_env->removePlayer(c.peer_id);
4422 // Set player client disconnected
4424 Player *player = m_env->getPlayer(c.peer_id);
4426 player->peer_id = 0;
4433 std::ostringstream os(std::ios_base::binary);
4434 for(core::map<u16, RemoteClient*>::Iterator
4435 i = m_clients.getIterator();
4436 i.atEnd() == false; i++)
4438 RemoteClient *client = i.getNode()->getValue();
4439 assert(client->peer_id == i.getNode()->getKey());
4440 if(client->serialization_version == SER_FMT_VER_INVALID)
4443 Player *player = m_env->getPlayer(client->peer_id);
4446 // Get name of player
4447 os<<player->getName()<<" ";
4450 actionstream<<player->getName()<<" "
4451 <<(c.timeout?"times out.":"leaves game.")
4452 <<" List of players: "
4453 <<os.str()<<std::endl;
4458 delete m_clients[c.peer_id];
4459 m_clients.remove(c.peer_id);
4461 // Send player info to all remaining clients
4464 // Send leave chat message to all remaining clients
4465 BroadcastChatMessage(message);
4474 void Server::handlePeerChanges()
4476 while(m_peer_change_queue.size() > 0)
4478 PeerChange c = m_peer_change_queue.pop_front();
4480 infostream<<"Server: Handling peer change: "
4481 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4484 handlePeerChange(c);
4488 u64 Server::getPlayerPrivs(Player *player)
4492 std::string playername = player->getName();
4493 // Local player gets all privileges regardless of
4494 // what's set on their account.
4495 if(g_settings->get("name") == playername)
4501 return getPlayerAuthPrivs(playername);
4505 void dedicated_server_loop(Server &server, bool &kill)
4507 DSTACK(__FUNCTION_NAME);
4509 infostream<<DTIME<<std::endl;
4510 infostream<<"========================"<<std::endl;
4511 infostream<<"Running dedicated server"<<std::endl;
4512 infostream<<"========================"<<std::endl;
4513 infostream<<std::endl;
4515 IntervalLimiter m_profiler_interval;
4519 // This is kind of a hack but can be done like this
4520 // because server.step() is very light
4522 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4527 if(server.getShutdownRequested() || kill)
4529 infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4536 float profiler_print_interval =
4537 g_settings->getFloat("profiler_print_interval");
4538 if(profiler_print_interval != 0)
4540 if(m_profiler_interval.step(0.030, profiler_print_interval))
4542 infostream<<"Profiler:"<<std::endl;
4543 g_profiler->print(infostream);
4544 g_profiler->clear();
4551 static int counter = 0;
4557 core::list<PlayerInfo> list = server.getPlayerInfo();
4558 core::list<PlayerInfo>::Iterator i;
4559 static u32 sum_old = 0;
4560 u32 sum = PIChecksum(list);
4563 infostream<<DTIME<<"Player info:"<<std::endl;
4564 for(i=list.begin(); i!=list.end(); i++)
4566 i->PrintLine(&infostream);