From a8479e31563bbb2357e5f95c9d270de8eeb19359 Mon Sep 17 00:00:00 2001 From: Squid Coder <92821989+realSquidCoder@users.noreply.github.com> Date: Wed, 15 Jan 2025 11:07:30 -0600 Subject: [PATCH 1/9] add the code to get the millis count millis count is now noted on load and save. --- library/LuaApi.cpp | 2 ++ library/include/modules/Persistence.h | 2 ++ library/modules/Persistence.cpp | 9 +++++++++ 3 files changed, 13 insertions(+) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index d25afb1270..97a5b216bd 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1343,6 +1343,7 @@ static string getArchitectureName() static string getDFVersion() { return Core::getInstance().vinfo->getVersion(); } static uint32_t getTickCount() { return Core::getInstance().p->getTickCount(); } +static uint32_t getCurSaveDur() { return Persistence::getSaveDur(); } static string getDFPath() { return Core::getInstance().p->getPath(); } static string getHackPath() { return Core::getInstance().getHackPath(); } @@ -1370,6 +1371,7 @@ static const LuaWrapper::FunctionReg dfhack_module[] = { WRAP(getDFVersion), WRAP(getDFPath), WRAP(getTickCount), + WRAP(getCurSaveDur), WRAP(getHackPath), WRAP(isWorldLoaded), WRAP(isMapLoaded), diff --git a/library/include/modules/Persistence.h b/library/include/modules/Persistence.h index b01f8c136d..a2ded42754 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 tickcount of the most recent save. + DFHACK_EXPORT uint32_t getSaveDur(); } } diff --git a/library/modules/Persistence.cpp b/library/modules/Persistence.cpp index 2e6dd19f6c..36a9770f55 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 lastTickCount = 0; + size_t next_entry_id = 0; // goes more positive int next_fake_df_id = -101; // goes more negative @@ -198,6 +200,7 @@ void Persistence::Internal::save(color_ostream& out) { CoreSuspender suspend; // write status + lastTickCount = Core::getInstance().p->getTickCount(); { auto file = std::ofstream(getSaveFilePath("current", "status")); file << "DF version: " << core.p->getDescriptor()->getVersion() << std::endl; @@ -307,6 +310,7 @@ void Persistence::Internal::load(color_ostream& out) { } if (found) + lastTickCount = Core::getInstance().p->getTickCount(); return; // new file formats not found; attempt to load legacy file @@ -417,3 +421,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::getSaveDur() { + uint32_t durMS = Core::getInstance().p->getTickCount() - lastTickCount; + return durMS / (60 * 1000); +} From 37e4ed099541b79db62639de075bb8c3fed0ea6f Mon Sep 17 00:00:00 2001 From: Squid Coder <92821989+realSquidCoder@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:12:36 -0600 Subject: [PATCH 2/9] give things better names and code locations --- library/include/modules/Persistence.h | 2 +- library/modules/Persistence.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/include/modules/Persistence.h b/library/include/modules/Persistence.h index a2ded42754..748994c4bb 100644 --- a/library/include/modules/Persistence.h +++ b/library/include/modules/Persistence.h @@ -214,6 +214,6 @@ namespace DFHack // equal to the given key. DFHACK_EXPORT void getAllByKey(std::vector &vec, int entity_id, const std::string &key); // Returns the tickcount of the most recent save. - DFHACK_EXPORT uint32_t getSaveDur(); + DFHACK_EXPORT uint32_t getUnsavedSeconds(); } } diff --git a/library/modules/Persistence.cpp b/library/modules/Persistence.cpp index 36a9770f55..a21feaeb28 100644 --- a/library/modules/Persistence.cpp +++ b/library/modules/Persistence.cpp @@ -49,7 +49,7 @@ using namespace DFHack; static std::unordered_map>> store; static std::unordered_map> entry_cache; -static uint32_t lastTickCount = 0; +static uint32_t lastLoadSaveTickCount = 0; size_t next_entry_id = 0; // goes more positive int next_fake_df_id = -101; // goes more negative @@ -200,7 +200,6 @@ void Persistence::Internal::save(color_ostream& out) { CoreSuspender suspend; // write status - lastTickCount = Core::getInstance().p->getTickCount(); { auto file = std::ofstream(getSaveFilePath("current", "status")); file << "DF version: " << core.p->getDescriptor()->getVersion() << std::endl; @@ -240,6 +239,7 @@ void Persistence::Internal::save(color_ostream& out) { color_ostream_wrapper wrapper(file); Lua::CallLuaModuleFunction(wrapper, "script-manager", "print_timers"); } + lastLoadSaveTickCount = Core::getInstance().p->getTickCount(); } static bool get_entity_id(const std::string & fname, int & entity_id) { @@ -309,8 +309,8 @@ void Persistence::Internal::load(color_ostream& out) { out.printerr("Cannot load data from: '%s'\n", path.c_str()); } + lastLoadSaveTickCount = Core::getInstance().p->getTickCount(); if (found) - lastTickCount = Core::getInstance().p->getTickCount(); return; // new file formats not found; attempt to load legacy file @@ -422,7 +422,7 @@ void Persistence::getAllByKey(std::vector &vec, int entity_i vec.emplace_back(it->second); } -uint32_t Persistence::getSaveDur() { - uint32_t durMS = Core::getInstance().p->getTickCount() - lastTickCount; - return durMS / (60 * 1000); +uint32_t Persistence::getUnsavedSeconds() { + uint32_t durMS = Core::getInstance().p->getTickCount() - lastLoadSaveTickCount; + return durMS / (1000); } From c50f5f5d7faa5d1a23ac6bbba52810c7de4480b5 Mon Sep 17 00:00:00 2001 From: Squid Coder <92821989+realSquidCoder@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:13:41 -0600 Subject: [PATCH 3/9] put things in the proper place per code review --- library/LuaApi.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 97a5b216bd..894ee4ea06 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_last_save_time(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 }, + { "getUnsavedSecs", dfhack_persistent_get_last_save_time }, { NULL, NULL } }; @@ -1343,7 +1349,7 @@ static string getArchitectureName() static string getDFVersion() { return Core::getInstance().vinfo->getVersion(); } static uint32_t getTickCount() { return Core::getInstance().p->getTickCount(); } -static uint32_t getCurSaveDur() { return Persistence::getSaveDur(); } +static uint32_t getCurSaveDur() { return Persistence::getUnsavedSeconds(); } static string getDFPath() { return Core::getInstance().p->getPath(); } static string getHackPath() { return Core::getInstance().getHackPath(); } From 001a94856b3f67a6f00ff980229322a8e8e1296c Mon Sep 17 00:00:00 2001 From: Squid Coder <92821989+realSquidCoder@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:32:30 -0600 Subject: [PATCH 4/9] Add docs for new API function --- docs/dev/Lua API.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 3369705a78..f57409b39f 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.getUnsavedSecs()`` + + 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. From 74c28450d3cdb06f6a4d26b02763f79d38f7075e Mon Sep 17 00:00:00 2001 From: Squid Coder <92821989+realSquidCoder@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:42:38 -0600 Subject: [PATCH 5/9] Apply suggestions from code review Co-authored-by: Myk --- library/LuaApi.cpp | 2 +- library/include/modules/Persistence.h | 2 +- library/modules/Persistence.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 894ee4ea06..1b357dcef3 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -365,7 +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 }, - { "getUnsavedSecs", dfhack_persistent_get_last_save_time }, + { "getUnsavedSeconds", dfhack_persistent_get_last_save_time }, { NULL, NULL } }; diff --git a/library/include/modules/Persistence.h b/library/include/modules/Persistence.h index 748994c4bb..49757e9baa 100644 --- a/library/include/modules/Persistence.h +++ b/library/include/modules/Persistence.h @@ -213,7 +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 tickcount of the most recent save. + // 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 a21feaeb28..652c550d6a 100644 --- a/library/modules/Persistence.cpp +++ b/library/modules/Persistence.cpp @@ -239,6 +239,7 @@ void Persistence::Internal::save(color_ostream& out) { color_ostream_wrapper wrapper(file); Lua::CallLuaModuleFunction(wrapper, "script-manager", "print_timers"); } + lastLoadSaveTickCount = Core::getInstance().p->getTickCount(); } @@ -424,5 +425,5 @@ void Persistence::getAllByKey(std::vector &vec, int entity_i uint32_t Persistence::getUnsavedSeconds() { uint32_t durMS = Core::getInstance().p->getTickCount() - lastLoadSaveTickCount; - return durMS / (1000); + return durMS / 1000; } From 950d9513996a07bdb35c8ea933a7ea54c5ba03af Mon Sep 17 00:00:00 2001 From: Squid Coder <92821989+realSquidCoder@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:51:18 -0600 Subject: [PATCH 6/9] Apply suggestions from code review Co-authored-by: Myk --- docs/dev/Lua API.rst | 4 ++-- library/LuaApi.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index f57409b39f..bfadfc6899 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -771,9 +771,9 @@ arbitrary Lua tables. Same semantics as for the ``Site`` functions, but will associated the data with the global world context. -* ``dfhack.persistent.getUnsavedSecs()`` +* ``dfhack.persistent.getUnsavedSeconds()`` - Returns the number of seconds since last save or load of a save + 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 1b357dcef3..edadc552e9 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -353,7 +353,7 @@ static int dfhack_persistent_delete_world_data(lua_State *L) { return delete_site_data(L, get_world_data); } -static int dfhack_persistent_get_last_save_time(lua_State *L) { +static int dfhack_persistent_get_unsaved_seconds(lua_State *L) { lua_pushinteger(L, Persistence::getUnsavedSeconds()); return 1; } @@ -365,7 +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_last_save_time }, + { "getUnsavedSeconds", dfhack_persistent_get_unsaved_seconds }, { NULL, NULL } }; From 770f0ba0d0a71133318a66219b86f706996ce00d Mon Sep 17 00:00:00 2001 From: Squid Coder <92821989+realSquidCoder@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:53:02 -0600 Subject: [PATCH 7/9] Remove old code --- library/LuaApi.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index edadc552e9..b92e0eddbb 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1349,7 +1349,6 @@ static string getArchitectureName() static string getDFVersion() { return Core::getInstance().vinfo->getVersion(); } static uint32_t getTickCount() { return Core::getInstance().p->getTickCount(); } -static uint32_t getCurSaveDur() { return Persistence::getUnsavedSeconds(); } static string getDFPath() { return Core::getInstance().p->getPath(); } static string getHackPath() { return Core::getInstance().getHackPath(); } @@ -1377,7 +1376,6 @@ static const LuaWrapper::FunctionReg dfhack_module[] = { WRAP(getDFVersion), WRAP(getDFPath), WRAP(getTickCount), - WRAP(getCurSaveDur), WRAP(getHackPath), WRAP(isWorldLoaded), WRAP(isMapLoaded), From 0070b57b647a7a040674458b5b8d6e0d95c62dfa Mon Sep 17 00:00:00 2001 From: Squid Coder <92821989+realSquidCoder@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:12:25 -0600 Subject: [PATCH 8/9] Use a wrapper for detecting save/load --- library/modules/Persistence.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/modules/Persistence.cpp b/library/modules/Persistence.cpp index 652c550d6a..0a6f1c3772 100644 --- a/library/modules/Persistence.cpp +++ b/library/modules/Persistence.cpp @@ -191,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(); @@ -198,6 +204,7 @@ void Persistence::Internal::save(color_ostream& out) { return; CoreSuspender suspend; + LastLoadSaveTickCountUpdater tickCountUpdater; // write status { @@ -240,7 +247,6 @@ void Persistence::Internal::save(color_ostream& out) { Lua::CallLuaModuleFunction(wrapper, "script-manager", "print_timers"); } - lastLoadSaveTickCount = Core::getInstance().p->getTickCount(); } static bool get_entity_id(const std::string & fname, int & entity_id) { @@ -287,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); @@ -310,7 +317,6 @@ void Persistence::Internal::load(color_ostream& out) { out.printerr("Cannot load data from: '%s'\n", path.c_str()); } - lastLoadSaveTickCount = Core::getInstance().p->getTickCount(); if (found) return; From a33aa17a6223a3ab35e5a1630b9e21fedc91a7ba Mon Sep 17 00:00:00 2001 From: Squid Coder <92821989+realSquidCoder@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:20:43 -0600 Subject: [PATCH 9/9] Update changelog.txt --- docs/changelog.txt | 2 ++ 1 file changed, 2 insertions(+) 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``