Apply IPS patches to a ROM on the way in, from either front end - #35
Closed
dimiro1 wants to merge 1 commit into
Closed
Apply IPS patches to a ROM on the way in, from either front end#35dimiro1 wants to merge 1 commit into
dimiro1 wants to merge 1 commit into
Conversation
A romhack is handed out as a patch rather than as a ROM, and until now there was nothing here to do with one. `--patch FILE` and **File > Open with Patch...** now apply an IPS patch to the bytes as they are read, so the .nes on disk is left exactly as it was and no patched copy of it exists anywhere. The patcher is a module of its own. IPS is a binary diff from 1990 that says nothing about what it patches -- a ROM, a save file, a disk image -- so `mynes-patch` depends on nothing at all, `mynes-core` included, and it is the front ends that join it to `Cart.load`. Records, RLE runs, growth past the end of the image and Lunar IPS's truncation extension are all read; anything malformed is refused with a sentence saying what is wrong with it. The patch is applied before the cartridge is parsed, because a patch is entitled to rewrite the iNES header and so to change the mapper or the size of the banks. That makes the patched image the thing that ran, which is why `cart.sha256` in the report is its digest rather than the file's, and why `cart.patches` lists what each patch held -- zero records is what a patch cut against a different dump of the same game looks like. In the window, a patched game keeps its own save states, .sav and screenshots, named after the patch rather than the ROM. Sharing them would let an afternoon with a hack write over fifty hours of the original. Which turned up a bug in the method that had to change for it: loadRom moved romPath before startMachine, whose first act is saveBattery(), so loading a game while another was running wrote the outgoing game's save RAM into the incoming game's .sav. The paths move after the save now. RomHackTests is the worked example, and the reason there is a public-domain hello-world cartridge and a real .ips vendored beside it: the twelve ASCII bytes of "Hello World!" become "MyNES Patch!", and the two pictures are compared. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
--patch FILEon the command line and File > Open with Patch... in the window apply an IPS patch to a ROM's bytes as they are read, so the.neson disk is left exactly as it was and no patched copy of it exists anywhere. The patcher is a module of its own,mynes-patch, depending on nothing at all includingmynes-core— IPS is a binary diff that says nothing about what it patches — and it reads records, RLE runs, growth past the end of the image and Lunar IPS's truncation extension, refusing anything malformed with a sentence saying what is wrong. It runs beforeCart.load, since a patch is entitled to rewrite the iNES header and change the mapper or the bank sizes, which is whycart.sha256in the report is the digest of the patched image andcart.patchessays how many records each patch held. In the window a patched game keeps its own save states,.savand screenshots, named after the patch rather than the ROM so a hack cannot write over the original's save — which turned up a pre-existing bug in the method that had to change for it:loadRommovedromPathbeforestartMachine'ssaveBattery(), so loading a game while another was running wrote the outgoing game's save RAM into the incoming game's.sav. Tests cover the format (IPSPatchTests), the flag end to end (HeadlessRunTests,OptionsTests) and a real romhack (RomHackTests, which patches a vendored public-domain hello-world cartridge with a checked-in.ipsand compares the two pictures);.DS_Storeis now ignored, and CLAUDE.md, the README andPROVENANCEare updated.🤖 Generated with Claude Code