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 "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "serverobject.h"
38 #include "genericobject.h"
42 #include "scripting_server.h"
47 #include "mapgen/mapgen.h"
48 #include "mapgen/mg_biome.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_sao.h"
52 #include "content/mods.h"
53 #include "modchannels.h"
54 #include "serverlist.h"
55 #include "util/string.h"
57 #include "util/serialize.h"
58 #include "util/thread.h"
59 #include "defaultsettings.h"
60 #include "server/mods.h"
61 #include "util/base64.h"
62 #include "util/sha1.h"
64 #include "database/database.h"
65 #include "chatmessage.h"
66 #include "chat_interface.h"
67 #include "remoteplayer.h"
69 class ClientNotFoundException : public BaseException
72 ClientNotFoundException(const char *s):
77 class ServerThread : public Thread
81 ServerThread(Server *server):
92 void *ServerThread::run()
94 BEGIN_DEBUG_EXCEPTION_HANDLER
96 m_server->AsyncRunStep(true);
98 while (!stopRequested()) {
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError(
112 "ServerThread::run Lua: " + std::string(e.what()));
116 END_DEBUG_EXCEPTION_HANDLER
121 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
123 if(pos_exists) *pos_exists = false;
128 if(pos_exists) *pos_exists = true;
133 ServerActiveObject *sao = env->getActiveObject(object);
136 if(pos_exists) *pos_exists = true;
137 return sao->getBasePosition(); }
142 void Server::ShutdownState::reset()
146 should_reconnect = false;
147 is_requested = false;
150 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
154 should_reconnect = reconnect;
157 void Server::ShutdownState::tick(float dtime, Server *server)
163 static const float shutdown_msg_times[] =
165 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
168 // Automated messages
169 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
170 for (float t : shutdown_msg_times) {
171 // If shutdown timer matches an automessage, shot it
172 if (m_timer > t && m_timer - dtime < t) {
173 std::wstring periodicMsg = getShutdownTimerMessage();
175 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
176 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
183 if (m_timer < 0.0f) {
189 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
191 std::wstringstream ws;
192 ws << L"*** Server shutting down in "
193 << duration_to_string(myround(m_timer)).c_str() << ".";
202 const std::string &path_world,
203 const SubgameSpec &gamespec,
204 bool simple_singleplayer_mode,
209 m_bind_addr(bind_addr),
210 m_path_world(path_world),
211 m_gamespec(gamespec),
212 m_simple_singleplayer_mode(simple_singleplayer_mode),
213 m_dedicated(dedicated),
214 m_async_fatal_error(""),
215 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
218 m_bind_addr.isIPv6(),
220 m_itemdef(createItemDefManager()),
221 m_nodedef(createNodeDefManager()),
222 m_craftdef(createCraftDefManager()),
223 m_thread(new ServerThread(this)),
227 m_modchannel_mgr(new ModChannelMgr())
229 m_lag = g_settings->getFloat("dedicated_server_step");
231 if (m_path_world.empty())
232 throw ServerError("Supplied empty world path");
234 if (!gamespec.isValid())
235 throw ServerError("Supplied invalid gamespec");
241 // Send shutdown message
242 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
243 L"*** Server shutting down"));
246 MutexAutoLock envlock(m_env_mutex);
248 infostream << "Server: Saving players" << std::endl;
249 m_env->saveLoadedPlayers();
251 infostream << "Server: Kicking players" << std::endl;
252 std::string kick_msg;
253 bool reconnect = false;
254 if (isShutdownRequested()) {
255 reconnect = m_shutdown_state.should_reconnect;
256 kick_msg = m_shutdown_state.message;
258 if (kick_msg.empty()) {
259 kick_msg = g_settings->get("kick_msg_shutdown");
261 m_env->saveLoadedPlayers(true);
262 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
263 kick_msg, reconnect);
266 actionstream << "Server: Shutting down" << std::endl;
268 // Do this before stopping the server in case mapgen callbacks need to access
269 // server-controlled resources (like ModStorages). Also do them before
270 // shutdown callbacks since they may modify state that is finalized in a
273 m_emerge->stopThreads();
276 MutexAutoLock envlock(m_env_mutex);
278 // Execute script shutdown hooks
279 infostream << "Executing shutdown hooks" << std::endl;
280 m_script->on_shutdown();
282 infostream << "Server: Saving environment metadata" << std::endl;
292 // Delete things in the reverse order of creation
301 // Deinitialize scripting
302 infostream << "Server: Deinitializing scripting" << std::endl;
305 // Delete detached inventories
306 for (auto &detached_inventory : m_detached_inventories) {
307 delete detached_inventory.second;
313 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
314 if (m_simple_singleplayer_mode)
315 infostream << " in simple singleplayer mode" << std::endl;
317 infostream << std::endl;
318 infostream << "- world: " << m_path_world << std::endl;
319 infostream << "- game: " << m_gamespec.path << std::endl;
321 // Create world if it doesn't exist
322 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
323 throw ServerError("Failed to initialize world");
325 // Create emerge manager
326 m_emerge = new EmergeManager(this);
328 // Create ban manager
329 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
330 m_banmanager = new BanManager(ban_path);
332 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
333 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
334 // complain about mods with unsatisfied dependencies
335 if (!m_modmgr->isConsistent()) {
336 m_modmgr->printUnsatisfiedModsError();
340 MutexAutoLock envlock(m_env_mutex);
342 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
343 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
345 // Initialize scripting
346 infostream << "Server: Initializing Lua" << std::endl;
348 m_script = new ServerScripting(this);
350 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
352 m_modmgr->loadMods(m_script);
354 // Read Textures and calculate sha1 sums
357 // Apply item aliases in the node definition manager
358 m_nodedef->updateAliases(m_itemdef);
360 // Apply texture overrides from texturepack/override.txt
361 std::vector<std::string> paths;
362 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
363 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
364 for (const std::string &path : paths)
365 m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
367 m_nodedef->setNodeRegistrationStatus(true);
369 // Perform pending node name resolutions
370 m_nodedef->runNodeResolveCallbacks();
372 // unmap node names for connected nodeboxes
373 m_nodedef->mapNodeboxConnections();
375 // init the recipe hashes to speed up crafting
376 m_craftdef->initHashes(this);
378 // Initialize Environment
379 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
381 m_clients.setEnv(m_env);
383 if (!servermap->settings_mgr.makeMapgenParams())
384 FATAL_ERROR("Couldn't create any mapgen type");
386 // Initialize mapgens
387 m_emerge->initMapgens(servermap->getMapgenParams());
389 if (g_settings->getBool("enable_rollback_recording")) {
390 // Create rollback manager
391 m_rollback = new RollbackManager(m_path_world, this);
394 // Give environment reference to scripting api
395 m_script->initializeEnvironment(m_env);
397 // Register us to receive map edit events
398 servermap->addEventReceiver(this);
402 m_liquid_transform_every = g_settings->getFloat("liquid_update");
403 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
404 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
405 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
410 infostream << "Starting server on " << m_bind_addr.serializeString()
411 << "..." << std::endl;
413 // Stop thread if already running
416 // Initialize connection
417 m_con->SetTimeoutMs(30);
418 m_con->Serve(m_bind_addr);
423 // ASCII art for the win!
425 << " .__ __ __ " << std::endl
426 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
427 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
428 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
429 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
430 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
431 actionstream << "World at [" << m_path_world << "]" << std::endl;
432 actionstream << "Server for gameid=\"" << m_gamespec.id
433 << "\" listening on " << m_bind_addr.serializeString() << ":"
434 << m_bind_addr.getPort() << "." << std::endl;
439 infostream<<"Server: Stopping and waiting threads"<<std::endl;
441 // Stop threads (set run=false first so both start stopping)
443 //m_emergethread.setRun(false);
445 //m_emergethread.stop();
447 infostream<<"Server: Threads stopped"<<std::endl;
450 void Server::step(float dtime)
456 MutexAutoLock lock(m_step_dtime_mutex);
457 m_step_dtime += dtime;
459 // Throw if fatal error occurred in thread
460 std::string async_err = m_async_fatal_error.get();
461 if (!async_err.empty()) {
462 if (!m_simple_singleplayer_mode) {
463 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
464 g_settings->get("kick_msg_crash"),
465 g_settings->getBool("ask_reconnect_on_crash"));
467 throw ServerError("AsyncErr: " + async_err);
471 void Server::AsyncRunStep(bool initial_step)
476 MutexAutoLock lock1(m_step_dtime_mutex);
477 dtime = m_step_dtime;
481 // Send blocks to clients
485 if((dtime < 0.001) && !initial_step)
488 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
491 MutexAutoLock lock1(m_step_dtime_mutex);
492 m_step_dtime -= dtime;
499 m_uptime.set(m_uptime.get() + dtime);
505 Update time of day and overall game time
507 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
510 Send to clients at constant intervals
513 m_time_of_day_send_timer -= dtime;
514 if(m_time_of_day_send_timer < 0.0) {
515 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
516 u16 time = m_env->getTimeOfDay();
517 float time_speed = g_settings->getFloat("time_speed");
518 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
522 MutexAutoLock lock(m_env_mutex);
523 // Figure out and report maximum lag to environment
524 float max_lag = m_env->getMaxLagEstimate();
525 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
527 if(dtime > 0.1 && dtime > max_lag * 2.0)
528 infostream<<"Server: Maximum lag peaked to "<<dtime
532 m_env->reportMaxLagEstimate(max_lag);
537 static const float map_timer_and_unload_dtime = 2.92;
538 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
540 MutexAutoLock lock(m_env_mutex);
541 // Run Map's timers and unload unused data
542 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
543 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
544 g_settings->getFloat("server_unload_unused_data_timeout"),
549 Listen to the admin chat, if available
552 if (!m_admin_chat->command_queue.empty()) {
553 MutexAutoLock lock(m_env_mutex);
554 while (!m_admin_chat->command_queue.empty()) {
555 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
556 handleChatInterfaceEvent(evt);
560 m_admin_chat->outgoing_queue.push_back(
561 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
568 /* Transform liquids */
569 m_liquid_transform_timer += dtime;
570 if(m_liquid_transform_timer >= m_liquid_transform_every)
572 m_liquid_transform_timer -= m_liquid_transform_every;
574 MutexAutoLock lock(m_env_mutex);
576 ScopeProfiler sp(g_profiler, "Server: liquid transform");
578 std::map<v3s16, MapBlock*> modified_blocks;
579 m_env->getMap().transformLiquids(modified_blocks, m_env);
582 Set the modified blocks unsent for all the clients
584 if (!modified_blocks.empty()) {
585 SetBlocksNotSent(modified_blocks);
588 m_clients.step(dtime);
590 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
592 // send masterserver announce
594 float &counter = m_masterserver_timer;
595 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
596 g_settings->getBool("server_announce")) {
597 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
598 ServerList::AA_START,
599 m_bind_addr.getPort(),
600 m_clients.getPlayerNames(),
602 m_env->getGameTime(),
605 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
615 Check added and deleted active objects
618 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
619 MutexAutoLock envlock(m_env_mutex);
622 const RemoteClientMap &clients = m_clients.getClientList();
623 ScopeProfiler sp(g_profiler, "Server: update objects within range");
625 for (const auto &client_it : clients) {
626 RemoteClient *client = client_it.second;
628 if (client->getState() < CS_DefinitionsSent)
631 // This can happen if the client times out somehow
632 if (!m_env->getPlayer(client->peer_id))
635 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
639 SendActiveObjectRemoveAdd(client, playersao);
643 // Save mod storages if modified
644 m_mod_storage_save_timer -= dtime;
645 if (m_mod_storage_save_timer <= 0.0f) {
646 infostream << "Saving registered mod storages." << std::endl;
647 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
648 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
649 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
650 if (it->second->isModified()) {
651 it->second->save(getModStoragePath());
661 MutexAutoLock envlock(m_env_mutex);
662 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
665 // Value = data sent by object
666 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
668 // Get active object messages from environment
670 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
674 std::vector<ActiveObjectMessage>* message_list = nullptr;
675 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
676 n = buffered_messages.find(aom.id);
677 if (n == buffered_messages.end()) {
678 message_list = new std::vector<ActiveObjectMessage>;
679 buffered_messages[aom.id] = message_list;
682 message_list = n->second;
684 message_list->push_back(aom);
688 const RemoteClientMap &clients = m_clients.getClientList();
689 // Route data to every client
690 for (const auto &client_it : clients) {
691 RemoteClient *client = client_it.second;
692 std::string reliable_data;
693 std::string unreliable_data;
694 // Go through all objects in message buffer
695 for (const auto &buffered_message : buffered_messages) {
696 // If object is not known by client, skip it
697 u16 id = buffered_message.first;
698 if (client->m_known_objects.find(id) == client->m_known_objects.end())
701 // Get message list of object
702 std::vector<ActiveObjectMessage>* list = buffered_message.second;
703 // Go through every message
704 for (const ActiveObjectMessage &aom : *list) {
705 // Compose the full new data with header
706 std::string new_data;
709 writeU16((u8*)&buf[0], aom.id);
710 new_data.append(buf, 2);
712 new_data += serializeString(aom.datastring);
713 // Add data to buffer
715 reliable_data += new_data;
717 unreliable_data += new_data;
721 reliable_data and unreliable_data are now ready.
724 if (!reliable_data.empty()) {
725 SendActiveObjectMessages(client->peer_id, reliable_data);
728 if (!unreliable_data.empty()) {
729 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
734 // Clear buffered_messages
735 for (auto &buffered_message : buffered_messages) {
736 delete buffered_message.second;
741 Send queued-for-sending map edit events.
744 // We will be accessing the environment
745 MutexAutoLock lock(m_env_mutex);
747 // Don't send too many at a time
750 // Single change sending is disabled if queue size is not small
751 bool disable_single_change_sending = false;
752 if(m_unsent_map_edit_queue.size() >= 4)
753 disable_single_change_sending = true;
755 int event_count = m_unsent_map_edit_queue.size();
757 // We'll log the amount of each
760 std::list<v3s16> node_meta_updates;
762 while (!m_unsent_map_edit_queue.empty()) {
763 MapEditEvent* event = m_unsent_map_edit_queue.front();
764 m_unsent_map_edit_queue.pop();
766 // Players far away from the change are stored here.
767 // Instead of sending the changes, MapBlocks are set not sent
769 std::unordered_set<u16> far_players;
771 switch (event->type) {
774 prof.add("MEET_ADDNODE", 1);
775 sendAddNode(event->p, event->n, &far_players,
776 disable_single_change_sending ? 5 : 30,
777 event->type == MEET_ADDNODE);
779 case MEET_REMOVENODE:
780 prof.add("MEET_REMOVENODE", 1);
781 sendRemoveNode(event->p, &far_players,
782 disable_single_change_sending ? 5 : 30);
784 case MEET_BLOCK_NODE_METADATA_CHANGED: {
785 verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
786 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
787 if (!event->is_private_change) {
788 // Don't send the change yet. Collect them to eliminate dupes.
789 node_meta_updates.remove(event->p);
790 node_meta_updates.push_back(event->p);
793 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
794 getNodeBlockPos(event->p))) {
795 block->raiseModified(MOD_STATE_WRITE_NEEDED,
796 MOD_REASON_REPORT_META_CHANGE);
801 infostream << "Server: MEET_OTHER" << std::endl;
802 prof.add("MEET_OTHER", 1);
803 for (const v3s16 &modified_block : event->modified_blocks) {
804 m_clients.markBlockposAsNotSent(modified_block);
808 prof.add("unknown", 1);
809 warningstream << "Server: Unknown MapEditEvent "
810 << ((u32)event->type) << std::endl;
815 Set blocks not sent to far players
817 if (!far_players.empty()) {
818 // Convert list format to that wanted by SetBlocksNotSent
819 std::map<v3s16, MapBlock*> modified_blocks2;
820 for (const v3s16 &modified_block : event->modified_blocks) {
821 modified_blocks2[modified_block] =
822 m_env->getMap().getBlockNoCreateNoEx(modified_block);
825 // Set blocks not sent
826 for (const u16 far_player : far_players) {
827 if (RemoteClient *client = getClient(far_player))
828 client->SetBlocksNotSent(modified_blocks2);
835 if (event_count >= 5) {
836 infostream << "Server: MapEditEvents:" << std::endl;
837 prof.print(infostream);
838 } else if (event_count != 0) {
839 verbosestream << "Server: MapEditEvents:" << std::endl;
840 prof.print(verbosestream);
843 // Send all metadata updates
844 if (node_meta_updates.size())
845 sendMetadataChanged(node_meta_updates);
849 Trigger emergethread (it somehow gets to a non-triggered but
850 bysy state sometimes)
853 float &counter = m_emergethread_trigger_timer;
855 if (counter >= 2.0) {
858 m_emerge->startThreads();
862 // Save map, players and auth stuff
864 float &counter = m_savemap_timer;
866 static thread_local const float save_interval =
867 g_settings->getFloat("server_map_save_interval");
868 if (counter >= save_interval) {
870 MutexAutoLock lock(m_env_mutex);
872 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
875 if (m_banmanager->isModified()) {
876 m_banmanager->save();
879 // Save changed parts of map
880 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
883 m_env->saveLoadedPlayers();
885 // Save environment metadata
890 m_shutdown_state.tick(dtime, this);
893 void Server::Receive()
895 session_t peer_id = 0;
898 m_con->Receive(&pkt);
899 peer_id = pkt.getPeerId();
901 } catch (const con::InvalidIncomingDataException &e) {
902 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
903 << e.what() << std::endl;
904 } catch (const SerializationError &e) {
905 infostream << "Server::Receive(): SerializationError: what()="
906 << e.what() << std::endl;
907 } catch (const ClientStateError &e) {
908 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
909 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
910 L"Try reconnecting or updating your client");
911 } catch (const con::PeerNotFoundException &e) {
916 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
918 std::string playername;
919 PlayerSAO *playersao = NULL;
922 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
924 playername = client->getName();
925 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
927 } catch (std::exception &e) {
933 RemotePlayer *player = m_env->getPlayer(playername.c_str());
936 if (!playersao || !player) {
937 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
938 actionstream << "Server: Failed to emerge player \"" << playername
939 << "\" (player allocated to an another client)" << std::endl;
940 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
941 L"name. If your client closed unexpectedly, try again in "
944 errorstream << "Server: " << playername << ": Failed to emerge player"
946 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
952 Send complete position information
954 SendMovePlayer(peer_id);
957 SendPlayerPrivileges(peer_id);
959 // Send inventory formspec
960 SendPlayerInventoryFormspec(peer_id);
963 SendInventory(playersao, false);
965 // Send HP or death screen
966 if (playersao->isDead())
967 SendDeathscreen(peer_id, false, v3f(0,0,0));
969 SendPlayerHPOrDie(playersao,
970 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
973 SendPlayerBreath(playersao);
975 Address addr = getPeerAddress(player->getPeerId());
976 std::string ip_str = addr.serializeString();
977 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
982 const std::vector<std::string> &names = m_clients.getPlayerNames();
984 actionstream << player->getName() << " joins game. List of players: ";
986 for (const std::string &name : names) {
987 actionstream << name << " ";
990 actionstream << player->getName() <<std::endl;
995 inline void Server::handleCommand(NetworkPacket *pkt)
997 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
998 (this->*opHandle.handler)(pkt);
1001 void Server::ProcessData(NetworkPacket *pkt)
1003 // Environment is locked first.
1004 MutexAutoLock envlock(m_env_mutex);
1006 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1007 u32 peer_id = pkt->getPeerId();
1010 Address address = getPeerAddress(peer_id);
1011 std::string addr_s = address.serializeString();
1013 if(m_banmanager->isIpBanned(addr_s)) {
1014 std::string ban_name = m_banmanager->getBanName(addr_s);
1015 infostream << "Server: A banned client tried to connect from "
1016 << addr_s << "; banned name was "
1017 << ban_name << std::endl;
1018 // This actually doesn't seem to transfer to the client
1019 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1020 + utf8_to_wide(ban_name));
1024 catch(con::PeerNotFoundException &e) {
1026 * no peer for this packet found
1027 * most common reason is peer timeout, e.g. peer didn't
1028 * respond for some time, your server was overloaded or
1031 infostream << "Server::ProcessData(): Canceling: peer "
1032 << peer_id << " not found" << std::endl;
1037 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1039 // Command must be handled into ToServerCommandHandler
1040 if (command >= TOSERVER_NUM_MSG_TYPES) {
1041 infostream << "Server: Ignoring unknown command "
1042 << command << std::endl;
1046 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1051 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1053 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1054 errorstream << "Server::ProcessData(): Cancelling: Peer"
1055 " serialization format invalid or not initialized."
1056 " Skipping incoming command=" << command << std::endl;
1060 /* Handle commands related to client startup */
1061 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1066 if (m_clients.getClientState(peer_id) < CS_Active) {
1067 if (command == TOSERVER_PLAYERPOS) return;
1069 errorstream << "Got packet command: " << command << " for peer id "
1070 << peer_id << " but client isn't active yet. Dropping packet "
1076 } catch (SendFailedException &e) {
1077 errorstream << "Server::ProcessData(): SendFailedException: "
1078 << "what=" << e.what()
1080 } catch (PacketError &e) {
1081 actionstream << "Server::ProcessData(): PacketError: "
1082 << "what=" << e.what()
1087 void Server::setTimeOfDay(u32 time)
1089 m_env->setTimeOfDay(time);
1090 m_time_of_day_send_timer = 0;
1093 void Server::onMapEditEvent(MapEditEvent *event)
1095 if (m_ignore_map_edit_events_area.contains(event->getArea()))
1097 MapEditEvent *e = event->clone();
1098 m_unsent_map_edit_queue.push(e);
1101 Inventory* Server::getInventory(const InventoryLocation &loc)
1104 case InventoryLocation::UNDEFINED:
1105 case InventoryLocation::CURRENT_PLAYER:
1107 case InventoryLocation::PLAYER:
1109 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1112 PlayerSAO *playersao = player->getPlayerSAO();
1115 return playersao->getInventory();
1118 case InventoryLocation::NODEMETA:
1120 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1123 return meta->getInventory();
1126 case InventoryLocation::DETACHED:
1128 if(m_detached_inventories.count(loc.name) == 0)
1130 return m_detached_inventories[loc.name];
1134 sanity_check(false); // abort
1140 void Server::setInventoryModified(const InventoryLocation &loc)
1143 case InventoryLocation::UNDEFINED:
1145 case InventoryLocation::PLAYER:
1148 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1153 player->setModified(true);
1154 player->inventory.setModified(true);
1155 // Updates are sent in ServerEnvironment::step()
1158 case InventoryLocation::NODEMETA:
1161 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1163 m_env->getMap().dispatchEvent(&event);
1166 case InventoryLocation::DETACHED:
1168 // Updates are sent in ServerEnvironment::step()
1172 sanity_check(false); // abort
1177 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1179 std::vector<session_t> clients = m_clients.getClientIDs();
1181 // Set the modified blocks unsent for all the clients
1182 for (const session_t client_id : clients) {
1183 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1184 client->SetBlocksNotSent(block);
1189 void Server::peerAdded(con::Peer *peer)
1191 verbosestream<<"Server::peerAdded(): peer->id="
1192 <<peer->id<<std::endl;
1194 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1197 void Server::deletingPeer(con::Peer *peer, bool timeout)
1199 verbosestream<<"Server::deletingPeer(): peer->id="
1200 <<peer->id<<", timeout="<<timeout<<std::endl;
1202 m_clients.event(peer->id, CSE_Disconnect);
1203 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1206 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1208 *retval = m_con->getPeerStat(peer_id,type);
1209 return *retval != -1;
1212 bool Server::getClientInfo(
1221 std::string* vers_string
1224 *state = m_clients.getClientState(peer_id);
1226 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1233 *uptime = client->uptime();
1234 *ser_vers = client->serialization_version;
1235 *prot_vers = client->net_proto_version;
1237 *major = client->getMajor();
1238 *minor = client->getMinor();
1239 *patch = client->getPatch();
1240 *vers_string = client->getPatch();
1247 void Server::handlePeerChanges()
1249 while(!m_peer_change_queue.empty())
1251 con::PeerChange c = m_peer_change_queue.front();
1252 m_peer_change_queue.pop();
1254 verbosestream<<"Server: Handling peer change: "
1255 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1260 case con::PEER_ADDED:
1261 m_clients.CreateClient(c.peer_id);
1264 case con::PEER_REMOVED:
1265 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1269 FATAL_ERROR("Invalid peer change event received!");
1275 void Server::printToConsoleOnly(const std::string &text)
1278 m_admin_chat->outgoing_queue.push_back(
1279 new ChatEventChat("", utf8_to_wide(text)));
1281 std::cout << text << std::endl;
1285 void Server::Send(NetworkPacket *pkt)
1287 Send(pkt->getPeerId(), pkt);
1290 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1292 m_clients.send(peer_id,
1293 clientCommandFactoryTable[pkt->getCommand()].channel,
1295 clientCommandFactoryTable[pkt->getCommand()].reliable);
1298 void Server::SendMovement(session_t peer_id)
1300 std::ostringstream os(std::ios_base::binary);
1302 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1304 pkt << g_settings->getFloat("movement_acceleration_default");
1305 pkt << g_settings->getFloat("movement_acceleration_air");
1306 pkt << g_settings->getFloat("movement_acceleration_fast");
1307 pkt << g_settings->getFloat("movement_speed_walk");
1308 pkt << g_settings->getFloat("movement_speed_crouch");
1309 pkt << g_settings->getFloat("movement_speed_fast");
1310 pkt << g_settings->getFloat("movement_speed_climb");
1311 pkt << g_settings->getFloat("movement_speed_jump");
1312 pkt << g_settings->getFloat("movement_liquid_fluidity");
1313 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1314 pkt << g_settings->getFloat("movement_liquid_sink");
1315 pkt << g_settings->getFloat("movement_gravity");
1320 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1322 if (playersao->isImmortal())
1325 session_t peer_id = playersao->getPeerID();
1326 bool is_alive = playersao->getHP() > 0;
1329 SendPlayerHP(peer_id);
1331 DiePlayer(peer_id, reason);
1334 void Server::SendHP(session_t peer_id, u16 hp)
1336 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1341 void Server::SendBreath(session_t peer_id, u16 breath)
1343 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1344 pkt << (u16) breath;
1348 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1349 const std::string &custom_reason, bool reconnect)
1351 assert(reason < SERVER_ACCESSDENIED_MAX);
1353 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1355 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1356 pkt << custom_reason;
1357 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1358 reason == SERVER_ACCESSDENIED_CRASH)
1359 pkt << custom_reason << (u8)reconnect;
1363 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1365 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1370 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1371 v3f camera_point_target)
1373 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1374 pkt << set_camera_point_target << camera_point_target;
1378 void Server::SendItemDef(session_t peer_id,
1379 IItemDefManager *itemdef, u16 protocol_version)
1381 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1385 u32 length of the next item
1386 zlib-compressed serialized ItemDefManager
1388 std::ostringstream tmp_os(std::ios::binary);
1389 itemdef->serialize(tmp_os, protocol_version);
1390 std::ostringstream tmp_os2(std::ios::binary);
1391 compressZlib(tmp_os.str(), tmp_os2);
1392 pkt.putLongString(tmp_os2.str());
1395 verbosestream << "Server: Sending item definitions to id(" << peer_id
1396 << "): size=" << pkt.getSize() << std::endl;
1401 void Server::SendNodeDef(session_t peer_id,
1402 const NodeDefManager *nodedef, u16 protocol_version)
1404 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1408 u32 length of the next item
1409 zlib-compressed serialized NodeDefManager
1411 std::ostringstream tmp_os(std::ios::binary);
1412 nodedef->serialize(tmp_os, protocol_version);
1413 std::ostringstream tmp_os2(std::ios::binary);
1414 compressZlib(tmp_os.str(), tmp_os2);
1416 pkt.putLongString(tmp_os2.str());
1419 verbosestream << "Server: Sending node definitions to id(" << peer_id
1420 << "): size=" << pkt.getSize() << std::endl;
1426 Non-static send methods
1429 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1431 RemotePlayer *player = sao->getPlayer();
1433 // Do not send new format to old clients
1434 incremental &= player->protocol_version >= 38;
1436 UpdateCrafting(player);
1442 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1444 std::ostringstream os(std::ios::binary);
1445 sao->getInventory()->serialize(os, incremental);
1446 sao->getInventory()->setModified(false);
1447 player->setModified(true);
1449 const std::string &s = os.str();
1450 pkt.putRawString(s.c_str(), s.size());
1454 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1456 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1458 u8 type = message.type;
1459 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1461 if (peer_id != PEER_ID_INEXISTENT) {
1462 RemotePlayer *player = m_env->getPlayer(peer_id);
1468 m_clients.sendToAll(&pkt);
1472 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1473 const std::string &formname)
1475 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1476 if (formspec.empty()){
1477 //the client should close the formspec
1478 //but make sure there wasn't another one open in meantime
1479 const auto it = m_formspec_state_data.find(peer_id);
1480 if (it != m_formspec_state_data.end() && it->second == formname) {
1481 m_formspec_state_data.erase(peer_id);
1483 pkt.putLongString("");
1485 m_formspec_state_data[peer_id] = formname;
1486 pkt.putLongString(formspec);
1493 // Spawns a particle on peer with peer_id
1494 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1495 v3f pos, v3f velocity, v3f acceleration,
1496 float expirationtime, float size, bool collisiondetection,
1497 bool collision_removal, bool object_collision,
1498 bool vertical, const std::string &texture,
1499 const struct TileAnimationParams &animation, u8 glow)
1501 static thread_local const float radius =
1502 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1504 if (peer_id == PEER_ID_INEXISTENT) {
1505 std::vector<session_t> clients = m_clients.getClientIDs();
1507 for (const session_t client_id : clients) {
1508 RemotePlayer *player = m_env->getPlayer(client_id);
1512 PlayerSAO *sao = player->getPlayerSAO();
1516 // Do not send to distant clients
1517 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1520 SendSpawnParticle(client_id, player->protocol_version,
1521 pos, velocity, acceleration,
1522 expirationtime, size, collisiondetection, collision_removal,
1523 object_collision, vertical, texture, animation, glow);
1528 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1530 pkt << pos << velocity << acceleration << expirationtime
1531 << size << collisiondetection;
1532 pkt.putLongString(texture);
1534 pkt << collision_removal;
1535 // This is horrible but required (why are there two ways to serialize pkts?)
1536 std::ostringstream os(std::ios_base::binary);
1537 animation.serialize(os, protocol_version);
1538 pkt.putRawString(os.str());
1540 pkt << object_collision;
1545 // Adds a ParticleSpawner on peer with peer_id
1546 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1547 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1548 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1549 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1550 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1551 const struct TileAnimationParams &animation, u8 glow)
1553 if (peer_id == PEER_ID_INEXISTENT) {
1554 // This sucks and should be replaced:
1555 std::vector<session_t> clients = m_clients.getClientIDs();
1556 for (const session_t client_id : clients) {
1557 RemotePlayer *player = m_env->getPlayer(client_id);
1560 SendAddParticleSpawner(client_id, player->protocol_version,
1561 amount, spawntime, minpos, maxpos,
1562 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1563 minsize, maxsize, collisiondetection, collision_removal,
1564 object_collision, attached_id, vertical, texture, id,
1570 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1572 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1573 << minacc << maxacc << minexptime << maxexptime << minsize
1574 << maxsize << collisiondetection;
1576 pkt.putLongString(texture);
1578 pkt << id << vertical;
1579 pkt << collision_removal;
1581 // This is horrible but required
1582 std::ostringstream os(std::ios_base::binary);
1583 animation.serialize(os, protocol_version);
1584 pkt.putRawString(os.str());
1586 pkt << object_collision;
1591 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1593 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1595 // Ugly error in this packet
1598 if (peer_id != PEER_ID_INEXISTENT)
1601 m_clients.sendToAll(&pkt);
1605 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1607 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1609 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1610 << form->text << form->number << form->item << form->dir
1611 << form->align << form->offset << form->world_pos << form->size;
1616 void Server::SendHUDRemove(session_t peer_id, u32 id)
1618 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1623 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1625 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1626 pkt << id << (u8) stat;
1630 case HUD_STAT_SCALE:
1631 case HUD_STAT_ALIGN:
1632 case HUD_STAT_OFFSET:
1633 pkt << *(v2f *) value;
1637 pkt << *(std::string *) value;
1639 case HUD_STAT_WORLD_POS:
1640 pkt << *(v3f *) value;
1643 pkt << *(v2s32 *) value;
1645 case HUD_STAT_NUMBER:
1649 pkt << *(u32 *) value;
1656 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1658 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1660 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1662 pkt << flags << mask;
1667 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1669 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1670 pkt << param << value;
1674 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1675 const std::string &type, const std::vector<std::string> ¶ms,
1678 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1679 pkt << bgcolor << type << (u16) params.size();
1681 for (const std::string ¶m : params)
1689 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1691 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1692 pkt << params.density << params.color_bright << params.color_ambient
1693 << params.height << params.thickness << params.speed;
1697 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1700 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1703 pkt << do_override << (u16) (ratio * 65535);
1708 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1710 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1711 pkt << time << time_speed;
1713 if (peer_id == PEER_ID_INEXISTENT) {
1714 m_clients.sendToAll(&pkt);
1721 void Server::SendPlayerHP(session_t peer_id)
1723 PlayerSAO *playersao = getPlayerSAO(peer_id);
1724 // In some rare case if the player is disconnected
1725 // while Lua call l_punch, for example, this can be NULL
1729 SendHP(peer_id, playersao->getHP());
1730 m_script->player_event(playersao,"health_changed");
1732 // Send to other clients
1733 std::string str = gob_cmd_punched(playersao->getHP());
1734 ActiveObjectMessage aom(playersao->getId(), true, str);
1735 playersao->m_messages_out.push(aom);
1738 void Server::SendPlayerBreath(PlayerSAO *sao)
1742 m_script->player_event(sao, "breath_changed");
1743 SendBreath(sao->getPeerID(), sao->getBreath());
1746 void Server::SendMovePlayer(session_t peer_id)
1748 RemotePlayer *player = m_env->getPlayer(peer_id);
1750 PlayerSAO *sao = player->getPlayerSAO();
1753 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1754 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1757 v3f pos = sao->getBasePosition();
1758 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1759 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1760 << " pitch=" << sao->getLookPitch()
1761 << " yaw=" << sao->getRotation().Y
1768 void Server::SendPlayerFov(session_t peer_id)
1770 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1, peer_id);
1772 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1773 pkt << fov_spec.fov << fov_spec.is_multiplier;
1778 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1779 f32 animation_speed)
1781 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1784 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1785 << animation_frames[3] << animation_speed;
1790 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1792 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1793 pkt << first << third;
1797 void Server::SendPlayerPrivileges(session_t peer_id)
1799 RemotePlayer *player = m_env->getPlayer(peer_id);
1801 if(player->getPeerId() == PEER_ID_INEXISTENT)
1804 std::set<std::string> privs;
1805 m_script->getAuth(player->getName(), NULL, &privs);
1807 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1808 pkt << (u16) privs.size();
1810 for (const std::string &priv : privs) {
1817 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1819 RemotePlayer *player = m_env->getPlayer(peer_id);
1821 if (player->getPeerId() == PEER_ID_INEXISTENT)
1824 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1825 pkt.putLongString(player->inventory_formspec);
1830 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1832 RemotePlayer *player = m_env->getPlayer(peer_id);
1834 if (player->getPeerId() == PEER_ID_INEXISTENT)
1837 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1838 pkt << player->formspec_prepend;
1842 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1844 // Radius inside which objects are active
1845 static thread_local const s16 radius =
1846 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1848 // Radius inside which players are active
1849 static thread_local const bool is_transfer_limited =
1850 g_settings->exists("unlimited_player_transfer_distance") &&
1851 !g_settings->getBool("unlimited_player_transfer_distance");
1853 static thread_local const s16 player_transfer_dist =
1854 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1856 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1857 radius : player_transfer_dist;
1859 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1863 std::queue<u16> removed_objects, added_objects;
1864 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1865 client->m_known_objects, removed_objects);
1866 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1867 client->m_known_objects, added_objects);
1869 int removed_count = removed_objects.size();
1870 int added_count = added_objects.size();
1872 if (removed_objects.empty() && added_objects.empty())
1878 // Handle removed objects
1879 writeU16((u8*)buf, removed_objects.size());
1880 data.append(buf, 2);
1881 while (!removed_objects.empty()) {
1883 u16 id = removed_objects.front();
1884 ServerActiveObject* obj = m_env->getActiveObject(id);
1886 // Add to data buffer for sending
1887 writeU16((u8*)buf, id);
1888 data.append(buf, 2);
1890 // Remove from known objects
1891 client->m_known_objects.erase(id);
1893 if (obj && obj->m_known_by_count > 0)
1894 obj->m_known_by_count--;
1896 removed_objects.pop();
1899 // Handle added objects
1900 writeU16((u8*)buf, added_objects.size());
1901 data.append(buf, 2);
1902 while (!added_objects.empty()) {
1904 u16 id = added_objects.front();
1905 ServerActiveObject* obj = m_env->getActiveObject(id);
1908 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1910 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
1912 type = obj->getSendType();
1914 // Add to data buffer for sending
1915 writeU16((u8*)buf, id);
1916 data.append(buf, 2);
1917 writeU8((u8*)buf, type);
1918 data.append(buf, 1);
1921 data.append(serializeLongString(
1922 obj->getClientInitializationData(client->net_proto_version)));
1924 data.append(serializeLongString(""));
1926 // Add to known objects
1927 client->m_known_objects.insert(id);
1930 obj->m_known_by_count++;
1932 added_objects.pop();
1935 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
1936 pkt.putRawString(data.c_str(), data.size());
1939 verbosestream << "Server::SendActiveObjectRemoveAdd: "
1940 << removed_count << " removed, " << added_count << " added, "
1941 << "packet size is " << pkt.getSize() << std::endl;
1944 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1947 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1948 datas.size(), peer_id);
1950 pkt.putRawString(datas.c_str(), datas.size());
1952 m_clients.send(pkt.getPeerId(),
1953 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1957 void Server::SendCSMRestrictionFlags(session_t peer_id)
1959 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1960 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1961 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1965 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
1967 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
1972 s32 Server::playSound(const SimpleSoundSpec &spec,
1973 const ServerSoundParams ¶ms)
1975 // Find out initial position of sound
1976 bool pos_exists = false;
1977 v3f pos = params.getPos(m_env, &pos_exists);
1978 // If position is not found while it should be, cancel sound
1979 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1982 // Filter destination clients
1983 std::vector<session_t> dst_clients;
1984 if(!params.to_player.empty()) {
1985 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1987 infostream<<"Server::playSound: Player \""<<params.to_player
1988 <<"\" not found"<<std::endl;
1991 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1992 infostream<<"Server::playSound: Player \""<<params.to_player
1993 <<"\" not connected"<<std::endl;
1996 dst_clients.push_back(player->getPeerId());
1998 std::vector<session_t> clients = m_clients.getClientIDs();
2000 for (const session_t client_id : clients) {
2001 RemotePlayer *player = m_env->getPlayer(client_id);
2005 PlayerSAO *sao = player->getPlayerSAO();
2010 if(sao->getBasePosition().getDistanceFrom(pos) >
2011 params.max_hear_distance)
2014 dst_clients.push_back(client_id);
2018 if(dst_clients.empty())
2022 s32 id = m_next_sound_id++;
2023 // The sound will exist as a reference in m_playing_sounds
2024 m_playing_sounds[id] = ServerPlayingSound();
2025 ServerPlayingSound &psound = m_playing_sounds[id];
2026 psound.params = params;
2029 float gain = params.gain * spec.gain;
2030 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2031 pkt << id << spec.name << gain
2032 << (u8) params.type << pos << params.object
2033 << params.loop << params.fade << params.pitch;
2035 // Backwards compability
2036 bool play_sound = gain > 0;
2038 for (const u16 dst_client : dst_clients) {
2039 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2040 psound.clients.insert(dst_client);
2041 m_clients.send(dst_client, 0, &pkt, true);
2046 void Server::stopSound(s32 handle)
2048 // Get sound reference
2049 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2050 m_playing_sounds.find(handle);
2051 if (i == m_playing_sounds.end())
2053 ServerPlayingSound &psound = i->second;
2055 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2058 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2059 si != psound.clients.end(); ++si) {
2061 m_clients.send(*si, 0, &pkt, true);
2063 // Remove sound reference
2064 m_playing_sounds.erase(i);
2067 void Server::fadeSound(s32 handle, float step, float gain)
2069 // Get sound reference
2070 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2071 m_playing_sounds.find(handle);
2072 if (i == m_playing_sounds.end())
2075 ServerPlayingSound &psound = i->second;
2076 psound.params.gain = gain;
2078 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2079 pkt << handle << step << gain;
2081 // Backwards compability
2082 bool play_sound = gain > 0;
2083 ServerPlayingSound compat_psound = psound;
2084 compat_psound.clients.clear();
2086 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2087 compat_pkt << handle;
2089 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2090 it != psound.clients.end();) {
2091 if (m_clients.getProtocolVersion(*it) >= 32) {
2093 m_clients.send(*it, 0, &pkt, true);
2096 compat_psound.clients.insert(*it);
2098 m_clients.send(*it, 0, &compat_pkt, true);
2099 psound.clients.erase(it++);
2103 // Remove sound reference
2104 if (!play_sound || psound.clients.empty())
2105 m_playing_sounds.erase(i);
2107 if (play_sound && !compat_psound.clients.empty()) {
2108 // Play new sound volume on older clients
2109 playSound(compat_psound.spec, compat_psound.params);
2113 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2116 float maxd = far_d_nodes * BS;
2117 v3f p_f = intToFloat(p, BS);
2118 v3s16 block_pos = getNodeBlockPos(p);
2120 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2123 std::vector<session_t> clients = m_clients.getClientIDs();
2126 for (session_t client_id : clients) {
2127 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2131 RemotePlayer *player = m_env->getPlayer(client_id);
2132 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2134 // If player is far away, only set modified blocks not sent
2135 if (!client->isBlockSent(block_pos) || (sao &&
2136 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2138 far_players->emplace(client_id);
2140 client->SetBlockNotSent(block_pos);
2145 m_clients.send(client_id, 0, &pkt, true);
2151 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2152 float far_d_nodes, bool remove_metadata)
2154 float maxd = far_d_nodes * BS;
2155 v3f p_f = intToFloat(p, BS);
2156 v3s16 block_pos = getNodeBlockPos(p);
2158 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2159 pkt << p << n.param0 << n.param1 << n.param2
2160 << (u8) (remove_metadata ? 0 : 1);
2162 std::vector<session_t> clients = m_clients.getClientIDs();
2165 for (session_t client_id : clients) {
2166 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2170 RemotePlayer *player = m_env->getPlayer(client_id);
2171 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2173 // If player is far away, only set modified blocks not sent
2174 if (!client->isBlockSent(block_pos) || (sao &&
2175 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2177 far_players->emplace(client_id);
2179 client->SetBlockNotSent(block_pos);
2184 m_clients.send(client_id, 0, &pkt, true);
2190 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2192 float maxd = far_d_nodes * BS;
2193 NodeMetadataList meta_updates_list(false);
2194 std::vector<session_t> clients = m_clients.getClientIDs();
2198 for (session_t i : clients) {
2199 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2203 ServerActiveObject *player = m_env->getActiveObject(i);
2204 v3f player_pos = player ? player->getBasePosition() : v3f();
2206 for (const v3s16 &pos : meta_updates) {
2207 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2212 v3s16 block_pos = getNodeBlockPos(pos);
2213 if (!client->isBlockSent(block_pos) || (player &&
2214 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2215 client->SetBlockNotSent(block_pos);
2219 // Add the change to send list
2220 meta_updates_list.set(pos, meta);
2222 if (meta_updates_list.size() == 0)
2225 // Send the meta changes
2226 std::ostringstream os(std::ios::binary);
2227 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2228 std::ostringstream oss(std::ios::binary);
2229 compressZlib(os.str(), oss);
2231 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2232 pkt.putLongString(oss.str());
2233 m_clients.send(i, 0, &pkt, true);
2235 meta_updates_list.clear();
2241 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2242 u16 net_proto_version)
2245 Create a packet with the block in the right format
2248 std::ostringstream os(std::ios_base::binary);
2249 block->serialize(os, ver, false);
2250 block->serializeNetworkSpecific(os);
2251 std::string s = os.str();
2253 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2255 pkt << block->getPos();
2256 pkt.putRawString(s.c_str(), s.size());
2260 void Server::SendBlocks(float dtime)
2262 MutexAutoLock envlock(m_env_mutex);
2263 //TODO check if one big lock could be faster then multiple small ones
2265 std::vector<PrioritySortedBlockTransfer> queue;
2267 u32 total_sending = 0;
2270 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2272 std::vector<session_t> clients = m_clients.getClientIDs();
2275 for (const session_t client_id : clients) {
2276 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2281 total_sending += client->getSendingCount();
2282 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2288 // Lowest priority number comes first.
2289 // Lowest is most important.
2290 std::sort(queue.begin(), queue.end());
2294 // Maximal total count calculation
2295 // The per-client block sends is halved with the maximal online users
2296 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2297 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2299 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2300 Map &map = m_env->getMap();
2302 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2303 if (total_sending >= max_blocks_to_send)
2306 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2310 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2315 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2316 client->net_proto_version);
2318 client->SentBlock(block_to_send.pos);
2324 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2326 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2331 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2332 if (!client || client->isBlockSent(blockpos)) {
2336 SendBlockNoLock(peer_id, block, client->serialization_version,
2337 client->net_proto_version);
2343 void Server::fillMediaCache()
2345 infostream<<"Server: Calculating media file checksums"<<std::endl;
2347 // Collect all media file paths
2348 std::vector<std::string> paths;
2349 m_modmgr->getModsMediaPaths(paths);
2350 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2351 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2353 // Collect media file information from paths into cache
2354 for (const std::string &mediapath : paths) {
2355 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2356 for (const fs::DirListNode &dln : dirlist) {
2357 if (dln.dir) // Ignode dirs
2359 std::string filename = dln.name;
2360 // If name contains illegal characters, ignore the file
2361 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2362 infostream<<"Server: ignoring illegal file name: \""
2363 << filename << "\"" << std::endl;
2366 // If name is not in a supported format, ignore it
2367 const char *supported_ext[] = {
2368 ".png", ".jpg", ".bmp", ".tga",
2369 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2371 ".x", ".b3d", ".md2", ".obj",
2372 // Custom translation file format
2376 if (removeStringEnd(filename, supported_ext).empty()){
2377 infostream << "Server: ignoring unsupported file extension: \""
2378 << filename << "\"" << std::endl;
2381 // Ok, attempt to load the file and add to cache
2382 std::string filepath;
2383 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2386 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2388 errorstream << "Server::fillMediaCache(): Could not open \""
2389 << filename << "\" for reading" << std::endl;
2392 std::ostringstream tmp_os(std::ios_base::binary);
2396 fis.read(buf, 1024);
2397 std::streamsize len = fis.gcount();
2398 tmp_os.write(buf, len);
2407 errorstream<<"Server::fillMediaCache(): Failed to read \""
2408 << filename << "\"" << std::endl;
2411 if(tmp_os.str().length() == 0) {
2412 errorstream << "Server::fillMediaCache(): Empty file \""
2413 << filepath << "\"" << std::endl;
2418 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2420 unsigned char *digest = sha1.getDigest();
2421 std::string sha1_base64 = base64_encode(digest, 20);
2422 std::string sha1_hex = hex_encode((char*)digest, 20);
2426 m_media[filename] = MediaInfo(filepath, sha1_base64);
2427 verbosestream << "Server: " << sha1_hex << " is " << filename
2433 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2435 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2439 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2442 std::string lang_suffix;
2443 lang_suffix.append(".").append(lang_code).append(".tr");
2444 for (const auto &i : m_media) {
2445 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2452 for (const auto &i : m_media) {
2453 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2455 pkt << i.first << i.second.sha1_digest;
2458 pkt << g_settings->get("remote_media");
2462 struct SendableMedia
2468 SendableMedia(const std::string &name_="", const std::string &path_="",
2469 const std::string &data_=""):
2476 void Server::sendRequestedMedia(session_t peer_id,
2477 const std::vector<std::string> &tosend)
2479 verbosestream<<"Server::sendRequestedMedia(): "
2480 <<"Sending files to client"<<std::endl;
2484 // Put 5kB in one bunch (this is not accurate)
2485 u32 bytes_per_bunch = 5000;
2487 std::vector< std::vector<SendableMedia> > file_bunches;
2488 file_bunches.emplace_back();
2490 u32 file_size_bunch_total = 0;
2492 for (const std::string &name : tosend) {
2493 if (m_media.find(name) == m_media.end()) {
2494 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2495 <<"unknown file \""<<(name)<<"\""<<std::endl;
2499 //TODO get path + name
2500 std::string tpath = m_media[name].path;
2503 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2505 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2506 <<tpath<<"\" for reading"<<std::endl;
2509 std::ostringstream tmp_os(std::ios_base::binary);
2513 fis.read(buf, 1024);
2514 std::streamsize len = fis.gcount();
2515 tmp_os.write(buf, len);
2516 file_size_bunch_total += len;
2525 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2526 <<name<<"\""<<std::endl;
2529 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2530 <<tname<<"\""<<std::endl;*/
2532 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2534 // Start next bunch if got enough data
2535 if(file_size_bunch_total >= bytes_per_bunch) {
2536 file_bunches.emplace_back();
2537 file_size_bunch_total = 0;
2542 /* Create and send packets */
2544 u16 num_bunches = file_bunches.size();
2545 for (u16 i = 0; i < num_bunches; i++) {
2548 u16 total number of texture bunches
2549 u16 index of this bunch
2550 u32 number of files in this bunch
2559 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2560 pkt << num_bunches << i << (u32) file_bunches[i].size();
2562 for (const SendableMedia &j : file_bunches[i]) {
2564 pkt.putLongString(j.data);
2567 verbosestream << "Server::sendRequestedMedia(): bunch "
2568 << i << "/" << num_bunches
2569 << " files=" << file_bunches[i].size()
2570 << " size=" << pkt.getSize() << std::endl;
2575 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2577 const auto &inv_it = m_detached_inventories.find(name);
2578 const auto &player_it = m_detached_inventories_player.find(name);
2580 if (player_it == m_detached_inventories_player.end() ||
2581 player_it->second.empty()) {
2582 // OK. Send to everyone
2585 return; // Mods are not done loading
2587 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2589 return; // Player is offline
2591 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2592 return; // Caller requested send to a different player, so don't send.
2594 peer_id = p->getPeerId();
2597 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2600 if (inv_it == m_detached_inventories.end()) {
2601 pkt << false; // Remove inventory
2603 pkt << true; // Update inventory
2605 // Serialization & NetworkPacket isn't a love story
2606 std::ostringstream os(std::ios_base::binary);
2607 inv_it->second->serialize(os);
2608 inv_it->second->setModified(false);
2610 const std::string &os_str = os.str();
2611 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2612 pkt.putRawString(os_str);
2615 if (peer_id == PEER_ID_INEXISTENT)
2616 m_clients.sendToAll(&pkt);
2621 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2623 for (const auto &detached_inventory : m_detached_inventories) {
2624 const std::string &name = detached_inventory.first;
2626 Inventory *inv = detached_inventory.second;
2627 if (!inv || !inv->checkModified())
2631 sendDetachedInventory(name, peer_id);
2639 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2641 PlayerSAO *playersao = getPlayerSAO(peer_id);
2642 // In some rare cases this can be NULL -- if the player is disconnected
2643 // when a Lua function modifies l_punch, for example
2647 infostream << "Server::DiePlayer(): Player "
2648 << playersao->getPlayer()->getName()
2649 << " dies" << std::endl;
2651 playersao->setHP(0, reason);
2652 playersao->clearParentAttachment();
2654 // Trigger scripted stuff
2655 m_script->on_dieplayer(playersao, reason);
2657 SendPlayerHP(peer_id);
2658 SendDeathscreen(peer_id, false, v3f(0,0,0));
2661 void Server::RespawnPlayer(session_t peer_id)
2663 PlayerSAO *playersao = getPlayerSAO(peer_id);
2666 infostream << "Server::RespawnPlayer(): Player "
2667 << playersao->getPlayer()->getName()
2668 << " respawns" << std::endl;
2670 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2671 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2672 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2674 bool repositioned = m_script->on_respawnplayer(playersao);
2675 if (!repositioned) {
2676 // setPos will send the new position to client
2677 playersao->setPos(findSpawnPos());
2680 SendPlayerHP(peer_id);
2684 void Server::DenySudoAccess(session_t peer_id)
2686 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2691 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2692 const std::string &str_reason, bool reconnect)
2694 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2696 m_clients.event(peer_id, CSE_SetDenied);
2697 DisconnectPeer(peer_id);
2701 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2702 const std::string &custom_reason)
2704 SendAccessDenied(peer_id, reason, custom_reason);
2705 m_clients.event(peer_id, CSE_SetDenied);
2706 DisconnectPeer(peer_id);
2709 // 13/03/15: remove this function when protocol version 25 will become
2710 // the minimum version for MT users, maybe in 1 year
2711 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2713 SendAccessDenied_Legacy(peer_id, reason);
2714 m_clients.event(peer_id, CSE_SetDenied);
2715 DisconnectPeer(peer_id);
2718 void Server::DisconnectPeer(session_t peer_id)
2720 m_modchannel_mgr->leaveAllChannels(peer_id);
2721 m_con->DisconnectPeer(peer_id);
2724 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2727 RemoteClient* client = getClient(peer_id, CS_Invalid);
2729 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2731 // Right now, the auth mechs don't change between login and sudo mode.
2732 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2733 client->allowed_sudo_mechs = sudo_auth_mechs;
2735 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2736 << g_settings->getFloat("dedicated_server_step")
2740 m_clients.event(peer_id, CSE_AuthAccept);
2742 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2744 // We only support SRP right now
2745 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2747 resp_pkt << sudo_auth_mechs;
2749 m_clients.event(peer_id, CSE_SudoSuccess);
2753 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2755 std::wstring message;
2758 Clear references to playing sounds
2760 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2761 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2762 ServerPlayingSound &psound = i->second;
2763 psound.clients.erase(peer_id);
2764 if (psound.clients.empty())
2765 m_playing_sounds.erase(i++);
2770 // clear formspec info so the next client can't abuse the current state
2771 m_formspec_state_data.erase(peer_id);
2773 RemotePlayer *player = m_env->getPlayer(peer_id);
2775 /* Run scripts and remove from environment */
2777 PlayerSAO *playersao = player->getPlayerSAO();
2780 playersao->clearChildAttachments();
2781 playersao->clearParentAttachment();
2783 // inform connected clients
2784 const std::string &player_name = player->getName();
2785 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2786 // (u16) 1 + std::string represents a vector serialization representation
2787 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2788 m_clients.sendToAll(¬ice);
2790 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2792 playersao->disconnected();
2799 if (player && reason != CDR_DENY) {
2800 std::ostringstream os(std::ios_base::binary);
2801 std::vector<session_t> clients = m_clients.getClientIDs();
2803 for (const session_t client_id : clients) {
2805 RemotePlayer *player = m_env->getPlayer(client_id);
2809 // Get name of player
2810 os << player->getName() << " ";
2813 std::string name = player->getName();
2814 actionstream << name << " "
2815 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2816 << " List of players: " << os.str() << std::endl;
2818 m_admin_chat->outgoing_queue.push_back(
2819 new ChatEventNick(CET_NICK_REMOVE, name));
2823 MutexAutoLock env_lock(m_env_mutex);
2824 m_clients.DeleteClient(peer_id);
2828 // Send leave chat message to all remaining clients
2829 if (!message.empty()) {
2830 SendChatMessage(PEER_ID_INEXISTENT,
2831 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2835 void Server::UpdateCrafting(RemotePlayer *player)
2837 InventoryList *clist = player->inventory.getList("craft");
2838 if (!clist || clist->getSize() == 0)
2841 if (!clist->checkModified()) {
2842 verbosestream << "Skip Server::UpdateCrafting(): list unmodified" << std::endl;
2846 // Get a preview for crafting
2848 InventoryLocation loc;
2849 loc.setPlayer(player->getName());
2850 std::vector<ItemStack> output_replacements;
2851 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2852 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2855 InventoryList *plist = player->inventory.getList("craftpreview");
2856 if (plist && plist->getSize() >= 1) {
2857 // Put the new preview in
2858 plist->changeItem(0, preview);
2862 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2864 if (evt->type == CET_NICK_ADD) {
2865 // The terminal informed us of its nick choice
2866 m_admin_nick = ((ChatEventNick *)evt)->nick;
2867 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2868 errorstream << "You haven't set up an account." << std::endl
2869 << "Please log in using the client as '"
2870 << m_admin_nick << "' with a secure password." << std::endl
2871 << "Until then, you can't execute admin tasks via the console," << std::endl
2872 << "and everybody can claim the user account instead of you," << std::endl
2873 << "giving them full control over this server." << std::endl;
2876 assert(evt->type == CET_CHAT);
2877 handleAdminChat((ChatEventChat *)evt);
2881 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2882 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2884 // If something goes wrong, this player is to blame
2885 RollbackScopeActor rollback_scope(m_rollback,
2886 std::string("player:") + name);
2888 if (g_settings->getBool("strip_color_codes"))
2889 wmessage = unescape_enriched(wmessage);
2892 switch (player->canSendChatMessage()) {
2893 case RPLAYER_CHATRESULT_FLOODING: {
2894 std::wstringstream ws;
2895 ws << L"You cannot send more messages. You are limited to "
2896 << g_settings->getFloat("chat_message_limit_per_10sec")
2897 << L" messages per 10 seconds.";
2900 case RPLAYER_CHATRESULT_KICK:
2901 DenyAccess_Legacy(player->getPeerId(),
2902 L"You have been kicked due to message flooding.");
2904 case RPLAYER_CHATRESULT_OK:
2907 FATAL_ERROR("Unhandled chat filtering result found.");
2911 if (m_max_chatmessage_length > 0
2912 && wmessage.length() > m_max_chatmessage_length) {
2913 return L"Your message exceed the maximum chat message limit set on the server. "
2914 L"It was refused. Send a shorter message";
2917 auto message = trim(wide_to_utf8(wmessage));
2918 if (message.find_first_of("\n\r") != std::wstring::npos) {
2919 return L"New lines are not permitted in chat messages";
2922 // Run script hook, exit if script ate the chat message
2923 if (m_script->on_chat_message(name, message))
2928 // Whether to send line to the player that sent the message, or to all players
2929 bool broadcast_line = true;
2931 if (check_shout_priv && !checkPriv(name, "shout")) {
2932 line += L"-!- You don't have permission to shout.";
2933 broadcast_line = false;
2935 line += narrow_to_wide(m_script->formatChatMessage(name,
2936 wide_to_narrow(wmessage)));
2940 Tell calling method to send the message to sender
2942 if (!broadcast_line)
2946 Send the message to others
2948 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2950 std::vector<session_t> clients = m_clients.getClientIDs();
2953 Send the message back to the inital sender
2954 if they are using protocol version >= 29
2957 session_t peer_id_to_avoid_sending =
2958 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2960 if (player && player->protocol_version >= 29)
2961 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2963 for (u16 cid : clients) {
2964 if (cid != peer_id_to_avoid_sending)
2965 SendChatMessage(cid, ChatMessage(line));
2970 void Server::handleAdminChat(const ChatEventChat *evt)
2972 std::string name = evt->nick;
2973 std::wstring wname = utf8_to_wide(name);
2974 std::wstring wmessage = evt->evt_msg;
2976 std::wstring answer = handleChat(name, wname, wmessage);
2978 // If asked to send answer to sender
2979 if (!answer.empty()) {
2980 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2984 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2986 RemoteClient *client = getClientNoEx(peer_id,state_min);
2988 throw ClientNotFoundException("Client not found");
2992 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2994 return m_clients.getClientNoEx(peer_id, state_min);
2997 std::string Server::getPlayerName(session_t peer_id)
2999 RemotePlayer *player = m_env->getPlayer(peer_id);
3001 return "[id="+itos(peer_id)+"]";
3002 return player->getName();
3005 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3007 RemotePlayer *player = m_env->getPlayer(peer_id);
3010 return player->getPlayerSAO();
3013 std::wstring Server::getStatusString()
3015 std::wostringstream os(std::ios_base::binary);
3016 os << L"# Server: ";
3018 os << L"version=" << narrow_to_wide(g_version_string);
3020 os << L", uptime=" << m_uptime.get();
3022 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3024 // Information about clients
3026 os << L", clients={";
3028 std::vector<session_t> clients = m_clients.getClientIDs();
3029 for (session_t client_id : clients) {
3030 RemotePlayer *player = m_env->getPlayer(client_id);
3032 // Get name of player
3033 std::wstring name = L"unknown";
3035 name = narrow_to_wide(player->getName());
3037 // Add name to information string
3048 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3049 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3051 if (!g_settings->get("motd").empty())
3052 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3057 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3059 std::set<std::string> privs;
3060 m_script->getAuth(name, NULL, &privs);
3064 bool Server::checkPriv(const std::string &name, const std::string &priv)
3066 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3067 return (privs.count(priv) != 0);
3070 void Server::reportPrivsModified(const std::string &name)
3073 std::vector<session_t> clients = m_clients.getClientIDs();
3074 for (const session_t client_id : clients) {
3075 RemotePlayer *player = m_env->getPlayer(client_id);
3076 reportPrivsModified(player->getName());
3079 RemotePlayer *player = m_env->getPlayer(name.c_str());
3082 SendPlayerPrivileges(player->getPeerId());
3083 PlayerSAO *sao = player->getPlayerSAO();
3086 sao->updatePrivileges(
3087 getPlayerEffectivePrivs(name),
3092 void Server::reportInventoryFormspecModified(const std::string &name)
3094 RemotePlayer *player = m_env->getPlayer(name.c_str());
3097 SendPlayerInventoryFormspec(player->getPeerId());
3100 void Server::reportFormspecPrependModified(const std::string &name)
3102 RemotePlayer *player = m_env->getPlayer(name.c_str());
3105 SendPlayerFormspecPrepend(player->getPeerId());
3108 void Server::setIpBanned(const std::string &ip, const std::string &name)
3110 m_banmanager->add(ip, name);
3113 void Server::unsetIpBanned(const std::string &ip_or_name)
3115 m_banmanager->remove(ip_or_name);
3118 std::string Server::getBanDescription(const std::string &ip_or_name)
3120 return m_banmanager->getBanDescription(ip_or_name);
3123 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3125 // m_env will be NULL if the server is initializing
3129 if (m_admin_nick == name && !m_admin_nick.empty()) {
3130 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3133 RemotePlayer *player = m_env->getPlayer(name);
3138 if (player->getPeerId() == PEER_ID_INEXISTENT)
3141 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3144 bool Server::showFormspec(const char *playername, const std::string &formspec,
3145 const std::string &formname)
3147 // m_env will be NULL if the server is initializing
3151 RemotePlayer *player = m_env->getPlayer(playername);
3155 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3159 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3164 u32 id = player->addHud(form);
3166 SendHUDAdd(player->getPeerId(), id, form);
3171 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3175 HudElement* todel = player->removeHud(id);
3182 SendHUDRemove(player->getPeerId(), id);
3186 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3191 SendHUDChange(player->getPeerId(), id, stat, data);
3195 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3200 SendHUDSetFlags(player->getPeerId(), flags, mask);
3201 player->hud_flags &= ~mask;
3202 player->hud_flags |= flags;
3204 PlayerSAO* playersao = player->getPlayerSAO();
3209 m_script->player_event(playersao, "hud_changed");
3213 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3218 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3221 player->setHotbarItemcount(hotbar_itemcount);
3222 std::ostringstream os(std::ios::binary);
3223 writeS32(os, hotbar_itemcount);
3224 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3228 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3233 player->setHotbarImage(name);
3234 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3237 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3242 player->setHotbarSelectedImage(name);
3243 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3246 Address Server::getPeerAddress(session_t peer_id)
3248 return m_con->GetPeerAddress(peer_id);
3251 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3252 v2s32 animation_frames[4], f32 frame_speed)
3254 sanity_check(player);
3255 player->setLocalAnimations(animation_frames, frame_speed);
3256 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3259 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3261 sanity_check(player);
3262 player->eye_offset_first = first;
3263 player->eye_offset_third = third;
3264 SendEyeOffset(player->getPeerId(), first, third);
3267 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3268 const std::string &type, const std::vector<std::string> ¶ms,
3271 sanity_check(player);
3272 player->setSky(bgcolor, type, params, clouds);
3273 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3276 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3278 sanity_check(player);
3279 player->setCloudParams(params);
3280 SendCloudParams(player->getPeerId(), params);
3283 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3289 player->overrideDayNightRatio(do_override, ratio);
3290 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3294 void Server::notifyPlayers(const std::wstring &msg)
3296 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3299 void Server::spawnParticle(const std::string &playername, v3f pos,
3300 v3f velocity, v3f acceleration,
3301 float expirationtime, float size, bool
3302 collisiondetection, bool collision_removal, bool object_collision,
3303 bool vertical, const std::string &texture,
3304 const struct TileAnimationParams &animation, u8 glow)
3306 // m_env will be NULL if the server is initializing
3310 session_t peer_id = PEER_ID_INEXISTENT;
3312 if (!playername.empty()) {
3313 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3316 peer_id = player->getPeerId();
3317 proto_ver = player->protocol_version;
3320 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3321 expirationtime, size, collisiondetection, collision_removal,
3322 object_collision, vertical, texture, animation, glow);
3325 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3326 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3327 float minexptime, float maxexptime, float minsize, float maxsize,
3328 bool collisiondetection, bool collision_removal, bool object_collision,
3329 ServerActiveObject *attached, bool vertical, const std::string &texture,
3330 const std::string &playername, const struct TileAnimationParams &animation,
3333 // m_env will be NULL if the server is initializing
3337 session_t peer_id = PEER_ID_INEXISTENT;
3339 if (!playername.empty()) {
3340 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3343 peer_id = player->getPeerId();
3344 proto_ver = player->protocol_version;
3347 u16 attached_id = attached ? attached->getId() : 0;
3350 if (attached_id == 0)
3351 id = m_env->addParticleSpawner(spawntime);
3353 id = m_env->addParticleSpawner(spawntime, attached_id);
3355 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3356 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3357 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3358 collision_removal, object_collision, attached_id, vertical,
3359 texture, id, animation, glow);
3364 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3366 // m_env will be NULL if the server is initializing
3368 throw ServerError("Can't delete particle spawners during initialisation!");
3370 session_t peer_id = PEER_ID_INEXISTENT;
3371 if (!playername.empty()) {
3372 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3375 peer_id = player->getPeerId();
3378 m_env->deleteParticleSpawner(id);
3379 SendDeleteParticleSpawner(peer_id, id);
3382 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3384 if(m_detached_inventories.count(name) > 0){
3385 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3386 delete m_detached_inventories[name];
3388 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3390 Inventory *inv = new Inventory(m_itemdef);
3392 m_detached_inventories[name] = inv;
3393 if (!player.empty())
3394 m_detached_inventories_player[name] = player;
3396 //TODO find a better way to do this
3397 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3401 bool Server::removeDetachedInventory(const std::string &name)
3403 const auto &inv_it = m_detached_inventories.find(name);
3404 if (inv_it == m_detached_inventories.end())
3407 delete inv_it->second;
3408 m_detached_inventories.erase(inv_it);
3410 if (!m_env) // Mods are not done loading
3413 const auto &player_it = m_detached_inventories_player.find(name);
3414 if (player_it != m_detached_inventories_player.end()) {
3415 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3417 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3418 sendDetachedInventory(name, player->getPeerId());
3420 m_detached_inventories_player.erase(player_it);
3422 // Notify all players about the change
3423 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3428 // actions: time-reversed list
3429 // Return value: success/failure
3430 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3431 std::list<std::string> *log)
3433 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3434 ServerMap *map = (ServerMap*)(&m_env->getMap());
3436 // Fail if no actions to handle
3437 if (actions.empty()) {
3439 log->push_back("Nothing to do.");
3446 for (const RollbackAction &action : actions) {
3448 bool success = action.applyRevert(map, this, this);
3451 std::ostringstream os;
3452 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3453 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3455 log->push_back(os.str());
3457 std::ostringstream os;
3458 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3459 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3461 log->push_back(os.str());
3465 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3466 <<" failed"<<std::endl;
3468 // Call it done if less than half failed
3469 return num_failed <= num_tried/2;
3472 // IGameDef interface
3474 IItemDefManager *Server::getItemDefManager()
3479 const NodeDefManager *Server::getNodeDefManager()
3484 ICraftDefManager *Server::getCraftDefManager()
3489 u16 Server::allocateUnknownNodeId(const std::string &name)
3491 return m_nodedef->allocateDummy(name);
3494 IWritableItemDefManager *Server::getWritableItemDefManager()
3499 NodeDefManager *Server::getWritableNodeDefManager()
3504 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3509 const std::vector<ModSpec> & Server::getMods() const
3511 return m_modmgr->getMods();
3514 const ModSpec *Server::getModSpec(const std::string &modname) const
3516 return m_modmgr->getModSpec(modname);
3519 void Server::getModNames(std::vector<std::string> &modlist)
3521 m_modmgr->getModNames(modlist);
3524 std::string Server::getBuiltinLuaPath()
3526 return porting::path_share + DIR_DELIM + "builtin";
3529 std::string Server::getModStoragePath() const
3531 return m_path_world + DIR_DELIM + "mod_storage";
3534 v3f Server::findSpawnPos()
3536 ServerMap &map = m_env->getServerMap();
3538 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3539 return nodeposf * BS;
3541 bool is_good = false;
3542 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3543 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3545 // Try to find a good place a few times
3546 for (s32 i = 0; i < 4000 && !is_good; i++) {
3547 s32 range = MYMIN(1 + i, range_max);
3548 // We're going to try to throw the player to this position
3549 v2s16 nodepos2d = v2s16(
3550 -range + (myrand() % (range * 2)),
3551 -range + (myrand() % (range * 2)));
3552 // Get spawn level at point
3553 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3554 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3555 // signify an unsuitable spawn position, or if outside limits.
3556 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3557 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3560 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3561 // Consecutive empty nodes
3564 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3565 // avoid obstructions in already-generated mapblocks.
3566 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3567 // no obstructions, but mapgen decorations are generated after spawn so
3568 // the player may end up inside one.
3569 for (s32 i = 0; i < 8; i++) {
3570 v3s16 blockpos = getNodeBlockPos(nodepos);
3571 map.emergeBlock(blockpos, true);
3572 content_t c = map.getNode(nodepos).getContent();
3574 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3575 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3576 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3578 if (air_count >= 2) {
3579 // Spawn in lower empty node
3581 nodeposf = intToFloat(nodepos, BS);
3582 // Don't spawn the player outside map boundaries
3583 if (objectpos_over_limit(nodeposf))
3584 // Exit this loop, positions above are probably over limit
3587 // Good position found, cause an exit from main loop
3601 // No suitable spawn point found, return fallback 0,0,0
3602 return v3f(0.0f, 0.0f, 0.0f);
3605 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3607 if (delay == 0.0f) {
3608 // No delay, shutdown immediately
3609 m_shutdown_state.is_requested = true;
3610 // only print to the infostream, a chat message saying
3611 // "Server Shutting Down" is sent when the server destructs.
3612 infostream << "*** Immediate Server shutdown requested." << std::endl;
3613 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3614 // Negative delay, cancel shutdown if requested
3615 m_shutdown_state.reset();
3616 std::wstringstream ws;
3618 ws << L"*** Server shutdown canceled.";
3620 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3621 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3622 // m_shutdown_* are already handled, skip.
3624 } else if (delay > 0.0f) {
3625 // Positive delay, tell the clients when the server will shut down
3626 std::wstringstream ws;
3628 ws << L"*** Server shutting down in "
3629 << duration_to_string(myround(delay)).c_str()
3632 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3633 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3636 m_shutdown_state.trigger(delay, msg, reconnect);
3639 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3642 Try to get an existing player
3644 RemotePlayer *player = m_env->getPlayer(name);
3646 // If player is already connected, cancel
3647 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3648 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3653 If player with the wanted peer_id already exists, cancel.
3655 if (m_env->getPlayer(peer_id)) {
3656 infostream<<"emergePlayer(): Player with wrong name but same"
3657 " peer_id already exists"<<std::endl;
3662 player = new RemotePlayer(name, idef());
3665 bool newplayer = false;
3668 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3670 // Complete init with server parts
3671 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3672 player->protocol_version = proto_version;
3676 m_script->on_newplayer(playersao);
3682 bool Server::registerModStorage(ModMetadata *storage)
3684 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3685 errorstream << "Unable to register same mod storage twice. Storage name: "
3686 << storage->getModName() << std::endl;
3690 m_mod_storages[storage->getModName()] = storage;
3694 void Server::unregisterModStorage(const std::string &name)
3696 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3697 if (it != m_mod_storages.end()) {
3698 // Save unconditionaly on unregistration
3699 it->second->save(getModStoragePath());
3700 m_mod_storages.erase(name);
3704 void dedicated_server_loop(Server &server, bool &kill)
3706 verbosestream<<"dedicated_server_loop()"<<std::endl;
3708 IntervalLimiter m_profiler_interval;
3710 static thread_local const float steplen =
3711 g_settings->getFloat("dedicated_server_step");
3712 static thread_local const float profiler_print_interval =
3713 g_settings->getFloat("profiler_print_interval");
3716 // This is kind of a hack but can be done like this
3717 // because server.step() is very light
3718 sleep_ms((int)(steplen*1000.0));
3719 server.step(steplen);
3721 if (server.isShutdownRequested() || kill)
3727 if (profiler_print_interval != 0) {
3728 if(m_profiler_interval.step(steplen, profiler_print_interval))
3730 infostream<<"Profiler:"<<std::endl;
3731 g_profiler->print(infostream);
3732 g_profiler->clear();
3737 infostream << "Dedicated server quitting" << std::endl;
3739 if (g_settings->getBool("server_announce"))
3740 ServerList::sendAnnounce(ServerList::AA_DELETE,
3741 server.m_bind_addr.getPort());
3750 bool Server::joinModChannel(const std::string &channel)
3752 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3753 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3756 bool Server::leaveModChannel(const std::string &channel)
3758 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3761 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3763 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3766 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3770 ModChannel* Server::getModChannel(const std::string &channel)
3772 return m_modchannel_mgr->getModChannel(channel);
3775 void Server::broadcastModChannelMessage(const std::string &channel,
3776 const std::string &message, session_t from_peer)
3778 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3782 if (message.size() > STRING_MAX_LEN) {
3783 warningstream << "ModChannel message too long, dropping before sending "
3784 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3785 << channel << ")" << std::endl;
3790 if (from_peer != PEER_ID_SERVER) {
3791 sender = getPlayerName(from_peer);
3794 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3795 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3796 resp_pkt << channel << sender << message;
3797 for (session_t peer_id : peers) {
3799 if (peer_id == from_peer)
3802 Send(peer_id, &resp_pkt);
3805 if (from_peer != PEER_ID_SERVER) {
3806 m_script->on_modchannel_message(channel, sender, message);