Originally a Voldeloom note
In 1.6, Forge stopped being a jarmod. Mojang was happy with this:
With the advent of the new launcher and other API stuff in the pipe, we expect the number of mods shipping base classes to drop significantly however, and Mojang has politely asked that FML and MinecraftForge, jointly the largest platform shipping base classes, to cease once the new launcher is established, a request with which I am happy to comply.
Instead, patches are done in a mildly less copyright-infringing way. The class cpw.mods.fml.common.patcher.ClassPatchManager
handles the patches; setup
loads them.
binpatches.pack.lzma
.binpatches.pack
.Pack200
-encoded jar (with no class files).binpatches.jar
contains a binpatch/client
and binpatch/server
directory.net.minecraft.block.Block.binpatch
, net.minecraft.block.BlockBaseRailLogic.binpatch
, etc.client
or server
directory.com.nothome.delta
(modified to not use GNU Trove collections)xz
for Java can do it.1
pack200 is an obscure, complex, and highly domain-specific compression scheme for Java archives, dating back to the applet days when download sizes were a big concern. It has been removed from the jdk so you need a third party decompressor such as Apache Commons Compress.
It was not the best compression scheme to use. Most of its complexity is about ways to compress class files, not resource files like these .binpatch
es.
For a while commons-compress’s pack200 parser was broken, giving you errors like Failed to unpack Jar:org.apache.commons.compress.harmony.pack200.Pack200Exception: Expected to read 48873 bytes but read 3274
. See https://github.com/apache/commons-compress/pull/360 . You can fix it by wrapping the input in an InputStream
that returns false
from markSupported
, and returns any nonzero value from available
, like this. The bug has been fixed so I removed the fix from voldeloom.
Forge reads all binpatches from ./binpatches/client/
on the physical client and ./binpatches/server
on the physical server.
The other set of files is ignored.
The .binpatch
file format is defined in terms of DataInputStream
:
field | read with |
---|---|
name | readUTF |
sourceClassName | readUTF |
targetClassName | readUTF |
exists | readBoolean |
checksum | if “exists”, call readInt ; else 0 |
patchLength | readInt |
patchBytes | readFully into a buffer the size of patchLength |
name
: Internal name of the patch. Afaik this is only used for debugging in ClassPatch#toString
.
sourceClassName
but it shouldn’t br relied upon for this purpose.sourceClassName
: The proguarded name of the class to diff against.
xyz
, it will look for binpatches whos sourceClassName
is xyz
.sourceClassName
is still relevant for exists = false
classes.)targetClassName
: The MCP mapped name of the class to create, in ‘package’ format.
IClassTransformer
passes in both the proguarded & mapped names, and forge checks that both match the binpatch.exists
:
true
, patchBytes
is a gdiff patch transforming the vanilla class into a patched class.false
, patchBytes
is a gdiff patch “from” a zero-length file into the target class.checksum
:
exists = true
, this is the ADLER-32 hash of the bytes of the vanilla class before applying the patch.-Dfml.ignorePatchDiscrepancies=true
) unless the hashes match.exists = false
, this field is not present in the file at all.patchLength
: The length, in bytes, of the rest of the file.patchBytes
: The actual sequence of gdiff instructions.To apply binpatches statically, like Voldeloom does:
sourceClassName
field of an existsAtTarget
binpatch, and write the patched class.!existsAtTarget
binpatches, apply them to new byte[0]
, and write the patched class under the name given in the sourceClassName
field of the binpatch.To apply binpatches at runtime:
targetClassName
. If so:
existsAtTarget
, get the bytes of the vanilla class with the corresponding sourceClassName
, apply the patch, and return the patched class bytes.new byte[0]
and return the patched class bytes.exists = false
patches used?
@SideOnly
annotation” by copying the class from the other jar using an exists = false
binpatch.It’s simply a gdiff file.
Free download no virus↩︎