Skip to content

Fetch a ROM's whole folder when it holds more than one file - #140

Merged
gantoine merged 5 commits into
rommapp:mainfrom
mrcbucci:fix/nested-roms-download-whole-folder
Sep 24, 2026
Merged

gantoine merged 5 commits into
rommapp:mainfrom
mrcbucci:fix/nested-roms-download-whole-folder

Conversation

@mrcbucci

Copy link
Copy Markdown
Contributor

Addresses the first half of #127 — pulling DLC and update files alongside the game.

The problem

RomM reports a ROM whose folder holds the game at the root with extras in subfolders (dlc/,
patch/ — the "Structure A" layout it documents) as has_nested_single_file, not
has_multiple_files: the game is the only file at the folder's root. RomMRevisionFactory.Build()
branched on has_multiple_files alone, so it took the single-file path and asked for the base game
by itself. The files list was never read as a set, so the DLC and the update were never requested
at all.

The folder-level endpoint already used for multi-file ROMs returns everything, with patch/
preserved at the archive root — the layout the install path expects. Full analysis and server
responses in #127.

The change

Two meanings were riding on one flag:

  • HasMultipleFiles — what RomM says. Unchanged. Decides whether every extracted file is a
    playable ROM, i.e. the discs of a multi-disc game.
  • DownloadAsArchive — new. Decides whether the folder is fetched whole:
    HasMultipleFiles || (HasNestedSingleFile && Files.Count > 1).
  • PlayableFile — new. The file to launch, relative to the ROM's folder.

has_simple_single_file is excluded on purpose: there fs_name names the file itself, so there is
no folder to ask for.

BuildRoms() registers every extracted file matching the emulator profile's extensions, which is
what exposes the discs of a genuine multi-file ROM. It is narrowed only when DownloadAsArchive && !HasMultipleFiles, where the file to launch is named outright so patch/ and dlc/ contents are
not offered as alternative ROMs. If that file is missing after extraction the scan still runs, with
a warning, rather than leaving the game with no ROM at all.

ROM.HasMultipleFiles is left alone deliberately: RomMImport uses it to rebuild the legacy
protobuf GameIds that migrate pre-0.6 libraries.

Install flat

A ROM fetched as a folder carries its own subfolders, so it cannot go flat: they would land in the
platform folder, where every game's patch/ would merge into one, and a flat uninstall — which
removes only the registered ROM files — would leave them behind. These ROMs keep their own folder
even under flat; single files still install flat. The importer and the install controller share one
helper, so the two paths cannot drift apart and break IsInstalled detection.

Uninstall now asks whether the install directory sits inside the mapping's destination, instead of
reading the setting. That keeps games already installed flat working, and fixes a pre-existing bug
where toggling the setting after installing sent uninstall down the wrong branch. "Inside" rather
than "different from" is deliberate: once a mapping is repointed, the recorded path is the previous
platform folder, and deleting it would take every ROM still in it. Uninstall also resolves
{PlayniteDir} now, so a portable install no longer skips what it was asked to delete.

Not covered

  • The second arrangement in [Feature] A way to pull DLC/Update files alongside games, and a way to determine their install path in the integration settings per emulator #127 — every file in its own subfolder, the base game included, so
    nothing sits at the folder's root. That is not a layout the docs describe: dlc and update are
    recognised subfolder names, a Game one is not, and the base game belongs at the root of its
    folder. RomM classifies it accordingly — top_level_file_count counts only files sitting directly
    in the ROM folder, so it is 0 and all three shape flags come out false — and the importer's
    existing fail-safe is what turns it into a multi-file ROM, where update and DLC still appear as
    launchable ROMs. Moving the base game up one level makes it the case this PR covers.
  • Multi-file ROMs under install flat still scatter their subfolders and still leave behind extracted
    files that are not registered as ROMs. Pre-existing.
  • Games installed before this change keep the base file alone until they are reinstalled.

Testing

The unit suite is green, with new cases for the criterion, the file-endpoint paths it must not
disturb, and the flat-layout decision — including a repointed mapping, which must not have its old
folder deleted.

Verified in Playnite 10.35 against RomM server 5.2.0:

  • Update Game Library reclassified 16 ROMs in a 146-game library as folder downloads; multi-file and
    single-file ones were left as they were.
  • A Switch game made of a base file and an update installed as the game plus patch/ —
    263,200,904 bytes, matching the server's fs_size_bytes, where 0.9.0 fetched the base file alone.
    Playnite registered one ROM, the base game; the update and the server-generated .m3u appear
    nowhere in the library.
  • With install flat enabled, the same game kept a folder of its own instead of scattering patch/
    across the platform folder, and uninstalling removed that folder whole.

@greptile-apps

greptile-apps Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

The PR should not merge until installation remains compatible with multi-file sidecars persisted by earlier plugin versions.

Fix All in Claude CodeFindings

  1. P1 Legacy archives stop extracting ▶
Fix with agent prompt
### Issue 1
Models/RomM/Rom/RomMRomLocal.cs:32
When a user upgrades and installs a previously imported multi-file ROM without refreshing the library, the old sidecar has no `DownloadAsArchive` field, so it deserializes as `false`. For a flat install, or when automatic extraction is disabled, this prevents the folder archive from being extracted. The downloaded archive is then registered as the game's only ROM instead of exposing its playable files. Please migrate legacy sidecars or preserve the previous `HasMultipleFiles` behavior when this field was not persisted.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

This PR separates RomM’s multi-file classification from whether content must be downloaded as a folder archive. It also carries an explicit playable file through revision persistence, keeps nested folder downloads isolated under flat mappings, and derives uninstall behavior from the recorded path layout.

  • Adds whole-folder downloads for nested single-file ROMs containing updates or DLC.
  • Restricts those installs to the intended primary playable file.
  • Centralizes flat-layout decisions between import and installation.
  • Resolves portable paths and distinguishes shared roots from game-owned directories during uninstall.
  • Retains a backward-compatibility defect for multi-file sidecars created by earlier plugin versions.

Reviews (1) · Last reviewed commit: "Exempt ROMs fetched as a folder from ins..."

Comment thread Models/RomM/Rom/RomMRomLocal.cs
mrcbucci and others added 3 commits September 22, 2026 22:43
… load

Uninstall only deletes a directory no other game also claims, so a flat
platform folder that ends up inside a repointed destination is no longer
wiped. A missing mapping or ROM list now falls back safely instead of
throwing. Pre-upgrade multi-file sidecars regain DownloadAsArchive at
deserialisation rather than at one reader, and the revision-to-install-info
copy lives in one place.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Add RomMInstallPaths.IsSingleRomInFolder; UsesFlatLayout takes it
  instead of re-deriving it, and BuildRoms reads the same value
- Drop the leftover downloadsArchive alias in the install controller
- Check PlayableFile with IsContained before combining it
- Share one StartsWithDirectory between IsInside and IsClaimedByAnother,
  normalising each path once; skip games with no install directory

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gantoine
gantoine merged commit 555d2bb into rommapp:main Sep 24, 2026
3 checks passed
@mrcbucci
mrcbucci deleted the fix/nested-roms-download-whole-folder branch September 24, 2026 18:48
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