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↩︎