snes9xgit / snes9x

Snes9x - Portable Super Nintendo Entertainment System (TM) emulator
http://www.snes9x.com
Other
2.65k stars 457 forks source link

RFC: .msu1 pack support #217

Closed qwertymodo closed 6 years ago

qwertymodo commented 7 years ago

I was recently discussing a project over on byuu's message board to develop a standard distribution format for MSU-1 game packs to simplify life for the end users, especially given the differences between the various implementations (manifests or not, track-#.pcm vs romname-#.pcm, etc), along with a utility to extract the files and rename them properly for each implementation. As it turns out, the distribution format that they settled on is nearly identical to the existing msu-zip support already added to Snes9x (it's basically just a zip file with a custom file extension), except using the higan naming scheme for the files within the archive, and with the addition of a patch file inside the archive so the MSU-1 patch can be distributed along with the audio and data files. I had the idea that since this format was nearly identical to the .msu.zip support already added by OV2, I could add support for it as well here. I've already implemented it in the msu-zip branch here: f8da1524414209e4e090c3ec45aee59999c9aaf3 and am looking for feedback before merging it into master.

For a test, you can try the Conker's High Rule Tail pack here: http://www.mediafire.com/?qasv12obaaob49b

Usage: -Download the test build here: https://dl.qwertymodo.com/snes9x-mercurial.zip -Download the .msu1 pack from the link above. -Acquire a copy of Zelda A Link to the Past (unheadered) and rename it "Conkers High Rule Tail (v1.2.3).sfc" to match the .msu1 file, and copy it to the same directory. -Load the ROM file as normal.

OV2 commented 7 years ago

I have no problems with this. I'd probably go as far as removing the .msu.zip check - if there is a common format then we should just use that. Have not had the time to try it yet, but looks simple enough.

qwertymodo commented 7 years ago

It was brought to my attention that the pack spec allows the pack to either contain a ROM file or a patch file, which complicates things a bit. Currently, the only game I know of that is distributed as a ROM is Super Road Blaster, but BS-Zelda also distributes their base ROMs, so they could conceivably release a .msu1 pack with a pre-patched ROM. Allowing the user to load .msu1 files as ROMs produces 6 different scenarios, depending on whether or not the .msu1 contains a ROM or patch, whether or not the user provides an external base ROM, and whether the user loads the .msu1 file or the base ROM. Right now, I'm leaning towards just failing if the user tries to load a .msu1 containing a patch ("ROM not found"), rather than trying to add the complicated try X, then try Y logic for all 6 scenarios.

However, since this would require allowing the .msu1 extension in the ROM loading dialog, and probably 90+% of those would not actually be ROM files, my thought would be to add the PATCH directory to the search path for .msu1 files, since .msu1 packs containing patch files are, in a sense, patches, it would make sense. Then the user can keep those files out of their ROM directory to avoid trying to load patch files as ROMs only to be told that the ROM wasn't found.

qwertymodo commented 7 years ago

Ok, I added the ability to load .msu1 files as ROMs. If they contain a file named program.rom, it will load as expected. If not, it will reject it as invalid (currently the message indicates that it is an invalid ZIP file, I don't know if we want to handle that separately). I also added the IPS_DIR to the search path for .msu1 files. So, the following scenarios are supported:

Not supported:

This behavior corresponds to the current behavior for patch loading when the .msu1 contains a patch, as well as the current behavior for loading zipped ROMs when it contains a ROM, i.e. you can load a zip file as a ROM, but it must actually contain a ROM or it is considered invalid.

qwertymodo commented 7 years ago

I've uploaded Super Road Blaster as a .msu1 pack to test embedded-ROM pack loading: http://www.mediafire.com/?3y1we1stcl64s11 and also updated my test build (same link as above). On Windows, if you're copying this over an existing .exe, you need to delete the Valid.Ext file, it will be regenerated on first launch.

qwertymodo commented 7 years ago

I had a thought regarding patch file priority. I think that if you have game.sfc+game.msu1, which contains patch.bps, but you also have game.bps in the same folder, game.bps should take priority over game.msu1/patch.bps. The reason for this is if you download the entire pack but then the hack releases an update to the patch, you don't want to have to re-download the entire pack again, and a lot of people might not realize that the pack is a zip file that they could update themselves. I don't believe we currently support applying multiple hot-patches, do we? Like, if you had game.ips, game.ups, and game.bps all in the same folder would they all get applied one after the other? If not, and we currently only apply the first patch found, then game.msu1/patch.bps should be the lowest priority in the search list.

OV2 commented 7 years ago

Currently patches are looked for like this:

  1. bps next to rom
  2. bps in zip of rom
  3. bps in patch dir
  4. ups next to rom
  5. ups in zip of rom
  6. ups in patch dir
  7. ips next to rom
  8. ips with .XXX.ips extension next to rom, XXX = 001 to 999, will stop if a number does not exist
  9. ips with .ipsX extension next to rom, X = 1 to MAX_INT, will stop if a number does not exist
  10. ips with .ipX extension next to rom, X = 1 to MAX_INT, will stop if a number does not exist
  11. ips in zip of rom (with the same three above variants)
  12. ips in patch dir (with the same three above variants)

If any patch is found it is applied and on success it stops. The only exception are numbered ips patches, those are all applied one after the other.

qwertymodo commented 7 years ago

Ok, that makes sense. I think that 2 and 3 should be switched for the reasons above, and that should do it. Or do you think 2 should go at the bottom of the list?