emmercm / igir

🕹 A zero-setup ROM collection manager that sorts, filters, extracts or archives, patches, and reports on collections of any size on any OS.
https://igir.io/
GNU General Public License v3.0
352 stars 17 forks source link

Add ability to apply multiple patches to same ROM #422

Open chainsawsalad opened 1 year ago

chainsawsalad commented 1 year ago

Is your feature request related to a problem?

No response

Describe the solution you'd like

Many ROMs have addendum patches that have patch dependencies; they assume the core ROM has already been patched. It seems that igir will produce a unique ROM for each patch file it finds, and does not combine them. Also for some patches, order of being applied matters.

Examples:

Kaeru no Tame ni Kane wa Naru: (order matters) Translation: https://www.romhacking.net/translations/1623/ Addendum (fix title screen): https://www.romhacking.net/translations/6517/

Final Fantasy II: (order doesn't matter) Ultima (contains multiple optional patches): https://www.romhacking.net/hacks/4134/

Additional context

For ips patches I've tried adding the CRC32 checksum of the dependency ROM for each successive patch, but it didn't make a difference. It only lead to the later patches failing to be applied because igir seems to be unaware of the matching checksum of a new ROM it generated after applying a patch.

Example

> ls $INPUT
Kaeru no Tame ni Kane wa Naru (Japan).gb

> ls $PATCHES
"Frog_v1.0.ips"
"The Frog for Whom the Bell Tolls.ips"

> crc32 $INPUT/"Kaeru no Tame ni Kane wa Naru (Japan).gb"
c18cd57a
> mv $PATCHES/"Frog_v1.0.ips" $PATCHES/"Frog_v1.0 c18cd57a.ips"

> crc32 Frog_v1.0.gb (obtained after manually patching)
630193e8
> mv $PATCHES/"The Frog for Whom the Bell Tolls.ips" $PATCHES/"The Frog for Whom the Bell Tolls 630193e8.ips"

> ls $PATCHES
"Frog_v1.0 c18cd57a.ips"
"The Frog for Whom the Bell Tolls 630193e8.ips"

> npx igir@latest copy --input $INPUT --output $OUTPUT --patch $PATCHES

...

> ls $OUTPUT/Kaeru no Tame ni Kane wa Naru (Japan)/
"Frog_v1.0.gb"
"Kaeru no Tame ni Kane wa Naru (Japan).gb"
(no "The Frog for Whom the Bell Tolls.gb")
emmercm commented 1 year ago

See the discussion here: https://github.com/emmercm/igir/discussions/317#discussioncomment-5295866.

I think it's going to be difficult to develop a solution that solves people's problems in an easy-to-understand way. I'm already convinced that a lot of people will get confused by the CRC32s in filenames for IPS and other patch types.

Do you have an existing process that works well for multiple patches?

chainsawsalad commented 1 year ago

Oh thanks for the link to that discussion--missed it.

I agree this is a problem that verges on the "advanced" use case. Having to edit the filename is both hard to grok (probably) for the average user (how do I find or generate the CRC32?; I missed in the docs that I had to manually edit a filename) and may make things more difficult to manage if a new or updated patch is released (you can't just unzip the new patch into a folder and be done with it).

Have you considered enforcing a more opinionated patching paradigm? For example, your --patch directories must contain folders within whose names either match ROM names exactly or are ROM CRC32s, with all patches within to be applied to their corresponding ROM. (This wouldn't solve the order problem, but maybe is a good generalized use case). I could see people maybe not liking this, but the structure possibly makes things clearer, and it at least solves the issue of "easier" patch management (not having to rename any patch files).

What I personally use is a sloppy, homespun version of what could be productized as a manifest. I use a bash script to parse a flat text file, but a solution could be to evolve that further, or use JSON.

[
  {
    name: "Kaeru no Tame ni Kane wa Naru (Japan)",
    crc32: "c18cd57a",
    patches: [
      "Frog_v1.0.ips",
      "The Frog for Whom the Bell Tolls.ips"
    ],
    output: "Kaeru no Tame ni Kane wa Naru (Japan) (patched)"
  },
...
]

Not necessarily advocating for either approach, but if BOTH approaches were implemented, behavior could default to "every patch in the corresponding folder is applied to a ROM in an undefined order" and if a manifest.json file is present in the folder, it uses that defined patch order.

But my solution that works for me (especially because I'm not drowning in patches or anything) is to just dump all the patches in one folder with one "manifest" file that helps me and my script to stay organized.