Skip to content

Conversation

UnknowableCoder
Copy link

I propose a set of functions to DFHack::Persistency to allow managing whole files, following the same entity ID and key logic as the pre-existing functions.

The API was designed around managing the possible paths for these files rather than the files themselves; it would be up to the callers to interact with them according to the demands of their particular use case. Every (entity ID, key) pair will be associated with a unique file ID, corresponding to a file with a name of the form dfhack-pf-<ID>.dat. The association between (entity ID, key) pairs and file IDs is saved as JSON in dfhack-extra-files.dat.

Files that are requested will be copied over to the current folder unless specifically requested as read only through the API (in which case modifying their contents leads to these changes not being reflected if the user does not save to the same folder).

No attempt is made at this stage to offer any particular form of synchronization or memory management of the files themselves. Operations that add to or query the list of available files are guarded by CoreSuspender, but this ultimately only protects the list of file IDs.

No provisions are made for associating more than one file to an (entity ID, key) pair.

Note: I surmised from perusing previous discussions that it was not yet consensual among the main developers whether DFHack should offer the ability to request an entire file for persistency. However, for my current project of overhauling the dwarf logic system, serialization/deserialization could be important for performance if the user configures many objects to be handled by my system, so a more optimized way of handling that seems desirable. My apologies if I overstep any boundaries by proposing this.

bool in_current;
std::filesystem::path to_current_path() const
{
return getSaveFilePath("current", "pf-" + std::to_string(id));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer that the filename prefix start with dfhack so as to clearly distinguish it as part of DFHack's cosave mechanics

Comment on lines +384 to +387
catch (std::exception&) {
// empty file?
return false;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least log the exception reason as a diagnostic; failing silently is unkind

Comment on lines +393 to +418
for (auto& entity : json)
{
if (entity.isMember("e"))
{
auto pair = file_storage.try_emplace(entity["e"].asInt());
if (entity.isMember("arr"))
{
auto arr = entity["arr"];
if (arr.isArray())
{
for (auto& k_v : arr)
{
if (k_v.isMember("k") && k_v.isMember("v"))
{
const size_t this_idx = k_v["v"].asUInt64();
max_idx = std::max(max_idx, this_idx);

pair.first->second[k_v["k"].asString()] = FileEntry{this_idx, false};
//file_storage[e][k] = v
}
}
}
}
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't like the deep nesting here and would suggest using std::ranges::filter to prefilter the iterators instead

int entity_id = Persistence::WORLD_ENTITY_ID;
if (fname != "dfhack-world.dat" && !get_entity_id(fname.string(), entity_id))
continue;
if (fname == "dfhack-extra-files")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using file names with no extension is rude to windows platform users


std::filesystem::path Persistence::getFile(int entity_id, const std::string& key, bool* added, bool just_for_reading)
{
if (!is_good_entity_id(entity_id) || key.empty() || !Core::getInstance().isWorldLoaded())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this exact test appears at least three times on lines 580, 600, 610, and in part in 645 and 673 (and possibly other places). should this be abstracted into a utility function to avoid repeating yourself?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants