Retromod

Retromod Is a Minecraft mod that allows you to play older mods on newer versions.

File Details

Retromod 1.2.0-Snapshot.5 (NeoForge 1.21.11)

  • B
  • Jun 29, 2026
  • 3.09 MB
  • 3
  • 1.21.11
  • NeoForge

File Name

retromod-1.2.0-snapshot.5+1.21.11.jar

Supported Versions

  • 1.21.11

Curse Maven Snippet

NeoForge

implementation "curse.maven:retromod-1532616:8341961"
Curse Maven does not yet support mods that have disabled 3rd party sharing

Learn more about Curse Maven

Fixed

  • Retromod didn't initialize at all on Forge (#102). Retromod's main jar registered a Forge IModLocator service (the #78 mods/Retromod/ locator). Forge's ModDirTransformerDiscoverer claims any mods/ jar that declares that service onto the early service/transformer layer, where it loads before mod discovery and is never scanned as a @Mod. So Retromod loaded as a bare locator, its RetromodForge @Mod entry never ran, and it transformed nothing; an old mod (Cart's, 1.16.5) was then rejected by Forge's own version check and looked like Retromod "ignored" it. The service registration is removed, so Retromod loads as a normal Forge mod again. This regressed in snapshot.2 when the Forge locator landed, and the snapshot.2 in-game check only verified the locator loading mods/Retromod/, not Retromod's own @Mod, so it was masked. The locator class is kept for a future locator-only stub jar; until then mods/Retromod/ loading is NeoForge-only and Forge users place jars directly in mods/. Regression-tested (RetromodForgeModLocatorTest asserts the service stays unregistered).

  • Transform aborted when a mod referenced a class in a protected Mixin package (#102). The transform verifier (a diagnostic that checks a transformed mod's references against the target MC) loads referenced classes to probe them. When one is a @Mixin class in a package owned by a *.mixins.json, Mixin throws IllegalClassLoadError on the direct load, an Error rather than an Exception. The probes caught only Exception, so the Error escaped and killed the entire transform pass, taking every input mod down with it (seen with the Mine Mine No Mi addon Cart's, which references a mineminenomi mixin class). The three resolution probes and the verifier's top-level guard now catch Throwable, so this diagnostic can never abort a transform. Regression-tested (TransformVerifierTest locks the probes' no-throw contract).

  • CLI/AOT emitted broken ResourceLocation constructor bytecode (CLI did not match an in-game boot). The offline transform/batch/aot paths applied the class-move table but not the ResourceLocation(String) -> Identifier.parse / (String, String) -> Identifier.fromNamespaceAndPath constructor redirects that the Fabric/NeoForge/Forge runtime applies, so any mod that constructs a ResourceLocation got a raw new Identifier(...) call (a constructor 26.1 removed) and would fail to load when prepared via the CLI/AOT, even though the same mod transformed in-game worked. AOT is the recommended NeoForge flow, so this hit the recommended path. Fixed by routing all five transform paths (three runtime entry points + CLI + AOT) through one shared registerIdentifierCtorRedirects helper, removing the "keep in sync by hand" drift. Verified byte-for-byte: 26 classes across a 6-mod corpus that previously emitted invokespecial Identifier.<init> now emit invokestatic Identifier.parse / fromNamespaceAndPath, matching the runtime. Regression-tested (RetromodCliAuxRedirectsTest).

Changed

  • Internal code cleanup and hot-path optimizations, no behavior change. Tightened comments and structure across the source, and applied behavior-preserving performance fixes to the transform core: an O(1) constructor-redirect fast path replacing a per-NEW-opcode key scan, constant sets and regexes hoisted out of per-class loops, single map lookups in the reflection remapper instead of contains-then-get, and a skipped guaranteed-no-op pass in the intermediary remapper. Verified byte-identical transform output across a 6-mod corpus (785 classes, MC 1.16.5-1.20.4 to 26.1) on top of the full test suite.
  • Resource and allocation hardening from a leak audit, no behavior change. Wrapped unclosed Files.walk/Files.list streams and jar.getInputStream() reads in try-with-resources across the AOT, hybrid, quilt, legacy, datapack, and pre-launch paths (file-descriptor leaks), shut down an executor in a finally, deleted temp dirs in a finally, and replaced a per-class-load full-String copy in the JIT agent's marker scan with a direct byte search. Verified byte-identical transform output and the full test suite.