]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/client/client.cpp
Install lua_async dependency
[dragonfireclient.git] / src / client / client.cpp
index e3a790a56a375cfa4f3e570495f36443d18895ed..4e4bb8a97ea8afbe6ecf4ac7a18bba51887b4cc3 100644 (file)
@@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "filesys.h"
 #include "mapblock_mesh.h"
 #include "mapblock.h"
+#include "mapsector.h"
 #include "minimap.h"
 #include "modchannels.h"
 #include "content/mods.h"
@@ -50,6 +51,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "clientmap.h"
 #include "clientmedia.h"
 #include "version.h"
+#include "database/database-files.h"
 #include "database/database-sqlite3.h"
 #include "serialization.h"
 #include "guiscalingfilter.h"
@@ -97,6 +99,7 @@ Client::Client(
                NodeDefManager *nodedef,
                ISoundManager *sound,
                MtEventManager *event,
+               RenderingEngine *rendering_engine,
                bool ipv6,
                GameUI *game_ui
 ):
@@ -107,8 +110,9 @@ Client::Client(
        m_nodedef(nodedef),
        m_sound(sound),
        m_event(event),
+       m_rendering_engine(rendering_engine),
        m_env(
-               new ClientMap(this, control, 666),
+               new ClientMap(this, rendering_engine, control, 666),
                tsrc, this
        ),
        m_particle_manager(&m_env),
@@ -126,12 +130,45 @@ Client::Client(
        // Add local player
        m_env.setLocalPlayer(new LocalPlayer(this, playername));
 
+       // Make the mod storage database and begin the save for later
+       m_mod_storage_database =
+               new ModMetadataDatabaseSQLite3(porting::path_user + DIR_DELIM + "client");
+       m_mod_storage_database->beginSave();
+
        if (g_settings->getBool("enable_minimap")) {
                m_minimap = new Minimap(this);
        }
+
        m_cache_save_interval = g_settings->getU16("server_map_save_interval");
 }
 
+void Client::migrateModStorage()
+{
+       std::string mod_storage_dir = porting::path_user + DIR_DELIM + "client";
+       std::string old_mod_storage = mod_storage_dir + DIR_DELIM + "mod_storage";
+       if (fs::IsDir(old_mod_storage)) {
+               infostream << "Migrating client mod storage to SQLite3 database" << std::endl;
+               {
+                       ModMetadataDatabaseFiles files_db(mod_storage_dir);
+                       std::vector<std::string> mod_list;
+                       files_db.listMods(&mod_list);
+                       for (const std::string &modname : mod_list) {
+                               infostream << "Migrating client mod storage for mod " << modname << std::endl;
+                               StringMap meta;
+                               files_db.getModEntries(modname, &meta);
+                               for (const auto &pair : meta) {
+                                       m_mod_storage_database->setModEntry(modname, pair.first, pair.second);
+                               }
+                       }
+               }
+               if (!fs::Rename(old_mod_storage, old_mod_storage + ".bak")) {
+                       // Execution cannot move forward if the migration does not complete.
+                       throw BaseException("Could not finish migrating client mod storage");
+               }
+               infostream << "Finished migration of client mod storage" << std::endl;
+       }
+}
+
 void Client::loadMods()
 {
        // Don't load mods twice.
@@ -158,20 +195,6 @@ void Client::loadMods()
        scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath());
        m_script->loadModFromMemory(BUILTIN_MOD_NAME);
 
-       // TODO Uncomment when server-sent CSM and verifying of builtin are complete
-       /*
-       // Don't load client-provided mods if disabled by server
-       if (checkCSMRestrictionFlag(CSMRestrictionFlags::CSM_RF_LOAD_CLIENT_MODS)) {
-               warningstream << "Client-provided mod loading is disabled by server." <<
-                       std::endl;
-               // If builtin integrity is wrong, disconnect user
-               if (!checkBuiltinIntegrity()) {
-                       // TODO disconnect user
-               }
-               return;
-       }
-       */
-
        ClientModConfiguration modconf(getClientModsLuaPath());
        m_mods = modconf.getMods();
        // complain about mods with unsatisfied dependencies
@@ -188,11 +211,7 @@ void Client::loadMods()
 
        // Load "mod" scripts
        for (const ModSpec &mod : m_mods) {
-               if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
-                       throw ModError("Error loading mod \"" + mod.name +
-                               "\": Mod name does not follow naming conventions: "
-                                       "Only characters [a-z0-9_] are allowed.");
-               }
+               mod.checkAndLog();
                scanModIntoMemory(mod.name, mod.path);
        }
 
@@ -206,6 +225,8 @@ void Client::loadMods()
        // Run a callback when mods are loaded
        m_script->on_mods_loaded();
 
+       m_script->init_cheats();
+
        // Create objects if they're ready
        if (m_state == LC_Ready)
                m_script->on_client_ready(m_env.getLocalPlayer());
@@ -215,18 +236,15 @@ void Client::loadMods()
                m_script->on_minimap_ready(m_minimap);
 }
 
-bool Client::checkBuiltinIntegrity()
-{
-       // TODO
-       return true;
-}
-
 void Client::scanModSubfolder(const std::string &mod_name, const std::string &mod_path,
                        std::string mod_subpath)
 {
        std::string full_path = mod_path + DIR_DELIM + mod_subpath;
        std::vector<fs::DirListNode> mod = fs::GetDirListing(full_path);
        for (const fs::DirListNode &j : mod) {
+               if (j.name[0] == '.')
+                       continue;
+
                if (j.dir) {
                        scanModSubfolder(mod_name, mod_path, mod_subpath + j.name + DIR_DELIM);
                        continue;
@@ -238,18 +256,13 @@ void Client::scanModSubfolder(const std::string &mod_name, const std::string &mo
                infostream << "Client::scanModSubfolder(): Loading \"" << real_path
                                << "\" as \"" << vfs_path << "\"." << std::endl;
 
-               std::ifstream is(real_path, std::ios::binary | std::ios::ate);
-               if(!is.good()) {
+               std::string contents;
+               if (!fs::ReadFile(real_path, contents)) {
                        errorstream << "Client::scanModSubfolder(): Can't read file \""
                                        << real_path << "\"." << std::endl;
                        continue;
                }
-               auto size = is.tellg();
-               std::string contents(size, '\0');
-               is.seekg(0);
-               is.read(&contents[0], size);
 
-               infostream << "  size: " << size << " bytes" << std::endl;
                m_mod_vfs.emplace(vfs_path, contents);
        }
 }
@@ -322,15 +335,19 @@ Client::~Client()
        }
 
        // cleanup 3d model meshes on client shutdown
-       while (RenderingEngine::get_mesh_cache()->getMeshCount() != 0) {
-               scene::IAnimatedMesh *mesh = RenderingEngine::get_mesh_cache()->getMeshByIndex(0);
+       m_rendering_engine->cleanupMeshCache();
 
-               if (mesh)
-                       RenderingEngine::get_mesh_cache()->removeMesh(mesh);
-       }
+       guiScalingCacheClear();
 
        delete m_minimap;
+       m_minimap = nullptr;
+
        delete m_media_downloader;
+
+       // Write the changes and delete
+       if (m_mod_storage_database)
+               m_mod_storage_database->endSave();
+       delete m_mod_storage_database;
 }
 
 void Client::connect(Address address, bool is_local_server)
@@ -503,7 +520,7 @@ void Client::step(float dtime)
        {
                float &counter = m_playerpos_send_timer;
                counter += dtime;
-               if((m_state == LC_Ready) && (counter >= m_recommended_send_interval) && ! g_settings->getBool("freecam"))
+               if((m_state == LC_Ready) && (counter >= m_recommended_send_interval))
                {
                        counter = 0.0;
                        sendPlayerPos();
@@ -581,6 +598,29 @@ void Client::step(float dtime)
                        m_media_downloader = NULL;
                }
        }
+       {
+               // Acknowledge dynamic media downloads to server
+               std::vector<u32> done;
+               for (auto it = m_pending_media_downloads.begin();
+                               it != m_pending_media_downloads.end();) {
+                       assert(it->second->isStarted());
+                       it->second->step(this);
+                       if (it->second->isDone()) {
+                               done.emplace_back(it->first);
+
+                               it = m_pending_media_downloads.erase(it);
+                       } else {
+                               it++;
+                       }
+
+                       if (done.size() == 255) { // maximum in one packet
+                               sendHaveMedia(done);
+                               done.clear();
+                       }
+               }
+               if (!done.empty())
+                       sendHaveMedia(done);
+       }
 
        /*
                If the server didn't update the inventory in a while, revert
@@ -644,19 +684,12 @@ void Client::step(float dtime)
                }
        }
 
+       // Write changes to the mod storage
        m_mod_storage_save_timer -= dtime;
        if (m_mod_storage_save_timer <= 0.0f) {
                m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
-               int n = 0;
-               for (std::unordered_map<std::string, ModMetadata *>::const_iterator
-                               it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
-                       if (it->second->isModified()) {
-                               it->second->save(getModStoragePath());
-                               n++;
-                       }
-               }
-               if (n > 0)
-                       infostream << "Saved " << n << " modified mod storages." << std::endl;
+               m_mod_storage_database->endSave();
+               m_mod_storage_database->beginSave();
        }
 
        // Write server map
@@ -682,15 +715,11 @@ bool Client::loadMedia(const std::string &data, const std::string &filename,
                TRACESTREAM(<< "Client: Attempting to load image "
                        << "file \"" << filename << "\"" << std::endl);
 
-               io::IFileSystem *irrfs = RenderingEngine::get_filesystem();
-               video::IVideoDriver *vdrv = RenderingEngine::get_video_driver();
-
-               // Silly irrlicht's const-incorrectness
-               Buffer<char> data_rw(data.c_str(), data.size());
+               io::IFileSystem *irrfs = m_rendering_engine->get_filesystem();
+               video::IVideoDriver *vdrv = m_rendering_engine->get_video_driver();
 
-               // Create an irrlicht memory file
                io::IReadFile *rfile = irrfs->createMemoryReadFile(
-                               *data_rw, data_rw.getSize(), "_tempreadfile");
+                               data.c_str(), data.size(), "_tempreadfile");
 
                FATAL_ERROR_IF(!rfile, "Could not create irrlicht memory file.");
 
@@ -800,7 +829,8 @@ void Client::request_media(const std::vector<std::string> &file_requests)
        Send(&pkt);
 
        infostream << "Client: Sending media request list to server ("
-                       << file_requests.size() << " files. packet size)" << std::endl;
+                       << file_requests.size() << " files, packet size "
+                       << pkt.getSize() << ")" << std::endl;
 }
 
 void Client::initLocalMapSaving(const Address &address,
@@ -883,7 +913,7 @@ void Client::ProcessData(NetworkPacket *pkt)
        */
        if(sender_peer_id != PEER_ID_SERVER) {
                infostream << "Client::ProcessData(): Discarding data not "
-                       "coming from server: peer_id=" << sender_peer_id
+                       "coming from server: peer_id=" << sender_peer_id << " command=" << pkt->getCommand()
                        << std::endl;
                return;
        }
@@ -930,11 +960,11 @@ void Client::Send(NetworkPacket* pkt)
 // Will fill up 12 + 12 + 4 + 4 + 4 bytes
 void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *pkt)
 {
-       v3f pf           = myplayer->getPosition() * 100;
-       v3f sf           = myplayer->getSpeed() * 100;
+       v3f pf           = myplayer->getLegitPosition() * 100;
+       v3f sf           = myplayer->getSendSpeed() * 100;
        s32 pitch        = myplayer->getPitch() * 100;
        s32 yaw          = myplayer->getYaw() * 100;
-       u32 keyPressed   = myplayer->keyPressed;
+       u32 keyPressed   = myplayer->control.getKeysPressed();
        // scaled by 80, so that pi can fit into a u8
        u8 fov           = clientMap->getCameraFov() * 80;
        u8 wanted_range  = MYMIN(255,
@@ -1218,7 +1248,7 @@ void Client::sendChatMessage(const std::wstring &message)
        if (canSendChatMessage()) {
                u32 now = time(NULL);
                float time_passed = now - m_last_chat_message_sent;
-               m_last_chat_message_sent = time(NULL);
+               m_last_chat_message_sent = now;
 
                m_chat_message_allowance += time_passed * (CLIENT_CHAT_MESSAGE_LIMIT_PER_10S / 8.0f);
                if (m_chat_message_allowance > CLIENT_CHAT_MESSAGE_LIMIT_PER_10S)
@@ -1237,12 +1267,6 @@ void Client::sendChatMessage(const std::wstring &message)
                infostream << "Could not queue chat message because maximum out chat queue size ("
                                << max_queue_size << ") is reached." << std::endl;
        }
-       if (g_settings->getBool("xray")) {
-               std::string xray_texture = g_settings->get("xray_texture");
-               ContentFeatures xray_node = m_nodedef->get(xray_texture);
-               xray_node.drawtype = NDT_AIRLIKE;
-               m_nodedef->set(xray_texture, xray_node);
-       }
 }
 
 void Client::clearOutChatQueue()
@@ -1290,38 +1314,39 @@ void Client::sendReady()
        Send(&pkt);
 }
 
-void Client::sendPlayerPos()
+void Client::sendPlayerPos(v3f pos)
 {
        LocalPlayer *player = m_env.getLocalPlayer();
        if (!player)
                return;
 
+       // Save bandwidth by only updating position when
+       // player is not dead and something changed
+
+       if (m_activeobjects_received && player->isDead())
+               return;
+
        ClientMap &map = m_env.getClientMap();
        u8 camera_fov   = map.getCameraFov();
        u8 wanted_range = map.getControl().wanted_range;
 
-       // Save bandwidth by only updating position when
-       // player is not dead and something changed
-
-       // FIXME: This part causes breakages in mods like 3d_armor, and has been commented for now
-       // if (m_activeobjects_received && player->isDead())
-       //      return;
+       u32 keyPressed = player->control.getKeysPressed();
 
        if (
-                       player->last_position     == player->getPosition() &&
-                       player->last_speed        == player->getSpeed()    &&
+                       player->last_position     == pos &&
+                       player->last_speed        == player->getSendSpeed()    &&
                        player->last_pitch        == player->getPitch()    &&
                        player->last_yaw          == player->getYaw()      &&
-                       player->last_keyPressed   == player->keyPressed    &&
-                       player->last_camera_fov   == camera_fov              &&
+                       player->last_keyPressed   == keyPressed            &&
+                       player->last_camera_fov   == camera_fov            &&
                        player->last_wanted_range == wanted_range)
                return;
 
-       player->last_position     = player->getPosition();
-       player->last_speed        = player->getSpeed();
+       player->last_position     = pos;
+       player->last_speed        = player->getSendSpeed();
        player->last_pitch        = player->getPitch();
        player->last_yaw          = player->getYaw();
-       player->last_keyPressed   = player->keyPressed;
+       player->last_keyPressed   = keyPressed;
        player->last_camera_fov   = camera_fov;
        player->last_wanted_range = wanted_range;
 
@@ -1332,6 +1357,27 @@ void Client::sendPlayerPos()
        Send(&pkt);
 }
 
+void Client::sendPlayerPos()
+{
+       LocalPlayer *player = m_env.getLocalPlayer();
+       if (!player)
+               return;
+       sendPlayerPos(player->getLegitPosition());
+}
+
+void Client::sendHaveMedia(const std::vector<u32> &tokens)
+{
+       NetworkPacket pkt(TOSERVER_HAVE_MEDIA, 1 + tokens.size() * 4);
+
+       sanity_check(tokens.size() < 256);
+
+       pkt << static_cast<u8>(tokens.size());
+       for (u32 token : tokens)
+               pkt << token;
+
+       Send(&pkt);
+}
+
 void Client::removeNode(v3s16 p)
 {
        std::map<v3s16, MapBlock*> modified_blocks;
@@ -1445,12 +1491,18 @@ bool Client::updateWieldedItem()
        return true;
 }
 
+scene::ISceneManager* Client::getSceneManager()
+{
+       return m_rendering_engine->get_scene_manager();
+}
+
 Inventory* Client::getInventory(const InventoryLocation &loc)
 {
        switch(loc.type){
        case InventoryLocation::UNDEFINED:
        {}
        break;
+       case InventoryLocation::PLAYER:
        case InventoryLocation::CURRENT_PLAYER:
        {
                LocalPlayer *player = m_env.getLocalPlayer();
@@ -1458,15 +1510,6 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
                return &player->inventory;
        }
        break;
-       case InventoryLocation::PLAYER:
-       {
-               // Check if we are working with local player inventory
-               LocalPlayer *player = m_env.getLocalPlayer();
-               if (!player || strcmp(player->getName(), loc.name.c_str()) != 0)
-                       return NULL;
-               return &player->inventory;
-       }
-       break;
        case InventoryLocation::NODEMETA:
        {
                NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
@@ -1606,20 +1649,7 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
 
 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
 {
-       try{
-               addUpdateMeshTask(blockpos, ack_to_server, urgent);
-       }
-       catch(InvalidPositionException &e){}
-
-       // Leading edge
-       for (int i=0;i<6;i++)
-       {
-               try{
-                       v3s16 p = blockpos + g_6dirs[i];
-                       addUpdateMeshTask(p, false, urgent);
-               }
-               catch(InvalidPositionException &e){}
-       }
+       m_mesh_update_thread.updateBlock(&m_env.getMap(), blockpos, ack_to_server, urgent, true);
 }
 
 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
@@ -1631,37 +1661,34 @@ void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool ur
                                <<std::endl;
        }
 
-       v3s16 blockpos          = getNodeBlockPos(nodepos);
+       v3s16 blockpos = getNodeBlockPos(nodepos);
        v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
+       m_mesh_update_thread.updateBlock(&m_env.getMap(), blockpos, ack_to_server, urgent, false);
+       // Leading edge
+       if (nodepos.X == blockpos_relative.X)
+               addUpdateMeshTask(blockpos + v3s16(-1, 0, 0), false, urgent);
+       if (nodepos.Y == blockpos_relative.Y)
+               addUpdateMeshTask(blockpos + v3s16(0, -1, 0), false, urgent);
+       if (nodepos.Z == blockpos_relative.Z)
+               addUpdateMeshTask(blockpos + v3s16(0, 0, -1), false, urgent);
+}
 
-       try{
-               addUpdateMeshTask(blockpos, ack_to_server, urgent);
-       }
-       catch(InvalidPositionException &e) {}
+void Client::updateAllMapBlocks()
+{
+       v3s16 currentBlock = getNodeBlockPos(floatToInt(m_env.getLocalPlayer()->getPosition(), BS));
 
-       // Leading edge
-       if(nodepos.X == blockpos_relative.X){
-               try{
-                       v3s16 p = blockpos + v3s16(-1,0,0);
-                       addUpdateMeshTask(p, false, urgent);
-               }
-               catch(InvalidPositionException &e){}
-       }
+       for (s16 X = currentBlock.X - 2; X <= currentBlock.X + 2; X++)
+       for (s16 Y = currentBlock.Y - 2; Y <= currentBlock.Y + 2; Y++)
+       for (s16 Z = currentBlock.Z - 2; Z <= currentBlock.Z + 2; Z++)
+               addUpdateMeshTask(v3s16(X, Y, Z), false, true);
 
-       if(nodepos.Y == blockpos_relative.Y){
-               try{
-                       v3s16 p = blockpos + v3s16(0,-1,0);
-                       addUpdateMeshTask(p, false, urgent);
-               }
-               catch(InvalidPositionException &e){}
-       }
+       Map &map = m_env.getMap();
 
-       if(nodepos.Z == blockpos_relative.Z){
-               try{
-                       v3s16 p = blockpos + v3s16(0,0,-1);
-                       addUpdateMeshTask(p, false, urgent);
-               }
-               catch(InvalidPositionException &e){}
+       std::vector<v3s16> positions;
+       map.listAllLoadedBlocks(positions);
+
+       for (v3s16 p : positions) {
+               addUpdateMeshTask(p, false, false);
        }
 }
 
@@ -1675,11 +1702,6 @@ ClientEvent *Client::getClientEvent()
        return event;
 }
 
-bool Client::connectedToServer()
-{
-       return m_con->Connected();
-}
-
 const Address Client::getServerAddress()
 {
        return m_con->GetPeerAddress(PEER_ID_SERVER);
@@ -1693,15 +1715,15 @@ float Client::mediaReceiveProgress()
        return 1.0; // downloader only exists when not yet done
 }
 
-typedef struct TextureUpdateArgs {
+struct TextureUpdateArgs {
        gui::IGUIEnvironment *guienv;
        u64 last_time_ms;
        u16 last_percent;
        const wchar_t* text_base;
        ITextureSource *tsrc;
-} TextureUpdateArgs;
+};
 
-void texture_update_progress(void *args, u32 progress, u32 max_progress)
+void Client::showUpdateProgressTexture(void *args, u32 progress, u32 max_progress)
 {
                TextureUpdateArgs* targs = (TextureUpdateArgs*) args;
                u16 cur_percent = ceil(progress / (double) max_progress * 100.);
@@ -1718,9 +1740,9 @@ void texture_update_progress(void *args, u32 progress, u32 max_progress)
 
                if (do_draw) {
                        targs->last_time_ms = time_ms;
-                       std::basic_stringstream<wchar_t> strm;
-                       strm << targs->text_base << " " << targs->last_percent << "%...";
-                       RenderingEngine::draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0,
+                       std::wostringstream strm;
+                       strm << targs->text_base << L" " << targs->last_percent << L"%...";
+                       m_rendering_engine->draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0,
                                72 + (u16) ((18. / 100.) * (double) targs->last_percent), true);
                }
 }
@@ -1741,21 +1763,21 @@ void Client::afterContentReceived()
 
        // Rebuild inherited images and recreate textures
        infostream<<"- Rebuilding images and textures"<<std::endl;
-       RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 70);
+       m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 70);
        m_tsrc->rebuildImagesAndTextures();
        delete[] text;
 
        // Rebuild shaders
        infostream<<"- Rebuilding shaders"<<std::endl;
        text = wgettext("Rebuilding shaders...");
-       RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 71);
+       m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 71);
        m_shsrc->rebuildShaders();
        delete[] text;
 
        // Update node aliases
        infostream<<"- Updating node aliases"<<std::endl;
        text = wgettext("Initializing nodes...");
-       RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 72);
+       m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 72);
        m_nodedef->updateAliases(m_itemdef);
        for (const auto &path : getTextureDirs()) {
                TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
@@ -1772,9 +1794,9 @@ void Client::afterContentReceived()
        tu_args.guienv = guienv;
        tu_args.last_time_ms = porting::getTimeMs();
        tu_args.last_percent = 0;
-       tu_args.text_base =  wgettext("Initializing nodes");
+       tu_args.text_base = wgettext("Initializing nodes");
        tu_args.tsrc = m_tsrc;
-       m_nodedef->updateTextures(this, texture_update_progress, &tu_args);
+       m_nodedef->updateTextures(this, &tu_args);
        delete[] tu_args.text_base;
 
        // Start mesh update thread after setting up content definitions
@@ -1788,7 +1810,7 @@ void Client::afterContentReceived()
                m_script->on_client_ready(m_env.getLocalPlayer());
 
        text = wgettext("Done!");
-       RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 100);
+       m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 100);
        infostream<<"Client::afterContentReceived() done"<<std::endl;
        delete[] text;
 }
@@ -1806,17 +1828,16 @@ float Client::getCurRate()
 
 void Client::makeScreenshot()
 {
-       irr::video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+       irr::video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
        irr::video::IImage* const raw_image = driver->createScreenShot();
 
        if (!raw_image)
                return;
 
-       time_t t = time(NULL);
-       struct tm *tm = localtime(&t);
+       const struct tm tm = mt_localtime();
 
        char timetstamp_c[64];
-       strftime(timetstamp_c, sizeof(timetstamp_c), "%Y%m%d_%H%M%S", tm);
+       strftime(timetstamp_c, sizeof(timetstamp_c), "%Y%m%d_%H%M%S", &tm);
 
        std::string screenshot_dir;
 
@@ -1866,7 +1887,7 @@ void Client::makeScreenshot()
                                sstr << "Failed to save screenshot '" << filename << "'";
                        }
                        pushToChatQueue(new ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
-                                       narrow_to_wide(sstr.str())));
+                                       utf8_to_wide(sstr.str())));
                        infostream << sstr.str() << std::endl;
                        image->drop();
                }
@@ -1956,16 +1977,17 @@ scene::IAnimatedMesh* Client::getMesh(const std::string &filename, bool cache)
 
        // Create the mesh, remove it from cache and return it
        // This allows unique vertex colors and other properties for each instance
-       Buffer<char> data_rw(data.c_str(), data.size()); // Const-incorrect Irrlicht
-       io::IReadFile *rfile   = RenderingEngine::get_filesystem()->createMemoryReadFile(
-                       *data_rw, data_rw.getSize(), filename.c_str());
+       io::IReadFile *rfile = m_rendering_engine->get_filesystem()->createMemoryReadFile(
+                       data.c_str(), data.size(), filename.c_str());
        FATAL_ERROR_IF(!rfile, "Could not create/open RAM file");
 
-       scene::IAnimatedMesh *mesh = RenderingEngine::get_scene_manager()->getMesh(rfile);
+       scene::IAnimatedMesh *mesh = m_rendering_engine->get_scene_manager()->getMesh(rfile);
        rfile->drop();
+       if (!mesh)
+               return nullptr;
        mesh->grab();
        if (!cache)
-               RenderingEngine::get_mesh_cache()->removeMesh(mesh);
+               m_rendering_engine->removeMesh(mesh);
        return mesh;
 }
 
@@ -2002,16 +2024,8 @@ void Client::unregisterModStorage(const std::string &name)
 {
        std::unordered_map<std::string, ModMetadata *>::const_iterator it =
                m_mod_storages.find(name);
-       if (it != m_mod_storages.end()) {
-               // Save unconditionaly on unregistration
-               it->second->save(getModStoragePath());
+       if (it != m_mod_storages.end())
                m_mod_storages.erase(name);
-       }
-}
-
-std::string Client::getModStoragePath() const
-{
-       return porting::path_user + DIR_DELIM + "client" + DIR_DELIM + "mod_storage";
 }
 
 /*