From eb88e5dd4b181a90b382c036cf6c4f42e63e8cc2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Lo=C3=AFc=20Blot?= Date: Thu, 16 Mar 2017 07:53:39 +0100 Subject: [PATCH] Add ModStorageAPI to client side modding (#5396) mod storage is located into user_path / client / mod_storage --- clientmods/preview/init.lua | 3 +++ src/client.cpp | 43 +++++++++++++++++++++++++++++++- src/client.h | 6 +++++ src/gamedef.h | 4 +++ src/script/clientscripting.cpp | 1 + src/script/lua_api/l_storage.cpp | 11 ++++---- src/server.h | 8 +++--- src/unittest/test.cpp | 3 +++ 8 files changed, 68 insertions(+), 11 deletions(-) diff --git a/clientmods/preview/init.lua b/clientmods/preview/init.lua index 2ca4594d3..60dccf304 100644 --- a/clientmods/preview/init.lua +++ b/clientmods/preview/init.lua @@ -1,4 +1,5 @@ local modname = core.get_current_modname() or "??" +local modstorage = core.get_mod_storage() -- This is an example function to ensure it's working properly, should be removed before merge core.register_on_shutdown(function() @@ -49,6 +50,8 @@ core.register_chatcommand("test_node", { core.after(2, function() print("[PREVIEW] loaded " .. modname .. " mod") + modstorage:set_string("current_mod", modname) + print(modstorage:get_string("current_mod")) end) core.register_on_dignode(function(pos, node) diff --git a/src/client.cpp b/src/client.cpp index 4ddabd814..567ee6dd7 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -249,7 +249,8 @@ Client::Client( m_removed_sounds_check_timer(0), m_state(LC_Created), m_localdb(NULL), - m_script(NULL) + m_script(NULL), + m_mod_storage_save_timer(10.0f) { // Add local player m_env.setLocalPlayer(new LocalPlayer(this, playername)); @@ -730,6 +731,18 @@ void Client::step(float dtime) } } + m_mod_storage_save_timer -= dtime; + if (m_mod_storage_save_timer <= 0.0f) { + verbosestream << "Saving registered mod storages." << std::endl; + m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval"); + for (UNORDERED_MAP::const_iterator + it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) { + if (it->second->isModified()) { + it->second->save(getModStoragePath()); + } + } + } + // Write server map if (m_localdb && m_localdb_save_interval.step(dtime, m_cache_save_interval)) { @@ -1998,3 +2011,31 @@ scene::IAnimatedMesh* Client::getMesh(const std::string &filename) smgr->getMeshCache()->removeMesh(mesh); return mesh; } + +bool Client::registerModStorage(ModMetadata *storage) +{ + if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) { + errorstream << "Unable to register same mod storage twice. Storage name: " + << storage->getModName() << std::endl; + return false; + } + + m_mod_storages[storage->getModName()] = storage; + return true; +} + +void Client::unregisterModStorage(const std::string &name) +{ + UNORDERED_MAP::const_iterator it = m_mod_storages.find(name); + if (it != m_mod_storages.end()) { + // Save unconditionaly on unregistration + it->second->save(getModStoragePath()); + m_mod_storages.erase(name); + } +} + +std::string Client::getModStoragePath() const +{ + return porting::path_user + DIR_DELIM + "client" + DIR_DELIM + "mod_storage"; +} + diff --git a/src/client.h b/src/client.h index 7f9cc559b..d72249315 100644 --- a/src/client.h +++ b/src/client.h @@ -554,6 +554,10 @@ public: { return checkPrivilege(priv); } virtual scene::IAnimatedMesh* getMesh(const std::string &filename); + virtual std::string getModStoragePath() const; + virtual bool registerModStorage(ModMetadata *meta); + virtual void unregisterModStorage(const std::string &name); + // The following set of functions is used by ClientMediaDownloader // Insert a media file appropriately into the appropriate manager bool loadMedia(const std::string &data, const std::string &filename); @@ -724,6 +728,8 @@ private: ClientScripting *m_script; bool m_modding_enabled; + UNORDERED_MAP m_mod_storages; + float m_mod_storage_save_timer; DISABLE_CLASS_COPY(Client); }; diff --git a/src/gamedef.h b/src/gamedef.h index 593d27e30..6cd01305f 100644 --- a/src/gamedef.h +++ b/src/gamedef.h @@ -34,6 +34,7 @@ class MtEventManager; class IRollbackManager; class EmergeManager; class Camera; +class ModMetadata; namespace irr { namespace scene { class IAnimatedMesh; @@ -75,6 +76,9 @@ public: virtual const std::vector &getMods() const = 0; virtual const ModSpec* getModSpec(const std::string &modname) const = 0; virtual std::string getWorldPath() const { return ""; } + virtual std::string getModStoragePath() const = 0; + virtual bool registerModStorage(ModMetadata *storage) = 0; + virtual void unregisterModStorage(const std::string &name) = 0; }; #endif diff --git a/src/script/clientscripting.cpp b/src/script/clientscripting.cpp index c1e308012..ccdcb928d 100644 --- a/src/script/clientscripting.cpp +++ b/src/script/clientscripting.cpp @@ -58,4 +58,5 @@ void ClientScripting::InitializeModApi(lua_State *L, int top) ModApiStorage::Initialize(L, top); LuaItemStack::Register(L); + StorageRef::Register(L); } diff --git a/src/script/lua_api/l_storage.cpp b/src/script/lua_api/l_storage.cpp index 42928255f..867ab9c8d 100644 --- a/src/script/lua_api/l_storage.cpp +++ b/src/script/lua_api/l_storage.cpp @@ -33,10 +33,9 @@ int ModApiStorage::l_get_mod_storage(lua_State *L) std::string mod_name = lua_tostring(L, -1); ModMetadata *store = new ModMetadata(mod_name); - // For server side - if (Server *server = getServer(L)) { - store->load(server->getModStoragePath()); - server->registerModStorage(store); + if (IGameDef *gamedef = getGameDef(L)) { + store->load(gamedef->getModStoragePath()); + gamedef->registerModStorage(store); } else { assert(false); // this should not happen } @@ -70,8 +69,8 @@ int StorageRef::gc_object(lua_State *L) { StorageRef *o = *(StorageRef **)(lua_touserdata(L, 1)); // Server side - if (Server *server = getServer(L)) - server->unregisterModStorage(getobject(o)->getModName()); + if (IGameDef *gamedef = getGameDef(L)) + gamedef->unregisterModStorage(getobject(o)->getModName()); delete o; return 0; } diff --git a/src/server.h b/src/server.h index f0bab1bbf..e1e8f84dc 100644 --- a/src/server.h +++ b/src/server.h @@ -299,8 +299,8 @@ public: virtual const ModSpec* getModSpec(const std::string &modname) const; void getModNames(std::vector &modlist); std::string getBuiltinLuaPath(); - std::string getWorldPath() const { return m_path_world; } - std::string getModStoragePath() const; + virtual std::string getWorldPath() const { return m_path_world; } + virtual std::string getModStoragePath() const; inline bool isSingleplayer() { return m_simple_singleplayer_mode; } @@ -361,8 +361,8 @@ public: void SendInventory(PlayerSAO* playerSAO); void SendMovePlayer(u16 peer_id); - bool registerModStorage(ModMetadata *storage); - void unregisterModStorage(const std::string &name); + virtual bool registerModStorage(ModMetadata *storage); + virtual void unregisterModStorage(const std::string &name); // Bind address Address m_bind_addr; diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index 9beb0afa6..9d223b82d 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -65,6 +65,9 @@ public: return testmodspec; } virtual const ModSpec* getModSpec(const std::string &modname) const { return NULL; } + virtual std::string getModStoragePath() const { return "."; } + virtual bool registerModStorage(ModMetadata *meta) { return true; } + virtual void unregisterModStorage(const std::string &name) {} private: IItemDefManager *m_itemdef; -- 2.25.1