3 Copyright (C) 2010-2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser 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.
24 #include "clientserver.h"
26 #include "environment.h"
28 #include "jmutexautolock.h"
30 #include "constants.h"
35 #include "serverobject.h"
36 #include "genericobject.h"
40 #include "scripting_game.h"
47 #include "content_mapnode.h"
48 #include "content_nodemeta.h"
49 #include "content_abm.h"
50 #include "content_sao.h"
55 #include "sound.h" // dummySoundManager
56 #include "event_manager.h"
58 #include "serverlist.h"
59 #include "util/string.h"
60 #include "util/pointedthing.h"
61 #include "util/mathconstants.h"
63 #include "util/serialize.h"
64 #include "util/thread.h"
65 #include "defaultsettings.h"
67 class ClientNotFoundException : public BaseException
70 ClientNotFoundException(const char *s):
75 class ServerThread : public SimpleThread
81 ServerThread(Server *server):
90 void * ServerThread::Thread()
94 log_register_thread("ServerThread");
96 DSTACK(__FUNCTION_NAME);
98 BEGIN_DEBUG_EXCEPTION_HANDLER
103 //TimeTaker timer("AsyncRunStep() + Receive()");
106 //TimeTaker timer("AsyncRunStep()");
107 m_server->AsyncRunStep();
110 //infostream<<"Running m_server->Receive()"<<std::endl;
113 catch(con::NoIncomingDataException &e)
116 catch(con::PeerNotFoundException &e)
118 infostream<<"Server: PeerNotFoundException"<<std::endl;
120 catch(ClientNotFoundException &e)
123 catch(con::ConnectionBindFailed &e)
125 m_server->setAsyncFatalError(e.what());
129 m_server->setAsyncFatalError(e.what());
133 END_DEBUG_EXCEPTION_HANDLER(errorstream)
138 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
140 if(pos_exists) *pos_exists = false;
145 if(pos_exists) *pos_exists = true;
150 ServerActiveObject *sao = env->getActiveObject(object);
153 if(pos_exists) *pos_exists = true;
154 return sao->getBasePosition(); }
159 void RemoteClient::GetNextBlocks(Server *server, float dtime,
160 std::vector<PrioritySortedBlockTransfer> &dest)
162 DSTACK(__FUNCTION_NAME);
165 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
168 m_nothing_to_send_pause_timer -= dtime;
169 m_nearest_unsent_reset_timer += dtime;
171 if(m_nothing_to_send_pause_timer >= 0)
174 Player *player = server->m_env->getPlayer(peer_id);
175 // This can happen sometimes; clients and players are not in perfect sync.
179 // Won't send anything if already sending
180 if(m_blocks_sending.size() >= g_settings->getU16
181 ("max_simultaneous_block_sends_per_client"))
183 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
187 //TimeTaker timer("RemoteClient::GetNextBlocks");
189 v3f playerpos = player->getPosition();
190 v3f playerspeed = player->getSpeed();
191 v3f playerspeeddir(0,0,0);
192 if(playerspeed.getLength() > 1.0*BS)
193 playerspeeddir = playerspeed / playerspeed.getLength();
194 // Predict to next block
195 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
197 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
199 v3s16 center = getNodeBlockPos(center_nodepos);
201 // Camera position and direction
202 v3f camera_pos = player->getEyePosition();
203 v3f camera_dir = v3f(0,0,1);
204 camera_dir.rotateYZBy(player->getPitch());
205 camera_dir.rotateXZBy(player->getYaw());
207 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
208 <<camera_dir.Z<<")"<<std::endl;*/
211 Get the starting value of the block finder radius.
214 if(m_last_center != center)
216 m_nearest_unsent_d = 0;
217 m_last_center = center;
220 /*infostream<<"m_nearest_unsent_reset_timer="
221 <<m_nearest_unsent_reset_timer<<std::endl;*/
223 // Reset periodically to workaround for some bugs or stuff
224 if(m_nearest_unsent_reset_timer > 20.0)
226 m_nearest_unsent_reset_timer = 0;
227 m_nearest_unsent_d = 0;
228 //infostream<<"Resetting m_nearest_unsent_d for "
229 // <<server->getPlayerName(peer_id)<<std::endl;
232 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
233 s16 d_start = m_nearest_unsent_d;
235 //infostream<<"d_start="<<d_start<<std::endl;
237 u16 max_simul_sends_setting = g_settings->getU16
238 ("max_simultaneous_block_sends_per_client");
239 u16 max_simul_sends_usually = max_simul_sends_setting;
242 Check the time from last addNode/removeNode.
244 Decrease send rate if player is building stuff.
246 m_time_from_building += dtime;
247 if(m_time_from_building < g_settings->getFloat(
248 "full_block_send_enable_min_time_from_building"))
250 max_simul_sends_usually
251 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
255 Number of blocks sending + number of blocks selected for sending
257 u32 num_blocks_selected = m_blocks_sending.size();
260 next time d will be continued from the d from which the nearest
261 unsent block was found this time.
263 This is because not necessarily any of the blocks found this
264 time are actually sent.
266 s32 new_nearest_unsent_d = -1;
268 s16 d_max = g_settings->getS16("max_block_send_distance");
269 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
271 // Don't loop very much at a time
272 s16 max_d_increment_at_time = 2;
273 if(d_max > d_start + max_d_increment_at_time)
274 d_max = d_start + max_d_increment_at_time;
275 /*if(d_max_gen > d_start+2)
276 d_max_gen = d_start+2;*/
278 //infostream<<"Starting from "<<d_start<<std::endl;
280 s32 nearest_emerged_d = -1;
281 s32 nearest_emergefull_d = -1;
282 s32 nearest_sent_d = -1;
283 bool queue_is_full = false;
286 for(d = d_start; d <= d_max; d++)
288 /*errorstream<<"checking d="<<d<<" for "
289 <<server->getPlayerName(peer_id)<<std::endl;*/
290 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
293 If m_nearest_unsent_d was changed by the EmergeThread
294 (it can change it to 0 through SetBlockNotSent),
296 Else update m_nearest_unsent_d
298 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
300 d = m_nearest_unsent_d;
301 last_nearest_unsent_d = m_nearest_unsent_d;
305 Get the border/face dot coordinates of a "d-radiused"
308 std::list<v3s16> list;
309 getFacePositions(list, d);
311 std::list<v3s16>::iterator li;
312 for(li=list.begin(); li!=list.end(); ++li)
314 v3s16 p = *li + center;
318 - Don't allow too many simultaneous transfers
319 - EXCEPT when the blocks are very close
321 Also, don't send blocks that are already flying.
324 // Start with the usual maximum
325 u16 max_simul_dynamic = max_simul_sends_usually;
327 // If block is very close, allow full maximum
328 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
329 max_simul_dynamic = max_simul_sends_setting;
331 // Don't select too many blocks for sending
332 if(num_blocks_selected >= max_simul_dynamic)
334 queue_is_full = true;
335 goto queue_full_break;
338 // Don't send blocks that are currently being transferred
339 if(m_blocks_sending.find(p) != m_blocks_sending.end())
345 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
346 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
347 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
348 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
349 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
350 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
353 // If this is true, inexistent block will be made from scratch
354 bool generate = d <= d_max_gen;
357 /*// Limit the generating area vertically to 2/3
358 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
361 // Limit the send area vertically to 1/2
362 if(abs(p.Y - center.Y) > d_max / 2)
368 If block is far away, don't generate it unless it is
374 // Block center y in nodes
375 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
376 // Don't generate if it's very high or very low
377 if(y < -64 || y > 64)
381 v2s16 p2d_nodes_center(
385 // Get ground height in nodes
386 s16 gh = server->m_env->getServerMap().findGroundLevel(
389 // If differs a lot, don't generate
390 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
392 // Actually, don't even send it
398 //infostream<<"d="<<d<<std::endl;
401 Don't generate or send if not in sight
402 FIXME This only works if the client uses a small enough
403 FOV setting. The default of 72 degrees is fine.
406 float camera_fov = (72.0*M_PI/180) * 4./3.;
407 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
413 Don't send already sent blocks
416 if(m_blocks_sent.find(p) != m_blocks_sent.end())
423 Check if map has this block
425 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
427 bool surely_not_found_on_disk = false;
428 bool block_is_invalid = false;
431 // Reset usage timer, this block will be of use in the future.
432 block->resetUsageTimer();
434 // Block is dummy if data doesn't exist.
435 // It means it has been not found from disk and not generated
438 surely_not_found_on_disk = true;
441 // Block is valid if lighting is up-to-date and data exists
442 if(block->isValid() == false)
444 block_is_invalid = true;
447 /*if(block->isFullyGenerated() == false)
449 block_is_invalid = true;
454 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
455 v2s16 chunkpos = map->sector_to_chunk(p2d);
456 if(map->chunkNonVolatile(chunkpos) == false)
457 block_is_invalid = true;
459 if(block->isGenerated() == false)
460 block_is_invalid = true;
463 If block is not close, don't send it unless it is near
466 Block is near ground level if night-time mesh
467 differs from day-time mesh.
471 if(block->getDayNightDiff() == false)
478 If block has been marked to not exist on disk (dummy)
479 and generating new ones is not wanted, skip block.
481 if(generate == false && surely_not_found_on_disk == true)
488 Add inexistent block to emerge queue.
490 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
492 /* //TODO: Get value from somewhere
493 // Allow only one block in emerge queue
494 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
495 // Allow two blocks in queue per client
496 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
498 // Make it more responsive when needing to generate stuff
499 if(surely_not_found_on_disk)
501 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
503 //infostream<<"Adding block to emerge queue"<<std::endl;
505 // Add it to the emerge queue and trigger the thread
508 if(generate == false)
509 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
511 server->m_emerge_queue.addBlock(peer_id, p, flags);
512 server->m_emergethread.trigger();
514 if(nearest_emerged_d == -1)
515 nearest_emerged_d = d;
517 if(nearest_emergefull_d == -1)
518 nearest_emergefull_d = d;
519 goto queue_full_break;
523 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
524 if (nearest_emerged_d == -1)
525 nearest_emerged_d = d;
527 if (nearest_emergefull_d == -1)
528 nearest_emergefull_d = d;
529 goto queue_full_break;
536 if(nearest_sent_d == -1)
540 Add block to send queue
543 /*errorstream<<"sending from d="<<d<<" to "
544 <<server->getPlayerName(peer_id)<<std::endl;*/
546 PrioritySortedBlockTransfer q((float)d, p, peer_id);
550 num_blocks_selected += 1;
555 //infostream<<"Stopped at "<<d<<std::endl;
557 // If nothing was found for sending and nothing was queued for
558 // emerging, continue next time browsing from here
559 if(nearest_emerged_d != -1){
560 new_nearest_unsent_d = nearest_emerged_d;
561 } else if(nearest_emergefull_d != -1){
562 new_nearest_unsent_d = nearest_emergefull_d;
564 if(d > g_settings->getS16("max_block_send_distance")){
565 new_nearest_unsent_d = 0;
566 m_nothing_to_send_pause_timer = 2.0;
567 /*infostream<<"GetNextBlocks(): d wrapped around for "
568 <<server->getPlayerName(peer_id)
569 <<"; setting to 0 and pausing"<<std::endl;*/
571 if(nearest_sent_d != -1)
572 new_nearest_unsent_d = nearest_sent_d;
574 new_nearest_unsent_d = d;
578 if(new_nearest_unsent_d != -1)
579 m_nearest_unsent_d = new_nearest_unsent_d;
581 /*timer_result = timer.stop(true);
582 if(timer_result != 0)
583 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
586 void RemoteClient::GotBlock(v3s16 p)
588 if(m_blocks_sending.find(p) != m_blocks_sending.end())
589 m_blocks_sending.erase(p);
592 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
593 " m_blocks_sending"<<std::endl;*/
594 m_excess_gotblocks++;
596 m_blocks_sent.insert(p);
599 void RemoteClient::SentBlock(v3s16 p)
601 if(m_blocks_sending.find(p) == m_blocks_sending.end())
602 m_blocks_sending[p] = 0.0;
604 infostream<<"RemoteClient::SentBlock(): Sent block"
605 " already in m_blocks_sending"<<std::endl;
608 void RemoteClient::SetBlockNotSent(v3s16 p)
610 m_nearest_unsent_d = 0;
612 if(m_blocks_sending.find(p) != m_blocks_sending.end())
613 m_blocks_sending.erase(p);
614 if(m_blocks_sent.find(p) != m_blocks_sent.end())
615 m_blocks_sent.erase(p);
618 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
620 m_nearest_unsent_d = 0;
622 for(std::map<v3s16, MapBlock*>::iterator
624 i != blocks.end(); ++i)
628 if(m_blocks_sending.find(p) != m_blocks_sending.end())
629 m_blocks_sending.erase(p);
630 if(m_blocks_sent.find(p) != m_blocks_sent.end())
631 m_blocks_sent.erase(p);
640 const std::string &path_world,
641 const SubgameSpec &gamespec,
642 bool simple_singleplayer_mode
644 m_path_world(path_world),
645 m_gamespec(gamespec),
646 m_simple_singleplayer_mode(simple_singleplayer_mode),
647 m_async_fatal_error(""),
649 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT,
650 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
653 m_rollback_sink_enabled(true),
654 m_enable_rollback_recording(false),
657 m_itemdef(createItemDefManager()),
658 m_nodedef(createNodeDefManager()),
659 m_craftdef(createCraftDefManager()),
660 m_event(new EventManager()),
662 m_time_of_day_send_timer(0),
664 m_shutdown_requested(false),
665 m_ignore_map_edit_events(false),
666 m_ignore_map_edit_events_peer_id(0)
668 m_liquid_transform_timer = 0.0;
669 m_liquid_transform_every = 1.0;
670 m_print_info_timer = 0.0;
671 m_masterserver_timer = 0.0;
672 m_objectdata_timer = 0.0;
673 m_emergethread_trigger_timer = 0.0;
674 m_savemap_timer = 0.0;
675 m_clients_number = 0;
679 m_step_dtime_mutex.Init();
683 throw ServerError("Supplied empty world path");
685 if(!gamespec.isValid())
686 throw ServerError("Supplied invalid gamespec");
688 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
689 if(m_simple_singleplayer_mode)
690 infostream<<" in simple singleplayer mode"<<std::endl;
692 infostream<<std::endl;
693 infostream<<"- world: "<<m_path_world<<std::endl;
694 infostream<<"- game: "<<m_gamespec.path<<std::endl;
696 // Initialize default settings and override defaults with those provided
698 set_default_settings(g_settings);
699 Settings gamedefaults;
700 getGameMinetestConfig(gamespec.path, gamedefaults);
701 override_default_settings(g_settings, &gamedefaults);
703 // Create server thread
704 m_thread = new ServerThread(this);
706 // Create emerge manager
707 m_emerge = new EmergeManager(this);
709 // Create ban manager
710 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
711 m_banmanager = new BanManager(ban_path);
713 // Create rollback manager
714 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
715 m_rollback = createRollbackManager(rollback_path, this);
717 // Create world if it doesn't exist
718 if(!initializeWorld(m_path_world, m_gamespec.id))
719 throw ServerError("Failed to initialize world");
721 ModConfiguration modconf(m_path_world);
722 m_mods = modconf.getMods();
723 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
724 // complain about mods with unsatisfied dependencies
725 if(!modconf.isConsistent())
727 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
728 it != unsatisfied_mods.end(); ++it)
731 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
732 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
733 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
734 errorstream << " \"" << *dep_it << "\"";
735 errorstream << std::endl;
739 Settings worldmt_settings;
740 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
741 worldmt_settings.readConfigFile(worldmt.c_str());
742 std::vector<std::string> names = worldmt_settings.getNames();
743 std::set<std::string> load_mod_names;
744 for(std::vector<std::string>::iterator it = names.begin();
745 it != names.end(); ++it)
747 std::string name = *it;
748 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
749 load_mod_names.insert(name.substr(9));
751 // complain about mods declared to be loaded, but not found
752 for(std::vector<ModSpec>::iterator it = m_mods.begin();
753 it != m_mods.end(); ++it)
754 load_mod_names.erase((*it).name);
755 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
756 it != unsatisfied_mods.end(); ++it)
757 load_mod_names.erase((*it).name);
758 if(!load_mod_names.empty())
760 errorstream << "The following mods could not be found:";
761 for(std::set<std::string>::iterator it = load_mod_names.begin();
762 it != load_mod_names.end(); ++it)
763 errorstream << " \"" << (*it) << "\"";
764 errorstream << std::endl;
767 // Path to builtin.lua
768 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
771 JMutexAutoLock envlock(m_env_mutex);
772 JMutexAutoLock conlock(m_con_mutex);
774 // Initialize scripting
776 infostream<<"Server: Initializing Lua"<<std::endl;
778 m_script = new GameScripting(this);
781 // Load and run builtin.lua
782 infostream<<"Server: Loading builtin.lua [\""
783 <<builtinpath<<"\"]"<<std::endl;
784 bool success = m_script->loadMod(builtinpath, "__builtin");
786 errorstream<<"Server: Failed to load and run "
787 <<builtinpath<<std::endl;
788 throw ModError("Failed to load and run "+builtinpath);
791 infostream<<"Server: Loading mods: ";
792 for(std::vector<ModSpec>::iterator i = m_mods.begin();
793 i != m_mods.end(); i++){
794 const ModSpec &mod = *i;
795 infostream<<mod.name<<" ";
797 infostream<<std::endl;
798 // Load and run "mod" scripts
799 for(std::vector<ModSpec>::iterator i = m_mods.begin();
800 i != m_mods.end(); i++){
801 const ModSpec &mod = *i;
802 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
803 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
804 <<scriptpath<<"\"]"<<std::endl;
805 bool success = m_script->loadMod(scriptpath, mod.name);
807 errorstream<<"Server: Failed to load and run "
808 <<scriptpath<<std::endl;
809 throw ModError("Failed to load and run "+scriptpath);
813 // Read Textures and calculate sha1 sums
816 // Apply item aliases in the node definition manager
817 m_nodedef->updateAliases(m_itemdef);
819 // Initialize Environment
820 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
821 m_env = new ServerEnvironment(servermap, m_script, this, m_emerge);
823 // Run some callbacks after the MG params have been set up but before activation
824 MapgenParams *mgparams = servermap->getMapgenParams();
825 m_script->environment_OnMapgenInit(mgparams);
827 // Initialize mapgens
828 m_emerge->initMapgens(mgparams);
830 // Give environment reference to scripting api
831 m_script->initializeEnvironment(m_env);
833 // Register us to receive map edit events
834 servermap->addEventReceiver(this);
836 // If file exists, load environment metadata
837 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
839 infostream<<"Server: Loading environment metadata"<<std::endl;
840 m_env->loadMeta(m_path_world);
844 infostream<<"Server: Loading players"<<std::endl;
845 m_env->deSerializePlayers(m_path_world);
848 Add some test ActiveBlockModifiers to environment
850 add_legacy_abms(m_env, m_nodedef);
852 m_liquid_transform_every = g_settings->getFloat("liquid_update");
857 infostream<<"Server destructing"<<std::endl;
860 Send shutdown message
863 JMutexAutoLock conlock(m_con_mutex);
865 std::wstring line = L"*** Server shutting down";
868 Send the message to clients
870 for(std::map<u16, RemoteClient*>::iterator
871 i = m_clients.begin();
872 i != m_clients.end(); ++i)
874 // Get client and check that it is valid
875 RemoteClient *client = i->second;
876 assert(client->peer_id == i->first);
877 if(client->serialization_version == SER_FMT_VER_INVALID)
881 SendChatMessage(client->peer_id, line);
883 catch(con::PeerNotFoundException &e)
889 JMutexAutoLock envlock(m_env_mutex);
890 JMutexAutoLock conlock(m_con_mutex);
893 Execute script shutdown hooks
895 m_script->on_shutdown();
899 JMutexAutoLock envlock(m_env_mutex);
904 infostream<<"Server: Saving players"<<std::endl;
905 m_env->serializePlayers(m_path_world);
908 Save environment metadata
910 infostream<<"Server: Saving environment metadata"<<std::endl;
911 m_env->saveMeta(m_path_world);
920 //shutdown all emerge threads first!
927 JMutexAutoLock clientslock(m_con_mutex);
929 for(std::map<u16, RemoteClient*>::iterator
930 i = m_clients.begin();
931 i != m_clients.end(); ++i)
939 // Delete things in the reverse order of creation
948 // Deinitialize scripting
949 infostream<<"Server: Deinitializing scripting"<<std::endl;
952 // Delete detached inventories
954 for(std::map<std::string, Inventory*>::iterator
955 i = m_detached_inventories.begin();
956 i != m_detached_inventories.end(); i++){
962 void Server::start(unsigned short port)
964 DSTACK(__FUNCTION_NAME);
965 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
967 // Stop thread if already running
970 // Initialize connection
971 m_con.SetTimeoutMs(30);
975 m_thread->setRun(true);
978 // ASCII art for the win!
980 <<" .__ __ __ "<<std::endl
981 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
982 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
983 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
984 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
985 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
986 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
987 actionstream<<"Server for gameid=\""<<m_gamespec.id
988 <<"\" listening on port "<<port<<"."<<std::endl;
993 DSTACK(__FUNCTION_NAME);
995 infostream<<"Server: Stopping and waiting threads"<<std::endl;
997 // Stop threads (set run=false first so both start stopping)
998 m_thread->setRun(false);
999 //m_emergethread.setRun(false);
1001 //m_emergethread.stop();
1003 infostream<<"Server: Threads stopped"<<std::endl;
1006 void Server::step(float dtime)
1008 DSTACK(__FUNCTION_NAME);
1013 JMutexAutoLock lock(m_step_dtime_mutex);
1014 m_step_dtime += dtime;
1016 // Throw if fatal error occurred in thread
1017 std::string async_err = m_async_fatal_error.get();
1018 if(async_err != ""){
1019 throw ServerError(async_err);
1023 void Server::AsyncRunStep()
1025 DSTACK(__FUNCTION_NAME);
1027 g_profiler->add("Server::AsyncRunStep (num)", 1);
1031 JMutexAutoLock lock1(m_step_dtime_mutex);
1032 dtime = m_step_dtime;
1036 // Send blocks to clients
1043 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1045 //infostream<<"Server steps "<<dtime<<std::endl;
1046 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1049 JMutexAutoLock lock1(m_step_dtime_mutex);
1050 m_step_dtime -= dtime;
1057 m_uptime.set(m_uptime.get() + dtime);
1061 // Process connection's timeouts
1062 JMutexAutoLock lock2(m_con_mutex);
1063 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1064 m_con.RunTimeouts(dtime);
1068 // This has to be called so that the client list gets synced
1069 // with the peer list of the connection
1070 handlePeerChanges();
1074 Update time of day and overall game time
1077 JMutexAutoLock envlock(m_env_mutex);
1079 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1082 Send to clients at constant intervals
1085 m_time_of_day_send_timer -= dtime;
1086 if(m_time_of_day_send_timer < 0.0)
1088 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1090 //JMutexAutoLock envlock(m_env_mutex);
1091 JMutexAutoLock conlock(m_con_mutex);
1093 u16 time = m_env->getTimeOfDay();
1094 float time_speed = g_settings->getFloat("time_speed");
1096 for(std::map<u16, RemoteClient*>::iterator
1097 i = m_clients.begin();
1098 i != m_clients.end(); ++i)
1100 RemoteClient *client = i->second;
1101 SendTimeOfDay(client->peer_id, time, time_speed);
1107 JMutexAutoLock lock(m_env_mutex);
1108 // Figure out and report maximum lag to environment
1109 float max_lag = m_env->getMaxLagEstimate();
1110 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
1111 if(dtime > max_lag){
1112 if(dtime > 0.1 && dtime > max_lag * 2.0)
1113 infostream<<"Server: Maximum lag peaked to "<<dtime
1117 m_env->reportMaxLagEstimate(max_lag);
1119 ScopeProfiler sp(g_profiler, "SEnv step");
1120 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1124 const float map_timer_and_unload_dtime = 2.92;
1125 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1127 JMutexAutoLock lock(m_env_mutex);
1128 // Run Map's timers and unload unused data
1129 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1130 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1131 g_settings->getFloat("server_unload_unused_data_timeout"));
1142 JMutexAutoLock lock(m_env_mutex);
1143 JMutexAutoLock lock2(m_con_mutex);
1145 ScopeProfiler sp(g_profiler, "Server: handle players");
1147 for(std::map<u16, RemoteClient*>::iterator
1148 i = m_clients.begin();
1149 i != m_clients.end(); ++i)
1151 RemoteClient *client = i->second;
1152 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1153 if(playersao == NULL)
1157 Handle player HPs (die if hp=0)
1159 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1161 if(playersao->getHP() == 0)
1162 DiePlayer(client->peer_id);
1164 SendPlayerHP(client->peer_id);
1168 Send player breath if changed
1170 if(playersao->m_breath_not_sent){
1171 SendPlayerBreath(client->peer_id);
1175 Send player inventories if necessary
1177 if(playersao->m_moved){
1178 SendMovePlayer(client->peer_id);
1179 playersao->m_moved = false;
1181 if(playersao->m_inventory_not_sent){
1182 UpdateCrafting(client->peer_id);
1183 SendInventory(client->peer_id);
1188 /* Transform liquids */
1189 m_liquid_transform_timer += dtime;
1190 if(m_liquid_transform_timer >= m_liquid_transform_every)
1192 m_liquid_transform_timer -= m_liquid_transform_every;
1194 JMutexAutoLock lock(m_env_mutex);
1196 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1198 std::map<v3s16, MapBlock*> modified_blocks;
1199 m_env->getMap().transformLiquids(modified_blocks);
1204 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1205 ServerMap &map = ((ServerMap&)m_env->getMap());
1206 map.updateLighting(modified_blocks, lighting_modified_blocks);
1208 // Add blocks modified by lighting to modified_blocks
1209 for(core::map<v3s16, MapBlock*>::Iterator
1210 i = lighting_modified_blocks.getIterator();
1211 i.atEnd() == false; i++)
1213 MapBlock *block = i.getNode()->getValue();
1214 modified_blocks.insert(block->getPos(), block);
1218 Set the modified blocks unsent for all the clients
1221 JMutexAutoLock lock2(m_con_mutex);
1223 for(std::map<u16, RemoteClient*>::iterator
1224 i = m_clients.begin();
1225 i != m_clients.end(); ++i)
1227 RemoteClient *client = i->second;
1229 if(modified_blocks.size() > 0)
1231 // Remove block from sent history
1232 client->SetBlocksNotSent(modified_blocks);
1237 // Periodically print some info
1239 float &counter = m_print_info_timer;
1245 JMutexAutoLock lock2(m_con_mutex);
1246 m_clients_number = 0;
1247 if(m_clients.size() != 0)
1248 infostream<<"Players:"<<std::endl;
1249 for(std::map<u16, RemoteClient*>::iterator
1250 i = m_clients.begin();
1251 i != m_clients.end(); ++i)
1253 //u16 peer_id = i.getNode()->getKey();
1254 RemoteClient *client = i->second;
1255 Player *player = m_env->getPlayer(client->peer_id);
1258 infostream<<"* "<<player->getName()<<"\t";
1259 client->PrintInfo(infostream);
1267 // send masterserver announce
1269 float &counter = m_masterserver_timer;
1270 if(!isSingleplayer() && (!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1272 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id, m_mods);
1279 //if(g_settings->getBool("enable_experimental"))
1283 Check added and deleted active objects
1286 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1287 JMutexAutoLock envlock(m_env_mutex);
1288 JMutexAutoLock conlock(m_con_mutex);
1290 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1292 // Radius inside which objects are active
1293 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1294 radius *= MAP_BLOCKSIZE;
1296 for(std::map<u16, RemoteClient*>::iterator
1297 i = m_clients.begin();
1298 i != m_clients.end(); ++i)
1300 RemoteClient *client = i->second;
1302 // If definitions and textures have not been sent, don't
1303 // send objects either
1304 if(!client->definitions_sent)
1307 Player *player = m_env->getPlayer(client->peer_id);
1310 // This can happen if the client timeouts somehow
1311 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1313 <<" has no associated player"<<std::endl;*/
1316 v3s16 pos = floatToInt(player->getPosition(), BS);
1318 std::set<u16> removed_objects;
1319 std::set<u16> added_objects;
1320 m_env->getRemovedActiveObjects(pos, radius,
1321 client->m_known_objects, removed_objects);
1322 m_env->getAddedActiveObjects(pos, radius,
1323 client->m_known_objects, added_objects);
1325 // Ignore if nothing happened
1326 if(removed_objects.size() == 0 && added_objects.size() == 0)
1328 //infostream<<"active objects: none changed"<<std::endl;
1332 std::string data_buffer;
1336 // Handle removed objects
1337 writeU16((u8*)buf, removed_objects.size());
1338 data_buffer.append(buf, 2);
1339 for(std::set<u16>::iterator
1340 i = removed_objects.begin();
1341 i != removed_objects.end(); ++i)
1345 ServerActiveObject* obj = m_env->getActiveObject(id);
1347 // Add to data buffer for sending
1348 writeU16((u8*)buf, id);
1349 data_buffer.append(buf, 2);
1351 // Remove from known objects
1352 client->m_known_objects.erase(id);
1354 if(obj && obj->m_known_by_count > 0)
1355 obj->m_known_by_count--;
1358 // Handle added objects
1359 writeU16((u8*)buf, added_objects.size());
1360 data_buffer.append(buf, 2);
1361 for(std::set<u16>::iterator
1362 i = added_objects.begin();
1363 i != added_objects.end(); ++i)
1367 ServerActiveObject* obj = m_env->getActiveObject(id);
1370 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1372 infostream<<"WARNING: "<<__FUNCTION_NAME
1373 <<": NULL object"<<std::endl;
1375 type = obj->getSendType();
1377 // Add to data buffer for sending
1378 writeU16((u8*)buf, id);
1379 data_buffer.append(buf, 2);
1380 writeU8((u8*)buf, type);
1381 data_buffer.append(buf, 1);
1384 data_buffer.append(serializeLongString(
1385 obj->getClientInitializationData(client->net_proto_version)));
1387 data_buffer.append(serializeLongString(""));
1389 // Add to known objects
1390 client->m_known_objects.insert(id);
1393 obj->m_known_by_count++;
1397 SharedBuffer<u8> reply(2 + data_buffer.size());
1398 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1399 memcpy((char*)&reply[2], data_buffer.c_str(),
1400 data_buffer.size());
1402 m_con.Send(client->peer_id, 0, reply, true);
1404 verbosestream<<"Server: Sent object remove/add: "
1405 <<removed_objects.size()<<" removed, "
1406 <<added_objects.size()<<" added, "
1407 <<"packet size is "<<reply.getSize()<<std::endl;
1412 Collect a list of all the objects known by the clients
1413 and report it back to the environment.
1416 core::map<u16, bool> all_known_objects;
1418 for(core::map<u16, RemoteClient*>::Iterator
1419 i = m_clients.getIterator();
1420 i.atEnd() == false; i++)
1422 RemoteClient *client = i.getNode()->getValue();
1423 // Go through all known objects of client
1424 for(core::map<u16, bool>::Iterator
1425 i = client->m_known_objects.getIterator();
1426 i.atEnd()==false; i++)
1428 u16 id = i.getNode()->getKey();
1429 all_known_objects[id] = true;
1433 m_env->setKnownActiveObjects(whatever);
1439 Send object messages
1442 JMutexAutoLock envlock(m_env_mutex);
1443 JMutexAutoLock conlock(m_con_mutex);
1445 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1448 // Value = data sent by object
1449 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1451 // Get active object messages from environment
1454 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1458 std::list<ActiveObjectMessage>* message_list = NULL;
1459 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1460 n = buffered_messages.find(aom.id);
1461 if(n == buffered_messages.end())
1463 message_list = new std::list<ActiveObjectMessage>;
1464 buffered_messages[aom.id] = message_list;
1468 message_list = n->second;
1470 message_list->push_back(aom);
1473 // Route data to every client
1474 for(std::map<u16, RemoteClient*>::iterator
1475 i = m_clients.begin();
1476 i != m_clients.end(); ++i)
1478 RemoteClient *client = i->second;
1479 std::string reliable_data;
1480 std::string unreliable_data;
1481 // Go through all objects in message buffer
1482 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1483 j = buffered_messages.begin();
1484 j != buffered_messages.end(); ++j)
1486 // If object is not known by client, skip it
1488 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1490 // Get message list of object
1491 std::list<ActiveObjectMessage>* list = j->second;
1492 // Go through every message
1493 for(std::list<ActiveObjectMessage>::iterator
1494 k = list->begin(); k != list->end(); ++k)
1496 // Compose the full new data with header
1497 ActiveObjectMessage aom = *k;
1498 std::string new_data;
1501 writeU16((u8*)&buf[0], aom.id);
1502 new_data.append(buf, 2);
1504 new_data += serializeString(aom.datastring);
1505 // Add data to buffer
1507 reliable_data += new_data;
1509 unreliable_data += new_data;
1513 reliable_data and unreliable_data are now ready.
1516 if(reliable_data.size() > 0)
1518 SharedBuffer<u8> reply(2 + reliable_data.size());
1519 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1520 memcpy((char*)&reply[2], reliable_data.c_str(),
1521 reliable_data.size());
1523 m_con.Send(client->peer_id, 0, reply, true);
1525 if(unreliable_data.size() > 0)
1527 SharedBuffer<u8> reply(2 + unreliable_data.size());
1528 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1529 memcpy((char*)&reply[2], unreliable_data.c_str(),
1530 unreliable_data.size());
1531 // Send as unreliable
1532 m_con.Send(client->peer_id, 0, reply, false);
1535 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1537 infostream<<"Server: Size of object message data: "
1538 <<"reliable: "<<reliable_data.size()
1539 <<", unreliable: "<<unreliable_data.size()
1544 // Clear buffered_messages
1545 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1546 i = buffered_messages.begin();
1547 i != buffered_messages.end(); ++i)
1553 } // enable_experimental
1556 Send queued-for-sending map edit events.
1559 // We will be accessing the environment and the connection
1560 JMutexAutoLock lock(m_env_mutex);
1561 JMutexAutoLock conlock(m_con_mutex);
1563 // Don't send too many at a time
1566 // Single change sending is disabled if queue size is not small
1567 bool disable_single_change_sending = false;
1568 if(m_unsent_map_edit_queue.size() >= 4)
1569 disable_single_change_sending = true;
1571 int event_count = m_unsent_map_edit_queue.size();
1573 // We'll log the amount of each
1576 while(m_unsent_map_edit_queue.size() != 0)
1578 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1580 // Players far away from the change are stored here.
1581 // Instead of sending the changes, MapBlocks are set not sent
1583 std::list<u16> far_players;
1585 if(event->type == MEET_ADDNODE)
1587 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1588 prof.add("MEET_ADDNODE", 1);
1589 if(disable_single_change_sending)
1590 sendAddNode(event->p, event->n, event->already_known_by_peer,
1593 sendAddNode(event->p, event->n, event->already_known_by_peer,
1596 else if(event->type == MEET_REMOVENODE)
1598 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1599 prof.add("MEET_REMOVENODE", 1);
1600 if(disable_single_change_sending)
1601 sendRemoveNode(event->p, event->already_known_by_peer,
1604 sendRemoveNode(event->p, event->already_known_by_peer,
1607 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1609 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1610 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1611 setBlockNotSent(event->p);
1613 else if(event->type == MEET_OTHER)
1615 infostream<<"Server: MEET_OTHER"<<std::endl;
1616 prof.add("MEET_OTHER", 1);
1617 for(std::set<v3s16>::iterator
1618 i = event->modified_blocks.begin();
1619 i != event->modified_blocks.end(); ++i)
1621 setBlockNotSent(*i);
1626 prof.add("unknown", 1);
1627 infostream<<"WARNING: Server: Unknown MapEditEvent "
1628 <<((u32)event->type)<<std::endl;
1632 Set blocks not sent to far players
1634 if(far_players.size() > 0)
1636 // Convert list format to that wanted by SetBlocksNotSent
1637 std::map<v3s16, MapBlock*> modified_blocks2;
1638 for(std::set<v3s16>::iterator
1639 i = event->modified_blocks.begin();
1640 i != event->modified_blocks.end(); ++i)
1642 modified_blocks2[*i] =
1643 m_env->getMap().getBlockNoCreateNoEx(*i);
1645 // Set blocks not sent
1646 for(std::list<u16>::iterator
1647 i = far_players.begin();
1648 i != far_players.end(); ++i)
1651 RemoteClient *client = getClient(peer_id);
1654 client->SetBlocksNotSent(modified_blocks2);
1660 /*// Don't send too many at a time
1662 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1666 if(event_count >= 5){
1667 infostream<<"Server: MapEditEvents:"<<std::endl;
1668 prof.print(infostream);
1669 } else if(event_count != 0){
1670 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1671 prof.print(verbosestream);
1677 Trigger emergethread (it somehow gets to a non-triggered but
1678 bysy state sometimes)
1681 float &counter = m_emergethread_trigger_timer;
1687 m_emerge->triggerAllThreads();
1689 // Update m_enable_rollback_recording here too
1690 m_enable_rollback_recording =
1691 g_settings->getBool("enable_rollback_recording");
1695 // Save map, players and auth stuff
1697 float &counter = m_savemap_timer;
1699 if(counter >= g_settings->getFloat("server_map_save_interval"))
1702 JMutexAutoLock lock(m_env_mutex);
1704 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1707 if(m_banmanager->isModified())
1708 m_banmanager->save();
1710 // Save changed parts of map
1711 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1714 m_env->serializePlayers(m_path_world);
1716 // Save environment metadata
1717 m_env->saveMeta(m_path_world);
1722 void Server::Receive()
1724 DSTACK(__FUNCTION_NAME);
1725 SharedBuffer<u8> data;
1730 JMutexAutoLock conlock(m_con_mutex);
1731 datasize = m_con.Receive(peer_id, data);
1734 // This has to be called so that the client list gets synced
1735 // with the peer list of the connection
1736 handlePeerChanges();
1738 ProcessData(*data, datasize, peer_id);
1740 catch(con::InvalidIncomingDataException &e)
1742 infostream<<"Server::Receive(): "
1743 "InvalidIncomingDataException: what()="
1744 <<e.what()<<std::endl;
1746 catch(con::PeerNotFoundException &e)
1748 //NOTE: This is not needed anymore
1750 // The peer has been disconnected.
1751 // Find the associated player and remove it.
1753 /*JMutexAutoLock envlock(m_env_mutex);
1755 infostream<<"ServerThread: peer_id="<<peer_id
1756 <<" has apparently closed connection. "
1757 <<"Removing player."<<std::endl;
1759 m_env->removePlayer(peer_id);*/
1763 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1765 DSTACK(__FUNCTION_NAME);
1766 // Environment is locked first.
1767 JMutexAutoLock envlock(m_env_mutex);
1768 JMutexAutoLock conlock(m_con_mutex);
1770 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1774 Address address = m_con.GetPeerAddress(peer_id);
1775 addr_s = address.serializeString();
1777 // drop player if is ip is banned
1778 if(m_banmanager->isIpBanned(addr_s)){
1779 std::string ban_name = m_banmanager->getBanName(addr_s);
1780 infostream<<"Server: A banned client tried to connect from "
1781 <<addr_s<<"; banned name was "
1782 <<ban_name<<std::endl;
1783 // This actually doesn't seem to transfer to the client
1784 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1785 +narrow_to_wide(ban_name));
1786 m_con.DeletePeer(peer_id);
1790 catch(con::PeerNotFoundException &e)
1792 infostream<<"Server::ProcessData(): Cancelling: peer "
1793 <<peer_id<<" not found"<<std::endl;
1797 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1805 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1807 if(command == TOSERVER_INIT)
1809 // [0] u16 TOSERVER_INIT
1810 // [2] u8 SER_FMT_VER_HIGHEST_READ
1811 // [3] u8[20] player_name
1812 // [23] u8[28] password <--- can be sent without this, from old versions
1814 if(datasize < 2+1+PLAYERNAME_SIZE)
1817 // If net_proto_version is set, this client has already been handled
1818 if(getClient(peer_id)->net_proto_version != 0){
1819 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1820 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1824 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1825 <<peer_id<<")"<<std::endl;
1827 // Do not allow multiple players in simple singleplayer mode.
1828 // This isn't a perfect way to do it, but will suffice for now.
1829 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1830 infostream<<"Server: Not allowing another client ("<<addr_s
1831 <<") to connect in simple singleplayer mode"<<std::endl;
1832 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1836 // First byte after command is maximum supported
1837 // serialization version
1838 u8 client_max = data[2];
1839 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1840 // Use the highest version supported by both
1841 u8 deployed = std::min(client_max, our_max);
1842 // If it's lower than the lowest supported, give up.
1843 if(deployed < SER_FMT_VER_LOWEST)
1844 deployed = SER_FMT_VER_INVALID;
1846 //peer->serialization_version = deployed;
1847 getClient(peer_id)->pending_serialization_version = deployed;
1849 if(deployed == SER_FMT_VER_INVALID)
1851 actionstream<<"Server: A mismatched client tried to connect from "
1852 <<addr_s<<std::endl;
1853 infostream<<"Server: Cannot negotiate serialization version with "
1854 <<addr_s<<std::endl;
1855 DenyAccess(peer_id, std::wstring(
1856 L"Your client's version is not supported.\n"
1857 L"Server version is ")
1858 + narrow_to_wide(VERSION_STRING) + L"."
1864 Read and check network protocol version
1867 u16 min_net_proto_version = 0;
1868 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1869 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1871 // Use same version as minimum and maximum if maximum version field
1872 // doesn't exist (backwards compatibility)
1873 u16 max_net_proto_version = min_net_proto_version;
1874 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1875 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1877 // Start with client's maximum version
1878 u16 net_proto_version = max_net_proto_version;
1880 // Figure out a working version if it is possible at all
1881 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1882 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1884 // If maximum is larger than our maximum, go with our maximum
1885 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1886 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1887 // Else go with client's maximum
1889 net_proto_version = max_net_proto_version;
1892 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1893 <<min_net_proto_version<<", max: "<<max_net_proto_version
1894 <<", chosen: "<<net_proto_version<<std::endl;
1896 getClient(peer_id)->net_proto_version = net_proto_version;
1898 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1899 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1901 actionstream<<"Server: A mismatched client tried to connect from "
1902 <<addr_s<<std::endl;
1903 DenyAccess(peer_id, std::wstring(
1904 L"Your client's version is not supported.\n"
1905 L"Server version is ")
1906 + narrow_to_wide(VERSION_STRING) + L",\n"
1907 + L"server's PROTOCOL_VERSION is "
1908 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1910 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1911 + L", client's PROTOCOL_VERSION is "
1912 + narrow_to_wide(itos(min_net_proto_version))
1914 + narrow_to_wide(itos(max_net_proto_version))
1919 if(g_settings->getBool("strict_protocol_version_checking"))
1921 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1923 actionstream<<"Server: A mismatched (strict) client tried to "
1924 <<"connect from "<<addr_s<<std::endl;
1925 DenyAccess(peer_id, std::wstring(
1926 L"Your client's version is not supported.\n"
1927 L"Server version is ")
1928 + narrow_to_wide(VERSION_STRING) + L",\n"
1929 + L"server's PROTOCOL_VERSION (strict) is "
1930 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1931 + L", client's PROTOCOL_VERSION is "
1932 + narrow_to_wide(itos(min_net_proto_version))
1934 + narrow_to_wide(itos(max_net_proto_version))
1945 char playername[PLAYERNAME_SIZE];
1946 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1948 playername[i] = data[3+i];
1950 playername[PLAYERNAME_SIZE-1] = 0;
1952 if(playername[0]=='\0')
1954 actionstream<<"Server: Player with an empty name "
1955 <<"tried to connect from "<<addr_s<<std::endl;
1956 DenyAccess(peer_id, L"Empty name");
1960 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1962 actionstream<<"Server: Player with an invalid name "
1963 <<"tried to connect from "<<addr_s<<std::endl;
1964 DenyAccess(peer_id, L"Name contains unallowed characters");
1968 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1970 actionstream<<"Server: Player with the name \"singleplayer\" "
1971 <<"tried to connect from "<<addr_s<<std::endl;
1972 DenyAccess(peer_id, L"Name is not allowed");
1976 infostream<<"Server: New connection: \""<<playername<<"\" from "
1977 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1980 char given_password[PASSWORD_SIZE];
1981 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1983 // old version - assume blank password
1984 given_password[0] = 0;
1988 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1990 given_password[i] = data[23+i];
1992 given_password[PASSWORD_SIZE-1] = 0;
1995 if(!base64_is_valid(given_password)){
1996 actionstream<<"Server: "<<playername
1997 <<" supplied invalid password hash"<<std::endl;
1998 DenyAccess(peer_id, L"Invalid password hash");
2002 // Enforce user limit.
2003 // Don't enforce for users that have some admin right
2004 if(m_clients.size() >= g_settings->getU16("max_users") &&
2005 !checkPriv(playername, "server") &&
2006 !checkPriv(playername, "ban") &&
2007 !checkPriv(playername, "privs") &&
2008 !checkPriv(playername, "password") &&
2009 playername != g_settings->get("name"))
2011 actionstream<<"Server: "<<playername<<" tried to join, but there"
2012 <<" are already max_users="
2013 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2014 DenyAccess(peer_id, L"Too many users.");
2018 std::string checkpwd; // Password hash to check against
2019 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2021 // If no authentication info exists for user, create it
2023 if(!isSingleplayer() &&
2024 g_settings->getBool("disallow_empty_password") &&
2025 std::string(given_password) == ""){
2026 actionstream<<"Server: "<<playername
2027 <<" supplied empty password"<<std::endl;
2028 DenyAccess(peer_id, L"Empty passwords are "
2029 L"disallowed. Set a password and try again.");
2032 std::wstring raw_default_password =
2033 narrow_to_wide(g_settings->get("default_password"));
2034 std::string initial_password =
2035 translatePassword(playername, raw_default_password);
2037 // If default_password is empty, allow any initial password
2038 if (raw_default_password.length() == 0)
2039 initial_password = given_password;
2041 m_script->createAuth(playername, initial_password);
2044 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2047 actionstream<<"Server: "<<playername<<" cannot be authenticated"
2048 <<" (auth handler does not work?)"<<std::endl;
2049 DenyAccess(peer_id, L"Not allowed to login");
2053 if(given_password != checkpwd){
2054 actionstream<<"Server: "<<playername<<" supplied wrong password"
2056 DenyAccess(peer_id, L"Wrong password");
2061 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2063 // If failed, cancel
2064 if(playersao == NULL)
2066 RemotePlayer *player =
2067 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
2068 if(player && player->peer_id != 0){
2069 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2070 <<" (player allocated to an another client)"<<std::endl;
2071 DenyAccess(peer_id, L"Another client is connected with this "
2072 L"name. If your client closed unexpectedly, try again in "
2075 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2077 DenyAccess(peer_id, L"Could not allocate player.");
2083 Answer with a TOCLIENT_INIT
2086 SharedBuffer<u8> reply(2+1+6+8+4);
2087 writeU16(&reply[0], TOCLIENT_INIT);
2088 writeU8(&reply[2], deployed);
2089 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2090 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2091 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2094 m_con.Send(peer_id, 0, reply, true);
2098 Send complete position information
2100 SendMovePlayer(peer_id);
2105 if(command == TOSERVER_INIT2)
2107 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2108 <<peer_id<<std::endl;
2110 Player *player = m_env->getPlayer(peer_id);
2112 verbosestream<<"Server: TOSERVER_INIT2: "
2113 <<"Player not found; ignoring."<<std::endl;
2117 RemoteClient *client = getClient(peer_id);
2118 client->serialization_version =
2119 getClient(peer_id)->pending_serialization_version;
2122 Send some initialization data
2125 infostream<<"Server: Sending content to "
2126 <<getPlayerName(peer_id)<<std::endl;
2128 // Send player movement settings
2129 SendMovement(m_con, peer_id);
2131 // Send item definitions
2132 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2134 // Send node definitions
2135 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2137 // Send media announcement
2138 sendMediaAnnouncement(peer_id);
2141 SendPlayerPrivileges(peer_id);
2143 // Send inventory formspec
2144 SendPlayerInventoryFormspec(peer_id);
2147 UpdateCrafting(peer_id);
2148 SendInventory(peer_id);
2151 if(g_settings->getBool("enable_damage"))
2152 SendPlayerHP(peer_id);
2155 SendPlayerBreath(peer_id);
2157 // Send detached inventories
2158 sendDetachedInventories(peer_id);
2160 // Show death screen if necessary
2162 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2166 u16 time = m_env->getTimeOfDay();
2167 float time_speed = g_settings->getFloat("time_speed");
2168 SendTimeOfDay(peer_id, time, time_speed);
2171 // Note things in chat if not in simple singleplayer mode
2172 if(!m_simple_singleplayer_mode)
2174 // Send information about server to player in chat
2175 SendChatMessage(peer_id, getStatusString());
2177 // Send information about joining in chat
2179 std::wstring name = L"unknown";
2180 Player *player = m_env->getPlayer(peer_id);
2182 name = narrow_to_wide(player->getName());
2184 std::wstring message;
2187 message += L" joined the game.";
2188 BroadcastChatMessage(message);
2192 // Warnings about protocol version can be issued here
2193 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2195 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2196 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2203 std::ostringstream os(std::ios_base::binary);
2204 for(std::map<u16, RemoteClient*>::iterator
2205 i = m_clients.begin();
2206 i != m_clients.end(); ++i)
2208 RemoteClient *client = i->second;
2209 assert(client->peer_id == i->first);
2210 if(client->serialization_version == SER_FMT_VER_INVALID)
2213 Player *player = m_env->getPlayer(client->peer_id);
2216 // Get name of player
2217 os<<player->getName()<<" ";
2220 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
2221 <<os.str()<<std::endl;
2227 if(peer_ser_ver == SER_FMT_VER_INVALID)
2229 infostream<<"Server::ProcessData(): Cancelling: Peer"
2230 " serialization format invalid or not initialized."
2231 " Skipping incoming command="<<command<<std::endl;
2235 Player *player = m_env->getPlayer(peer_id);
2237 infostream<<"Server::ProcessData(): Cancelling: "
2238 "No player for peer_id="<<peer_id
2243 PlayerSAO *playersao = player->getPlayerSAO();
2244 if(playersao == NULL){
2245 infostream<<"Server::ProcessData(): Cancelling: "
2246 "No player object for peer_id="<<peer_id
2251 if(command == TOSERVER_PLAYERPOS)
2253 if(datasize < 2+12+12+4+4)
2257 v3s32 ps = readV3S32(&data[start+2]);
2258 v3s32 ss = readV3S32(&data[start+2+12]);
2259 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2260 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2262 if(datasize >= 2+12+12+4+4+4)
2263 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2264 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2265 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2266 pitch = wrapDegrees(pitch);
2267 yaw = wrapDegrees(yaw);
2269 player->setPosition(position);
2270 player->setSpeed(speed);
2271 player->setPitch(pitch);
2272 player->setYaw(yaw);
2273 player->keyPressed=keyPressed;
2274 player->control.up = (bool)(keyPressed&1);
2275 player->control.down = (bool)(keyPressed&2);
2276 player->control.left = (bool)(keyPressed&4);
2277 player->control.right = (bool)(keyPressed&8);
2278 player->control.jump = (bool)(keyPressed&16);
2279 player->control.aux1 = (bool)(keyPressed&32);
2280 player->control.sneak = (bool)(keyPressed&64);
2281 player->control.LMB = (bool)(keyPressed&128);
2282 player->control.RMB = (bool)(keyPressed&256);
2284 bool cheated = playersao->checkMovementCheat();
2287 m_script->on_cheat(playersao, "moved_too_fast");
2290 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2291 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2292 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2294 else if(command == TOSERVER_GOTBLOCKS)
2307 u16 count = data[2];
2308 for(u16 i=0; i<count; i++)
2310 if((s16)datasize < 2+1+(i+1)*6)
2311 throw con::InvalidIncomingDataException
2312 ("GOTBLOCKS length is too short");
2313 v3s16 p = readV3S16(&data[2+1+i*6]);
2314 /*infostream<<"Server: GOTBLOCKS ("
2315 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2316 RemoteClient *client = getClient(peer_id);
2317 client->GotBlock(p);
2320 else if(command == TOSERVER_DELETEDBLOCKS)
2333 u16 count = data[2];
2334 for(u16 i=0; i<count; i++)
2336 if((s16)datasize < 2+1+(i+1)*6)
2337 throw con::InvalidIncomingDataException
2338 ("DELETEDBLOCKS length is too short");
2339 v3s16 p = readV3S16(&data[2+1+i*6]);
2340 /*infostream<<"Server: DELETEDBLOCKS ("
2341 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2342 RemoteClient *client = getClient(peer_id);
2343 client->SetBlockNotSent(p);
2346 else if(command == TOSERVER_CLICK_OBJECT)
2348 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2351 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2353 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2356 else if(command == TOSERVER_GROUND_ACTION)
2358 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2362 else if(command == TOSERVER_RELEASE)
2364 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2367 else if(command == TOSERVER_SIGNTEXT)
2369 infostream<<"Server: SIGNTEXT not supported anymore"
2373 else if(command == TOSERVER_SIGNNODETEXT)
2375 infostream<<"Server: SIGNNODETEXT not supported anymore"
2379 else if(command == TOSERVER_INVENTORY_ACTION)
2381 // Strip command and create a stream
2382 std::string datastring((char*)&data[2], datasize-2);
2383 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2384 std::istringstream is(datastring, std::ios_base::binary);
2386 InventoryAction *a = InventoryAction::deSerialize(is);
2389 infostream<<"TOSERVER_INVENTORY_ACTION: "
2390 <<"InventoryAction::deSerialize() returned NULL"
2395 // If something goes wrong, this player is to blame
2396 RollbackScopeActor rollback_scope(m_rollback,
2397 std::string("player:")+player->getName());
2400 Note: Always set inventory not sent, to repair cases
2401 where the client made a bad prediction.
2405 Handle restrictions and special cases of the move action
2407 if(a->getType() == IACTION_MOVE)
2409 IMoveAction *ma = (IMoveAction*)a;
2411 ma->from_inv.applyCurrentPlayer(player->getName());
2412 ma->to_inv.applyCurrentPlayer(player->getName());
2414 setInventoryModified(ma->from_inv);
2415 setInventoryModified(ma->to_inv);
2417 bool from_inv_is_current_player =
2418 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2419 (ma->from_inv.name == player->getName());
2421 bool to_inv_is_current_player =
2422 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2423 (ma->to_inv.name == player->getName());
2426 Disable moving items out of craftpreview
2428 if(ma->from_list == "craftpreview")
2430 infostream<<"Ignoring IMoveAction from "
2431 <<(ma->from_inv.dump())<<":"<<ma->from_list
2432 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2433 <<" because src is "<<ma->from_list<<std::endl;
2439 Disable moving items into craftresult and craftpreview
2441 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2443 infostream<<"Ignoring IMoveAction from "
2444 <<(ma->from_inv.dump())<<":"<<ma->from_list
2445 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2446 <<" because dst is "<<ma->to_list<<std::endl;
2451 // Disallow moving items in elsewhere than player's inventory
2452 // if not allowed to interact
2453 if(!checkPriv(player->getName(), "interact") &&
2454 (!from_inv_is_current_player ||
2455 !to_inv_is_current_player))
2457 infostream<<"Cannot move outside of player's inventory: "
2458 <<"No interact privilege"<<std::endl;
2464 Handle restrictions and special cases of the drop action
2466 else if(a->getType() == IACTION_DROP)
2468 IDropAction *da = (IDropAction*)a;
2470 da->from_inv.applyCurrentPlayer(player->getName());
2472 setInventoryModified(da->from_inv);
2475 Disable dropping items out of craftpreview
2477 if(da->from_list == "craftpreview")
2479 infostream<<"Ignoring IDropAction from "
2480 <<(da->from_inv.dump())<<":"<<da->from_list
2481 <<" because src is "<<da->from_list<<std::endl;
2486 // Disallow dropping items if not allowed to interact
2487 if(!checkPriv(player->getName(), "interact"))
2494 Handle restrictions and special cases of the craft action
2496 else if(a->getType() == IACTION_CRAFT)
2498 ICraftAction *ca = (ICraftAction*)a;
2500 ca->craft_inv.applyCurrentPlayer(player->getName());
2502 setInventoryModified(ca->craft_inv);
2504 //bool craft_inv_is_current_player =
2505 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2506 // (ca->craft_inv.name == player->getName());
2508 // Disallow crafting if not allowed to interact
2509 if(!checkPriv(player->getName(), "interact"))
2511 infostream<<"Cannot craft: "
2512 <<"No interact privilege"<<std::endl;
2519 a->apply(this, playersao, this);
2523 else if(command == TOSERVER_CHAT_MESSAGE)
2531 std::string datastring((char*)&data[2], datasize-2);
2532 std::istringstream is(datastring, std::ios_base::binary);
2535 is.read((char*)buf, 2);
2536 u16 len = readU16(buf);
2538 std::wstring message;
2539 for(u16 i=0; i<len; i++)
2541 is.read((char*)buf, 2);
2542 message += (wchar_t)readU16(buf);
2545 // If something goes wrong, this player is to blame
2546 RollbackScopeActor rollback_scope(m_rollback,
2547 std::string("player:")+player->getName());
2549 // Get player name of this client
2550 std::wstring name = narrow_to_wide(player->getName());
2553 bool ate = m_script->on_chat_message(player->getName(),
2554 wide_to_narrow(message));
2555 // If script ate the message, don't proceed
2559 // Line to send to players
2561 // Whether to send to the player that sent the line
2562 bool send_to_sender = false;
2563 // Whether to send to other players
2564 bool send_to_others = false;
2566 // Commands are implemented in Lua, so only catch invalid
2567 // commands that were not "eaten" and send an error back
2568 if(message[0] == L'/')
2570 message = message.substr(1);
2571 send_to_sender = true;
2572 if(message.length() == 0)
2573 line += L"-!- Empty command";
2575 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2579 if(checkPriv(player->getName(), "shout")){
2584 send_to_others = true;
2586 line += L"-!- You don't have permission to shout.";
2587 send_to_sender = true;
2594 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2597 Send the message to clients
2599 for(std::map<u16, RemoteClient*>::iterator
2600 i = m_clients.begin();
2601 i != m_clients.end(); ++i)
2603 // Get client and check that it is valid
2604 RemoteClient *client = i->second;
2605 assert(client->peer_id == i->first);
2606 if(client->serialization_version == SER_FMT_VER_INVALID)
2610 bool sender_selected = (peer_id == client->peer_id);
2611 if(sender_selected == true && send_to_sender == false)
2613 if(sender_selected == false && send_to_others == false)
2616 SendChatMessage(client->peer_id, line);
2620 else if(command == TOSERVER_DAMAGE)
2622 std::string datastring((char*)&data[2], datasize-2);
2623 std::istringstream is(datastring, std::ios_base::binary);
2624 u8 damage = readU8(is);
2626 if(g_settings->getBool("enable_damage"))
2628 actionstream<<player->getName()<<" damaged by "
2629 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2632 playersao->setHP(playersao->getHP() - damage);
2634 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2637 if(playersao->m_hp_not_sent)
2638 SendPlayerHP(peer_id);
2641 else if(command == TOSERVER_BREATH)
2643 std::string datastring((char*)&data[2], datasize-2);
2644 std::istringstream is(datastring, std::ios_base::binary);
2645 u16 breath = readU16(is);
2646 playersao->setBreath(breath);
2648 else if(command == TOSERVER_PASSWORD)
2651 [0] u16 TOSERVER_PASSWORD
2652 [2] u8[28] old password
2653 [30] u8[28] new password
2656 if(datasize != 2+PASSWORD_SIZE*2)
2658 /*char password[PASSWORD_SIZE];
2659 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2660 password[i] = data[2+i];
2661 password[PASSWORD_SIZE-1] = 0;*/
2663 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2671 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2673 char c = data[2+PASSWORD_SIZE+i];
2679 if(!base64_is_valid(newpwd)){
2680 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2681 // Wrong old password supplied!!
2682 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2686 infostream<<"Server: Client requests a password change from "
2687 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2689 std::string playername = player->getName();
2691 std::string checkpwd;
2692 m_script->getAuth(playername, &checkpwd, NULL);
2694 if(oldpwd != checkpwd)
2696 infostream<<"Server: invalid old password"<<std::endl;
2697 // Wrong old password supplied!!
2698 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2702 bool success = m_script->setPassword(playername, newpwd);
2704 actionstream<<player->getName()<<" changes password"<<std::endl;
2705 SendChatMessage(peer_id, L"Password change successful.");
2707 actionstream<<player->getName()<<" tries to change password but "
2708 <<"it fails"<<std::endl;
2709 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2712 else if(command == TOSERVER_PLAYERITEM)
2717 u16 item = readU16(&data[2]);
2718 playersao->setWieldIndex(item);
2720 else if(command == TOSERVER_RESPAWN)
2722 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2725 RespawnPlayer(peer_id);
2727 actionstream<<player->getName()<<" respawns at "
2728 <<PP(player->getPosition()/BS)<<std::endl;
2730 // ActiveObject is added to environment in AsyncRunStep after
2731 // the previous addition has been succesfully removed
2733 else if(command == TOSERVER_REQUEST_MEDIA) {
2734 std::string datastring((char*)&data[2], datasize-2);
2735 std::istringstream is(datastring, std::ios_base::binary);
2737 std::list<MediaRequest> tosend;
2738 u16 numfiles = readU16(is);
2740 infostream<<"Sending "<<numfiles<<" files to "
2741 <<getPlayerName(peer_id)<<std::endl;
2742 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2744 for(int i = 0; i < numfiles; i++) {
2745 std::string name = deSerializeString(is);
2746 tosend.push_back(MediaRequest(name));
2747 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2751 sendRequestedMedia(peer_id, tosend);
2753 // Now the client should know about everything
2754 // (definitions and files)
2755 getClient(peer_id)->definitions_sent = true;
2757 else if(command == TOSERVER_RECEIVED_MEDIA) {
2758 getClient(peer_id)->definitions_sent = true;
2760 else if(command == TOSERVER_INTERACT)
2762 std::string datastring((char*)&data[2], datasize-2);
2763 std::istringstream is(datastring, std::ios_base::binary);
2769 [5] u32 length of the next item
2770 [9] serialized PointedThing
2772 0: start digging (from undersurface) or use
2773 1: stop digging (all parameters ignored)
2774 2: digging completed
2775 3: place block or item (to abovesurface)
2778 u8 action = readU8(is);
2779 u16 item_i = readU16(is);
2780 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2781 PointedThing pointed;
2782 pointed.deSerialize(tmp_is);
2784 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2785 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2789 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2790 <<" tried to interact, but is dead!"<<std::endl;
2794 v3f player_pos = playersao->getLastGoodPosition();
2796 // Update wielded item
2797 playersao->setWieldIndex(item_i);
2799 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2800 v3s16 p_under = pointed.node_undersurface;
2801 v3s16 p_above = pointed.node_abovesurface;
2803 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2804 ServerActiveObject *pointed_object = NULL;
2805 if(pointed.type == POINTEDTHING_OBJECT)
2807 pointed_object = m_env->getActiveObject(pointed.object_id);
2808 if(pointed_object == NULL)
2810 verbosestream<<"TOSERVER_INTERACT: "
2811 "pointed object is NULL"<<std::endl;
2817 v3f pointed_pos_under = player_pos;
2818 v3f pointed_pos_above = player_pos;
2819 if(pointed.type == POINTEDTHING_NODE)
2821 pointed_pos_under = intToFloat(p_under, BS);
2822 pointed_pos_above = intToFloat(p_above, BS);
2824 else if(pointed.type == POINTEDTHING_OBJECT)
2826 pointed_pos_under = pointed_object->getBasePosition();
2827 pointed_pos_above = pointed_pos_under;
2831 Check that target is reasonably close
2832 (only when digging or placing things)
2834 if(action == 0 || action == 2 || action == 3)
2836 float d = player_pos.getDistanceFrom(pointed_pos_under);
2837 float max_d = BS * 14; // Just some large enough value
2839 actionstream<<"Player "<<player->getName()
2840 <<" tried to access "<<pointed.dump()
2842 <<"d="<<d<<", max_d="<<max_d
2843 <<". ignoring."<<std::endl;
2844 // Re-send block to revert change on client-side
2845 RemoteClient *client = getClient(peer_id);
2846 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2847 client->SetBlockNotSent(blockpos);
2849 m_script->on_cheat(playersao, "interacted_too_far");
2856 Make sure the player is allowed to do it
2858 if(!checkPriv(player->getName(), "interact"))
2860 actionstream<<player->getName()<<" attempted to interact with "
2861 <<pointed.dump()<<" without 'interact' privilege"
2863 // Re-send block to revert change on client-side
2864 RemoteClient *client = getClient(peer_id);
2865 // Digging completed -> under
2867 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2868 client->SetBlockNotSent(blockpos);
2870 // Placement -> above
2872 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2873 client->SetBlockNotSent(blockpos);
2879 If something goes wrong, this player is to blame
2881 RollbackScopeActor rollback_scope(m_rollback,
2882 std::string("player:")+player->getName());
2885 0: start digging or punch object
2889 if(pointed.type == POINTEDTHING_NODE)
2892 NOTE: This can be used in the future to check if
2893 somebody is cheating, by checking the timing.
2895 MapNode n(CONTENT_IGNORE);
2898 n = m_env->getMap().getNode(p_under);
2900 catch(InvalidPositionException &e)
2902 infostream<<"Server: Not punching: Node not found."
2903 <<" Adding block to emerge queue."
2905 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2907 if(n.getContent() != CONTENT_IGNORE)
2908 m_script->node_on_punch(p_under, n, playersao);
2910 playersao->noCheatDigStart(p_under);
2912 else if(pointed.type == POINTEDTHING_OBJECT)
2914 // Skip if object has been removed
2915 if(pointed_object->m_removed)
2918 actionstream<<player->getName()<<" punches object "
2919 <<pointed.object_id<<": "
2920 <<pointed_object->getDescription()<<std::endl;
2922 ItemStack punchitem = playersao->getWieldedItem();
2923 ToolCapabilities toolcap =
2924 punchitem.getToolCapabilities(m_itemdef);
2925 v3f dir = (pointed_object->getBasePosition() -
2926 (player->getPosition() + player->getEyeOffset())
2928 float time_from_last_punch =
2929 playersao->resetTimeFromLastPunch();
2930 pointed_object->punch(dir, &toolcap, playersao,
2931 time_from_last_punch);
2939 else if(action == 1)
2944 2: Digging completed
2946 else if(action == 2)
2948 // Only digging of nodes
2949 if(pointed.type == POINTEDTHING_NODE)
2951 MapNode n(CONTENT_IGNORE);
2954 n = m_env->getMap().getNode(p_under);
2956 catch(InvalidPositionException &e)
2958 infostream<<"Server: Not finishing digging: Node not found."
2959 <<" Adding block to emerge queue."
2961 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2964 /* Cheat prevention */
2965 bool is_valid_dig = true;
2966 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2968 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2969 float nocheat_t = playersao->getNoCheatDigTime();
2970 playersao->noCheatDigEnd();
2971 // If player didn't start digging this, ignore dig
2972 if(nocheat_p != p_under){
2973 infostream<<"Server: NoCheat: "<<player->getName()
2974 <<" started digging "
2975 <<PP(nocheat_p)<<" and completed digging "
2976 <<PP(p_under)<<"; not digging."<<std::endl;
2977 is_valid_dig = false;
2979 m_script->on_cheat(playersao, "finished_unknown_dig");
2981 // Get player's wielded item
2982 ItemStack playeritem;
2983 InventoryList *mlist = playersao->getInventory()->getList("main");
2985 playeritem = mlist->getItem(playersao->getWieldIndex());
2986 ToolCapabilities playeritem_toolcap =
2987 playeritem.getToolCapabilities(m_itemdef);
2988 // Get diggability and expected digging time
2989 DigParams params = getDigParams(m_nodedef->get(n).groups,
2990 &playeritem_toolcap);
2991 // If can't dig, try hand
2992 if(!params.diggable){
2993 const ItemDefinition &hand = m_itemdef->get("");
2994 const ToolCapabilities *tp = hand.tool_capabilities;
2996 params = getDigParams(m_nodedef->get(n).groups, tp);
2998 // If can't dig, ignore dig
2999 if(!params.diggable){
3000 infostream<<"Server: NoCheat: "<<player->getName()
3001 <<" completed digging "<<PP(p_under)
3002 <<", which is not diggable with tool. not digging."
3004 is_valid_dig = false;
3006 m_script->on_cheat(playersao, "dug_unbreakable");
3008 // Check digging time
3009 // If already invalidated, we don't have to
3011 // Well not our problem then
3013 // Clean and long dig
3014 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
3015 // All is good, but grab time from pool; don't care if
3016 // it's actually available
3017 playersao->getDigPool().grab(params.time);
3019 // Short or laggy dig
3020 // Try getting the time from pool
3021 else if(playersao->getDigPool().grab(params.time)){
3026 infostream<<"Server: NoCheat: "<<player->getName()
3027 <<" completed digging "<<PP(p_under)
3028 <<"too fast; not digging."<<std::endl;
3029 is_valid_dig = false;
3031 m_script->on_cheat(playersao, "dug_too_fast");
3035 /* Actually dig node */
3037 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3038 m_script->node_on_dig(p_under, n, playersao);
3040 // Send unusual result (that is, node not being removed)
3041 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3043 // Re-send block to revert change on client-side
3044 RemoteClient *client = getClient(peer_id);
3045 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3046 client->SetBlockNotSent(blockpos);
3052 3: place block or right-click object
3054 else if(action == 3)
3056 ItemStack item = playersao->getWieldedItem();
3058 // Reset build time counter
3059 if(pointed.type == POINTEDTHING_NODE &&
3060 item.getDefinition(m_itemdef).type == ITEM_NODE)
3061 getClient(peer_id)->m_time_from_building = 0.0;
3063 if(pointed.type == POINTEDTHING_OBJECT)
3065 // Right click object
3067 // Skip if object has been removed
3068 if(pointed_object->m_removed)
3071 actionstream<<player->getName()<<" right-clicks object "
3072 <<pointed.object_id<<": "
3073 <<pointed_object->getDescription()<<std::endl;
3076 pointed_object->rightClick(playersao);
3078 else if(m_script->item_OnPlace(
3079 item, playersao, pointed))
3081 // Placement was handled in lua
3083 // Apply returned ItemStack
3084 playersao->setWieldedItem(item);
3087 // If item has node placement prediction, always send the
3088 // blocks to make sure the client knows what exactly happened
3089 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3090 RemoteClient *client = getClient(peer_id);
3091 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3092 client->SetBlockNotSent(blockpos);
3093 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3094 if(blockpos2 != blockpos){
3095 client->SetBlockNotSent(blockpos2);
3103 else if(action == 4)
3105 ItemStack item = playersao->getWieldedItem();
3107 actionstream<<player->getName()<<" uses "<<item.name
3108 <<", pointing at "<<pointed.dump()<<std::endl;
3110 if(m_script->item_OnUse(
3111 item, playersao, pointed))
3113 // Apply returned ItemStack
3114 playersao->setWieldedItem(item);
3121 Catch invalid actions
3125 infostream<<"WARNING: Server: Invalid action "
3126 <<action<<std::endl;
3129 else if(command == TOSERVER_REMOVED_SOUNDS)
3131 std::string datastring((char*)&data[2], datasize-2);
3132 std::istringstream is(datastring, std::ios_base::binary);
3134 int num = readU16(is);
3135 for(int k=0; k<num; k++){
3136 s32 id = readS32(is);
3137 std::map<s32, ServerPlayingSound>::iterator i =
3138 m_playing_sounds.find(id);
3139 if(i == m_playing_sounds.end())
3141 ServerPlayingSound &psound = i->second;
3142 psound.clients.erase(peer_id);
3143 if(psound.clients.size() == 0)
3144 m_playing_sounds.erase(i++);
3147 else if(command == TOSERVER_NODEMETA_FIELDS)
3149 std::string datastring((char*)&data[2], datasize-2);
3150 std::istringstream is(datastring, std::ios_base::binary);
3152 v3s16 p = readV3S16(is);
3153 std::string formname = deSerializeString(is);
3154 int num = readU16(is);
3155 std::map<std::string, std::string> fields;
3156 for(int k=0; k<num; k++){
3157 std::string fieldname = deSerializeString(is);
3158 std::string fieldvalue = deSerializeLongString(is);
3159 fields[fieldname] = fieldvalue;
3162 // If something goes wrong, this player is to blame
3163 RollbackScopeActor rollback_scope(m_rollback,
3164 std::string("player:")+player->getName());
3166 // Check the target node for rollback data; leave others unnoticed
3167 RollbackNode rn_old(&m_env->getMap(), p, this);
3169 m_script->node_on_receive_fields(p, formname, fields,playersao);
3171 // Report rollback data
3172 RollbackNode rn_new(&m_env->getMap(), p, this);
3173 if(rollback() && rn_new != rn_old){
3174 RollbackAction action;
3175 action.setSetNode(p, rn_old, rn_new);
3176 rollback()->reportAction(action);
3179 else if(command == TOSERVER_INVENTORY_FIELDS)
3181 std::string datastring((char*)&data[2], datasize-2);
3182 std::istringstream is(datastring, std::ios_base::binary);
3184 std::string formname = deSerializeString(is);
3185 int num = readU16(is);
3186 std::map<std::string, std::string> fields;
3187 for(int k=0; k<num; k++){
3188 std::string fieldname = deSerializeString(is);
3189 std::string fieldvalue = deSerializeLongString(is);
3190 fields[fieldname] = fieldvalue;
3193 m_script->on_playerReceiveFields(playersao, formname, fields);
3197 infostream<<"Server::ProcessData(): Ignoring "
3198 "unknown command "<<command<<std::endl;
3202 catch(SendFailedException &e)
3204 errorstream<<"Server::ProcessData(): SendFailedException: "
3210 void Server::setTimeOfDay(u32 time)
3212 m_env->setTimeOfDay(time);
3213 m_time_of_day_send_timer = 0;
3216 void Server::onMapEditEvent(MapEditEvent *event)
3218 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3219 if(m_ignore_map_edit_events)
3221 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3223 MapEditEvent *e = event->clone();
3224 m_unsent_map_edit_queue.push_back(e);
3227 Inventory* Server::getInventory(const InventoryLocation &loc)
3230 case InventoryLocation::UNDEFINED:
3233 case InventoryLocation::CURRENT_PLAYER:
3236 case InventoryLocation::PLAYER:
3238 Player *player = m_env->getPlayer(loc.name.c_str());
3241 PlayerSAO *playersao = player->getPlayerSAO();
3244 return playersao->getInventory();
3247 case InventoryLocation::NODEMETA:
3249 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3252 return meta->getInventory();
3255 case InventoryLocation::DETACHED:
3257 if(m_detached_inventories.count(loc.name) == 0)
3259 return m_detached_inventories[loc.name];
3267 void Server::setInventoryModified(const InventoryLocation &loc)
3270 case InventoryLocation::UNDEFINED:
3273 case InventoryLocation::PLAYER:
3275 Player *player = m_env->getPlayer(loc.name.c_str());
3278 PlayerSAO *playersao = player->getPlayerSAO();
3281 playersao->m_inventory_not_sent = true;
3282 playersao->m_wielded_item_not_sent = true;
3285 case InventoryLocation::NODEMETA:
3287 v3s16 blockpos = getNodeBlockPos(loc.p);
3289 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3291 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3293 setBlockNotSent(blockpos);
3296 case InventoryLocation::DETACHED:
3298 sendDetachedInventoryToAll(loc.name);
3306 void Server::peerAdded(con::Peer *peer)
3308 DSTACK(__FUNCTION_NAME);
3309 verbosestream<<"Server::peerAdded(): peer->id="
3310 <<peer->id<<std::endl;
3313 c.type = PEER_ADDED;
3314 c.peer_id = peer->id;
3316 m_peer_change_queue.push_back(c);
3319 void Server::deletingPeer(con::Peer *peer, bool timeout)
3321 DSTACK(__FUNCTION_NAME);
3322 verbosestream<<"Server::deletingPeer(): peer->id="
3323 <<peer->id<<", timeout="<<timeout<<std::endl;
3326 c.type = PEER_REMOVED;
3327 c.peer_id = peer->id;
3328 c.timeout = timeout;
3329 m_peer_change_queue.push_back(c);
3336 void Server::SendMovement(con::Connection &con, u16 peer_id)
3338 DSTACK(__FUNCTION_NAME);
3339 std::ostringstream os(std::ios_base::binary);
3341 writeU16(os, TOCLIENT_MOVEMENT);
3342 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3343 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3344 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3345 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3346 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3347 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3348 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3349 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3350 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3351 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3352 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3353 writeF1000(os, g_settings->getFloat("movement_gravity"));
3356 std::string s = os.str();
3357 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3359 con.Send(peer_id, 0, data, true);
3362 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3364 DSTACK(__FUNCTION_NAME);
3365 std::ostringstream os(std::ios_base::binary);
3367 writeU16(os, TOCLIENT_HP);
3371 std::string s = os.str();
3372 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3374 con.Send(peer_id, 0, data, true);
3377 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3379 DSTACK(__FUNCTION_NAME);
3380 std::ostringstream os(std::ios_base::binary);
3382 writeU16(os, TOCLIENT_BREATH);
3383 writeU16(os, breath);
3386 std::string s = os.str();
3387 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3389 con.Send(peer_id, 0, data, true);
3392 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3393 const std::wstring &reason)
3395 DSTACK(__FUNCTION_NAME);
3396 std::ostringstream os(std::ios_base::binary);
3398 writeU16(os, TOCLIENT_ACCESS_DENIED);
3399 os<<serializeWideString(reason);
3402 std::string s = os.str();
3403 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3405 con.Send(peer_id, 0, data, true);
3408 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3409 bool set_camera_point_target, v3f camera_point_target)
3411 DSTACK(__FUNCTION_NAME);
3412 std::ostringstream os(std::ios_base::binary);
3414 writeU16(os, TOCLIENT_DEATHSCREEN);
3415 writeU8(os, set_camera_point_target);
3416 writeV3F1000(os, camera_point_target);
3419 std::string s = os.str();
3420 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3422 con.Send(peer_id, 0, data, true);
3425 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3426 IItemDefManager *itemdef, u16 protocol_version)
3428 DSTACK(__FUNCTION_NAME);
3429 std::ostringstream os(std::ios_base::binary);
3433 u32 length of the next item
3434 zlib-compressed serialized ItemDefManager
3436 writeU16(os, TOCLIENT_ITEMDEF);
3437 std::ostringstream tmp_os(std::ios::binary);
3438 itemdef->serialize(tmp_os, protocol_version);
3439 std::ostringstream tmp_os2(std::ios::binary);
3440 compressZlib(tmp_os.str(), tmp_os2);
3441 os<<serializeLongString(tmp_os2.str());
3444 std::string s = os.str();
3445 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3446 <<"): size="<<s.size()<<std::endl;
3447 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3449 con.Send(peer_id, 0, data, true);
3452 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3453 INodeDefManager *nodedef, u16 protocol_version)
3455 DSTACK(__FUNCTION_NAME);
3456 std::ostringstream os(std::ios_base::binary);
3460 u32 length of the next item
3461 zlib-compressed serialized NodeDefManager
3463 writeU16(os, TOCLIENT_NODEDEF);
3464 std::ostringstream tmp_os(std::ios::binary);
3465 nodedef->serialize(tmp_os, protocol_version);
3466 std::ostringstream tmp_os2(std::ios::binary);
3467 compressZlib(tmp_os.str(), tmp_os2);
3468 os<<serializeLongString(tmp_os2.str());
3471 std::string s = os.str();
3472 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3473 <<"): size="<<s.size()<<std::endl;
3474 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3476 con.Send(peer_id, 0, data, true);
3480 Non-static send methods
3483 void Server::SendInventory(u16 peer_id)
3485 DSTACK(__FUNCTION_NAME);
3487 PlayerSAO *playersao = getPlayerSAO(peer_id);
3490 playersao->m_inventory_not_sent = false;
3496 std::ostringstream os;
3497 playersao->getInventory()->serialize(os);
3499 std::string s = os.str();
3501 SharedBuffer<u8> data(s.size()+2);
3502 writeU16(&data[0], TOCLIENT_INVENTORY);
3503 memcpy(&data[2], s.c_str(), s.size());
3506 m_con.Send(peer_id, 0, data, true);
3509 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3511 DSTACK(__FUNCTION_NAME);
3513 std::ostringstream os(std::ios_base::binary);
3517 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3518 os.write((char*)buf, 2);
3521 writeU16(buf, message.size());
3522 os.write((char*)buf, 2);
3525 for(u32 i=0; i<message.size(); i++)
3529 os.write((char*)buf, 2);
3533 std::string s = os.str();
3534 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3536 m_con.Send(peer_id, 0, data, true);
3539 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3540 const std::string formname)
3542 DSTACK(__FUNCTION_NAME);
3544 std::ostringstream os(std::ios_base::binary);
3548 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3549 os.write((char*)buf, 2);
3550 os<<serializeLongString(formspec);
3551 os<<serializeString(formname);
3554 std::string s = os.str();
3555 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3557 m_con.Send(peer_id, 0, data, true);
3560 // Spawns a particle on peer with peer_id
3561 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3562 float expirationtime, float size, bool collisiondetection,
3563 std::string texture)
3565 DSTACK(__FUNCTION_NAME);
3567 std::ostringstream os(std::ios_base::binary);
3568 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3569 writeV3F1000(os, pos);
3570 writeV3F1000(os, velocity);
3571 writeV3F1000(os, acceleration);
3572 writeF1000(os, expirationtime);
3573 writeF1000(os, size);
3574 writeU8(os, collisiondetection);
3575 os<<serializeLongString(texture);
3578 std::string s = os.str();
3579 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3581 m_con.Send(peer_id, 0, data, true);
3584 // Spawns a particle on all peers
3585 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3586 float expirationtime, float size, bool collisiondetection,
3587 std::string texture)
3589 for(std::map<u16, RemoteClient*>::iterator
3590 i = m_clients.begin();
3591 i != m_clients.end(); i++)
3593 // Get client and check that it is valid
3594 RemoteClient *client = i->second;
3595 assert(client->peer_id == i->first);
3596 if(client->serialization_version == SER_FMT_VER_INVALID)
3599 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3600 expirationtime, size, collisiondetection, texture);
3604 // Adds a ParticleSpawner on peer with peer_id
3605 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3606 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3607 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3609 DSTACK(__FUNCTION_NAME);
3611 std::ostringstream os(std::ios_base::binary);
3612 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3614 writeU16(os, amount);
3615 writeF1000(os, spawntime);
3616 writeV3F1000(os, minpos);
3617 writeV3F1000(os, maxpos);
3618 writeV3F1000(os, minvel);
3619 writeV3F1000(os, maxvel);
3620 writeV3F1000(os, minacc);
3621 writeV3F1000(os, maxacc);
3622 writeF1000(os, minexptime);
3623 writeF1000(os, maxexptime);
3624 writeF1000(os, minsize);
3625 writeF1000(os, maxsize);
3626 writeU8(os, collisiondetection);
3627 os<<serializeLongString(texture);
3631 std::string s = os.str();
3632 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3634 m_con.Send(peer_id, 0, data, true);
3637 // Adds a ParticleSpawner on all peers
3638 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3639 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3640 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3642 for(std::map<u16, RemoteClient*>::iterator
3643 i = m_clients.begin();
3644 i != m_clients.end(); i++)
3646 // Get client and check that it is valid
3647 RemoteClient *client = i->second;
3648 assert(client->peer_id == i->first);
3649 if(client->serialization_version == SER_FMT_VER_INVALID)
3652 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3653 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3654 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3658 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3660 DSTACK(__FUNCTION_NAME);
3662 std::ostringstream os(std::ios_base::binary);
3663 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3668 std::string s = os.str();
3669 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3671 m_con.Send(peer_id, 0, data, true);
3674 void Server::SendDeleteParticleSpawnerAll(u32 id)
3676 for(std::map<u16, RemoteClient*>::iterator
3677 i = m_clients.begin();
3678 i != m_clients.end(); i++)
3680 // Get client and check that it is valid
3681 RemoteClient *client = i->second;
3682 assert(client->peer_id == i->first);
3683 if(client->serialization_version == SER_FMT_VER_INVALID)
3686 SendDeleteParticleSpawner(client->peer_id, id);
3690 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3692 std::ostringstream os(std::ios_base::binary);
3695 writeU16(os, TOCLIENT_HUDADD);
3697 writeU8(os, (u8)form->type);
3698 writeV2F1000(os, form->pos);
3699 os << serializeString(form->name);
3700 writeV2F1000(os, form->scale);
3701 os << serializeString(form->text);
3702 writeU32(os, form->number);
3703 writeU32(os, form->item);
3704 writeU32(os, form->dir);
3705 writeV2F1000(os, form->align);
3706 writeV2F1000(os, form->offset);
3709 std::string s = os.str();
3710 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3712 m_con.Send(peer_id, 0, data, true);
3715 void Server::SendHUDRemove(u16 peer_id, u32 id)
3717 std::ostringstream os(std::ios_base::binary);
3720 writeU16(os, TOCLIENT_HUDRM);
3724 std::string s = os.str();
3725 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3727 m_con.Send(peer_id, 0, data, true);
3730 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3732 std::ostringstream os(std::ios_base::binary);
3735 writeU16(os, TOCLIENT_HUDCHANGE);
3737 writeU8(os, (u8)stat);
3740 case HUD_STAT_SCALE:
3741 case HUD_STAT_ALIGN:
3742 case HUD_STAT_OFFSET:
3743 writeV2F1000(os, *(v2f *)value);
3747 os << serializeString(*(std::string *)value);
3749 case HUD_STAT_NUMBER:
3753 writeU32(os, *(u32 *)value);
3758 std::string s = os.str();
3759 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3761 m_con.Send(peer_id, 0, data, true);
3764 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3766 std::ostringstream os(std::ios_base::binary);
3769 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3770 writeU32(os, flags);
3774 std::string s = os.str();
3775 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3777 m_con.Send(peer_id, 0, data, true);
3780 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3782 std::ostringstream os(std::ios_base::binary);
3785 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3786 writeU16(os, param);
3787 os<<serializeString(value);
3790 std::string s = os.str();
3791 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3793 m_con.Send(peer_id, 0, data, true);
3796 void Server::BroadcastChatMessage(const std::wstring &message)
3798 for(std::map<u16, RemoteClient*>::iterator
3799 i = m_clients.begin();
3800 i != m_clients.end(); ++i)
3802 // Get client and check that it is valid
3803 RemoteClient *client = i->second;
3804 assert(client->peer_id == i->first);
3805 if(client->serialization_version == SER_FMT_VER_INVALID)
3808 SendChatMessage(client->peer_id, message);
3812 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3814 DSTACK(__FUNCTION_NAME);
3817 SharedBuffer<u8> data(2+2+4);
3818 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3819 writeU16(&data[2], time);
3820 writeF1000(&data[4], time_speed);
3823 m_con.Send(peer_id, 0, data, true);
3826 void Server::SendPlayerHP(u16 peer_id)
3828 DSTACK(__FUNCTION_NAME);
3829 PlayerSAO *playersao = getPlayerSAO(peer_id);
3831 playersao->m_hp_not_sent = false;
3832 SendHP(m_con, peer_id, playersao->getHP());
3834 // Send to other clients
3835 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3836 ActiveObjectMessage aom(playersao->getId(), true, str);
3837 playersao->m_messages_out.push_back(aom);
3840 void Server::SendPlayerBreath(u16 peer_id)
3842 DSTACK(__FUNCTION_NAME);
3843 PlayerSAO *playersao = getPlayerSAO(peer_id);
3845 playersao->m_breath_not_sent = false;
3846 SendBreath(m_con, peer_id, playersao->getBreath());
3849 void Server::SendMovePlayer(u16 peer_id)
3851 DSTACK(__FUNCTION_NAME);
3852 Player *player = m_env->getPlayer(peer_id);
3855 std::ostringstream os(std::ios_base::binary);
3856 writeU16(os, TOCLIENT_MOVE_PLAYER);
3857 writeV3F1000(os, player->getPosition());
3858 writeF1000(os, player->getPitch());
3859 writeF1000(os, player->getYaw());
3862 v3f pos = player->getPosition();
3863 f32 pitch = player->getPitch();
3864 f32 yaw = player->getYaw();
3865 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3866 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3873 std::string s = os.str();
3874 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3876 m_con.Send(peer_id, 0, data, true);
3879 void Server::SendPlayerPrivileges(u16 peer_id)
3881 Player *player = m_env->getPlayer(peer_id);
3883 if(player->peer_id == PEER_ID_INEXISTENT)
3886 std::set<std::string> privs;
3887 m_script->getAuth(player->getName(), NULL, &privs);
3889 std::ostringstream os(std::ios_base::binary);
3890 writeU16(os, TOCLIENT_PRIVILEGES);
3891 writeU16(os, privs.size());
3892 for(std::set<std::string>::const_iterator i = privs.begin();
3893 i != privs.end(); i++){
3894 os<<serializeString(*i);
3898 std::string s = os.str();
3899 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3901 m_con.Send(peer_id, 0, data, true);
3904 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3906 Player *player = m_env->getPlayer(peer_id);
3908 if(player->peer_id == PEER_ID_INEXISTENT)
3911 std::ostringstream os(std::ios_base::binary);
3912 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3913 os<<serializeLongString(player->inventory_formspec);
3916 std::string s = os.str();
3917 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3919 m_con.Send(peer_id, 0, data, true);
3922 s32 Server::playSound(const SimpleSoundSpec &spec,
3923 const ServerSoundParams ¶ms)
3925 // Find out initial position of sound
3926 bool pos_exists = false;
3927 v3f pos = params.getPos(m_env, &pos_exists);
3928 // If position is not found while it should be, cancel sound
3929 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3931 // Filter destination clients
3932 std::set<RemoteClient*> dst_clients;
3933 if(params.to_player != "")
3935 Player *player = m_env->getPlayer(params.to_player.c_str());
3937 infostream<<"Server::playSound: Player \""<<params.to_player
3938 <<"\" not found"<<std::endl;
3941 if(player->peer_id == PEER_ID_INEXISTENT){
3942 infostream<<"Server::playSound: Player \""<<params.to_player
3943 <<"\" not connected"<<std::endl;
3946 RemoteClient *client = getClient(player->peer_id);
3947 dst_clients.insert(client);
3951 for(std::map<u16, RemoteClient*>::iterator
3952 i = m_clients.begin(); i != m_clients.end(); ++i)
3954 RemoteClient *client = i->second;
3955 Player *player = m_env->getPlayer(client->peer_id);
3959 if(player->getPosition().getDistanceFrom(pos) >
3960 params.max_hear_distance)
3963 dst_clients.insert(client);
3966 if(dst_clients.size() == 0)
3969 s32 id = m_next_sound_id++;
3970 // The sound will exist as a reference in m_playing_sounds
3971 m_playing_sounds[id] = ServerPlayingSound();
3972 ServerPlayingSound &psound = m_playing_sounds[id];
3973 psound.params = params;
3974 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3975 i != dst_clients.end(); i++)
3976 psound.clients.insert((*i)->peer_id);
3978 std::ostringstream os(std::ios_base::binary);
3979 writeU16(os, TOCLIENT_PLAY_SOUND);
3981 os<<serializeString(spec.name);
3982 writeF1000(os, spec.gain * params.gain);
3983 writeU8(os, params.type);
3984 writeV3F1000(os, pos);
3985 writeU16(os, params.object);
3986 writeU8(os, params.loop);
3988 std::string s = os.str();
3989 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3991 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3992 i != dst_clients.end(); i++){
3994 m_con.Send((*i)->peer_id, 0, data, true);
3998 void Server::stopSound(s32 handle)
4000 // Get sound reference
4001 std::map<s32, ServerPlayingSound>::iterator i =
4002 m_playing_sounds.find(handle);
4003 if(i == m_playing_sounds.end())
4005 ServerPlayingSound &psound = i->second;
4007 std::ostringstream os(std::ios_base::binary);
4008 writeU16(os, TOCLIENT_STOP_SOUND);
4009 writeS32(os, handle);
4011 std::string s = os.str();
4012 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4014 for(std::set<u16>::iterator i = psound.clients.begin();
4015 i != psound.clients.end(); i++){
4017 m_con.Send(*i, 0, data, true);
4019 // Remove sound reference
4020 m_playing_sounds.erase(i);
4023 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4024 std::list<u16> *far_players, float far_d_nodes)
4026 float maxd = far_d_nodes*BS;
4027 v3f p_f = intToFloat(p, BS);
4031 SharedBuffer<u8> reply(replysize);
4032 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4033 writeS16(&reply[2], p.X);
4034 writeS16(&reply[4], p.Y);
4035 writeS16(&reply[6], p.Z);
4037 for(std::map<u16, RemoteClient*>::iterator
4038 i = m_clients.begin();
4039 i != m_clients.end(); ++i)
4041 // Get client and check that it is valid
4042 RemoteClient *client = i->second;
4043 assert(client->peer_id == i->first);
4044 if(client->serialization_version == SER_FMT_VER_INVALID)
4047 // Don't send if it's the same one
4048 if(client->peer_id == ignore_id)
4054 Player *player = m_env->getPlayer(client->peer_id);
4057 // If player is far away, only set modified blocks not sent
4058 v3f player_pos = player->getPosition();
4059 if(player_pos.getDistanceFrom(p_f) > maxd)
4061 far_players->push_back(client->peer_id);
4068 m_con.Send(client->peer_id, 0, reply, true);
4072 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4073 std::list<u16> *far_players, float far_d_nodes)
4075 float maxd = far_d_nodes*BS;
4076 v3f p_f = intToFloat(p, BS);
4078 for(std::map<u16, RemoteClient*>::iterator
4079 i = m_clients.begin();
4080 i != m_clients.end(); ++i)
4082 // Get client and check that it is valid
4083 RemoteClient *client = i->second;
4084 assert(client->peer_id == i->first);
4085 if(client->serialization_version == SER_FMT_VER_INVALID)
4088 // Don't send if it's the same one
4089 if(client->peer_id == ignore_id)
4095 Player *player = m_env->getPlayer(client->peer_id);
4098 // If player is far away, only set modified blocks not sent
4099 v3f player_pos = player->getPosition();
4100 if(player_pos.getDistanceFrom(p_f) > maxd)
4102 far_players->push_back(client->peer_id);
4109 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4110 SharedBuffer<u8> reply(replysize);
4111 writeU16(&reply[0], TOCLIENT_ADDNODE);
4112 writeS16(&reply[2], p.X);
4113 writeS16(&reply[4], p.Y);
4114 writeS16(&reply[6], p.Z);
4115 n.serialize(&reply[8], client->serialization_version);
4118 m_con.Send(client->peer_id, 0, reply, true);
4122 void Server::setBlockNotSent(v3s16 p)
4124 for(std::map<u16, RemoteClient*>::iterator
4125 i = m_clients.begin();
4126 i != m_clients.end(); ++i)
4128 RemoteClient *client = i->second;
4129 client->SetBlockNotSent(p);
4133 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4135 DSTACK(__FUNCTION_NAME);
4137 v3s16 p = block->getPos();
4141 bool completely_air = true;
4142 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4143 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4144 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4146 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4148 completely_air = false;
4149 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4154 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4156 infostream<<"[completely air] ";
4157 infostream<<std::endl;
4161 Create a packet with the block in the right format
4164 std::ostringstream os(std::ios_base::binary);
4165 block->serialize(os, ver, false);
4166 block->serializeNetworkSpecific(os, net_proto_version);
4167 std::string s = os.str();
4168 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4170 u32 replysize = 8 + blockdata.getSize();
4171 SharedBuffer<u8> reply(replysize);
4172 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4173 writeS16(&reply[2], p.X);
4174 writeS16(&reply[4], p.Y);
4175 writeS16(&reply[6], p.Z);
4176 memcpy(&reply[8], *blockdata, blockdata.getSize());
4178 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4179 <<": \tpacket size: "<<replysize<<std::endl;*/
4184 m_con.Send(peer_id, 1, reply, true);
4187 void Server::SendBlocks(float dtime)
4189 DSTACK(__FUNCTION_NAME);
4191 JMutexAutoLock envlock(m_env_mutex);
4192 JMutexAutoLock conlock(m_con_mutex);
4194 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4196 std::vector<PrioritySortedBlockTransfer> queue;
4198 s32 total_sending = 0;
4201 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4203 for(std::map<u16, RemoteClient*>::iterator
4204 i = m_clients.begin();
4205 i != m_clients.end(); ++i)
4207 RemoteClient *client = i->second;
4208 assert(client->peer_id == i->first);
4210 // If definitions and textures have not been sent, don't
4211 // send MapBlocks either
4212 if(!client->definitions_sent)
4215 total_sending += client->SendingCount();
4217 if(client->serialization_version == SER_FMT_VER_INVALID)
4220 client->GetNextBlocks(this, dtime, queue);
4225 // Lowest priority number comes first.
4226 // Lowest is most important.
4227 std::sort(queue.begin(), queue.end());
4229 for(u32 i=0; i<queue.size(); i++)
4231 //TODO: Calculate limit dynamically
4232 if(total_sending >= g_settings->getS32
4233 ("max_simultaneous_block_sends_server_total"))
4236 PrioritySortedBlockTransfer q = queue[i];
4238 MapBlock *block = NULL;
4241 block = m_env->getMap().getBlockNoCreate(q.pos);
4243 catch(InvalidPositionException &e)
4248 RemoteClient *client = getClientNoEx(q.peer_id);
4254 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4256 client->SentBlock(q.pos);
4262 void Server::fillMediaCache()
4264 DSTACK(__FUNCTION_NAME);
4266 infostream<<"Server: Calculating media file checksums"<<std::endl;
4268 // Collect all media file paths
4269 std::list<std::string> paths;
4270 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4271 i != m_mods.end(); i++){
4272 const ModSpec &mod = *i;
4273 paths.push_back(mod.path + DIR_DELIM + "textures");
4274 paths.push_back(mod.path + DIR_DELIM + "sounds");
4275 paths.push_back(mod.path + DIR_DELIM + "media");
4276 paths.push_back(mod.path + DIR_DELIM + "models");
4278 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4280 // Collect media file information from paths into cache
4281 for(std::list<std::string>::iterator i = paths.begin();
4282 i != paths.end(); i++)
4284 std::string mediapath = *i;
4285 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4286 for(u32 j=0; j<dirlist.size(); j++){
4287 if(dirlist[j].dir) // Ignode dirs
4289 std::string filename = dirlist[j].name;
4290 // If name contains illegal characters, ignore the file
4291 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4292 infostream<<"Server: ignoring illegal file name: \""
4293 <<filename<<"\""<<std::endl;
4296 // If name is not in a supported format, ignore it
4297 const char *supported_ext[] = {
4298 ".png", ".jpg", ".bmp", ".tga",
4299 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4301 ".x", ".b3d", ".md2", ".obj",
4304 if(removeStringEnd(filename, supported_ext) == ""){
4305 infostream<<"Server: ignoring unsupported file extension: \""
4306 <<filename<<"\""<<std::endl;
4309 // Ok, attempt to load the file and add to cache
4310 std::string filepath = mediapath + DIR_DELIM + filename;
4312 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4313 if(fis.good() == false){
4314 errorstream<<"Server::fillMediaCache(): Could not open \""
4315 <<filename<<"\" for reading"<<std::endl;
4318 std::ostringstream tmp_os(std::ios_base::binary);
4322 fis.read(buf, 1024);
4323 std::streamsize len = fis.gcount();
4324 tmp_os.write(buf, len);
4333 errorstream<<"Server::fillMediaCache(): Failed to read \""
4334 <<filename<<"\""<<std::endl;
4337 if(tmp_os.str().length() == 0){
4338 errorstream<<"Server::fillMediaCache(): Empty file \""
4339 <<filepath<<"\""<<std::endl;
4344 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4346 unsigned char *digest = sha1.getDigest();
4347 std::string sha1_base64 = base64_encode(digest, 20);
4348 std::string sha1_hex = hex_encode((char*)digest, 20);
4352 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4353 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4358 struct SendableMediaAnnouncement
4361 std::string sha1_digest;
4363 SendableMediaAnnouncement(const std::string name_="",
4364 const std::string sha1_digest_=""):
4366 sha1_digest(sha1_digest_)
4370 void Server::sendMediaAnnouncement(u16 peer_id)
4372 DSTACK(__FUNCTION_NAME);
4374 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4377 std::list<SendableMediaAnnouncement> file_announcements;
4379 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4380 i != m_media.end(); i++){
4382 file_announcements.push_back(
4383 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4387 std::ostringstream os(std::ios_base::binary);
4395 u16 length of sha1_digest
4400 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4401 writeU16(os, file_announcements.size());
4403 for(std::list<SendableMediaAnnouncement>::iterator
4404 j = file_announcements.begin();
4405 j != file_announcements.end(); ++j){
4406 os<<serializeString(j->name);
4407 os<<serializeString(j->sha1_digest);
4409 os<<serializeString(g_settings->get("remote_media"));
4412 std::string s = os.str();
4413 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4416 m_con.Send(peer_id, 0, data, true);
4419 struct SendableMedia
4425 SendableMedia(const std::string &name_="", const std::string path_="",
4426 const std::string &data_=""):
4433 void Server::sendRequestedMedia(u16 peer_id,
4434 const std::list<MediaRequest> &tosend)
4436 DSTACK(__FUNCTION_NAME);
4438 verbosestream<<"Server::sendRequestedMedia(): "
4439 <<"Sending files to client"<<std::endl;
4443 // Put 5kB in one bunch (this is not accurate)
4444 u32 bytes_per_bunch = 5000;
4446 std::vector< std::list<SendableMedia> > file_bunches;
4447 file_bunches.push_back(std::list<SendableMedia>());
4449 u32 file_size_bunch_total = 0;
4451 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4452 i != tosend.end(); ++i)
4454 if(m_media.find(i->name) == m_media.end()){
4455 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4456 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4460 //TODO get path + name
4461 std::string tpath = m_media[(*i).name].path;
4464 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4465 if(fis.good() == false){
4466 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4467 <<tpath<<"\" for reading"<<std::endl;
4470 std::ostringstream tmp_os(std::ios_base::binary);
4474 fis.read(buf, 1024);
4475 std::streamsize len = fis.gcount();
4476 tmp_os.write(buf, len);
4477 file_size_bunch_total += len;
4486 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4487 <<(*i).name<<"\""<<std::endl;
4490 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4491 <<tname<<"\""<<std::endl;*/
4493 file_bunches[file_bunches.size()-1].push_back(
4494 SendableMedia((*i).name, tpath, tmp_os.str()));
4496 // Start next bunch if got enough data
4497 if(file_size_bunch_total >= bytes_per_bunch){
4498 file_bunches.push_back(std::list<SendableMedia>());
4499 file_size_bunch_total = 0;
4504 /* Create and send packets */
4506 u32 num_bunches = file_bunches.size();
4507 for(u32 i=0; i<num_bunches; i++)
4509 std::ostringstream os(std::ios_base::binary);
4513 u16 total number of texture bunches
4514 u16 index of this bunch
4515 u32 number of files in this bunch
4524 writeU16(os, TOCLIENT_MEDIA);
4525 writeU16(os, num_bunches);
4527 writeU32(os, file_bunches[i].size());
4529 for(std::list<SendableMedia>::iterator
4530 j = file_bunches[i].begin();
4531 j != file_bunches[i].end(); ++j){
4532 os<<serializeString(j->name);
4533 os<<serializeLongString(j->data);
4537 std::string s = os.str();
4538 verbosestream<<"Server::sendRequestedMedia(): bunch "
4539 <<i<<"/"<<num_bunches
4540 <<" files="<<file_bunches[i].size()
4541 <<" size=" <<s.size()<<std::endl;
4542 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4544 m_con.Send(peer_id, 0, data, true);
4548 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4550 if(m_detached_inventories.count(name) == 0){
4551 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4554 Inventory *inv = m_detached_inventories[name];
4556 std::ostringstream os(std::ios_base::binary);
4557 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4558 os<<serializeString(name);
4562 std::string s = os.str();
4563 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4565 m_con.Send(peer_id, 0, data, true);
4568 void Server::sendDetachedInventoryToAll(const std::string &name)
4570 DSTACK(__FUNCTION_NAME);
4572 for(std::map<u16, RemoteClient*>::iterator
4573 i = m_clients.begin();
4574 i != m_clients.end(); ++i){
4575 RemoteClient *client = i->second;
4576 sendDetachedInventory(name, client->peer_id);
4580 void Server::sendDetachedInventories(u16 peer_id)
4582 DSTACK(__FUNCTION_NAME);
4584 for(std::map<std::string, Inventory*>::iterator
4585 i = m_detached_inventories.begin();
4586 i != m_detached_inventories.end(); i++){
4587 const std::string &name = i->first;
4588 //Inventory *inv = i->second;
4589 sendDetachedInventory(name, peer_id);
4597 void Server::DiePlayer(u16 peer_id)
4599 DSTACK(__FUNCTION_NAME);
4601 PlayerSAO *playersao = getPlayerSAO(peer_id);
4604 infostream<<"Server::DiePlayer(): Player "
4605 <<playersao->getPlayer()->getName()
4606 <<" dies"<<std::endl;
4608 playersao->setHP(0);
4610 // Trigger scripted stuff
4611 m_script->on_dieplayer(playersao);
4613 SendPlayerHP(peer_id);
4614 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4617 void Server::RespawnPlayer(u16 peer_id)
4619 DSTACK(__FUNCTION_NAME);
4621 PlayerSAO *playersao = getPlayerSAO(peer_id);
4624 infostream<<"Server::RespawnPlayer(): Player "
4625 <<playersao->getPlayer()->getName()
4626 <<" respawns"<<std::endl;
4628 playersao->setHP(PLAYER_MAX_HP);
4630 bool repositioned = m_script->on_respawnplayer(playersao);
4632 v3f pos = findSpawnPos(m_env->getServerMap());
4633 playersao->setPos(pos);
4637 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4639 DSTACK(__FUNCTION_NAME);
4641 SendAccessDenied(m_con, peer_id, reason);
4643 RemoteClient *client = getClientNoEx(peer_id);
4645 client->denied = true;
4647 // If there are way too many clients, get rid of denied new ones immediately
4648 if(m_clients.size() > 2 * g_settings->getU16("max_users")){
4649 verbosestream<<"Server: DenyAccess: Too many clients; getting rid of "
4650 <<"peer_id="<<peer_id<<" immediately"<<std::endl;
4651 // Delete peer to stop sending it data
4652 m_con.DeletePeer(peer_id);
4653 // Delete client also to stop block sends and other stuff
4654 DeleteClient(peer_id, CDR_DENY);
4658 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4660 DSTACK(__FUNCTION_NAME);
4663 std::map<u16, RemoteClient*>::iterator n;
4664 n = m_clients.find(peer_id);
4665 // The client may not exist; clients are immediately removed if their
4666 // access is denied, and this event occurs later then.
4667 if(n == m_clients.end())
4671 Mark objects to be not known by the client
4673 RemoteClient *client = n->second;
4675 for(std::set<u16>::iterator
4676 i = client->m_known_objects.begin();
4677 i != client->m_known_objects.end(); ++i)
4681 ServerActiveObject* obj = m_env->getActiveObject(id);
4683 if(obj && obj->m_known_by_count > 0)
4684 obj->m_known_by_count--;
4688 Clear references to playing sounds
4690 for(std::map<s32, ServerPlayingSound>::iterator
4691 i = m_playing_sounds.begin();
4692 i != m_playing_sounds.end();)
4694 ServerPlayingSound &psound = i->second;
4695 psound.clients.erase(peer_id);
4696 if(psound.clients.size() == 0)
4697 m_playing_sounds.erase(i++);
4702 Player *player = m_env->getPlayer(peer_id);
4704 // Collect information about leaving in chat
4705 std::wstring message;
4707 if(player != NULL && reason != CDR_DENY)
4709 std::wstring name = narrow_to_wide(player->getName());
4712 message += L" left the game.";
4713 if(reason == CDR_TIMEOUT)
4714 message += L" (timed out)";
4718 /* Run scripts and remove from environment */
4722 PlayerSAO *playersao = player->getPlayerSAO();
4725 m_script->on_leaveplayer(playersao);
4727 playersao->disconnected();
4735 if(player != NULL && reason != CDR_DENY)
4737 std::ostringstream os(std::ios_base::binary);
4738 for(std::map<u16, RemoteClient*>::iterator
4739 i = m_clients.begin();
4740 i != m_clients.end(); ++i)
4742 RemoteClient *client = i->second;
4743 assert(client->peer_id == i->first);
4744 if(client->serialization_version == SER_FMT_VER_INVALID)
4747 Player *player = m_env->getPlayer(client->peer_id);
4750 // Get name of player
4751 os<<player->getName()<<" ";
4754 actionstream<<player->getName()<<" "
4755 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4756 <<" List of players: "<<os.str()<<std::endl;
4761 delete m_clients[peer_id];
4762 m_clients.erase(peer_id);
4764 // Send leave chat message to all remaining clients
4765 if(message.length() != 0)
4766 BroadcastChatMessage(message);
4769 void Server::UpdateCrafting(u16 peer_id)
4771 DSTACK(__FUNCTION_NAME);
4773 Player* player = m_env->getPlayer(peer_id);
4776 // Get a preview for crafting
4778 getCraftingResult(&player->inventory, preview, false, this);
4780 // Put the new preview in
4781 InventoryList *plist = player->inventory.getList("craftpreview");
4783 assert(plist->getSize() >= 1);
4784 plist->changeItem(0, preview);
4787 RemoteClient* Server::getClient(u16 peer_id)
4789 RemoteClient *client = getClientNoEx(peer_id);
4791 throw ClientNotFoundException("Client not found");
4794 RemoteClient* Server::getClientNoEx(u16 peer_id)
4796 std::map<u16, RemoteClient*>::iterator n;
4797 n = m_clients.find(peer_id);
4798 // The client may not exist; clients are immediately removed if their
4799 // access is denied, and this event occurs later then.
4800 if(n == m_clients.end())
4805 std::string Server::getPlayerName(u16 peer_id)
4807 Player *player = m_env->getPlayer(peer_id);
4809 return "[id="+itos(peer_id)+"]";
4810 return player->getName();
4813 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4815 Player *player = m_env->getPlayer(peer_id);
4818 return player->getPlayerSAO();
4821 std::wstring Server::getStatusString()
4823 std::wostringstream os(std::ios_base::binary);
4826 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4828 os<<L", uptime="<<m_uptime.get();
4830 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4831 // Information about clients
4832 std::map<u16, RemoteClient*>::iterator i;
4835 for(i = m_clients.begin(), first = true;
4836 i != m_clients.end(); ++i)
4838 // Get client and check that it is valid
4839 RemoteClient *client = i->second;
4840 assert(client->peer_id == i->first);
4841 if(client->serialization_version == SER_FMT_VER_INVALID)
4844 Player *player = m_env->getPlayer(client->peer_id);
4845 // Get name of player
4846 std::wstring name = L"unknown";
4848 name = narrow_to_wide(player->getName());
4849 // Add name to information string
4857 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4858 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4859 if(g_settings->get("motd") != "")
4860 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4864 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4866 std::set<std::string> privs;
4867 m_script->getAuth(name, NULL, &privs);
4871 bool Server::checkPriv(const std::string &name, const std::string &priv)
4873 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4874 return (privs.count(priv) != 0);
4877 void Server::reportPrivsModified(const std::string &name)
4880 for(std::map<u16, RemoteClient*>::iterator
4881 i = m_clients.begin();
4882 i != m_clients.end(); ++i){
4883 RemoteClient *client = i->second;
4884 Player *player = m_env->getPlayer(client->peer_id);
4885 reportPrivsModified(player->getName());
4888 Player *player = m_env->getPlayer(name.c_str());
4891 SendPlayerPrivileges(player->peer_id);
4892 PlayerSAO *sao = player->getPlayerSAO();
4895 sao->updatePrivileges(
4896 getPlayerEffectivePrivs(name),
4901 void Server::reportInventoryFormspecModified(const std::string &name)
4903 Player *player = m_env->getPlayer(name.c_str());
4906 SendPlayerInventoryFormspec(player->peer_id);
4909 void Server::setIpBanned(const std::string &ip, const std::string &name)
4911 m_banmanager->add(ip, name);
4914 void Server::unsetIpBanned(const std::string &ip_or_name)
4916 m_banmanager->remove(ip_or_name);
4919 std::string Server::getBanDescription(const std::string &ip_or_name)
4921 return m_banmanager->getBanDescription(ip_or_name);
4924 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4926 Player *player = m_env->getPlayer(name);
4930 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4932 SendChatMessage(player->peer_id, msg);
4935 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4937 Player *player = m_env->getPlayer(playername);
4941 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4945 SendShowFormspecMessage(player->peer_id, formspec, formname);
4949 u32 Server::hudAdd(Player *player, HudElement *form) {
4953 u32 id = player->getFreeHudID();
4954 if (id < player->hud.size())
4955 player->hud[id] = form;
4957 player->hud.push_back(form);
4959 SendHUDAdd(player->peer_id, id, form);
4963 bool Server::hudRemove(Player *player, u32 id) {
4964 if (!player || id >= player->hud.size() || !player->hud[id])
4967 delete player->hud[id];
4968 player->hud[id] = NULL;
4970 SendHUDRemove(player->peer_id, id);
4974 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4978 SendHUDChange(player->peer_id, id, stat, data);
4982 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4986 SendHUDSetFlags(player->peer_id, flags, mask);
4990 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4993 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4996 std::ostringstream os(std::ios::binary);
4997 writeS32(os, hotbar_itemcount);
4998 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
5002 void Server::notifyPlayers(const std::wstring msg)
5004 BroadcastChatMessage(msg);
5007 void Server::spawnParticle(const char *playername, v3f pos,
5008 v3f velocity, v3f acceleration,
5009 float expirationtime, float size, bool
5010 collisiondetection, std::string texture)
5012 Player *player = m_env->getPlayer(playername);
5015 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
5016 expirationtime, size, collisiondetection, texture);
5019 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
5020 float expirationtime, float size,
5021 bool collisiondetection, std::string texture)
5023 SendSpawnParticleAll(pos, velocity, acceleration,
5024 expirationtime, size, collisiondetection, texture);
5027 u32 Server::addParticleSpawner(const char *playername,
5028 u16 amount, float spawntime,
5029 v3f minpos, v3f maxpos,
5030 v3f minvel, v3f maxvel,
5031 v3f minacc, v3f maxacc,
5032 float minexptime, float maxexptime,
5033 float minsize, float maxsize,
5034 bool collisiondetection, std::string texture)
5036 Player *player = m_env->getPlayer(playername);
5041 for(;;) // look for unused particlespawner id
5044 if (std::find(m_particlespawner_ids.begin(),
5045 m_particlespawner_ids.end(), id)
5046 == m_particlespawner_ids.end())
5048 m_particlespawner_ids.push_back(id);
5053 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5054 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5055 minexptime, maxexptime, minsize, maxsize,
5056 collisiondetection, texture, id);
5061 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5062 v3f minpos, v3f maxpos,
5063 v3f minvel, v3f maxvel,
5064 v3f minacc, v3f maxacc,
5065 float minexptime, float maxexptime,
5066 float minsize, float maxsize,
5067 bool collisiondetection, std::string texture)
5070 for(;;) // look for unused particlespawner id
5073 if (std::find(m_particlespawner_ids.begin(),
5074 m_particlespawner_ids.end(), id)
5075 == m_particlespawner_ids.end())
5077 m_particlespawner_ids.push_back(id);
5082 SendAddParticleSpawnerAll(amount, spawntime,
5083 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5084 minexptime, maxexptime, minsize, maxsize,
5085 collisiondetection, texture, id);
5090 void Server::deleteParticleSpawner(const char *playername, u32 id)
5092 Player *player = m_env->getPlayer(playername);
5096 m_particlespawner_ids.erase(
5097 std::remove(m_particlespawner_ids.begin(),
5098 m_particlespawner_ids.end(), id),
5099 m_particlespawner_ids.end());
5100 SendDeleteParticleSpawner(player->peer_id, id);
5103 void Server::deleteParticleSpawnerAll(u32 id)
5105 m_particlespawner_ids.erase(
5106 std::remove(m_particlespawner_ids.begin(),
5107 m_particlespawner_ids.end(), id),
5108 m_particlespawner_ids.end());
5109 SendDeleteParticleSpawnerAll(id);
5112 Inventory* Server::createDetachedInventory(const std::string &name)
5114 if(m_detached_inventories.count(name) > 0){
5115 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5116 delete m_detached_inventories[name];
5118 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5120 Inventory *inv = new Inventory(m_itemdef);
5122 m_detached_inventories[name] = inv;
5123 sendDetachedInventoryToAll(name);
5130 BoolScopeSet(bool *dst, bool val):
5133 m_orig_state = *m_dst;
5138 *m_dst = m_orig_state;
5145 // actions: time-reversed list
5146 // Return value: success/failure
5147 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5148 std::list<std::string> *log)
5150 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5151 ServerMap *map = (ServerMap*)(&m_env->getMap());
5152 // Disable rollback report sink while reverting
5153 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
5155 // Fail if no actions to handle
5156 if(actions.empty()){
5157 log->push_back("Nothing to do.");
5164 for(std::list<RollbackAction>::const_iterator
5165 i = actions.begin();
5166 i != actions.end(); i++)
5168 const RollbackAction &action = *i;
5170 bool success = action.applyRevert(map, this, this);
5173 std::ostringstream os;
5174 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5175 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5177 log->push_back(os.str());
5179 std::ostringstream os;
5180 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5181 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5183 log->push_back(os.str());
5187 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5188 <<" failed"<<std::endl;
5190 // Call it done if less than half failed
5191 return num_failed <= num_tried/2;
5194 // IGameDef interface
5196 IItemDefManager* Server::getItemDefManager()
5200 INodeDefManager* Server::getNodeDefManager()
5204 ICraftDefManager* Server::getCraftDefManager()
5208 ITextureSource* Server::getTextureSource()
5212 IShaderSource* Server::getShaderSource()
5216 u16 Server::allocateUnknownNodeId(const std::string &name)
5218 return m_nodedef->allocateDummy(name);
5220 ISoundManager* Server::getSoundManager()
5222 return &dummySoundManager;
5224 MtEventManager* Server::getEventManager()
5228 IRollbackReportSink* Server::getRollbackReportSink()
5230 if(!m_enable_rollback_recording)
5232 if(!m_rollback_sink_enabled)
5237 IWritableItemDefManager* Server::getWritableItemDefManager()
5241 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5245 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5250 const ModSpec* Server::getModSpec(const std::string &modname)
5252 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5253 i != m_mods.end(); i++){
5254 const ModSpec &mod = *i;
5255 if(mod.name == modname)
5260 void Server::getModNames(std::list<std::string> &modlist)
5262 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5264 modlist.push_back(i->name);
5267 std::string Server::getBuiltinLuaPath()
5269 return porting::path_share + DIR_DELIM + "builtin";
5272 v3f findSpawnPos(ServerMap &map)
5274 //return v3f(50,50,50)*BS;
5279 nodepos = v2s16(0,0);
5284 s16 water_level = map.m_mgparams->water_level;
5286 // Try to find a good place a few times
5287 for(s32 i=0; i<1000; i++)
5290 // We're going to try to throw the player to this position
5291 v2s16 nodepos2d = v2s16(
5292 -range + (myrand() % (range * 2)),
5293 -range + (myrand() % (range * 2)));
5295 // Get ground height at point
5296 s16 groundheight = map.findGroundLevel(nodepos2d);
5297 if (groundheight <= water_level) // Don't go underwater
5299 if (groundheight > water_level + 6) // Don't go to high places
5302 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5303 bool is_good = false;
5305 for (s32 i = 0; i < 10; i++) {
5306 v3s16 blockpos = getNodeBlockPos(nodepos);
5307 map.emergeBlock(blockpos, true);
5308 content_t c = map.getNodeNoEx(nodepos).getContent();
5309 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5311 if (air_count >= 2){
5319 // Found a good place
5320 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5326 return intToFloat(nodepos, BS);
5329 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5331 RemotePlayer *player = NULL;
5332 bool newplayer = false;
5335 Try to get an existing player
5337 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5339 // If player is already connected, cancel
5340 if(player != NULL && player->peer_id != 0)
5342 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5347 If player with the wanted peer_id already exists, cancel.
5349 if(m_env->getPlayer(peer_id) != NULL)
5351 infostream<<"emergePlayer(): Player with wrong name but same"
5352 " peer_id already exists"<<std::endl;
5357 Create a new player if it doesn't exist yet
5362 player = new RemotePlayer(this);
5363 player->updateName(name);
5365 /* Set player position */
5366 infostream<<"Server: Finding spawn place for player \""
5367 <<name<<"\""<<std::endl;
5368 v3f pos = findSpawnPos(m_env->getServerMap());
5369 player->setPosition(pos);
5371 /* Add player to environment */
5372 m_env->addPlayer(player);
5376 Create a new player active object
5378 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5379 getPlayerEffectivePrivs(player->getName()),
5382 /* Clean up old HUD elements from previous sessions */
5383 player->hud.clear();
5385 /* Add object to environment */
5386 m_env->addActiveObject(playersao);
5390 m_script->on_newplayer(playersao);
5392 m_script->on_joinplayer(playersao);
5397 void Server::handlePeerChange(PeerChange &c)
5399 JMutexAutoLock envlock(m_env_mutex);
5400 JMutexAutoLock conlock(m_con_mutex);
5402 if(c.type == PEER_ADDED)
5409 std::map<u16, RemoteClient*>::iterator n;
5410 n = m_clients.find(c.peer_id);
5411 // The client shouldn't already exist
5412 assert(n == m_clients.end());
5415 RemoteClient *client = new RemoteClient();
5416 client->peer_id = c.peer_id;
5417 m_clients[client->peer_id] = client;
5420 else if(c.type == PEER_REMOVED)
5426 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
5435 void Server::handlePeerChanges()
5437 while(m_peer_change_queue.size() > 0)
5439 PeerChange c = m_peer_change_queue.pop_front();
5441 verbosestream<<"Server: Handling peer change: "
5442 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5445 handlePeerChange(c);
5449 void dedicated_server_loop(Server &server, bool &kill)
5451 DSTACK(__FUNCTION_NAME);
5453 verbosestream<<"dedicated_server_loop()"<<std::endl;
5455 IntervalLimiter m_profiler_interval;
5459 float steplen = g_settings->getFloat("dedicated_server_step");
5460 // This is kind of a hack but can be done like this
5461 // because server.step() is very light
5463 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5464 sleep_ms((int)(steplen*1000.0));
5466 server.step(steplen);
5468 if(server.getShutdownRequested() || kill)
5470 infostream<<"Dedicated server quitting"<<std::endl;
5472 if(g_settings->getBool("server_announce") == true)
5473 ServerList::sendAnnounce("delete");
5481 float profiler_print_interval =
5482 g_settings->getFloat("profiler_print_interval");
5483 if(profiler_print_interval != 0)
5485 if(m_profiler_interval.step(steplen, profiler_print_interval))
5487 infostream<<"Profiler:"<<std::endl;
5488 g_profiler->print(infostream);
5489 g_profiler->clear();