Sunday, April 6, 2014

Making Patches with diffr and patchr

ResidualVM comes with two tools we can use to modify scripts while running a game in the engine. These tools are diffr and patchr, and can be found in the residual-tools repository.

diffr takes two files, and prepares a binary difference patch between them, outputting the result into a .patchr file. patchr takes the original file and the patch, and outputs the patched file. Let's say we've made a fix to the game logic that we'd like to ship with ResidualVM. In this example, I'm replacing the call to ReadRegistryValue in the EMI Demo so that instead of trying to read the value SfxVolume from a non-existent registry and segfaulting (remember that bug?) the script instead reads from system_prefs.cfg.sfxvolume, which is implemented properly in ResidualVM for EMI.

Once we have made the desired change to our script, the first step is to compile a new script. If we can, it's desirable to base this script on the previous script to reduce the amount of binary changes for patchr. Note that the luac referenced here is the one distributed with residualvm-tools, a regular copy won't work!
  • luac -b <old compiled script> -o <new file output> <script to compile>
With the compiled script, we'll now ask diffr to make a patchr file for us, describing the binary differences between the two files:
  • diffr <old compiled script> <new compiled script> <patchr file>
Now, we need to add this to the file containing the patches used at runtime. In the source directory, there is a folder that contains the existing patches. It can be found here for EMI's patches: dists/engine-data/patches/emi. Once we have generated a patchr file, move it into this directory. Then, from dists/engine-data we'll generate a new copy of residualvm-emi-patch.m4b containing our patch:
  • mklab --emi patches/emi residualvm-emi-patch.m4b
Now, what happens if someone has already made a patchr for the file we'd like to change? In this case, we'll patch the binary file using patchr, then delua it like normal so we can make our changes:
  • patchr <old file> <new output file> <patchr file>
Remember that when building the new file and generating the patchr file, the old file is the original file from EMI, not the one we generated using patchr.

In this way, we preserved the changes already made, and can safely overwrite the patchr file when making our modified residualvm-emi-patch.m4b.

As an added bonus, I've also written a script to let you get a regular old patch file from a patchr file. Simply pass the file to be patched and the patchr file, and the script will spit out a text patch that describes the changes made. Obviously, this only works if your patchr file is patching a Lua script. Here's how to use it:
  • patchr_diff _options.lua _options.lua_1.patchr

No comments:

Post a Comment