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 "server/serveractiveobject.h"
41 #include "scripting_server.h"
46 #include "mapgen/mapgen.h"
47 #include "mapgen/mg_biome.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content/mods.h"
51 #include "modchannels.h"
52 #include "serverlist.h"
53 #include "util/string.h"
55 #include "util/serialize.h"
56 #include "util/thread.h"
57 #include "defaultsettings.h"
58 #include "server/mods.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
62 #include "database/database.h"
63 #include "chatmessage.h"
64 #include "chat_interface.h"
65 #include "remoteplayer.h"
66 #include "server/player_sao.h"
67 #include "translation.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
97 * The real business of the server happens on the ServerThread.
99 * AsyncRunStep() runs an actual server step as soon as enough time has
100 * passed (dedicated_server_loop keeps track of that).
101 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
102 * doesn't busy wait) and will process any remaining packets.
105 m_server->AsyncRunStep(true);
107 while (!stopRequested()) {
109 m_server->AsyncRunStep();
113 } catch (con::PeerNotFoundException &e) {
114 infostream<<"Server: PeerNotFoundException"<<std::endl;
115 } catch (ClientNotFoundException &e) {
116 } catch (con::ConnectionBindFailed &e) {
117 m_server->setAsyncFatalError(e.what());
118 } catch (LuaError &e) {
119 m_server->setAsyncFatalError(
120 "ServerThread::run Lua: " + std::string(e.what()));
124 END_DEBUG_EXCEPTION_HANDLER
129 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
131 if(pos_exists) *pos_exists = false;
136 if(pos_exists) *pos_exists = true;
141 ServerActiveObject *sao = env->getActiveObject(object);
144 if(pos_exists) *pos_exists = true;
145 return sao->getBasePosition(); }
150 void Server::ShutdownState::reset()
154 should_reconnect = false;
155 is_requested = false;
158 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
162 should_reconnect = reconnect;
165 void Server::ShutdownState::tick(float dtime, Server *server)
171 static const float shutdown_msg_times[] =
173 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
176 // Automated messages
177 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
178 for (float t : shutdown_msg_times) {
179 // If shutdown timer matches an automessage, shot it
180 if (m_timer > t && m_timer - dtime < t) {
181 std::wstring periodicMsg = getShutdownTimerMessage();
183 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
184 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
191 if (m_timer < 0.0f) {
197 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
199 std::wstringstream ws;
200 ws << L"*** Server shutting down in "
201 << duration_to_string(myround(m_timer)).c_str() << ".";
210 const std::string &path_world,
211 const SubgameSpec &gamespec,
212 bool simple_singleplayer_mode,
217 m_bind_addr(bind_addr),
218 m_path_world(path_world),
219 m_gamespec(gamespec),
220 m_simple_singleplayer_mode(simple_singleplayer_mode),
221 m_dedicated(dedicated),
222 m_async_fatal_error(""),
223 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
226 m_bind_addr.isIPv6(),
228 m_itemdef(createItemDefManager()),
229 m_nodedef(createNodeDefManager()),
230 m_craftdef(createCraftDefManager()),
231 m_thread(new ServerThread(this)),
235 m_modchannel_mgr(new ModChannelMgr())
237 m_lag = g_settings->getFloat("dedicated_server_step");
239 if (m_path_world.empty())
240 throw ServerError("Supplied empty world path");
242 if (!gamespec.isValid())
243 throw ServerError("Supplied invalid gamespec");
249 // Send shutdown message
250 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
251 L"*** Server shutting down"));
254 MutexAutoLock envlock(m_env_mutex);
256 infostream << "Server: Saving players" << std::endl;
257 m_env->saveLoadedPlayers();
259 infostream << "Server: Kicking players" << std::endl;
260 std::string kick_msg;
261 bool reconnect = false;
262 if (isShutdownRequested()) {
263 reconnect = m_shutdown_state.should_reconnect;
264 kick_msg = m_shutdown_state.message;
266 if (kick_msg.empty()) {
267 kick_msg = g_settings->get("kick_msg_shutdown");
269 m_env->saveLoadedPlayers(true);
270 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
271 kick_msg, reconnect);
274 actionstream << "Server: Shutting down" << std::endl;
276 // Do this before stopping the server in case mapgen callbacks need to access
277 // server-controlled resources (like ModStorages). Also do them before
278 // shutdown callbacks since they may modify state that is finalized in a
281 m_emerge->stopThreads();
284 MutexAutoLock envlock(m_env_mutex);
286 // Execute script shutdown hooks
287 infostream << "Executing shutdown hooks" << std::endl;
288 m_script->on_shutdown();
290 infostream << "Server: Saving environment metadata" << std::endl;
300 // Delete things in the reverse order of creation
309 // Deinitialize scripting
310 infostream << "Server: Deinitializing scripting" << std::endl;
313 // Delete detached inventories
314 for (auto &detached_inventory : m_detached_inventories) {
315 delete detached_inventory.second;
318 while (!m_unsent_map_edit_queue.empty()) {
319 delete m_unsent_map_edit_queue.front();
320 m_unsent_map_edit_queue.pop();
326 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
327 if (m_simple_singleplayer_mode)
328 infostream << " in simple singleplayer mode" << std::endl;
330 infostream << std::endl;
331 infostream << "- world: " << m_path_world << std::endl;
332 infostream << "- game: " << m_gamespec.path << std::endl;
334 // Create world if it doesn't exist
335 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
336 throw ServerError("Failed to initialize world");
338 // Create emerge manager
339 m_emerge = new EmergeManager(this);
341 // Create ban manager
342 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
343 m_banmanager = new BanManager(ban_path);
345 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
346 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
347 // complain about mods with unsatisfied dependencies
348 if (!m_modmgr->isConsistent()) {
349 m_modmgr->printUnsatisfiedModsError();
353 MutexAutoLock envlock(m_env_mutex);
355 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
356 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
358 // Initialize scripting
359 infostream << "Server: Initializing Lua" << std::endl;
361 m_script = new ServerScripting(this);
363 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
365 m_modmgr->loadMods(m_script);
367 // Read Textures and calculate sha1 sums
370 // Apply item aliases in the node definition manager
371 m_nodedef->updateAliases(m_itemdef);
373 // Apply texture overrides from texturepack/override.txt
374 std::vector<std::string> paths;
375 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
376 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
377 for (const std::string &path : paths) {
378 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
379 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
380 m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
383 m_nodedef->setNodeRegistrationStatus(true);
385 // Perform pending node name resolutions
386 m_nodedef->runNodeResolveCallbacks();
388 // unmap node names for connected nodeboxes
389 m_nodedef->mapNodeboxConnections();
391 // init the recipe hashes to speed up crafting
392 m_craftdef->initHashes(this);
394 // Initialize Environment
395 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
397 m_clients.setEnv(m_env);
399 if (!servermap->settings_mgr.makeMapgenParams())
400 FATAL_ERROR("Couldn't create any mapgen type");
402 // Initialize mapgens
403 m_emerge->initMapgens(servermap->getMapgenParams());
405 if (g_settings->getBool("enable_rollback_recording")) {
406 // Create rollback manager
407 m_rollback = new RollbackManager(m_path_world, this);
410 // Give environment reference to scripting api
411 m_script->initializeEnvironment(m_env);
413 // Register us to receive map edit events
414 servermap->addEventReceiver(this);
418 m_liquid_transform_every = g_settings->getFloat("liquid_update");
419 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
420 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
421 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
426 infostream << "Starting server on " << m_bind_addr.serializeString()
427 << "..." << std::endl;
429 // Stop thread if already running
432 // Initialize connection
433 m_con->SetTimeoutMs(30);
434 m_con->Serve(m_bind_addr);
439 // ASCII art for the win!
441 << " .__ __ __ " << std::endl
442 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
443 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
444 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
445 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
446 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
447 actionstream << "World at [" << m_path_world << "]" << std::endl;
448 actionstream << "Server for gameid=\"" << m_gamespec.id
449 << "\" listening on " << m_bind_addr.serializeString() << ":"
450 << m_bind_addr.getPort() << "." << std::endl;
455 infostream<<"Server: Stopping and waiting threads"<<std::endl;
457 // Stop threads (set run=false first so both start stopping)
459 //m_emergethread.setRun(false);
461 //m_emergethread.stop();
463 infostream<<"Server: Threads stopped"<<std::endl;
466 void Server::step(float dtime)
472 MutexAutoLock lock(m_step_dtime_mutex);
473 m_step_dtime += dtime;
475 // Throw if fatal error occurred in thread
476 std::string async_err = m_async_fatal_error.get();
477 if (!async_err.empty()) {
478 if (!m_simple_singleplayer_mode) {
479 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
480 g_settings->get("kick_msg_crash"),
481 g_settings->getBool("ask_reconnect_on_crash"));
483 throw ServerError("AsyncErr: " + async_err);
487 void Server::AsyncRunStep(bool initial_step)
492 MutexAutoLock lock1(m_step_dtime_mutex);
493 dtime = m_step_dtime;
497 // Send blocks to clients
501 if((dtime < 0.001) && !initial_step)
504 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
507 MutexAutoLock lock1(m_step_dtime_mutex);
508 m_step_dtime -= dtime;
515 m_uptime.set(m_uptime.get() + dtime);
521 Update time of day and overall game time
523 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
526 Send to clients at constant intervals
529 m_time_of_day_send_timer -= dtime;
530 if(m_time_of_day_send_timer < 0.0) {
531 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
532 u16 time = m_env->getTimeOfDay();
533 float time_speed = g_settings->getFloat("time_speed");
534 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
538 MutexAutoLock lock(m_env_mutex);
539 // Figure out and report maximum lag to environment
540 float max_lag = m_env->getMaxLagEstimate();
541 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
543 if(dtime > 0.1 && dtime > max_lag * 2.0)
544 infostream<<"Server: Maximum lag peaked to "<<dtime
548 m_env->reportMaxLagEstimate(max_lag);
553 static const float map_timer_and_unload_dtime = 2.92;
554 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
556 MutexAutoLock lock(m_env_mutex);
557 // Run Map's timers and unload unused data
558 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
559 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
560 g_settings->getFloat("server_unload_unused_data_timeout"),
565 Listen to the admin chat, if available
568 if (!m_admin_chat->command_queue.empty()) {
569 MutexAutoLock lock(m_env_mutex);
570 while (!m_admin_chat->command_queue.empty()) {
571 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
572 handleChatInterfaceEvent(evt);
576 m_admin_chat->outgoing_queue.push_back(
577 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
584 /* Transform liquids */
585 m_liquid_transform_timer += dtime;
586 if(m_liquid_transform_timer >= m_liquid_transform_every)
588 m_liquid_transform_timer -= m_liquid_transform_every;
590 MutexAutoLock lock(m_env_mutex);
592 ScopeProfiler sp(g_profiler, "Server: liquid transform");
594 std::map<v3s16, MapBlock*> modified_blocks;
595 m_env->getMap().transformLiquids(modified_blocks, m_env);
598 Set the modified blocks unsent for all the clients
600 if (!modified_blocks.empty()) {
601 SetBlocksNotSent(modified_blocks);
604 m_clients.step(dtime);
606 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
608 // send masterserver announce
610 float &counter = m_masterserver_timer;
611 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
612 g_settings->getBool("server_announce")) {
613 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
614 ServerList::AA_START,
615 m_bind_addr.getPort(),
616 m_clients.getPlayerNames(),
618 m_env->getGameTime(),
621 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
631 Check added and deleted active objects
634 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
635 MutexAutoLock envlock(m_env_mutex);
638 const RemoteClientMap &clients = m_clients.getClientList();
639 ScopeProfiler sp(g_profiler, "Server: update objects within range");
641 for (const auto &client_it : clients) {
642 RemoteClient *client = client_it.second;
644 if (client->getState() < CS_DefinitionsSent)
647 // This can happen if the client times out somehow
648 if (!m_env->getPlayer(client->peer_id))
651 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
655 SendActiveObjectRemoveAdd(client, playersao);
659 // Save mod storages if modified
660 m_mod_storage_save_timer -= dtime;
661 if (m_mod_storage_save_timer <= 0.0f) {
662 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
664 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
665 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
666 if (it->second->isModified()) {
667 it->second->save(getModStoragePath());
672 infostream << "Saved " << n << " modified mod storages." << std::endl;
680 MutexAutoLock envlock(m_env_mutex);
681 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
684 // Value = data sent by object
685 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
687 // Get active object messages from environment
689 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
693 std::vector<ActiveObjectMessage>* message_list = nullptr;
694 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
695 n = buffered_messages.find(aom.id);
696 if (n == buffered_messages.end()) {
697 message_list = new std::vector<ActiveObjectMessage>;
698 buffered_messages[aom.id] = message_list;
701 message_list = n->second;
703 message_list->push_back(aom);
707 const RemoteClientMap &clients = m_clients.getClientList();
708 // Route data to every client
709 for (const auto &client_it : clients) {
710 RemoteClient *client = client_it.second;
711 PlayerSAO *player = getPlayerSAO(client->peer_id);
712 std::string reliable_data;
713 std::string unreliable_data;
714 // Go through all objects in message buffer
715 for (const auto &buffered_message : buffered_messages) {
716 // If object does not exist or is not known by client, skip it
717 u16 id = buffered_message.first;
718 ServerActiveObject *sao = m_env->getActiveObject(id);
719 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
722 // Get message list of object
723 std::vector<ActiveObjectMessage>* list = buffered_message.second;
724 // Go through every message
725 for (const ActiveObjectMessage &aom : *list) {
726 // Send position updates to players who do not see the attachment
727 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
728 if (sao->getId() == player->getId())
731 // Do not send position updates for attached players
732 // as long the parent is known to the client
733 ServerActiveObject *parent = sao->getParent();
734 if (parent && client->m_known_objects.find(parent->getId()) !=
735 client->m_known_objects.end())
738 // Compose the full new data with header
739 std::string new_data;
742 writeU16((u8*)&buf[0], aom.id);
743 new_data.append(buf, 2);
745 new_data += serializeString(aom.datastring);
746 // Add data to buffer
748 reliable_data += new_data;
750 unreliable_data += new_data;
754 reliable_data and unreliable_data are now ready.
757 if (!reliable_data.empty()) {
758 SendActiveObjectMessages(client->peer_id, reliable_data);
761 if (!unreliable_data.empty()) {
762 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
767 // Clear buffered_messages
768 for (auto &buffered_message : buffered_messages) {
769 delete buffered_message.second;
774 Send queued-for-sending map edit events.
777 // We will be accessing the environment
778 MutexAutoLock lock(m_env_mutex);
780 // Don't send too many at a time
783 // Single change sending is disabled if queue size is not small
784 bool disable_single_change_sending = false;
785 if(m_unsent_map_edit_queue.size() >= 4)
786 disable_single_change_sending = true;
788 int event_count = m_unsent_map_edit_queue.size();
790 // We'll log the amount of each
793 std::list<v3s16> node_meta_updates;
795 while (!m_unsent_map_edit_queue.empty()) {
796 MapEditEvent* event = m_unsent_map_edit_queue.front();
797 m_unsent_map_edit_queue.pop();
799 // Players far away from the change are stored here.
800 // Instead of sending the changes, MapBlocks are set not sent
802 std::unordered_set<u16> far_players;
804 switch (event->type) {
807 prof.add("MEET_ADDNODE", 1);
808 sendAddNode(event->p, event->n, &far_players,
809 disable_single_change_sending ? 5 : 30,
810 event->type == MEET_ADDNODE);
812 case MEET_REMOVENODE:
813 prof.add("MEET_REMOVENODE", 1);
814 sendRemoveNode(event->p, &far_players,
815 disable_single_change_sending ? 5 : 30);
817 case MEET_BLOCK_NODE_METADATA_CHANGED: {
818 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
819 if (!event->is_private_change) {
820 // Don't send the change yet. Collect them to eliminate dupes.
821 node_meta_updates.remove(event->p);
822 node_meta_updates.push_back(event->p);
825 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
826 getNodeBlockPos(event->p))) {
827 block->raiseModified(MOD_STATE_WRITE_NEEDED,
828 MOD_REASON_REPORT_META_CHANGE);
833 prof.add("MEET_OTHER", 1);
834 for (const v3s16 &modified_block : event->modified_blocks) {
835 m_clients.markBlockposAsNotSent(modified_block);
839 prof.add("unknown", 1);
840 warningstream << "Server: Unknown MapEditEvent "
841 << ((u32)event->type) << std::endl;
846 Set blocks not sent to far players
848 if (!far_players.empty()) {
849 // Convert list format to that wanted by SetBlocksNotSent
850 std::map<v3s16, MapBlock*> modified_blocks2;
851 for (const v3s16 &modified_block : event->modified_blocks) {
852 modified_blocks2[modified_block] =
853 m_env->getMap().getBlockNoCreateNoEx(modified_block);
856 // Set blocks not sent
857 for (const u16 far_player : far_players) {
858 if (RemoteClient *client = getClient(far_player))
859 client->SetBlocksNotSent(modified_blocks2);
866 if (event_count >= 5) {
867 infostream << "Server: MapEditEvents:" << std::endl;
868 prof.print(infostream);
869 } else if (event_count != 0) {
870 verbosestream << "Server: MapEditEvents:" << std::endl;
871 prof.print(verbosestream);
874 // Send all metadata updates
875 if (node_meta_updates.size())
876 sendMetadataChanged(node_meta_updates);
880 Trigger emergethread (it somehow gets to a non-triggered but
881 bysy state sometimes)
884 float &counter = m_emergethread_trigger_timer;
886 if (counter >= 2.0) {
889 m_emerge->startThreads();
893 // Save map, players and auth stuff
895 float &counter = m_savemap_timer;
897 static thread_local const float save_interval =
898 g_settings->getFloat("server_map_save_interval");
899 if (counter >= save_interval) {
901 MutexAutoLock lock(m_env_mutex);
903 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
906 if (m_banmanager->isModified()) {
907 m_banmanager->save();
910 // Save changed parts of map
911 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
914 m_env->saveLoadedPlayers();
916 // Save environment metadata
921 m_shutdown_state.tick(dtime, this);
924 void Server::Receive()
934 In the first iteration *wait* for a packet, afterwards process
935 all packets that are immediately available (no waiting).
938 m_con->Receive(&pkt);
941 if (!m_con->TryReceive(&pkt))
945 peer_id = pkt.getPeerId();
947 } catch (const con::InvalidIncomingDataException &e) {
948 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
949 << e.what() << std::endl;
950 } catch (const SerializationError &e) {
951 infostream << "Server::Receive(): SerializationError: what()="
952 << e.what() << std::endl;
953 } catch (const ClientStateError &e) {
954 errorstream << "ProcessData: peer=" << peer_id << " what()="
955 << e.what() << std::endl;
956 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
957 L"Try reconnecting or updating your client");
958 } catch (const con::PeerNotFoundException &e) {
960 } catch (const con::NoIncomingDataException &e) {
966 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
968 std::string playername;
969 PlayerSAO *playersao = NULL;
972 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
974 playername = client->getName();
975 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
977 } catch (std::exception &e) {
983 RemotePlayer *player = m_env->getPlayer(playername.c_str());
986 if (!playersao || !player) {
987 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
988 actionstream << "Server: Failed to emerge player \"" << playername
989 << "\" (player allocated to an another client)" << std::endl;
990 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
991 L"name. If your client closed unexpectedly, try again in "
994 errorstream << "Server: " << playername << ": Failed to emerge player"
996 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1002 Send complete position information
1004 SendMovePlayer(peer_id);
1007 SendPlayerPrivileges(peer_id);
1009 // Send inventory formspec
1010 SendPlayerInventoryFormspec(peer_id);
1013 SendInventory(playersao, false);
1015 // Send HP or death screen
1016 if (playersao->isDead())
1017 SendDeathscreen(peer_id, false, v3f(0,0,0));
1019 SendPlayerHPOrDie(playersao,
1020 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1023 SendPlayerBreath(playersao);
1029 Address addr = getPeerAddress(player->getPeerId());
1030 std::string ip_str = addr.serializeString();
1031 const std::vector<std::string> &names = m_clients.getPlayerNames();
1033 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1035 for (const std::string &name : names) {
1036 actionstream << name << " ";
1039 actionstream << player->getName() <<std::endl;
1044 inline void Server::handleCommand(NetworkPacket *pkt)
1046 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1047 (this->*opHandle.handler)(pkt);
1050 void Server::ProcessData(NetworkPacket *pkt)
1052 // Environment is locked first.
1053 MutexAutoLock envlock(m_env_mutex);
1055 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1056 u32 peer_id = pkt->getPeerId();
1059 Address address = getPeerAddress(peer_id);
1060 std::string addr_s = address.serializeString();
1062 if(m_banmanager->isIpBanned(addr_s)) {
1063 std::string ban_name = m_banmanager->getBanName(addr_s);
1064 infostream << "Server: A banned client tried to connect from "
1065 << addr_s << "; banned name was "
1066 << ban_name << std::endl;
1067 // This actually doesn't seem to transfer to the client
1068 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1069 + utf8_to_wide(ban_name));
1073 catch(con::PeerNotFoundException &e) {
1075 * no peer for this packet found
1076 * most common reason is peer timeout, e.g. peer didn't
1077 * respond for some time, your server was overloaded or
1080 infostream << "Server::ProcessData(): Canceling: peer "
1081 << peer_id << " not found" << std::endl;
1086 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1088 // Command must be handled into ToServerCommandHandler
1089 if (command >= TOSERVER_NUM_MSG_TYPES) {
1090 infostream << "Server: Ignoring unknown command "
1091 << command << std::endl;
1095 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1100 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1102 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1103 errorstream << "Server::ProcessData(): Cancelling: Peer"
1104 " serialization format invalid or not initialized."
1105 " Skipping incoming command=" << command << std::endl;
1109 /* Handle commands related to client startup */
1110 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1115 if (m_clients.getClientState(peer_id) < CS_Active) {
1116 if (command == TOSERVER_PLAYERPOS) return;
1118 errorstream << "Got packet command: " << command << " for peer id "
1119 << peer_id << " but client isn't active yet. Dropping packet "
1125 } catch (SendFailedException &e) {
1126 errorstream << "Server::ProcessData(): SendFailedException: "
1127 << "what=" << e.what()
1129 } catch (PacketError &e) {
1130 actionstream << "Server::ProcessData(): PacketError: "
1131 << "what=" << e.what()
1136 void Server::setTimeOfDay(u32 time)
1138 m_env->setTimeOfDay(time);
1139 m_time_of_day_send_timer = 0;
1142 void Server::onMapEditEvent(const MapEditEvent &event)
1144 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1147 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1150 Inventory* Server::getInventory(const InventoryLocation &loc)
1153 case InventoryLocation::UNDEFINED:
1154 case InventoryLocation::CURRENT_PLAYER:
1156 case InventoryLocation::PLAYER:
1158 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1161 PlayerSAO *playersao = player->getPlayerSAO();
1164 return playersao->getInventory();
1167 case InventoryLocation::NODEMETA:
1169 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1172 return meta->getInventory();
1175 case InventoryLocation::DETACHED:
1177 if(m_detached_inventories.count(loc.name) == 0)
1179 return m_detached_inventories[loc.name];
1183 sanity_check(false); // abort
1189 void Server::setInventoryModified(const InventoryLocation &loc)
1192 case InventoryLocation::UNDEFINED:
1194 case InventoryLocation::PLAYER:
1197 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1202 player->setModified(true);
1203 player->inventory.setModified(true);
1204 // Updates are sent in ServerEnvironment::step()
1207 case InventoryLocation::NODEMETA:
1210 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1212 m_env->getMap().dispatchEvent(event);
1215 case InventoryLocation::DETACHED:
1217 // Updates are sent in ServerEnvironment::step()
1221 sanity_check(false); // abort
1226 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1228 std::vector<session_t> clients = m_clients.getClientIDs();
1230 // Set the modified blocks unsent for all the clients
1231 for (const session_t client_id : clients) {
1232 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1233 client->SetBlocksNotSent(block);
1238 void Server::peerAdded(con::Peer *peer)
1240 verbosestream<<"Server::peerAdded(): peer->id="
1241 <<peer->id<<std::endl;
1243 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1246 void Server::deletingPeer(con::Peer *peer, bool timeout)
1248 verbosestream<<"Server::deletingPeer(): peer->id="
1249 <<peer->id<<", timeout="<<timeout<<std::endl;
1251 m_clients.event(peer->id, CSE_Disconnect);
1252 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1255 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1257 *retval = m_con->getPeerStat(peer_id,type);
1258 return *retval != -1;
1261 bool Server::getClientInfo(
1270 std::string* vers_string,
1271 std::string* lang_code
1274 *state = m_clients.getClientState(peer_id);
1276 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1283 *uptime = client->uptime();
1284 *ser_vers = client->serialization_version;
1285 *prot_vers = client->net_proto_version;
1287 *major = client->getMajor();
1288 *minor = client->getMinor();
1289 *patch = client->getPatch();
1290 *vers_string = client->getFull();
1291 *lang_code = client->getLangCode();
1298 void Server::handlePeerChanges()
1300 while(!m_peer_change_queue.empty())
1302 con::PeerChange c = m_peer_change_queue.front();
1303 m_peer_change_queue.pop();
1305 verbosestream<<"Server: Handling peer change: "
1306 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1311 case con::PEER_ADDED:
1312 m_clients.CreateClient(c.peer_id);
1315 case con::PEER_REMOVED:
1316 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1320 FATAL_ERROR("Invalid peer change event received!");
1326 void Server::printToConsoleOnly(const std::string &text)
1329 m_admin_chat->outgoing_queue.push_back(
1330 new ChatEventChat("", utf8_to_wide(text)));
1332 std::cout << text << std::endl;
1336 void Server::Send(NetworkPacket *pkt)
1338 Send(pkt->getPeerId(), pkt);
1341 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1343 m_clients.send(peer_id,
1344 clientCommandFactoryTable[pkt->getCommand()].channel,
1346 clientCommandFactoryTable[pkt->getCommand()].reliable);
1349 void Server::SendMovement(session_t peer_id)
1351 std::ostringstream os(std::ios_base::binary);
1353 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1355 pkt << g_settings->getFloat("movement_acceleration_default");
1356 pkt << g_settings->getFloat("movement_acceleration_air");
1357 pkt << g_settings->getFloat("movement_acceleration_fast");
1358 pkt << g_settings->getFloat("movement_speed_walk");
1359 pkt << g_settings->getFloat("movement_speed_crouch");
1360 pkt << g_settings->getFloat("movement_speed_fast");
1361 pkt << g_settings->getFloat("movement_speed_climb");
1362 pkt << g_settings->getFloat("movement_speed_jump");
1363 pkt << g_settings->getFloat("movement_liquid_fluidity");
1364 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1365 pkt << g_settings->getFloat("movement_liquid_sink");
1366 pkt << g_settings->getFloat("movement_gravity");
1371 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1373 if (playersao->isImmortal())
1376 session_t peer_id = playersao->getPeerID();
1377 bool is_alive = playersao->getHP() > 0;
1380 SendPlayerHP(peer_id);
1382 DiePlayer(peer_id, reason);
1385 void Server::SendHP(session_t peer_id, u16 hp)
1387 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1392 void Server::SendBreath(session_t peer_id, u16 breath)
1394 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1395 pkt << (u16) breath;
1399 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1400 const std::string &custom_reason, bool reconnect)
1402 assert(reason < SERVER_ACCESSDENIED_MAX);
1404 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1406 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1407 pkt << custom_reason;
1408 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1409 reason == SERVER_ACCESSDENIED_CRASH)
1410 pkt << custom_reason << (u8)reconnect;
1414 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1416 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1421 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1422 v3f camera_point_target)
1424 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1425 pkt << set_camera_point_target << camera_point_target;
1429 void Server::SendItemDef(session_t peer_id,
1430 IItemDefManager *itemdef, u16 protocol_version)
1432 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1436 u32 length of the next item
1437 zlib-compressed serialized ItemDefManager
1439 std::ostringstream tmp_os(std::ios::binary);
1440 itemdef->serialize(tmp_os, protocol_version);
1441 std::ostringstream tmp_os2(std::ios::binary);
1442 compressZlib(tmp_os.str(), tmp_os2);
1443 pkt.putLongString(tmp_os2.str());
1446 verbosestream << "Server: Sending item definitions to id(" << peer_id
1447 << "): size=" << pkt.getSize() << std::endl;
1452 void Server::SendNodeDef(session_t peer_id,
1453 const NodeDefManager *nodedef, u16 protocol_version)
1455 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1459 u32 length of the next item
1460 zlib-compressed serialized NodeDefManager
1462 std::ostringstream tmp_os(std::ios::binary);
1463 nodedef->serialize(tmp_os, protocol_version);
1464 std::ostringstream tmp_os2(std::ios::binary);
1465 compressZlib(tmp_os.str(), tmp_os2);
1467 pkt.putLongString(tmp_os2.str());
1470 verbosestream << "Server: Sending node definitions to id(" << peer_id
1471 << "): size=" << pkt.getSize() << std::endl;
1477 Non-static send methods
1480 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1482 RemotePlayer *player = sao->getPlayer();
1484 // Do not send new format to old clients
1485 incremental &= player->protocol_version >= 38;
1487 UpdateCrafting(player);
1493 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1495 std::ostringstream os(std::ios::binary);
1496 sao->getInventory()->serialize(os, incremental);
1497 sao->getInventory()->setModified(false);
1498 player->setModified(true);
1500 const std::string &s = os.str();
1501 pkt.putRawString(s.c_str(), s.size());
1505 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1507 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1509 u8 type = message.type;
1510 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1512 if (peer_id != PEER_ID_INEXISTENT) {
1513 RemotePlayer *player = m_env->getPlayer(peer_id);
1519 m_clients.sendToAll(&pkt);
1523 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1524 const std::string &formname)
1526 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1527 if (formspec.empty()){
1528 //the client should close the formspec
1529 //but make sure there wasn't another one open in meantime
1530 const auto it = m_formspec_state_data.find(peer_id);
1531 if (it != m_formspec_state_data.end() && it->second == formname) {
1532 m_formspec_state_data.erase(peer_id);
1534 pkt.putLongString("");
1536 m_formspec_state_data[peer_id] = formname;
1537 pkt.putLongString(formspec);
1544 // Spawns a particle on peer with peer_id
1545 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1546 v3f pos, v3f velocity, v3f acceleration,
1547 float expirationtime, float size, bool collisiondetection,
1548 bool collision_removal, bool object_collision,
1549 bool vertical, const std::string &texture,
1550 const struct TileAnimationParams &animation, u8 glow)
1552 static thread_local const float radius =
1553 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1555 if (peer_id == PEER_ID_INEXISTENT) {
1556 std::vector<session_t> clients = m_clients.getClientIDs();
1558 for (const session_t client_id : clients) {
1559 RemotePlayer *player = m_env->getPlayer(client_id);
1563 PlayerSAO *sao = player->getPlayerSAO();
1567 // Do not send to distant clients
1568 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1571 SendSpawnParticle(client_id, player->protocol_version,
1572 pos, velocity, acceleration,
1573 expirationtime, size, collisiondetection, collision_removal,
1574 object_collision, vertical, texture, animation, glow);
1579 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1581 pkt << pos << velocity << acceleration << expirationtime
1582 << size << collisiondetection;
1583 pkt.putLongString(texture);
1585 pkt << collision_removal;
1586 // This is horrible but required (why are there two ways to serialize pkts?)
1587 std::ostringstream os(std::ios_base::binary);
1588 animation.serialize(os, protocol_version);
1589 pkt.putRawString(os.str());
1591 pkt << object_collision;
1596 // Adds a ParticleSpawner on peer with peer_id
1597 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1598 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1599 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1600 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1601 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1602 const struct TileAnimationParams &animation, u8 glow)
1604 if (peer_id == PEER_ID_INEXISTENT) {
1605 // This sucks and should be replaced:
1606 std::vector<session_t> clients = m_clients.getClientIDs();
1607 for (const session_t client_id : clients) {
1608 RemotePlayer *player = m_env->getPlayer(client_id);
1611 SendAddParticleSpawner(client_id, player->protocol_version,
1612 amount, spawntime, minpos, maxpos,
1613 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1614 minsize, maxsize, collisiondetection, collision_removal,
1615 object_collision, attached_id, vertical, texture, id,
1621 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1623 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1624 << minacc << maxacc << minexptime << maxexptime << minsize
1625 << maxsize << collisiondetection;
1627 pkt.putLongString(texture);
1629 pkt << id << vertical;
1630 pkt << collision_removal;
1632 // This is horrible but required
1633 std::ostringstream os(std::ios_base::binary);
1634 animation.serialize(os, protocol_version);
1635 pkt.putRawString(os.str());
1637 pkt << object_collision;
1642 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1644 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1646 // Ugly error in this packet
1649 if (peer_id != PEER_ID_INEXISTENT)
1652 m_clients.sendToAll(&pkt);
1656 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1658 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1660 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1661 << form->text << form->number << form->item << form->dir
1662 << form->align << form->offset << form->world_pos << form->size
1668 void Server::SendHUDRemove(session_t peer_id, u32 id)
1670 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1675 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1677 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1678 pkt << id << (u8) stat;
1682 case HUD_STAT_SCALE:
1683 case HUD_STAT_ALIGN:
1684 case HUD_STAT_OFFSET:
1685 pkt << *(v2f *) value;
1689 pkt << *(std::string *) value;
1691 case HUD_STAT_WORLD_POS:
1692 pkt << *(v3f *) value;
1695 pkt << *(v2s32 *) value;
1697 case HUD_STAT_NUMBER:
1701 pkt << *(u32 *) value;
1708 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1710 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1712 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1714 pkt << flags << mask;
1719 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1721 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1722 pkt << param << value;
1726 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1728 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1730 // Handle prior clients here
1731 if (m_clients.getProtocolVersion(peer_id) < 39) {
1732 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1734 for (const std::string& texture : params.textures)
1737 pkt << params.clouds;
1738 } else { // Handle current clients and future clients
1739 pkt << params.bgcolor << params.type
1740 << params.clouds << params.sun_tint
1741 << params.moon_tint << params.tint_type;
1743 if (params.type == "skybox") {
1744 pkt << (u16) params.textures.size();
1745 for (const std::string &texture : params.textures)
1747 } else if (params.type == "regular") {
1748 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1749 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1750 << params.sky_color.night_sky << params.sky_color.night_horizon
1751 << params.sky_color.indoors;
1758 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1760 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1761 pkt << params.visible << params.texture
1762 << params.tonemap << params.sunrise
1763 << params.sunrise_visible << params.scale;
1767 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1769 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1771 pkt << params.visible << params.texture
1772 << params.tonemap << params.scale;
1776 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1778 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1780 pkt << params.visible << params.count
1781 << params.starcolor << params.scale;
1786 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1788 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1789 pkt << params.density << params.color_bright << params.color_ambient
1790 << params.height << params.thickness << params.speed;
1794 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1797 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1800 pkt << do_override << (u16) (ratio * 65535);
1805 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1807 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1808 pkt << time << time_speed;
1810 if (peer_id == PEER_ID_INEXISTENT) {
1811 m_clients.sendToAll(&pkt);
1818 void Server::SendPlayerHP(session_t peer_id)
1820 PlayerSAO *playersao = getPlayerSAO(peer_id);
1823 SendHP(peer_id, playersao->getHP());
1824 m_script->player_event(playersao,"health_changed");
1826 // Send to other clients
1827 playersao->sendPunchCommand();
1830 void Server::SendPlayerBreath(PlayerSAO *sao)
1834 m_script->player_event(sao, "breath_changed");
1835 SendBreath(sao->getPeerID(), sao->getBreath());
1838 void Server::SendMovePlayer(session_t peer_id)
1840 RemotePlayer *player = m_env->getPlayer(peer_id);
1842 PlayerSAO *sao = player->getPlayerSAO();
1845 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1846 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1849 v3f pos = sao->getBasePosition();
1850 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1851 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1852 << " pitch=" << sao->getLookPitch()
1853 << " yaw=" << sao->getRotation().Y
1860 void Server::SendPlayerFov(session_t peer_id)
1862 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1, peer_id);
1864 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1865 pkt << fov_spec.fov << fov_spec.is_multiplier;
1870 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1871 f32 animation_speed)
1873 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1876 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1877 << animation_frames[3] << animation_speed;
1882 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1884 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1885 pkt << first << third;
1889 void Server::SendPlayerPrivileges(session_t peer_id)
1891 RemotePlayer *player = m_env->getPlayer(peer_id);
1893 if(player->getPeerId() == PEER_ID_INEXISTENT)
1896 std::set<std::string> privs;
1897 m_script->getAuth(player->getName(), NULL, &privs);
1899 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1900 pkt << (u16) privs.size();
1902 for (const std::string &priv : privs) {
1909 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1911 RemotePlayer *player = m_env->getPlayer(peer_id);
1913 if (player->getPeerId() == PEER_ID_INEXISTENT)
1916 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1917 pkt.putLongString(player->inventory_formspec);
1922 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1924 RemotePlayer *player = m_env->getPlayer(peer_id);
1926 if (player->getPeerId() == PEER_ID_INEXISTENT)
1929 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1930 pkt << player->formspec_prepend;
1934 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1936 // Radius inside which objects are active
1937 static thread_local const s16 radius =
1938 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1940 // Radius inside which players are active
1941 static thread_local const bool is_transfer_limited =
1942 g_settings->exists("unlimited_player_transfer_distance") &&
1943 !g_settings->getBool("unlimited_player_transfer_distance");
1945 static thread_local const s16 player_transfer_dist =
1946 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1948 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1949 radius : player_transfer_dist;
1951 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1955 std::queue<u16> removed_objects, added_objects;
1956 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1957 client->m_known_objects, removed_objects);
1958 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1959 client->m_known_objects, added_objects);
1961 int removed_count = removed_objects.size();
1962 int added_count = added_objects.size();
1964 if (removed_objects.empty() && added_objects.empty())
1970 // Handle removed objects
1971 writeU16((u8*)buf, removed_objects.size());
1972 data.append(buf, 2);
1973 while (!removed_objects.empty()) {
1975 u16 id = removed_objects.front();
1976 ServerActiveObject* obj = m_env->getActiveObject(id);
1978 // Add to data buffer for sending
1979 writeU16((u8*)buf, id);
1980 data.append(buf, 2);
1982 // Remove from known objects
1983 client->m_known_objects.erase(id);
1985 if (obj && obj->m_known_by_count > 0)
1986 obj->m_known_by_count--;
1988 removed_objects.pop();
1991 // Handle added objects
1992 writeU16((u8*)buf, added_objects.size());
1993 data.append(buf, 2);
1994 while (!added_objects.empty()) {
1996 u16 id = added_objects.front();
1997 ServerActiveObject *obj = m_env->getActiveObject(id);
1998 added_objects.pop();
2001 warningstream << FUNCTION_NAME << ": NULL object id="
2002 << (int)id << std::endl;
2007 u8 type = obj->getSendType();
2009 // Add to data buffer for sending
2010 writeU16((u8*)buf, id);
2011 data.append(buf, 2);
2012 writeU8((u8*)buf, type);
2013 data.append(buf, 1);
2015 data.append(serializeLongString(
2016 obj->getClientInitializationData(client->net_proto_version)));
2018 // Add to known objects
2019 client->m_known_objects.insert(id);
2021 obj->m_known_by_count++;
2024 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2025 pkt.putRawString(data.c_str(), data.size());
2028 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2029 << removed_count << " removed, " << added_count << " added, "
2030 << "packet size is " << pkt.getSize() << std::endl;
2033 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2036 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2037 datas.size(), peer_id);
2039 pkt.putRawString(datas.c_str(), datas.size());
2041 m_clients.send(pkt.getPeerId(),
2042 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2046 void Server::SendCSMRestrictionFlags(session_t peer_id)
2048 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2049 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2050 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2054 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2056 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2061 inline s32 Server::nextSoundId()
2063 s32 ret = m_next_sound_id;
2064 if (m_next_sound_id == INT32_MAX)
2065 m_next_sound_id = 0; // signed overflow is undefined
2071 s32 Server::playSound(const SimpleSoundSpec &spec,
2072 const ServerSoundParams ¶ms, bool ephemeral)
2074 // Find out initial position of sound
2075 bool pos_exists = false;
2076 v3f pos = params.getPos(m_env, &pos_exists);
2077 // If position is not found while it should be, cancel sound
2078 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2081 // Filter destination clients
2082 std::vector<session_t> dst_clients;
2083 if (!params.to_player.empty()) {
2084 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2086 infostream<<"Server::playSound: Player \""<<params.to_player
2087 <<"\" not found"<<std::endl;
2090 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2091 infostream<<"Server::playSound: Player \""<<params.to_player
2092 <<"\" not connected"<<std::endl;
2095 dst_clients.push_back(player->getPeerId());
2097 std::vector<session_t> clients = m_clients.getClientIDs();
2099 for (const session_t client_id : clients) {
2100 RemotePlayer *player = m_env->getPlayer(client_id);
2103 if (!params.exclude_player.empty() &&
2104 params.exclude_player == player->getName())
2107 PlayerSAO *sao = player->getPlayerSAO();
2112 if(sao->getBasePosition().getDistanceFrom(pos) >
2113 params.max_hear_distance)
2116 dst_clients.push_back(client_id);
2120 if(dst_clients.empty())
2125 ServerPlayingSound *psound = nullptr;
2127 id = -1; // old clients will still use this, so pick a reserved ID
2130 // The sound will exist as a reference in m_playing_sounds
2131 m_playing_sounds[id] = ServerPlayingSound();
2132 psound = &m_playing_sounds[id];
2133 psound->params = params;
2134 psound->spec = spec;
2137 float gain = params.gain * spec.gain;
2138 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2139 pkt << id << spec.name << gain
2140 << (u8) params.type << pos << params.object
2141 << params.loop << params.fade << params.pitch
2144 bool as_reliable = !ephemeral;
2146 for (const u16 dst_client : dst_clients) {
2148 psound->clients.insert(dst_client);
2149 m_clients.send(dst_client, 0, &pkt, as_reliable);
2153 void Server::stopSound(s32 handle)
2155 // Get sound reference
2156 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2157 m_playing_sounds.find(handle);
2158 if (i == m_playing_sounds.end())
2160 ServerPlayingSound &psound = i->second;
2162 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2165 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2166 si != psound.clients.end(); ++si) {
2168 m_clients.send(*si, 0, &pkt, true);
2170 // Remove sound reference
2171 m_playing_sounds.erase(i);
2174 void Server::fadeSound(s32 handle, float step, float gain)
2176 // Get sound reference
2177 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2178 m_playing_sounds.find(handle);
2179 if (i == m_playing_sounds.end())
2182 ServerPlayingSound &psound = i->second;
2183 psound.params.gain = gain;
2185 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2186 pkt << handle << step << gain;
2188 // Backwards compability
2189 bool play_sound = gain > 0;
2190 ServerPlayingSound compat_psound = psound;
2191 compat_psound.clients.clear();
2193 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2194 compat_pkt << handle;
2196 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2197 it != psound.clients.end();) {
2198 if (m_clients.getProtocolVersion(*it) >= 32) {
2200 m_clients.send(*it, 0, &pkt, true);
2203 compat_psound.clients.insert(*it);
2205 m_clients.send(*it, 0, &compat_pkt, true);
2206 psound.clients.erase(it++);
2210 // Remove sound reference
2211 if (!play_sound || psound.clients.empty())
2212 m_playing_sounds.erase(i);
2214 if (play_sound && !compat_psound.clients.empty()) {
2215 // Play new sound volume on older clients
2216 playSound(compat_psound.spec, compat_psound.params);
2220 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2223 float maxd = far_d_nodes * BS;
2224 v3f p_f = intToFloat(p, BS);
2225 v3s16 block_pos = getNodeBlockPos(p);
2227 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2230 std::vector<session_t> clients = m_clients.getClientIDs();
2233 for (session_t client_id : clients) {
2234 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2238 RemotePlayer *player = m_env->getPlayer(client_id);
2239 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2241 // If player is far away, only set modified blocks not sent
2242 if (!client->isBlockSent(block_pos) || (sao &&
2243 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2245 far_players->emplace(client_id);
2247 client->SetBlockNotSent(block_pos);
2252 m_clients.send(client_id, 0, &pkt, true);
2258 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2259 float far_d_nodes, bool remove_metadata)
2261 float maxd = far_d_nodes * BS;
2262 v3f p_f = intToFloat(p, BS);
2263 v3s16 block_pos = getNodeBlockPos(p);
2265 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2266 pkt << p << n.param0 << n.param1 << n.param2
2267 << (u8) (remove_metadata ? 0 : 1);
2269 std::vector<session_t> clients = m_clients.getClientIDs();
2272 for (session_t client_id : clients) {
2273 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2277 RemotePlayer *player = m_env->getPlayer(client_id);
2278 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2280 // If player is far away, only set modified blocks not sent
2281 if (!client->isBlockSent(block_pos) || (sao &&
2282 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2284 far_players->emplace(client_id);
2286 client->SetBlockNotSent(block_pos);
2291 m_clients.send(client_id, 0, &pkt, true);
2297 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2299 float maxd = far_d_nodes * BS;
2300 NodeMetadataList meta_updates_list(false);
2301 std::vector<session_t> clients = m_clients.getClientIDs();
2305 for (session_t i : clients) {
2306 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2310 ServerActiveObject *player = m_env->getActiveObject(i);
2311 v3f player_pos = player ? player->getBasePosition() : v3f();
2313 for (const v3s16 &pos : meta_updates) {
2314 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2319 v3s16 block_pos = getNodeBlockPos(pos);
2320 if (!client->isBlockSent(block_pos) || (player &&
2321 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2322 client->SetBlockNotSent(block_pos);
2326 // Add the change to send list
2327 meta_updates_list.set(pos, meta);
2329 if (meta_updates_list.size() == 0)
2332 // Send the meta changes
2333 std::ostringstream os(std::ios::binary);
2334 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2335 std::ostringstream oss(std::ios::binary);
2336 compressZlib(os.str(), oss);
2338 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2339 pkt.putLongString(oss.str());
2340 m_clients.send(i, 0, &pkt, true);
2342 meta_updates_list.clear();
2348 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2349 u16 net_proto_version)
2352 Create a packet with the block in the right format
2355 std::ostringstream os(std::ios_base::binary);
2356 block->serialize(os, ver, false);
2357 block->serializeNetworkSpecific(os);
2358 std::string s = os.str();
2360 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2362 pkt << block->getPos();
2363 pkt.putRawString(s.c_str(), s.size());
2367 void Server::SendBlocks(float dtime)
2369 MutexAutoLock envlock(m_env_mutex);
2370 //TODO check if one big lock could be faster then multiple small ones
2372 std::vector<PrioritySortedBlockTransfer> queue;
2374 u32 total_sending = 0;
2377 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2379 std::vector<session_t> clients = m_clients.getClientIDs();
2382 for (const session_t client_id : clients) {
2383 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2388 total_sending += client->getSendingCount();
2389 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2395 // Lowest priority number comes first.
2396 // Lowest is most important.
2397 std::sort(queue.begin(), queue.end());
2401 // Maximal total count calculation
2402 // The per-client block sends is halved with the maximal online users
2403 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2404 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2406 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2407 Map &map = m_env->getMap();
2409 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2410 if (total_sending >= max_blocks_to_send)
2413 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2417 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2422 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2423 client->net_proto_version);
2425 client->SentBlock(block_to_send.pos);
2431 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2433 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2438 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2439 if (!client || client->isBlockSent(blockpos)) {
2443 SendBlockNoLock(peer_id, block, client->serialization_version,
2444 client->net_proto_version);
2450 void Server::fillMediaCache()
2452 infostream<<"Server: Calculating media file checksums"<<std::endl;
2454 // Collect all media file paths
2455 std::vector<std::string> paths;
2456 m_modmgr->getModsMediaPaths(paths);
2457 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2458 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2460 // Collect media file information from paths into cache
2461 for (const std::string &mediapath : paths) {
2462 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2463 for (const fs::DirListNode &dln : dirlist) {
2464 if (dln.dir) // Ignode dirs
2466 std::string filename = dln.name;
2467 // If name contains illegal characters, ignore the file
2468 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2469 infostream<<"Server: ignoring illegal file name: \""
2470 << filename << "\"" << std::endl;
2473 // If name is not in a supported format, ignore it
2474 const char *supported_ext[] = {
2475 ".png", ".jpg", ".bmp", ".tga",
2476 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2478 ".x", ".b3d", ".md2", ".obj",
2479 // Custom translation file format
2483 if (removeStringEnd(filename, supported_ext).empty()){
2484 infostream << "Server: ignoring unsupported file extension: \""
2485 << filename << "\"" << std::endl;
2488 // Ok, attempt to load the file and add to cache
2489 std::string filepath;
2490 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2493 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2495 errorstream << "Server::fillMediaCache(): Could not open \""
2496 << filename << "\" for reading" << std::endl;
2499 std::ostringstream tmp_os(std::ios_base::binary);
2503 fis.read(buf, 1024);
2504 std::streamsize len = fis.gcount();
2505 tmp_os.write(buf, len);
2514 errorstream<<"Server::fillMediaCache(): Failed to read \""
2515 << filename << "\"" << std::endl;
2518 if(tmp_os.str().length() == 0) {
2519 errorstream << "Server::fillMediaCache(): Empty file \""
2520 << filepath << "\"" << std::endl;
2525 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2527 unsigned char *digest = sha1.getDigest();
2528 std::string sha1_base64 = base64_encode(digest, 20);
2529 std::string sha1_hex = hex_encode((char*)digest, 20);
2533 m_media[filename] = MediaInfo(filepath, sha1_base64);
2534 verbosestream << "Server: " << sha1_hex << " is " << filename
2540 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2543 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2546 std::string lang_suffix;
2547 lang_suffix.append(".").append(lang_code).append(".tr");
2548 for (const auto &i : m_media) {
2549 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2556 for (const auto &i : m_media) {
2557 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2559 pkt << i.first << i.second.sha1_digest;
2562 pkt << g_settings->get("remote_media");
2565 verbosestream << "Server: Announcing files to id(" << peer_id
2566 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2569 struct SendableMedia
2575 SendableMedia(const std::string &name_="", const std::string &path_="",
2576 const std::string &data_=""):
2583 void Server::sendRequestedMedia(session_t peer_id,
2584 const std::vector<std::string> &tosend)
2586 verbosestream<<"Server::sendRequestedMedia(): "
2587 <<"Sending files to client"<<std::endl;
2591 // Put 5kB in one bunch (this is not accurate)
2592 u32 bytes_per_bunch = 5000;
2594 std::vector< std::vector<SendableMedia> > file_bunches;
2595 file_bunches.emplace_back();
2597 u32 file_size_bunch_total = 0;
2599 for (const std::string &name : tosend) {
2600 if (m_media.find(name) == m_media.end()) {
2601 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2602 <<"unknown file \""<<(name)<<"\""<<std::endl;
2606 //TODO get path + name
2607 std::string tpath = m_media[name].path;
2610 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2612 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2613 <<tpath<<"\" for reading"<<std::endl;
2616 std::ostringstream tmp_os(std::ios_base::binary);
2620 fis.read(buf, 1024);
2621 std::streamsize len = fis.gcount();
2622 tmp_os.write(buf, len);
2623 file_size_bunch_total += len;
2632 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2633 <<name<<"\""<<std::endl;
2636 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2637 <<tname<<"\""<<std::endl;*/
2639 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2641 // Start next bunch if got enough data
2642 if(file_size_bunch_total >= bytes_per_bunch) {
2643 file_bunches.emplace_back();
2644 file_size_bunch_total = 0;
2649 /* Create and send packets */
2651 u16 num_bunches = file_bunches.size();
2652 for (u16 i = 0; i < num_bunches; i++) {
2655 u16 total number of texture bunches
2656 u16 index of this bunch
2657 u32 number of files in this bunch
2666 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2667 pkt << num_bunches << i << (u32) file_bunches[i].size();
2669 for (const SendableMedia &j : file_bunches[i]) {
2671 pkt.putLongString(j.data);
2674 verbosestream << "Server::sendRequestedMedia(): bunch "
2675 << i << "/" << num_bunches
2676 << " files=" << file_bunches[i].size()
2677 << " size=" << pkt.getSize() << std::endl;
2682 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2684 const auto &inv_it = m_detached_inventories.find(name);
2685 const auto &player_it = m_detached_inventories_player.find(name);
2687 if (player_it == m_detached_inventories_player.end() ||
2688 player_it->second.empty()) {
2689 // OK. Send to everyone
2692 return; // Mods are not done loading
2694 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2696 return; // Player is offline
2698 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2699 return; // Caller requested send to a different player, so don't send.
2701 peer_id = p->getPeerId();
2704 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2707 if (inv_it == m_detached_inventories.end()) {
2708 pkt << false; // Remove inventory
2710 pkt << true; // Update inventory
2712 // Serialization & NetworkPacket isn't a love story
2713 std::ostringstream os(std::ios_base::binary);
2714 inv_it->second->serialize(os);
2715 inv_it->second->setModified(false);
2717 const std::string &os_str = os.str();
2718 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2719 pkt.putRawString(os_str);
2722 if (peer_id == PEER_ID_INEXISTENT)
2723 m_clients.sendToAll(&pkt);
2728 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2730 for (const auto &detached_inventory : m_detached_inventories) {
2731 const std::string &name = detached_inventory.first;
2733 Inventory *inv = detached_inventory.second;
2734 if (!inv || !inv->checkModified())
2738 sendDetachedInventory(name, peer_id);
2746 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2748 PlayerSAO *playersao = getPlayerSAO(peer_id);
2751 infostream << "Server::DiePlayer(): Player "
2752 << playersao->getPlayer()->getName()
2753 << " dies" << std::endl;
2755 playersao->setHP(0, reason);
2756 playersao->clearParentAttachment();
2758 // Trigger scripted stuff
2759 m_script->on_dieplayer(playersao, reason);
2761 SendPlayerHP(peer_id);
2762 SendDeathscreen(peer_id, false, v3f(0,0,0));
2765 void Server::RespawnPlayer(session_t peer_id)
2767 PlayerSAO *playersao = getPlayerSAO(peer_id);
2770 infostream << "Server::RespawnPlayer(): Player "
2771 << playersao->getPlayer()->getName()
2772 << " respawns" << std::endl;
2774 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2775 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2776 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2778 bool repositioned = m_script->on_respawnplayer(playersao);
2779 if (!repositioned) {
2780 // setPos will send the new position to client
2781 playersao->setPos(findSpawnPos());
2784 SendPlayerHP(peer_id);
2788 void Server::DenySudoAccess(session_t peer_id)
2790 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2795 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2796 const std::string &str_reason, bool reconnect)
2798 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2800 m_clients.event(peer_id, CSE_SetDenied);
2801 DisconnectPeer(peer_id);
2805 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2806 const std::string &custom_reason)
2808 SendAccessDenied(peer_id, reason, custom_reason);
2809 m_clients.event(peer_id, CSE_SetDenied);
2810 DisconnectPeer(peer_id);
2813 // 13/03/15: remove this function when protocol version 25 will become
2814 // the minimum version for MT users, maybe in 1 year
2815 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2817 SendAccessDenied_Legacy(peer_id, reason);
2818 m_clients.event(peer_id, CSE_SetDenied);
2819 DisconnectPeer(peer_id);
2822 void Server::DisconnectPeer(session_t peer_id)
2824 m_modchannel_mgr->leaveAllChannels(peer_id);
2825 m_con->DisconnectPeer(peer_id);
2828 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2831 RemoteClient* client = getClient(peer_id, CS_Invalid);
2833 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2835 // Right now, the auth mechs don't change between login and sudo mode.
2836 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2837 client->allowed_sudo_mechs = sudo_auth_mechs;
2839 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2840 << g_settings->getFloat("dedicated_server_step")
2844 m_clients.event(peer_id, CSE_AuthAccept);
2846 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2848 // We only support SRP right now
2849 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2851 resp_pkt << sudo_auth_mechs;
2853 m_clients.event(peer_id, CSE_SudoSuccess);
2857 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2859 std::wstring message;
2862 Clear references to playing sounds
2864 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2865 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2866 ServerPlayingSound &psound = i->second;
2867 psound.clients.erase(peer_id);
2868 if (psound.clients.empty())
2869 m_playing_sounds.erase(i++);
2874 // clear formspec info so the next client can't abuse the current state
2875 m_formspec_state_data.erase(peer_id);
2877 RemotePlayer *player = m_env->getPlayer(peer_id);
2879 /* Run scripts and remove from environment */
2881 PlayerSAO *playersao = player->getPlayerSAO();
2884 playersao->clearChildAttachments();
2885 playersao->clearParentAttachment();
2887 // inform connected clients
2888 const std::string &player_name = player->getName();
2889 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2890 // (u16) 1 + std::string represents a vector serialization representation
2891 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2892 m_clients.sendToAll(¬ice);
2894 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2896 playersao->disconnected();
2903 if (player && reason != CDR_DENY) {
2904 std::ostringstream os(std::ios_base::binary);
2905 std::vector<session_t> clients = m_clients.getClientIDs();
2907 for (const session_t client_id : clients) {
2909 RemotePlayer *player = m_env->getPlayer(client_id);
2913 // Get name of player
2914 os << player->getName() << " ";
2917 std::string name = player->getName();
2918 actionstream << name << " "
2919 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2920 << " List of players: " << os.str() << std::endl;
2922 m_admin_chat->outgoing_queue.push_back(
2923 new ChatEventNick(CET_NICK_REMOVE, name));
2927 MutexAutoLock env_lock(m_env_mutex);
2928 m_clients.DeleteClient(peer_id);
2932 // Send leave chat message to all remaining clients
2933 if (!message.empty()) {
2934 SendChatMessage(PEER_ID_INEXISTENT,
2935 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2939 void Server::UpdateCrafting(RemotePlayer *player)
2941 InventoryList *clist = player->inventory.getList("craft");
2942 if (!clist || clist->getSize() == 0)
2945 if (!clist->checkModified())
2948 // Get a preview for crafting
2950 InventoryLocation loc;
2951 loc.setPlayer(player->getName());
2952 std::vector<ItemStack> output_replacements;
2953 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2954 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2957 InventoryList *plist = player->inventory.getList("craftpreview");
2958 if (plist && plist->getSize() >= 1) {
2959 // Put the new preview in
2960 plist->changeItem(0, preview);
2964 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2966 if (evt->type == CET_NICK_ADD) {
2967 // The terminal informed us of its nick choice
2968 m_admin_nick = ((ChatEventNick *)evt)->nick;
2969 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2970 errorstream << "You haven't set up an account." << std::endl
2971 << "Please log in using the client as '"
2972 << m_admin_nick << "' with a secure password." << std::endl
2973 << "Until then, you can't execute admin tasks via the console," << std::endl
2974 << "and everybody can claim the user account instead of you," << std::endl
2975 << "giving them full control over this server." << std::endl;
2978 assert(evt->type == CET_CHAT);
2979 handleAdminChat((ChatEventChat *)evt);
2983 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2984 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2986 // If something goes wrong, this player is to blame
2987 RollbackScopeActor rollback_scope(m_rollback,
2988 std::string("player:") + name);
2990 if (g_settings->getBool("strip_color_codes"))
2991 wmessage = unescape_enriched(wmessage);
2994 switch (player->canSendChatMessage()) {
2995 case RPLAYER_CHATRESULT_FLOODING: {
2996 std::wstringstream ws;
2997 ws << L"You cannot send more messages. You are limited to "
2998 << g_settings->getFloat("chat_message_limit_per_10sec")
2999 << L" messages per 10 seconds.";
3002 case RPLAYER_CHATRESULT_KICK:
3003 DenyAccess_Legacy(player->getPeerId(),
3004 L"You have been kicked due to message flooding.");
3006 case RPLAYER_CHATRESULT_OK:
3009 FATAL_ERROR("Unhandled chat filtering result found.");
3013 if (m_max_chatmessage_length > 0
3014 && wmessage.length() > m_max_chatmessage_length) {
3015 return L"Your message exceed the maximum chat message limit set on the server. "
3016 L"It was refused. Send a shorter message";
3019 auto message = trim(wide_to_utf8(wmessage));
3020 if (message.find_first_of("\n\r") != std::wstring::npos) {
3021 return L"New lines are not permitted in chat messages";
3024 // Run script hook, exit if script ate the chat message
3025 if (m_script->on_chat_message(name, message))
3030 // Whether to send line to the player that sent the message, or to all players
3031 bool broadcast_line = true;
3033 if (check_shout_priv && !checkPriv(name, "shout")) {
3034 line += L"-!- You don't have permission to shout.";
3035 broadcast_line = false;
3038 Workaround for fixing chat on Android. Lua doesn't handle
3039 the Cyrillic alphabet and some characters on older Android devices
3042 line += L"<" + wname + L"> " + wmessage;
3044 line += narrow_to_wide(m_script->formatChatMessage(name,
3045 wide_to_narrow(wmessage)));
3050 Tell calling method to send the message to sender
3052 if (!broadcast_line)
3056 Send the message to others
3058 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
3060 std::vector<session_t> clients = m_clients.getClientIDs();
3063 Send the message back to the inital sender
3064 if they are using protocol version >= 29
3067 session_t peer_id_to_avoid_sending =
3068 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
3070 if (player && player->protocol_version >= 29)
3071 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
3073 for (u16 cid : clients) {
3074 if (cid != peer_id_to_avoid_sending)
3075 SendChatMessage(cid, ChatMessage(line));
3080 void Server::handleAdminChat(const ChatEventChat *evt)
3082 std::string name = evt->nick;
3083 std::wstring wname = utf8_to_wide(name);
3084 std::wstring wmessage = evt->evt_msg;
3086 std::wstring answer = handleChat(name, wname, wmessage);
3088 // If asked to send answer to sender
3089 if (!answer.empty()) {
3090 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3094 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3096 RemoteClient *client = getClientNoEx(peer_id,state_min);
3098 throw ClientNotFoundException("Client not found");
3102 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3104 return m_clients.getClientNoEx(peer_id, state_min);
3107 std::string Server::getPlayerName(session_t peer_id)
3109 RemotePlayer *player = m_env->getPlayer(peer_id);
3111 return "[id="+itos(peer_id)+"]";
3112 return player->getName();
3115 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3117 RemotePlayer *player = m_env->getPlayer(peer_id);
3120 return player->getPlayerSAO();
3123 std::wstring Server::getStatusString()
3125 std::wostringstream os(std::ios_base::binary);
3126 os << L"# Server: ";
3128 os << L"version=" << narrow_to_wide(g_version_string);
3130 os << L", uptime=" << m_uptime.get();
3132 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3134 // Information about clients
3136 os << L", clients={";
3138 std::vector<session_t> clients = m_clients.getClientIDs();
3139 for (session_t client_id : clients) {
3140 RemotePlayer *player = m_env->getPlayer(client_id);
3142 // Get name of player
3143 std::wstring name = L"unknown";
3145 name = narrow_to_wide(player->getName());
3147 // Add name to information string
3158 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3159 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3161 if (!g_settings->get("motd").empty())
3162 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3167 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3169 std::set<std::string> privs;
3170 m_script->getAuth(name, NULL, &privs);
3174 bool Server::checkPriv(const std::string &name, const std::string &priv)
3176 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3177 return (privs.count(priv) != 0);
3180 void Server::reportPrivsModified(const std::string &name)
3183 std::vector<session_t> clients = m_clients.getClientIDs();
3184 for (const session_t client_id : clients) {
3185 RemotePlayer *player = m_env->getPlayer(client_id);
3186 reportPrivsModified(player->getName());
3189 RemotePlayer *player = m_env->getPlayer(name.c_str());
3192 SendPlayerPrivileges(player->getPeerId());
3193 PlayerSAO *sao = player->getPlayerSAO();
3196 sao->updatePrivileges(
3197 getPlayerEffectivePrivs(name),
3202 void Server::reportInventoryFormspecModified(const std::string &name)
3204 RemotePlayer *player = m_env->getPlayer(name.c_str());
3207 SendPlayerInventoryFormspec(player->getPeerId());
3210 void Server::reportFormspecPrependModified(const std::string &name)
3212 RemotePlayer *player = m_env->getPlayer(name.c_str());
3215 SendPlayerFormspecPrepend(player->getPeerId());
3218 void Server::setIpBanned(const std::string &ip, const std::string &name)
3220 m_banmanager->add(ip, name);
3223 void Server::unsetIpBanned(const std::string &ip_or_name)
3225 m_banmanager->remove(ip_or_name);
3228 std::string Server::getBanDescription(const std::string &ip_or_name)
3230 return m_banmanager->getBanDescription(ip_or_name);
3233 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3235 // m_env will be NULL if the server is initializing
3239 if (m_admin_nick == name && !m_admin_nick.empty()) {
3240 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3243 RemotePlayer *player = m_env->getPlayer(name);
3248 if (player->getPeerId() == PEER_ID_INEXISTENT)
3251 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3254 bool Server::showFormspec(const char *playername, const std::string &formspec,
3255 const std::string &formname)
3257 // m_env will be NULL if the server is initializing
3261 RemotePlayer *player = m_env->getPlayer(playername);
3265 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3269 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3274 u32 id = player->addHud(form);
3276 SendHUDAdd(player->getPeerId(), id, form);
3281 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3285 HudElement* todel = player->removeHud(id);
3292 SendHUDRemove(player->getPeerId(), id);
3296 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3301 SendHUDChange(player->getPeerId(), id, stat, data);
3305 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3310 SendHUDSetFlags(player->getPeerId(), flags, mask);
3311 player->hud_flags &= ~mask;
3312 player->hud_flags |= flags;
3314 PlayerSAO* playersao = player->getPlayerSAO();
3319 m_script->player_event(playersao, "hud_changed");
3323 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3328 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3331 player->setHotbarItemcount(hotbar_itemcount);
3332 std::ostringstream os(std::ios::binary);
3333 writeS32(os, hotbar_itemcount);
3334 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3338 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3343 player->setHotbarImage(name);
3344 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3347 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3352 player->setHotbarSelectedImage(name);
3353 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3356 Address Server::getPeerAddress(session_t peer_id)
3358 return m_con->GetPeerAddress(peer_id);
3361 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3362 v2s32 animation_frames[4], f32 frame_speed)
3364 sanity_check(player);
3365 player->setLocalAnimations(animation_frames, frame_speed);
3366 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3369 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3371 sanity_check(player);
3372 player->eye_offset_first = first;
3373 player->eye_offset_third = third;
3374 SendEyeOffset(player->getPeerId(), first, third);
3377 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3379 sanity_check(player);
3380 player->setSky(params);
3381 SendSetSky(player->getPeerId(), params);
3384 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3386 sanity_check(player);
3387 player->setSun(params);
3388 SendSetSun(player->getPeerId(), params);
3391 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3393 sanity_check(player);
3394 player->setMoon(params);
3395 SendSetMoon(player->getPeerId(), params);
3398 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3400 sanity_check(player);
3401 player->setStars(params);
3402 SendSetStars(player->getPeerId(), params);
3405 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3407 sanity_check(player);
3408 player->setCloudParams(params);
3409 SendCloudParams(player->getPeerId(), params);
3412 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3418 player->overrideDayNightRatio(do_override, ratio);
3419 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3423 void Server::notifyPlayers(const std::wstring &msg)
3425 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3428 void Server::spawnParticle(const std::string &playername, v3f pos,
3429 v3f velocity, v3f acceleration,
3430 float expirationtime, float size, bool
3431 collisiondetection, bool collision_removal, bool object_collision,
3432 bool vertical, const std::string &texture,
3433 const struct TileAnimationParams &animation, u8 glow)
3435 // m_env will be NULL if the server is initializing
3439 session_t peer_id = PEER_ID_INEXISTENT;
3441 if (!playername.empty()) {
3442 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3445 peer_id = player->getPeerId();
3446 proto_ver = player->protocol_version;
3449 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3450 expirationtime, size, collisiondetection, collision_removal,
3451 object_collision, vertical, texture, animation, glow);
3454 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3455 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3456 float minexptime, float maxexptime, float minsize, float maxsize,
3457 bool collisiondetection, bool collision_removal, bool object_collision,
3458 ServerActiveObject *attached, bool vertical, const std::string &texture,
3459 const std::string &playername, const struct TileAnimationParams &animation,
3462 // m_env will be NULL if the server is initializing
3466 session_t peer_id = PEER_ID_INEXISTENT;
3468 if (!playername.empty()) {
3469 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3472 peer_id = player->getPeerId();
3473 proto_ver = player->protocol_version;
3476 u16 attached_id = attached ? attached->getId() : 0;
3479 if (attached_id == 0)
3480 id = m_env->addParticleSpawner(spawntime);
3482 id = m_env->addParticleSpawner(spawntime, attached_id);
3484 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3485 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3486 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3487 collision_removal, object_collision, attached_id, vertical,
3488 texture, id, animation, glow);
3493 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3495 // m_env will be NULL if the server is initializing
3497 throw ServerError("Can't delete particle spawners during initialisation!");
3499 session_t peer_id = PEER_ID_INEXISTENT;
3500 if (!playername.empty()) {
3501 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3504 peer_id = player->getPeerId();
3507 m_env->deleteParticleSpawner(id);
3508 SendDeleteParticleSpawner(peer_id, id);
3511 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3513 if(m_detached_inventories.count(name) > 0){
3514 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3515 delete m_detached_inventories[name];
3517 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3519 Inventory *inv = new Inventory(m_itemdef);
3521 m_detached_inventories[name] = inv;
3522 if (!player.empty())
3523 m_detached_inventories_player[name] = player;
3525 //TODO find a better way to do this
3526 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3530 bool Server::removeDetachedInventory(const std::string &name)
3532 const auto &inv_it = m_detached_inventories.find(name);
3533 if (inv_it == m_detached_inventories.end())
3536 delete inv_it->second;
3537 m_detached_inventories.erase(inv_it);
3539 if (!m_env) // Mods are not done loading
3542 const auto &player_it = m_detached_inventories_player.find(name);
3543 if (player_it != m_detached_inventories_player.end()) {
3544 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3546 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3547 sendDetachedInventory(name, player->getPeerId());
3549 m_detached_inventories_player.erase(player_it);
3551 // Notify all players about the change
3552 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3557 // actions: time-reversed list
3558 // Return value: success/failure
3559 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3560 std::list<std::string> *log)
3562 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3563 ServerMap *map = (ServerMap*)(&m_env->getMap());
3565 // Fail if no actions to handle
3566 if (actions.empty()) {
3568 log->push_back("Nothing to do.");
3575 for (const RollbackAction &action : actions) {
3577 bool success = action.applyRevert(map, this, this);
3580 std::ostringstream os;
3581 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3582 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3584 log->push_back(os.str());
3586 std::ostringstream os;
3587 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3588 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3590 log->push_back(os.str());
3594 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3595 <<" failed"<<std::endl;
3597 // Call it done if less than half failed
3598 return num_failed <= num_tried/2;
3601 // IGameDef interface
3603 IItemDefManager *Server::getItemDefManager()
3608 const NodeDefManager *Server::getNodeDefManager()
3613 ICraftDefManager *Server::getCraftDefManager()
3618 u16 Server::allocateUnknownNodeId(const std::string &name)
3620 return m_nodedef->allocateDummy(name);
3623 IWritableItemDefManager *Server::getWritableItemDefManager()
3628 NodeDefManager *Server::getWritableNodeDefManager()
3633 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3638 const std::vector<ModSpec> & Server::getMods() const
3640 return m_modmgr->getMods();
3643 const ModSpec *Server::getModSpec(const std::string &modname) const
3645 return m_modmgr->getModSpec(modname);
3648 void Server::getModNames(std::vector<std::string> &modlist)
3650 m_modmgr->getModNames(modlist);
3653 std::string Server::getBuiltinLuaPath()
3655 return porting::path_share + DIR_DELIM + "builtin";
3658 std::string Server::getModStoragePath() const
3660 return m_path_world + DIR_DELIM + "mod_storage";
3663 v3f Server::findSpawnPos()
3665 ServerMap &map = m_env->getServerMap();
3667 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3668 return nodeposf * BS;
3670 bool is_good = false;
3671 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3672 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3674 // Try to find a good place a few times
3675 for (s32 i = 0; i < 4000 && !is_good; i++) {
3676 s32 range = MYMIN(1 + i, range_max);
3677 // We're going to try to throw the player to this position
3678 v2s16 nodepos2d = v2s16(
3679 -range + (myrand() % (range * 2)),
3680 -range + (myrand() % (range * 2)));
3681 // Get spawn level at point
3682 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3683 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3684 // signify an unsuitable spawn position, or if outside limits.
3685 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3686 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3689 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3690 // Consecutive empty nodes
3693 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3694 // avoid obstructions in already-generated mapblocks.
3695 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3696 // no obstructions, but mapgen decorations are generated after spawn so
3697 // the player may end up inside one.
3698 for (s32 i = 0; i < 8; i++) {
3699 v3s16 blockpos = getNodeBlockPos(nodepos);
3700 map.emergeBlock(blockpos, true);
3701 content_t c = map.getNode(nodepos).getContent();
3703 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3704 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3705 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3707 if (air_count >= 2) {
3708 // Spawn in lower empty node
3710 nodeposf = intToFloat(nodepos, BS);
3711 // Don't spawn the player outside map boundaries
3712 if (objectpos_over_limit(nodeposf))
3713 // Exit this loop, positions above are probably over limit
3716 // Good position found, cause an exit from main loop
3730 // No suitable spawn point found, return fallback 0,0,0
3731 return v3f(0.0f, 0.0f, 0.0f);
3734 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3736 if (delay == 0.0f) {
3737 // No delay, shutdown immediately
3738 m_shutdown_state.is_requested = true;
3739 // only print to the infostream, a chat message saying
3740 // "Server Shutting Down" is sent when the server destructs.
3741 infostream << "*** Immediate Server shutdown requested." << std::endl;
3742 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3743 // Negative delay, cancel shutdown if requested
3744 m_shutdown_state.reset();
3745 std::wstringstream ws;
3747 ws << L"*** Server shutdown canceled.";
3749 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3750 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3751 // m_shutdown_* are already handled, skip.
3753 } else if (delay > 0.0f) {
3754 // Positive delay, tell the clients when the server will shut down
3755 std::wstringstream ws;
3757 ws << L"*** Server shutting down in "
3758 << duration_to_string(myround(delay)).c_str()
3761 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3762 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3765 m_shutdown_state.trigger(delay, msg, reconnect);
3768 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3771 Try to get an existing player
3773 RemotePlayer *player = m_env->getPlayer(name);
3775 // If player is already connected, cancel
3776 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3777 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3782 If player with the wanted peer_id already exists, cancel.
3784 if (m_env->getPlayer(peer_id)) {
3785 infostream<<"emergePlayer(): Player with wrong name but same"
3786 " peer_id already exists"<<std::endl;
3791 player = new RemotePlayer(name, idef());
3794 bool newplayer = false;
3797 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3799 // Complete init with server parts
3800 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3801 player->protocol_version = proto_version;
3805 m_script->on_newplayer(playersao);
3811 bool Server::registerModStorage(ModMetadata *storage)
3813 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3814 errorstream << "Unable to register same mod storage twice. Storage name: "
3815 << storage->getModName() << std::endl;
3819 m_mod_storages[storage->getModName()] = storage;
3823 void Server::unregisterModStorage(const std::string &name)
3825 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3826 if (it != m_mod_storages.end()) {
3827 // Save unconditionaly on unregistration
3828 it->second->save(getModStoragePath());
3829 m_mod_storages.erase(name);
3833 void dedicated_server_loop(Server &server, bool &kill)
3835 verbosestream<<"dedicated_server_loop()"<<std::endl;
3837 IntervalLimiter m_profiler_interval;
3839 static thread_local const float steplen =
3840 g_settings->getFloat("dedicated_server_step");
3841 static thread_local const float profiler_print_interval =
3842 g_settings->getFloat("profiler_print_interval");
3845 * The dedicated server loop only does time-keeping (in Server::step) and
3846 * provides a way to main.cpp to kill the server externally (bool &kill).
3850 // This is kind of a hack but can be done like this
3851 // because server.step() is very light
3852 sleep_ms((int)(steplen*1000.0));
3853 server.step(steplen);
3855 if (server.isShutdownRequested() || kill)
3861 if (profiler_print_interval != 0) {
3862 if(m_profiler_interval.step(steplen, profiler_print_interval))
3864 infostream<<"Profiler:"<<std::endl;
3865 g_profiler->print(infostream);
3866 g_profiler->clear();
3871 infostream << "Dedicated server quitting" << std::endl;
3873 if (g_settings->getBool("server_announce"))
3874 ServerList::sendAnnounce(ServerList::AA_DELETE,
3875 server.m_bind_addr.getPort());
3884 bool Server::joinModChannel(const std::string &channel)
3886 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3887 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3890 bool Server::leaveModChannel(const std::string &channel)
3892 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3895 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3897 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3900 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3904 ModChannel* Server::getModChannel(const std::string &channel)
3906 return m_modchannel_mgr->getModChannel(channel);
3909 void Server::broadcastModChannelMessage(const std::string &channel,
3910 const std::string &message, session_t from_peer)
3912 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3916 if (message.size() > STRING_MAX_LEN) {
3917 warningstream << "ModChannel message too long, dropping before sending "
3918 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3919 << channel << ")" << std::endl;
3924 if (from_peer != PEER_ID_SERVER) {
3925 sender = getPlayerName(from_peer);
3928 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3929 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3930 resp_pkt << channel << sender << message;
3931 for (session_t peer_id : peers) {
3933 if (peer_id == from_peer)
3936 Send(peer_id, &resp_pkt);
3939 if (from_peer != PEER_ID_SERVER) {
3940 m_script->on_modchannel_message(channel, sender, message);
3944 void Server::loadTranslationLanguage(const std::string &lang_code)
3946 if (g_server_translations->count(lang_code))
3947 return; // Already loaded
3949 std::string suffix = "." + lang_code + ".tr";
3950 for (const auto &i : m_media) {
3951 if (str_ends_with(i.first, suffix)) {
3952 std::ifstream t(i.second.path);
3953 std::string data((std::istreambuf_iterator<char>(t)),
3954 std::istreambuf_iterator<char>());
3956 (*g_server_translations)[lang_code].loadTranslation(data);