File Details
Retromod 1.2.0-snapshot.4 (NeoForge 1.21.4)
- B
- Jun 25, 2026
- 3.08 MB
- 3
- 1.21.4
- NeoForge
File Name
retromod-1.2.0-snapshot.4+1.21.4.jar
Supported Versions
- 1.21.4
Curse Maven Snippet
Starts the real Forge -> NeoForge migration for 1.20.1 Forge mods on a NeoForge 26.x host (#85): the registry and event surfaces that nearly every Forge content mod touches. See the roadmap.
Added
- Forge -> NeoForge registry migration (#85). A 1.20.1 Forge mod's registration and lookup idioms now translate onto NeoForge 26.x.
ForgeRegistries.BLOCKS(and the other 13 vanilla registries) is represented as the vanillaBuiltInRegistriesregistry instance, which serves both Forge idioms at once:DeferredRegister.create(ForgeRegistries.BLOCKS, id)maps onto NeoForge'screate(Registry, String), andForgeRegistries.ITEMS.getValue(loc)/.getKey(v)/.containsKey(loc)map onto the matchingnet/minecraft/core/Registrymethods (getValueisgeton 26.x; the others are identical).RegistryObjectbecomesDeferredHolder. This also removes a pre-existing crash: three shims blanket-redirectedForgeRegistriesto (three different, wrong) classes, and any such class redirect rewrote the field-read owner before the field redirect could match, so a transformed mod died at<clinit>withNoSuchFieldError: NeoForgeRegistries.BLOCKS. Those broken redirects are gone, andIForgeRegistryis supplied as an empty synthetic marker interface for stray type references. Every mapping (field types,createoverloads,Registrymethod names) was verified against the real NeoForge 26.1 jar. NeoForge runtime only; transform-tested (ForgeRegistryMigrationTest). - Forge -> NeoForge event-package migration (#85). NeoForge forked Forge's event package wholesale (
net.minecraftforge.eventtonet.neoforged.neoforge.event), keeping most class names. Retromod now class-redirects 308 cleanly-renamed event classes (coreevent/**andclient/event/**, top-level and inner), generated by diffing the real Forge 1.20.1 and NeoForge 26.1 jars and shipped as theforge-event-renames.jsondata table. The handful NeoForge genuinely renamed or merged (EntityJoinWorldEventtoEntityJoinLevelEvent,LivingHurtEventtoLivingDamageEvent,world/*tolevel/*, and so on) stay hand-mapped and take precedence over the bulk table. Events that were reshaped rather than renamed (the TickEvent phase to Pre/Post redesign, the capability system) are out of scope: a class redirect can't rewrite a changed handler body. NeoForge runtime only; transform-tested (ForgeEventMigrationTest). - Forge -> NeoForge
DistExecutor+Distmarkers (#85).DistExecutor(the client/server-split helper,DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> clientOnly())) was deleted in the Forge -> NeoForge split, so there is no class to redirect to. Retromod now supplies it as a per-mod-embedded synthetic that reimplements all ninerun/call/forDistmethods (plus thesafe*variants' serializable SAMs) by delegating toFMLEnvironment.getDist(). TheDistenum itself is package-renamed (net.minecraftforge.api.distmarker.Dist->net.neoforged.api.distmarker.Dist) and@OnlyInmapped to a no-op, both wired into the migration shim so they apply on the NeoForge runtime path (the equivalentAnnotationPolyfillredirects only run on Fabric and the CLI). NeoForge runtime only; transform-tested (ForgeNeoForgeSyntheticsTest). - Forge -> NeoForge FML lifecycle migration (#85). Every
@Modruns its setup through FML, which NeoForge package-renamed fromnet.minecraftforge.fml.*tonet.neoforged.fml.*. Retromod now class-redirects the 20 mod-facing FML classes NeoForge kept under the same name: the lifecycle and config events (FMLCommonSetupEvent,FMLClientSetupEvent,FMLConstructModEvent,FMLDedicatedServerSetupEvent,FMLLoadCompleteEvent,InterModEnqueueEvent/InterModProcessEvent,ModConfigEventand its inners) plusIExtensionPoint,InterModComms,ModList, andModContainer. The table (forge-fml-renames.json) was generated from the NeoForge loader jar (every target verified present) and excludes the FML classes already handled (ModLoadingContext/FMLPaths/@Modin the migration shim, theFMLJavaModLoadingContextsynthetic). This closes the gap the event migration left: it coveredevent/**but notfml/event/**, where the setup events that every Forge mod subscribes to actually live. NeoForge runtime only; transform-tested (ForgeEventMigrationTest).
Fixed
- Retromod's
mods/Retromod/locator crashed NeoForge 1.21.x servers at boot (#100). The locator (the #78 mods-subfolder feature) calledILaunchContext.gameDirectory(), which only exists on NeoForge loader 11.x (MC 26.x); on loader 4.x (MC 1.21.x) that method is absent, so the call threwNoSuchMethodErrorduring mod discovery and crashed the server before any mod loaded. The game directory is now resolved version-safely (reflectively off the launch context where the method exists, otherwiseFMLPaths.GAMEDIR, the same route the Forge locator and in-game screen already use), so Retromod itself loads on 1.21.x again. Verified against the real NeoForge 21.1.x and 26.x loader jars; regression-tested (RetromodModLocatorTestasserts no directgameDirectory()call survives in the compiled locator). - The NeoForge in-place runtime transform applied no polyfills (now it does, safely).
PolyfillRegistry.loadAndRegisterran only on the Fabric entry, so a NeoForge user transforming mods at runtime silently missed everyPolyfillProvider: the Forge -> NeoForgeDist/@OnlyInredirects (theAnnotationPolyfillones, distinct from the hand-wired migration-shim copy added earlier this snapshot), the removed-vanilla-class bridges, and the third-party API bridges (GeckoLib 3->4, JEI, EMI, ...).RetromodNeoForgenow loads them, mirroring the Fabric entry. The 36 providers were re-audited for a Mojang-named runtime, where CLAUDE.md #17 inverts (Mojang-keyed redirects that are dead against intermediary Fabric mods are LIVE against NeoForge mods): intermediary (class_XXXX) and old-MCP/Yarn-named redirects no-op, the Forge -> NeoForge migration applies, and the version-specific removed-class providers (DirectionProperty,LazyLoadedValue, theRenderTypeaccessors, theItemStackNBT methods) now self-gate onRetromodVersion.TARGET_MC_VERSIONso they only fire where the class is actually gone, not on a pre-removal host. Theneoforge-category transfer polyfills stay disabled on this path: the host-gatedNeoForge_1_21_8_to_1_21_9shim already owns the 1.21.9 transfer-API rework, so running both would conflict and the un-gated polyfill wouldNoClassDefFoundErroron a pre-1.21.9 host. NeoForge runtime; transform-tested (RetromodNeoForgePolyfillTest, plus host-gating inBlockPropertyPolyfillTest). - OptiFine-compat hardening. Closed several hangs in the OptiFine compatibility path: infinite wait-loops in the compatibility dialog (and its broken cancel path) and in five config parsers, an AOT-prompt dialog that could hang, and a hardcoded version reference.
Notes
- This is the registry + event slice of the Forge -> NeoForge migration. The Forge-host branch (a Forge 26.x runtime, which needs a Forge 26.x jar to verify against) and the deeper API redesigns remain follow-ups; see CLAUDE.md #13.

