Repository navigation
Steam's remotecache.vdf is the launcher's file, not a save change - #52
Conversation
|
@ChakraFusion is attempting to deploy a commit to the sivadaboi's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
The failing job is The test passed on every run of this branch on my fork, 8/8 locally, and 50/50 with the race detector on Windows runners. It's a rare timing flake, and a re-run of the failed job should pass. I'm still trying to catch it with the daemons' logs, and will open a separate fix if I find the cause. |
|
Follow-up: I caught that failure with the daemons' logs (once in 150 race-detector runs), and it's a real bug, not the test. The deck took an automatic snapshot of a save it had already kept: a newly tracked game had no recorded baseline, so writing a log into its excluded folder counted as a change. That copy was then the deck's newest save, so the desktop's newer one wasn't offered. It's unrelated to this PR. The fix is #56. |
2f57b6c to
272850e
Compare
|
Rebased onto today's |
|
Merging #49 just now created a conflict in |
Steam rewrites remotecache.vdf in a game's userdata folder on every start. It counted as a new save: an automatic snapshot of a game nobody played, a sync to every other device, and where the folder is under Program Files a copy that failed with "access denied" on every pass. It is Steam's record of what Steam Cloud uploaded for this device, not part of the save. - delta.NeverSynced names such files (remotecache.vdf for now). - syncengine: they are left out wherever decisions are made, exactly like an exclusion rule - one check, excluded(), used by filterManifest, filterLineage, filterPathList and the recorded deletions. The filter now runs whether or not the game has rules of its own, and the translation of a base recorded before a rule existed runs always too, so a base recorded while the file still counted is not read as both sides moving. The manifest a device serves still lists the file: a device on an older build must not read the gap as a deletion. - watcher: such files do not wake it and do not count toward the content hash. A hash recorded by an earlier build, which counted them, is recognised once and re-taken, so the update itself is not snapshotted as a change. No migration needed. - An emptied-folder hold does not wait for such a file to come back. Tests: delta.NeverSynced; the content hash with and without rules, and the hash an older build recorded; left alone on both sides, still served, one-sided is no difference; e2e: Steam rewriting the file on one device is no snapshot and changes nothing on the other, while a real save change still syncs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
272850e to
31dab19
Compare
|
Rebased onto One Windows shard failed on |
A game that keeps its settings beside its saves had one PC's graphics settings handed to every other: Crimson Desert's save/user_engine_option_save.xml, among others. The game database (Ludusavi manifest) already says which files are a game's settings: it tags them "config", as opposed to "save" - 16,700 entries. The index now keeps those (indexedGame.Config, index format v3, rebuilt once), and for each tracked game the ones inside its save folder become exclusion patterns relative to it (presets.DeviceSettings), matched component by component so a template's <storeUserId> wildcard meets the folder actually tracked. An entry tagged both is a save. A pattern that would cover the whole folder is never applied: a wrong exclusion loses saves, a missed one only syncs a setting. They are applied as the game's exclusion rules are, through one function everything that applies rules now takes them from (syncengine.Engine.IgnoreText), exactly like Liquid-co#52's launcher files: never synced in either direction, never deleted on another device, still in every snapshot, and kept on this device by a restore. The game's own rules come after them, so a "!" line brings one back; a per-game switch (games.sync_device_settings, migration 0040, "Sync these settings between devices too" in the configuration tab, with the files listed) syncs them all. The tab's new text is in the catalogs (en, zh-CN). The list changes without anyone writing a rule, at the first start with this build, so at start a game's last-snapshot hash is re-taken under the new list where the save is the one it was recorded for (daemon.adoptExclusionView); otherwise the watcher would snapshot and sync a game nobody played. The base agreed with each device needs nothing: the sync engine already translates a base recorded under other exclusions (Liquid-co#52). Toggling the switch goes through the same path as editing the rules. On top of Liquid-co#54, so the two merge one after the other (Liquid-co#52 is merged). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… time The patch writer settles a pulled file as OpenSave's own when it commits it (owntouch, Liquid-co#23). The batched pull then gave the file the peer's modification time without marking it again, as the per-file path does, so the exact time-and-size comparison failed and the watcher took the pull for the game saving: an automatic snapshot after every sync of small files, and a sync back of a change this device never made. Found once Liquid-co#52's test ran against this branch on dev-public (TestLauncherFile_SteamRewritingRemotecacheIsNoSaveChange: 4/4 failures before, 10/10 passes after, in separate runs). Both batched paths now set the time the way the per-file path does (setPulledMtime: mark, set, settle). Test: TestSetPulledMtime_KeepsThePullOpenSavesOwn fails without the marking. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entries for Liquid-co#90, Liquid-co#78, Liquid-co#80, Liquid-co#54, Liquid-co#52, Liquid-co#94 and Liquid-co#79 under Fixed; Liquid-co#84, Liquid-co#55, Liquid-co#53 and Liquid-co#74 under Changed; Liquid-co#73 under Added.
… time The patch writer settles a pulled file as OpenSave's own when it commits it (owntouch, Liquid-co#23). The batched pull then gave the file the peer's modification time without marking it again, as the per-file path does, so the exact time-and-size comparison failed and the watcher took the pull for the game saving: an automatic snapshot after every sync of small files, and a sync back of a change this device never made. Found once Liquid-co#52's test ran against this branch on dev-public (TestLauncherFile_SteamRewritingRemotecacheIsNoSaveChange: 4/4 failures before, 10/10 passes after, in separate runs). Both batched paths now set the time the way the per-file path does (setPulledMtime: mark, set, settle). Test: TestSetPulledMtime_KeepsThePullOpenSavesOwn fails without the marking. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
As offered in #21. Steam rewrites
remotecache.vdfin a game's userdata folder on every start. It counted as a new save: an automatic snapshot of a game nobody played, and a sync to every other device. Worse, the new e2e test shows that ondev-public, two PCs whose Steam keeps different bookkeeping read as diverged, so a real save change on one of them never reached the other.delta.NeverSyncednames such files (remotecache.vdffor now).excluded()check used byfilterManifest,filterLineage,filterPathListand the recorded deletions. The filtering now runs whether or not the game has rules of its own, and so does the translation of a base recorded before a rule existed. That way a base recorded while the file still counted isn't read as both sides moving.Tests:
delta.NeverSynced; the content hash with and without rules, plus the hash an older build recorded; left alone on both sides, still served, one-sided is no difference; e2eTestLauncherFile_SteamRewritingRemotecacheIsNoSaveChange, which fails ondev-public.🤖 Generated with Claude Code