Skip to content
BonsUnleashed edited this page Oct 7, 2026 · 7 revisions

Forge

Minecraft 1.20.1 / Forge: this page documents that build and its measurements. For the separate 170-control Minecraft 1.21.1 port, see Minecraft 1.21.1 NeoForge.

Six controls patch Forge 47.4.16 itself (the loader's own classes, not a mod). Four are pure equivalences on both sides; the render-layer memo is client-only and also covers the hook Oculus adds to the same method, and forge_custom_payload_heap_copy fixes a memory leak on clients that are connected to a server. Forge is LGPL-2.1; none of its code is carried, the mixins hold only our own code and call the original methods.

Key Patched Side Since Result
forge_render_layer_memo ItemBlockRenderTypes.getRenderLayers (with Oculus 1.8.0's hook) CLIENT 1.0.23 122 → 50 ns per call
forge_status_ping_channel_groups ServerStatusPing.toBuf BOTH 1.0.23 4.2-5.8 → 0.14-0.20 ms per ping
forge_plain_translation_format ForgeI18n.parseFormat BOTH 1.0.23 formatter skipped for 85,518 of 88,886 strings
forge_object_holder_pass_index GameData, ObjectHolderRegistry BOTH 1.0.29 about 150 → 2.5 ns per holder at start-up
forge_status_ping_memo ServerStatusPing BOTH 1.0.29 4.5 → 0.15 ms per status update with 440 mods
forge_custom_payload_heap_copy ClientboundCustomPayloadPacket BOTH 1.0.32 fix: mod packets no longer leave direct memory behind on a connected client

Every switch fingerprints the Forge 47.4.16 methods it touches; another Forge build within 47.x is left untouched with one WARN.


forge_render_layer_memo

Since: 1.0.23 · Side: CLIENT · Mixins: RenderLayerMemoMixin, BlockRenderLayerMemoMixin · Helper: bons.furious.patch.forge.RenderLayerMemo Patched: net.minecraft.client.renderer.ItemBlockRenderTypes.getRenderLayers and setRenderLayer; Oculus' MixinItemBlockRenderTypes and WorldRenderingSettings block-type ids

What upstream did. Chunk meshing asks for the render layers of every block it meshes, which looked the block up in the shader pack's map (Oculus) and then in Forge's map, both through the block's registry delegate and a hash lookup.

What the patch does. For every block except leaves the answer depends only on the block, the shader pack's map (replaced on every shader reload) and Forge's map (fixed after loading), so each block remembers it together with those inputs and reuses it while they are unchanged; otherwise the original method runs, with Oculus' and Embeddium's hooks in it (the mixin is a MixinExtras @WrapMethod, so those hooks stay in place). Leaves always ask, because their answer follows the leaves-quality setting. The memo stays off, with one log line, if another mod hooks this class. An earlier design that replaced the method crashed with Embeddium at startup (Embeddium redirects the fancy-leaves read inside it) and was dropped before release.

What stays the same. The layer set: in game 1,109,161 block states identical with the memo on and off, also after a fancy-graphics toggle and a shader reload; 20,757 blocks remembered, 180 leaves blocks always ask.

Measured. 50 ns instead of 122 ns per call; the lookup was 11.7-13.9 % of chunk meshing in review 8.


forge_status_ping_channel_groups

Since: 1.0.23 · Side: BOTH · Mixin: StatusPingChannelGroupsMixin · Helper: bons.furious.patch.forge.StatusPingChannels Patched: net.minecraftforge.network.ServerStatusPing.toBuf and getChannelsForMod

What upstream did. Writing the mod list of a server-list ping scanned the whole network channel map once per mod.

What the patch does. The channels are grouped by mod in one pass at the start of each ping, in the same order, and every mod takes its group from there.

What stays the same. The bytes sent: in game the ping bytes were identical with the groups on and off (16,336 bytes, 550 mods, 234 channels).

Measured. 4.2-5.8 → 0.14-0.20 ms per ping offline (440 mods, 900 channels).


forge_plain_translation_format

Since: 1.0.23 · Side: BOTH · Mixin: PlainTranslationFormatMixin · Helper: bons.furious.patch.forge.PlainTranslation Patched: net.minecraftforge.common.ForgeI18n.parseFormat

What upstream did. Every translation string went through a freshly parsed MessageFormat.

What the patch does. A string with no {, } or apostrophe has no placeholder and no quoting, so the formatter returns it unchanged; it is now returned directly. Strings with any of those characters are formatted exactly as before.

What stays the same. The formatted text: in game all 85,518 plain templates among the pack's 88,886 translations format identically (compared with Forge's own formatter); the 2,607 malformed ones throw exactly as before.

Measured. The formatter was 2.3 % of integrated-server allocation in review 8.


forge_object_holder_pass_index

Since: 1.0.29 · Target: Forge 47.4.16 · Side: BOTH · Kind: opt

Mixins: HolderPassGameDataMixin, HolderPassRegistryMixin, RegistryObjectAccessor, RegistryObjectHandlerAccessor

Forge: after each registry is registered at startup, only that registry's object holders are updated. At startup Forge registers about 300 registries one after another, and after each one it walks every object holder of every mod (about 100,000 in this pack, one per registered block, item, sound and so on) to update the few that belong to that registry. Each holder remembers which registry it belongs to, so the walk now keeps one list of the holders in Forge's own order and, for each registry, calls just the holders of that registry (plus any holder of an unknown kind, and each holder once more until its first registry check has run). The same holders are updated in the same order with the same errors; the list is rebuilt whenever a holder is added or removed.

Measured: offline on Forge's own classes, 178 registry passes compared with the switch off and on from the same state (holders updated, errors and their order, a holder added mid-pass) were identical on both sides; 300 passes over 103,000 holders took 4.2-4.6 s -> 76 ms (about 150 -> 2.5 ns per holder). In this pack's profiles the walk was 7% of the dedicated server's startup thread (about 1.1 s) and 2.7% of the client's (about 1.5 s).


forge_status_ping_memo

Since: 1.0.29 · Target: Forge 47.4.16 · Side: BOTH · Kind: opt

Mixin: ServerStatusPingMemoMixin

Forge: the mod and channel part of the server-list status is reused while it is unchanged. The server-list status carries every mod and network channel in a packed string. Forge rebuilt that string from scratch on every status update (comparing every mod with every channel), every 5 seconds normally and every tick while Chunk Pregenerator shows its progress in the server list. The mod list cannot change in a running game, so the last result is reused when the mods and channels, in the same order, are the same as last time; anything else is rebuilt.

Measured: offline on Forge's own class, the status text came out identical for pack-sized, truncated, reordered, changed and empty mod lists; 4.5 ms -> 0.15 ms per status update with 440 mods. During a pregeneration it was 16.6% of the dedicated server thread.


forge_custom_payload_heap_copy

Since: 1.0.32 · Target: Forge 47.4.16 (Minecraft 1.20.1) · Side: BOTH · Kind: fix

Mixin: CustomPayloadHeapCopyMixin

Forge: mod network packets no longer leave a direct memory buffer behind on the client. When a client is connected to a server, every packet a mod sends through Forge's network channels is copied once for Forge's network event, and that copy, a pooled direct buffer, is never released, so memory outside the Java heap grows with every mod packet until the game is closed. The copy is now an ordinary heap buffer with the same bytes, positions and sizes, which the garbage collector frees like any other object. Singleplayer does not take this path. Forge 47.4.24 and newer make the same change; there this switch does not apply.

Idea: Forge issue 10861 and the Forge 47.4.24 change log, idea text only

Measured: on the transformed packet class, 20,000 packets (decoded from pooled direct network buffers and built from heap data, empty to 40 KB) gave the same bytes, positions, capacity and maximum capacity as the original copy. 5,000 copies of 2 KB packets kept the way Forge's event keeps them: pooled direct memory +8 MiB with the original copy, +0 with the switch.

Bons and Furious

Minecraft 1.20.1 / Forge 1.0.34

Compatibility

Controls by mod

Links

Clone this wiki locally