]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/server.cpp
Merge pull request #35 from arydevy/patch-1
[dragonfireclient.git] / src / server.cpp
index 982f904f4c491a515cf25678001b4b20714e6c07..a8d45278308b940a5336f0602e0336f861d7bd90 100644 (file)
@@ -351,6 +351,8 @@ Server::~Server()
        // Deinitialize scripting
        infostream << "Server: Deinitializing scripting" << std::endl;
        delete m_script;
+       delete m_startup_server_map; // if available
+       delete m_game_settings;
 
        while (!m_unsent_map_edit_queue.empty()) {
                delete m_unsent_map_edit_queue.front();
@@ -368,6 +370,8 @@ void Server::init()
        infostream << "- world:  " << m_path_world << std::endl;
        infostream << "- game:   " << m_gamespec.path << std::endl;
 
+       m_game_settings = Settings::createLayer(SL_GAME);
+
        // Create world if it doesn't exist
        try {
                loadGameConfAndInitWorld(m_path_world,
@@ -396,6 +400,7 @@ void Server::init()
 
        // Create the Map (loads map_meta.txt, overriding configured mapgen params)
        ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge, m_metrics_backend.get());
+       m_startup_server_map = servermap;
 
        // Initialize scripting
        infostream << "Server: Initializing Lua" << std::endl;
@@ -437,6 +442,7 @@ void Server::init()
        m_craftdef->initHashes(this);
 
        // Initialize Environment
+       m_startup_server_map = nullptr; // Ownership moved to ServerEnvironment
        m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
 
        m_inventory_mgr->setEnv(m_env);
@@ -1239,20 +1245,8 @@ bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float*
        return *retval != -1;
 }
 
-bool Server::getClientInfo(
-               session_t    peer_id,
-               ClientState* state,
-               u32*         uptime,
-               u8*          ser_vers,
-               u16*         prot_vers,
-               u8*          major,
-               u8*          minor,
-               u8*          patch,
-               std::string* vers_string,
-               std::string* lang_code
-       )
-{
-       *state = m_clients.getClientState(peer_id);
+bool Server::getClientInfo(session_t peer_id, ClientInfo &ret)
+{
        m_clients.lock();
        RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
 
@@ -1261,15 +1255,18 @@ bool Server::getClientInfo(
                return false;
        }
 
-       *uptime = client->uptime();
-       *ser_vers = client->serialization_version;
-       *prot_vers = client->net_proto_version;
+       ret.state = client->getState();
+       ret.addr = client->getAddress();
+       ret.uptime = client->uptime();
+       ret.ser_vers = client->serialization_version;
+       ret.prot_vers = client->net_proto_version;
 
-       *major = client->getMajor();
-       *minor = client->getMinor();
-       *patch = client->getPatch();
-       *vers_string = client->getFull();
-       *lang_code = client->getLangCode();
+       ret.major = client->getMajor();
+       ret.minor = client->getMinor();
+       ret.patch = client->getPatch();
+       ret.vers_string = client->getFullVer();
+
+       ret.lang_code = client->getLangCode();
 
        m_clients.unlock();
 
@@ -1355,7 +1352,7 @@ void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason
                return;
 
        session_t peer_id = playersao->getPeerID();
-       bool is_alive = playersao->getHP() > 0;
+       bool is_alive = !playersao->isDead();
 
        if (is_alive)
                SendPlayerHP(peer_id);
@@ -1488,7 +1485,8 @@ void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
        NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
        u8 version = 1;
        u8 type = message.type;
-       pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
+       pkt << version << type << message.sender << message.message
+               << static_cast<u64>(message.timestamp);
 
        if (peer_id != PEER_ID_INEXISTENT) {
                RemotePlayer *player = m_env->getPlayer(peer_id);
@@ -1823,6 +1821,9 @@ void Server::SendMovePlayer(session_t peer_id)
        PlayerSAO *sao = player->getPlayerSAO();
        assert(sao);
 
+       // Send attachment updates instantly to the client prior updating position
+       sao->sendOutdatedData();
+
        NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
        pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
 
@@ -2332,9 +2333,9 @@ void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
        /*
                Create a packet with the block in the right format
        */
-
+       thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
        std::ostringstream os(std::ios_base::binary);
-       block->serialize(os, ver, false);
+       block->serialize(os, ver, false, net_compression_level);
        block->serializeNetworkSpecific(os);
        std::string s = os.str();
 
@@ -2495,7 +2496,9 @@ void Server::fillMediaCache()
 
        // Collect all media file paths
        std::vector<std::string> paths;
-       // The paths are ordered in descending priority
+
+       // ordered in descending priority
+       paths.push_back(getBuiltinLuaPath() + DIR_DELIM + "locale");
        fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
        fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
        m_modmgr->getModsMediaPaths(paths);
@@ -2662,6 +2665,23 @@ void Server::sendRequestedMedia(session_t peer_id,
        }
 }
 
+void Server::SendMinimapModes(session_t peer_id,
+               std::vector<MinimapMode> &modes, size_t wanted_mode)
+{
+       RemotePlayer *player = m_env->getPlayer(peer_id);
+       assert(player);
+       if (player->getPeerId() == PEER_ID_INEXISTENT)
+               return;
+
+       NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
+       pkt << (u16)modes.size() << (u16)wanted_mode;
+
+       for (auto &mode : modes)
+               pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
+
+       Send(&pkt);
+}
+
 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
 {
        NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
@@ -2944,7 +2964,7 @@ void Server::handleChatInterfaceEvent(ChatEvent *evt)
        }
 }
 
-std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
+std::wstring Server::handleChat(const std::string &name,
        std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
 {
        // If something goes wrong, this player is to blame
@@ -2982,7 +3002,7 @@ std::wstring Server::handleChat(const std::string &name, const std::wstring &wna
 
        auto message = trim(wide_to_utf8(wmessage));
        if (message.find_first_of("\n\r") != std::wstring::npos) {
-               return L"New lines are not permitted in chat messages";
+               return L"Newlines are not permitted in chat messages";
        }
 
        // Run script hook, exit if script ate the chat message
@@ -3003,10 +3023,10 @@ std::wstring Server::handleChat(const std::string &name, const std::wstring &wna
                        the Cyrillic alphabet and some characters on older Android devices
                */
 #ifdef __ANDROID__
-               line += L"<" + wname + L"> " + wmessage;
+               line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
 #else
-               line += narrow_to_wide(m_script->formatChatMessage(name,
-                               wide_to_narrow(wmessage)));
+               line += utf8_to_wide(m_script->formatChatMessage(name,
+                               wide_to_utf8(wmessage)));
 #endif
        }
 
@@ -3019,35 +3039,23 @@ std::wstring Server::handleChat(const std::string &name, const std::wstring &wna
        /*
                Send the message to others
        */
-       actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
-
-       std::vector<session_t> clients = m_clients.getClientIDs();
-
-       /*
-               Send the message back to the inital sender
-               if they are using protocol version >= 29
-       */
+       actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
 
-       session_t peer_id_to_avoid_sending =
-               (player ? player->getPeerId() : PEER_ID_INEXISTENT);
+       ChatMessage chatmsg(line);
 
-       if (player && player->protocol_version >= 29)
-               peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
+       std::vector<session_t> clients = m_clients.getClientIDs();
+       for (u16 cid : clients)
+               SendChatMessage(cid, chatmsg);
 
-       for (u16 cid : clients) {
-               if (cid != peer_id_to_avoid_sending)
-                       SendChatMessage(cid, ChatMessage(line));
-       }
        return L"";
 }
 
 void Server::handleAdminChat(const ChatEventChat *evt)
 {
        std::string name = evt->nick;
-       std::wstring wname = utf8_to_wide(name);
        std::wstring wmessage = evt->evt_msg;
 
-       std::wstring answer = handleChat(name, wname, wmessage);
+       std::wstring answer = handleChat(name, wmessage);
 
        // If asked to send answer to sender
        if (!answer.empty()) {
@@ -3084,46 +3092,43 @@ PlayerSAO *Server::getPlayerSAO(session_t peer_id)
        return player->getPlayerSAO();
 }
 
-std::wstring Server::getStatusString()
+std::string Server::getStatusString()
 {
-       std::wostringstream os(std::ios_base::binary);
-       os << L"# Server: ";
+       std::ostringstream os(std::ios_base::binary);
+       os << "# Server: ";
        // Version
-       os << L"version=" << narrow_to_wide(g_version_string);
+       os << "version=" << g_version_string;
        // Uptime
-       os << L", uptime=" << m_uptime_counter->get();
+       os << ", uptime=" << m_uptime_counter->get();
        // Max lag estimate
-       os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
+       os << ", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
 
        // Information about clients
        bool first = true;
-       os << L", clients={";
+       os << ", clients={";
        if (m_env) {
                std::vector<session_t> clients = m_clients.getClientIDs();
                for (session_t client_id : clients) {
                        RemotePlayer *player = m_env->getPlayer(client_id);
 
                        // Get name of player
-                       std::wstring name = L"unknown";
-                       if (player)
-                               name = narrow_to_wide(player->getName());
+                       const char *name = player ? player->getName() : "<unknown>";
 
                        // Add name to information string
                        if (!first)
-                               os << L", ";
+                               os << ", ";
                        else
                                first = false;
-
                        os << name;
                }
        }
-       os << L"}";
+       os << "}";
 
        if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
-               os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
+               os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
 
        if (!g_settings->get("motd").empty())
-               os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
+               os << std::endl << "# Server: " << g_settings->get("motd");
 
        return os.str();
 }
@@ -3319,7 +3324,8 @@ void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &
 
 Address Server::getPeerAddress(session_t peer_id)
 {
-       return m_con->GetPeerAddress(peer_id);
+       // Note that this is only set after Init was received in Server::handleCommand_Init
+       return getClient(peer_id, CS_Invalid)->getAddress();
 }
 
 void Server::setLocalPlayerAnimations(RemotePlayer *player,
@@ -3453,7 +3459,8 @@ void Server::deleteParticleSpawner(const std::string &playername, u32 id)
        SendDeleteParticleSpawner(peer_id, id);
 }
 
-bool Server::dynamicAddMedia(const std::string &filepath)
+bool Server::dynamicAddMedia(const std::string &filepath,
+       std::vector<RemotePlayer*> &sent_to)
 {
        std::string filename = fs::GetFilenameFromPath(filepath.c_str());
        if (m_media.find(filename) != m_media.end()) {
@@ -3473,9 +3480,17 @@ bool Server::dynamicAddMedia(const std::string &filepath)
        pkt << raw_hash << filename << (bool) true;
        pkt.putLongString(filedata);
 
-       auto client_ids = m_clients.getClientIDs(CS_DefinitionsSent);
-       for (session_t client_id : client_ids) {
+       m_clients.lock();
+       for (auto &pair : m_clients.getClientList()) {
+               if (pair.second->getState() < CS_DefinitionsSent)
+                       continue;
+               if (pair.second->net_proto_version < 39)
+                       continue;
+
+               if (auto player = m_env->getPlayer(pair.second->peer_id))
+                       sent_to.emplace_back(player);
                /*
+                       FIXME: this is a very awful hack
                        The network layer only guarantees ordered delivery inside a channel.
                        Since the very next packet could be one that uses the media, we have
                        to push the media over ALL channels to ensure it is processed before
@@ -3484,9 +3499,10 @@ bool Server::dynamicAddMedia(const std::string &filepath)
                        - channel 1 (HUD)
                        - channel 0 (everything else: e.g. play_sound, object messages)
                */
-               m_clients.send(client_id, 1, &pkt, true);
-               m_clients.send(client_id, 0, &pkt, true);
+               m_clients.send(pair.second->peer_id, 1, &pkt, true);
+               m_clients.send(pair.second->peer_id, 0, &pkt, true);
        }
+       m_clients.unlock();
 
        return true;
 }