OptiFabric Reforged

Quick rating

Community listing page, reviews here may not be monitored by the author.

OptiFabric Reforged

No reviews yet

OptiFine on Fabric, with Fabric API loaded alongside.

Mod Loaders
Minecraft

About

Description

OptiFabric — OptiFine on Fabric

A Fabric mod that brings OptiFine to Fabric. Put OptiFabric and your own OptiFine jar into mods/ and it takes care of the rest — no jar patching by hand, no OptiFine installer to run, no Forge.

ℹ️ OptiFine is not bundled or redistributed. Get the build that matches your Minecraft version from the official site — 1.20.6 and 26.1.2 have preview builds only so far.

OptiFabric is developed as one project per release line; the jars are not interchangeable, and each one carries the Minecraft version in its file name:

Line Minecraft Jar Loader Java
1.20.6 1.20.6 <button class="_fileMention_177e0_288" title="OptiFabric-1.0.0+mc1.20.6.jar" type="button" aria-label="打开 OptiFabric-1.0.0+mc1.20.6.jar">OptiFabric-1.0.0+mc1.20.6.jar</button> ≥ 0.19.3 21+
1.21.x 1.21 – 1.21.11 (ten releases) <button class="_fileMention_177e0_288" title="OptiFabric-1.1.2+mc&lt;version&gt;.jar" type="button" aria-label="打开 OptiFabric-1.1.2+mc&lt;version&gt;.jar">OptiFabric-1.1.2+mc<version>.jar</button> (1.21 / 1.21.1 are <button class="_fileMention_177e0_288" title="1.1.0" type="button" aria-label="打开 1.1.0">1.1.0</button>) ≥ 0.19.5 21+
26.x 26.1.2 <button class="_fileMention_177e0_288" title="OptiFabric-Reforged-2.0.0+mc26.1.2.jar" type="button" aria-label="打开 OptiFabric-Reforged-2.0.0+mc26.1.2.jar">OptiFabric-Reforged-2.0.0+mc26.1.2.jar</button> ≥ 0.19.5 25

Why it is needed

OptiFine is built for vanilla (and Forge): its patches are compiled against the official obfuscated names, while Fabric runs in the intermediary namespace. Fabric API also injects into many of the same classes. Put together, the two disagree in ways that are hard to diagnose — different constructor shapes, different synthetic field names, helper methods inlined away, object creation replaced by OptiFine's own subclasses, and so on.

The disagreements are not cosmetic. Remapping without the game on the remapper's classpath silently left 35 methods unmapped in a single class, which showed up as 281 broken abstract contracts and 254 lost virtual overrides. OptiFine's recompiler turns vanilla methods into thin shells that forward to its own overloads — which moves Fabric API's injection points out from under it, and Mixin then fails the whole class at load. OptiFine also replaces classes wholesale (its ChunkOF chunk, its video-settings screen including the superclass) and rewrites the lambda bodies Fabric matches injection points against.

On the 26.x line the problem changes shape: Minecraft 26.1 and newer is unobfuscated — the official names are the runtime names, and there is no yarn and no real intermediary to remap through (26.1.2 publishes only the 0.0.0 placeholder). So that line takes no mappings at all, runs in the official namespace, and carries its own mod id (optifabric_reforged), because some mods declare "breaks": {"optifabric": "*"} and Fabric Loader matches that by id — a display-name change would not be enough.

What it does

At the earliest point of startup (the loader's preLaunch), OptiFabric will:

  1. run OptiFine's own installer to extract its patches for the game classes (since 1.21.6 the patches travel as xdelta diffs; optifine.Patcher is used the same way);
  2. drop the volde-ification, and rebuild the lambdas whose targets OptiFine moved (LambdaRebuilder);
  3. remap the patches from official to intermediary — with the game jar in the remapper's classpath and inputs, so members inherited from a supertype keep their mapped names;
  4. repair the known structural conflicts between OptiFine and Fabric API, each one traced down to the bytecode level;
  5. split the result in two: OptiFine's own classes and resources go on the game class path, the patched net/minecraft/** classes go into a ClassCache;
  6. hand the repaired classes to Fabric Loader's own GameTransformer and cache everything under <game dir>/.optifine/<OptiFine version>/, so later launches reuse it instead of doing the work again (1–2 seconds instead of 5–7).

Steps 2 and 3 are skipped on the 26.x line, which is the whole reason it exists as a separate project.

Replacement happens before Mixin: when a Minecraft class is about to be loaded, Loader asks the game provider's GameTransformer.transform(...) for ready-made bytecode. What OptiFabric hands over is therefore Mixin's input, not its output — which is why other mods' mixins against those same classes keep working. There is one hard constraint that follows from this: before the classes are handed over, nothing may reflect on game classes — a single Class.getMethods() loads every type in those method signatures and pins the class to vanilla for the rest of the session.

The cache directory holds cache-format.txt (currently 26; a mismatch rebuilds everything), Optifine-mapped.jar (OptiFine without MC classes, i.e. what goes on the class path) and Optifine.classes.gz (the patched MC classes).

Installation

  1. Install a client for your Minecraft version with Fabric Loader (≥ 0.19.3 for 1.20.6, ≥ 0.19.5 for 1.21.x and 26.x), on Java 21+ — or Java 25 for 26.1.2, which is the game's own requirement.
  2. Put OptiFabric and your own OptiFine jar for that exact version into that instance's mods/ folder. Dropping the OptiFine installer jar in is enough — you do not need to run its installer first (an already-extracted OptiFine with notch/ classes works too). Do not install two OptiFine jars (the game reports DUPLICATED), and do not mix jars from two lines.
  3. Start the game with the Fabric profile — not a launcher-made 1.21.x-OptiFine_xxx profile, which injects OptiFine itself. The OptiFine version appears in the top left of the title screen when it works, and its options appear in video settings.

Fabric API can be loaded alongside (this port is adapted for it specifically). With version isolation enabled (PCL2 / HMCL), the game directory and mods/ live under versions/<name>/, and the .optifine/ cache is created there too.

Requirements

  1.20.6 1.21.x 26.x
Minecraft 1.20.6 1.21 – 1.21.11 (one jar each) 26.1.2
Fabric Loader 0.19.3 or newer 0.19.5 or newer 0.19.5 or newer
Java 21+ (tested on 25) 21+ (tested on 25) 25
Side client client client
OptiFine <button class="_fileMention_177e0_288" title="preview_OptiFine_1.20.6_HD_U_I9_pre1.jar" type="button" aria-label="打开 preview_OptiFine_1.20.6_HD_U_I9_pre1.jar">preview_OptiFine_1.20.6_HD_U_I9_pre1.jar</button> (preview only) your own build, exact version match <button class="_fileMention_177e0_288" title="preview_OptiFine_26.1.2_HD_U_K1_pre2" type="button" aria-label="打开 preview_OptiFine_26.1.2_HD_U_K1_pre2">preview_OptiFine_26.1.2_HD_U_K1_pre2</button> (preview only)
Optional Fabric API (supported) Fabric API (supported) Fabric API (tested 0.155.3+26.1.2)

What was verified

Every release is checked by one command, in a single loader, the same way the game loads those classes: the JVM verifier plus an ASM data-flow verifier over every patched class and every OptiFine class, followed by five scanners (mixin member references, @At injection points, abstract contracts / lost virtual overrides / unresolvable references, invokedynamic handles, local-variable captures).

Minecraft Patched game classes (JVM) OptiFine classes (JVM) ASM verifier Scanners
1.20.6 425 / 425 0 problems clean
1.21.3 / 1.21.4 440 / 440 · 474 / 474 816 / 816 · 812 / 812 0 only the disabled-Indigo @At misses
1.21.6 / 1.21.7 / 1.21.8 487 / 487 · 500 / 500 · 516 / 516 820 / 820 · 823 / 823 · 831 / 831 0 same
1.21.9 / 1.21.10 / 1.21.11 519 / 519 · 553 / 553 · 570 / 570 832 / 832 · 836 / 836 · 874 / 874 0 same
26.1.2 567 / 567 879 / 879 0 all columns 0 (this line declares no contains_renderer, so Indigo is live)

In game: startup, title screen, single-player, multiplayer servers, block/chunk/item and entity rendering, shaders (verified with ComplementaryReimagined), anti-aliasing on 1.21.3 – 1.21.11, F3 debug screen, with [ERROR]-free sessions and no crash reports. On 26.1.2 Indigo registers its own renderer and mods that generate geometry per block position (LambdaBetterGrass' better grass, connected textures) render correctly with shaders on.

Compatibility issues that are fixed

All of these were found through real crashes and traced to the bytecode:

  • Fabric API's ShaderProgramMixin injected before super() → OptiFine's delegating constructor is rewritten, and the inlined identifier creation now copies the game's own Identifier.ofVanilla(...) call (the wrapper targets exactly that call, and new Identifier(...) bypassed it);
  • fields OptiFine left obfuscated with a mismatching descriptor (e.g. the particle factory table) → realigned by name, type and stored value, following the inheritance hierarchy to find the override;
  • private helpers OptiFine inlined away while recompiling → the vanilla method body is restored so injections have a target again;
  • methods OptiFine turned into forwarders to its own overloads (chunk building, model baking, block outline, item models) → vanilla bodies restored — this was behind "every model fails to bake" and invisible blocks;
  • object creation OptiFine redirects to its own subclass (the ChunkOF chunk object) → an inert marker puts Fabric's NEW injection point back;
  • a ported fixer that dropped a field initialisation together with the constructor it replaced → the constructor is no longer replaced (this one disconnected multiplayer sessions after two seconds);
  • lambda bodies recompiled under a different name and signature (lambda$addMainPass$1 grew an argument) → vanilla bodies restored; where OptiFine replaced method references with its own lambdas, LambdaMethodRefFix renames them back to the method name, because that release's Fabric API matches custom injection points by bootstrap handle;
  • a region constructor that never stored the section position (ChunkCacheOF.renderStart() then NPEs inside a null region) → the fixer calls the six-argument constructor and derives its argument from the packed long the method already has — the 1.21 – 1.21.4 shape takes a ChunkSectionPos object instead, and both shapes are handled;
  • a Fabric hook whose context OptiFine's render-pass structure never fills in (BEFORE_BLOCK_OUTLINE) → StubInjectionTargetFix renames the target and leaves a same-named copy, so the hook injects into code nobody calls: the crash is gone and the block outline is still drawn by OptiFine;
  • the same trick failing for the moving-blocks renderer hook, whose caller lives in another class and was reaching the injected copy → CallSiteRedirectFix redirects that call site too (without it, multiplayer clients crashed ~30 seconds in);
  • F3 crashing while nothing was registered as the renderer — declaring contains_renderer only makes Indigo step aside; Fabric's own debug entries still call Renderer.get() → RendererApiFallback registers an inert placeholder renderer;
  • the placeholder's first version breaking the whole session — it read the Fabric API interface with Class.getMethods(), which loaded game classes before the patched ones were handed over and pinned them to vanilla forever → the placeholder is now generated with ASM from the interface's class file alone (no type resolution), registered through MethodHandles.findStatic, and only after the classes are in place; on 26.1.2 the renderer API had also moved to api.client.renderer.v1, where the old lookup failed silently;
  • classes no fixer modifies no longer get their stack frames recomputed — the global override fixer always reports a change, so recomputing every patched class degenerated merged local types to java.lang.Object and the game rejected the class with VerifyError: Bad type on operand stack;
  • 26.x: OptiFine's thin shells leave two same-named methods, while Fabric API names its targets without descriptors → each site is disambiguated (delete the overload nobody calls; rename the one that is still called with CallSiteRedirectFix following its callers). Getting this wrong shows up as LVTGeneratorError: Could not locate method metadata … or as Scanned 0 target(s);
  • 26.x: models that emit their own quads silently vanished — Fabric's terrain hook injects into the BlockPos.betweenClosed loop of the vanilla chunk build, and OptiFine's own compile overload has no such loop, so the hook ran nowhere. FrapiTesselateBridgeFix + OptifineFrapiBridge route that one tessellation call through Fabric's renderer and hand the quads to OptiFine's own BlockQuadOutput, so vertex format, layers, lighting and shader attributes stay OptiFine's; only models whose emitQuads is declared outside net.minecraft. are routed (vanilla models stay on OptiFine's path, or shaders lose OptiFine's extra vertex attributes);
  • anti-aliasing: the FXAA chain is resolved by the game's post-chain loader from post_effect/, so an earlier build of this mod that "helpfully" deleted that file made every resource reload log Resource not found: minecraft:post_effect/fxaa_of_2x.json and every anti-aliasing toggle fail with Failed to load post chain. OptiFine's own chain files are now left exactly as they ship, and on 1.21.9 / 1.21.10 — whose post pipeline draws an attribute-less fullscreen triangle from gl_VertexID while OptiFine's fxaa_of_*.vsh still reads the Position attribute (this was the "antialiasing turns the screen black" bug) — the two vertex shaders are rewritten accordingly.

The full list (symptom / cause / fix) is in the changelog, with the per-round evidence in docs/DEVELOPMENT.md (and docs/PORT_26.x.md for the unobfuscated line).

Known issues

  • Conflicts with Sodium — both are renderers; do not install them together.
  • Incompatible with RyoamicLights — OptiFine replaces the whole video settings screen (including its superclass), which makes that mod's injection fail and crashes as soon as the screen is opened. OptiFine has built-in dynamic lights (Video Settings → Quality → Dynamic Lights), so it is not needed.
  • Mods that rely on FRAPI/indigo no longer get indigo's custom rendering on 1.20.6 and 1.21.x; terrain is rendered by OptiFine and Renderer.get() returns an inert placeholder (F3 shows OptifineRendererPlaceholder). On 26.1.2 the opposite is true — Indigo registers its own renderer and that geometry renders.
  • Two Fabric API hooks are intentionally inert (the BEFORE_BLOCK_OUTLINE event does not fire; the moving-block FRAPI path is bypassed). Both paths still render correctly through vanilla/OptiFine.
  • 1.21.6 / 1.21.7 crash as soon as shaders are enabled (NullPointerException … "multiTex" is null in ShadersTex.initDynamicTextureNS). It is not the shader pack (three unrelated packs crash identically, and stripping a pack's custom textures does not help) and not this mod: OptiFine's own preview builds for those two releases inject a call into the first texture creation without the setParentTexture association the later builds perform. All seven OptiFine builds available for them crash the same way. Without shaders both releases start and play.
  • 26.1.2 needs Java 25 — starting it on Java 21 fails before the window appears. That is the game's requirement, not this mod's.
  • OptiFine cannot see resources inside Fabric mods — you will see Unknown resource pack type: ...ModNioResourcePack in the log. This is a limitation on OptiFine's side.
  • Shader packs that do not match your OptiFine version log [Shaders] Invalid program name: ...Unknown macro value: IRIS_VERSION or ParseException: Model variable not found: …; those come from the shader pack.
  • Only the releases listed above are covered — other Minecraft versions need their own pass, and OptiFine has published no build at all for 1.21.2 / 1.21.5 or for anything after 26.1.2.

Troubleshooting

Where is the cache / how do I force a rebuild? <game dir>/.optifine/<OptiFine version>/. Delete the .optifine/ folder to force a rebuild — the cache format (26) normally rebuilds it by itself after an upgrade.

Why can't I find [OptiFabric] in the log? Its output goes to the launcher console, not to logs/latest.log; the loader only writes log4j output there. Filtering for [OptiFabric] shows how many classes were prepared and how many Loader took over.

The game jar cannot be found / I want to point at it manually — add -Doptifabric.mc-jar=<path to the vanilla client jar>.

I want to inspect the patched classes — add -Doptifabric.extract=true; the remapped OptiFine classes are unpacked to .optifine/<version>/optifine-classes/.

Stuck on the loading screen — take two thread dumps (jstack <pid>, ~15 seconds apart) and compare them. Identical stacks with flat CPU means a real stall; a stack sitting in a native call (glfwSwapBuffers) is a presentation problem, and do not minimise the window while loading (with vsync on the render thread blocks there).

Models/items/textures disappearing wholesale (a log full of Unable to bake … model) — a Fabric mixin failed to transform that class; the outermost message usually hides the real cause. OptiFine turning vanilla methods into forwarders is the usual reason the injection point moved.

Warnings that are normal and can be ignored — [OptiFine] (Reflector) Class not present: net.minecraftforge.* / sun.misc.SharedSecrets (OptiFine probing for Forge and old JDKs), Failed to locate initialiser injection point in <init>(class_2591,…) (the price of applying OptiFine's BlockEntity patch), [OptiFabric] Resource not found: minecraft:shaders/post/fxaa_of_{2,4}x.json (OptiFine probing its pre-1.21.6 chain location; the chain in use lives in post_effect/), and Skipping bad option: lastServer.

Reporting a problem

Please attach:

  • logs/latest.log (plus the matching file from crash-reports/ if it crashed — it ends with an -- OptiFabric -- section listing the OptiFine version, jar status and remapped jar path);
  • your mods/ folder listing;
  • your OptiFine version (e.g. OptiFine_1.21.11_HD_U_J9) and which Minecraft version you run.

License and credits

A port of Chocohead/OptiFabric by Modmuss50 and Chocohead, licensed under MPL-2.0; ported files keep their origin headers. OptiFine itself is neither included nor redistributed — it is sp614x's work, get it from the official site. This is a community port and is not affiliated with, endorsed by or supported by the OptiFine, Fabric or Mojang teams.