diff --git a/docs/changelog.txt b/docs/changelog.txt index a89869972b..eaee5ed00a 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -77,11 +77,13 @@ Template for new versions: - ``Units::isUnitInBox``, ``Units::getUnitsInBox``: add versions accepting pos arguments - ``Units::getVisibleName``: when acting on a unit without an impersonated identity, returns the unit's name structure instead of the associated histfig's name structure - ``Translation::generateName``: generates in-game names, mirroring DF's internal logic +- ``Persistence::getUnsavedSeconds``: returns the number of seconds since last save or last load ## Lua - ``dfhack.units.isUnitInBox``, ``dfhack.units.getUnitsInBox``: add versions accepting pos arguments - ``widgets.FilteredList``: search keys for list items can now be functions that return a string - ``dfhack.translation.generateName``: Lua API for ``Translation::generateName`` +- ``dfhack.persistent.getUnsavedSeconds``: Lua API for ``Persistence::getUnsavedSeconds`` ## Removed - ``dfhack.TranslateName`` has been renamed to ``dfhack.translation.translateName`` diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 3369705a78..bfadfc6899 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -771,6 +771,10 @@ arbitrary Lua tables. Same semantics as for the ``Site`` functions, but will associated the data with the global world context. +* ``dfhack.persistent.getUnsavedSeconds()`` + + Returns the number of seconds since last save or load of a save. + The data is kept in memory, so no I/O occurs when getting or saving keys. It is all written to a json file in the game save directory when the game is saved. diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index d25afb1270..b92e0eddbb 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -353,6 +353,11 @@ static int dfhack_persistent_delete_world_data(lua_State *L) { return delete_site_data(L, get_world_data); } +static int dfhack_persistent_get_unsaved_seconds(lua_State *L) { + lua_pushinteger(L, Persistence::getUnsavedSeconds()); + return 1; +} + static const luaL_Reg dfhack_persistent_funcs[] = { { "getSiteDataString", dfhack_persistent_get_site_data_string }, { "saveSiteDataString", dfhack_persistent_save_site_data_string }, @@ -360,6 +365,7 @@ static const luaL_Reg dfhack_persistent_funcs[] = { { "getWorldDataString", dfhack_persistent_get_world_data_string }, { "saveWorldDataString", dfhack_persistent_save_world_data_string }, { "deleteWorldData", dfhack_persistent_delete_world_data }, + { "getUnsavedSeconds", dfhack_persistent_get_unsaved_seconds }, { NULL, NULL } }; diff --git a/library/include/modules/Persistence.h b/library/include/modules/Persistence.h index b01f8c136d..49757e9baa 100644 --- a/library/include/modules/Persistence.h +++ b/library/include/modules/Persistence.h @@ -213,5 +213,7 @@ namespace DFHack // Fills the vector with references to each persistent item with a key that is // equal to the given key. DFHACK_EXPORT void getAllByKey(std::vector &vec, int entity_id, const std::string &key); + // Returns the number of seconds since the current savegame was saved or loaded. + DFHACK_EXPORT uint32_t getUnsavedSeconds(); } } diff --git a/library/modules/Persistence.cpp b/library/modules/Persistence.cpp index 2e6dd19f6c..0a6f1c3772 100644 --- a/library/modules/Persistence.cpp +++ b/library/modules/Persistence.cpp @@ -49,6 +49,8 @@ using namespace DFHack; static std::unordered_map>> store; static std::unordered_map> entry_cache; +static uint32_t lastLoadSaveTickCount = 0; + size_t next_entry_id = 0; // goes more positive int next_fake_df_id = -101; // goes more negative @@ -189,6 +191,12 @@ static std::string getSaveFilePath(const std::string &world, const std::string & return getSavePath(world) + "/dfhack-" + filterSaveFileName(name) + ".dat"; } +struct LastLoadSaveTickCountUpdater { + ~LastLoadSaveTickCountUpdater() { + lastLoadSaveTickCount = Core::getInstance().p->getTickCount(); + } +}; + void Persistence::Internal::save(color_ostream& out) { Core &core = Core::getInstance(); @@ -196,6 +204,7 @@ void Persistence::Internal::save(color_ostream& out) { return; CoreSuspender suspend; + LastLoadSaveTickCountUpdater tickCountUpdater; // write status { @@ -237,6 +246,7 @@ void Persistence::Internal::save(color_ostream& out) { color_ostream_wrapper wrapper(file); Lua::CallLuaModuleFunction(wrapper, "script-manager", "print_timers"); } + } static bool get_entity_id(const std::string & fname, int & entity_id) { @@ -283,6 +293,7 @@ static bool load_file(const std::string & path, int entity_id) { void Persistence::Internal::load(color_ostream& out) { CoreSuspender suspend; + LastLoadSaveTickCountUpdater tickCountUpdater; clear(out); @@ -417,3 +428,8 @@ void Persistence::getAllByKey(std::vector &vec, int entity_i for (auto it = range.first; it != range.second; ++it) vec.emplace_back(it->second); } + +uint32_t Persistence::getUnsavedSeconds() { + uint32_t durMS = Core::getInstance().p->getTickCount() - lastLoadSaveTickCount; + return durMS / 1000; +}