Skip to content

fix(saveslot): carry accrued playtime onto a copied slot - #785

Open
buildthomas wants to merge 1 commit into
Quenty:mainfrom
buildthomas:users/buildthomas/saveslot-copy-playtime
Open

fix(saveslot): carry accrued playtime onto a copied slot#785
buildthomas wants to merge 1 commit into
Quenty:mainfrom
buildthomas:users/buildthomas/saveslot-copy-playtime

Conversation

@buildthomas

Copy link
Copy Markdown

Problem

Copying a save slot loses its playtime — the copy shows as 0 time played even though it carries the same progress.

Both copy paths seed the new slot with only SlotName and Summary:

  • HasSaveSlots.PromiseDuplicateSlot passes those two to PromiseCreateSlot
  • PromiseExportSlot builds a SaveSlotExport of {data, slotName, summary}, and PromiseImportSlot seeds the new slot from those

TimePlayed is never part of that hand-off, so it starts nil on every copy.

Fix

Playtime travels with the progress it measures:

  • SaveSlotCreateMetadata takes an optional TimePlayed, applied in PromiseCreateSlot (it is already one of MUTABLE_METADATA_KEYS, so _buildSlot persists it like any other metadata field)
  • PromiseDuplicateSlot and PromiseImportSlot pass the source's value through
  • SaveSlotExport gains timePlayed, written by PromiseExportSlot and validated as an optional number by isSaveSlotExport
  • Both duplicate and export call _flushPlaytime() first, so copying the active slot includes the running session rather than only what the last save wrote

Timestamps and session counters (PlayCount, LastSessionLength) still start fresh on a copy — those describe the new slot's own sessions, not the progress being copied.

Backwards compatibility

  • Exports written before this change have no timePlayed; they still validate and import to a slot with no accrued playtime, exactly as they did when written
  • A newer export read by older code just carries an unused field
  • No change to how slot metadata is stored or loaded: TimePlayed was already an optional attribute, this only seeds it at creation
  • SaveSlotExportUtils.create gained a trailing optional parameter, so existing 3-argument callers are unaffected

TimePlayed in the create metadata is not a new trust surface: PromiseSetSlotMetadata is already client-callable and accepts the full SaveSlotMetadata, TimePlayed included.

Tests

New coverage in HasSaveSlots.spec.lua (duplicate carries playtime including the unflushed live session; a never-played slot's copy still has none), HasSaveSlots.ExportImport.spec.lua (export/import round-trips playtime, exports the live session, imports a pre-change export, refuses a non-numeric timePlayed), and SaveSlotExportUtils.spec.lua (create/validation).

stylua and selene pass. I could not run nevermore test --cloud here — no Open Cloud key in this environment, and the local rojo shim is broken on this machine — so the new specs have not been executed against the engine.

Copying a slot -- PromiseDuplicateSlot, or an export/import round trip -- seeded the new
slot with only its name and summary, so the copy read as 0 time played even though it
carries the same progress.

Playtime now travels with the progress it measures: SaveSlotCreateMetadata takes an
optional TimePlayed, the duplicate and import paths pass the source's value through, and
the export carries it as `timePlayed`. Both paths flush the live play session first, so
copying the active slot includes the current session rather than only what was last saved.

Backwards compatible in both directions: exports written before this lack `timePlayed`
and import exactly as they did before (a slot with no accrued playtime), and the field is
validated as an optional number so a malformed one is still refused. Timestamps and
session counters (PlayCount, LastSessionLength) still start fresh on a copy.
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.

1 participant