Skip to content
Merged
2 changes: 2 additions & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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``
Expand Down
4 changes: 4 additions & 0 deletions docs/dev/Lua API.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
6 changes: 6 additions & 0 deletions library/LuaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,13 +353,19 @@ 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 },
{ "deleteSiteData", dfhack_persistent_delete_site_data },
{ "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 }
};

Expand Down
2 changes: 2 additions & 0 deletions library/include/modules/Persistence.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<PersistentDataItem> &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();
}
}
16 changes: 16 additions & 0 deletions library/modules/Persistence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ using namespace DFHack;
static std::unordered_map<int, std::multimap<std::string, std::shared_ptr<Persistence::DataEntry>>> store;
static std::unordered_map<size_t, std::shared_ptr<Persistence::DataEntry>> 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

Expand Down Expand Up @@ -189,13 +191,20 @@ 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();

if (!core.isWorldLoaded())
return;

CoreSuspender suspend;
LastLoadSaveTickCountUpdater tickCountUpdater;

// write status
{
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -417,3 +428,8 @@ void Persistence::getAllByKey(std::vector<PersistentDataItem> &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;
}
Loading