Skip to content

Legacy 1.4.7 Estimate

github-actions[bot] edited this page Nov 8, 2026 · 9 revisions

Estimate: legacy 1.4.7 Forge mods on NeoForge 1.21.1

Written 2026-11-06 after the M0 work (corpus, scanner, tables, loader groundwork). Measured numbers are in Legacy-1.4.7-Corpus; the model is the 1.6.4 one (Legacy-1.6.4-Estimate), with 1.5.2 as the version in between. Back to Home, plan in Version-Roadmap.

Short answer

About 1.5 to 2.5 days of wall-clock time after the 1.5.2 layer loads (the roadmap said 0.5 to 1 day), 3 to 5 agents in parallel, plus or minus 50%. The delta over 1.5.2 is mostly three things the roadmap did not count: sprite-sheet textures (1.4.7 has no Icon), the ModLoader BaseMod emulation (27% of the corpus touches it) and the notch-name dependence (96% of the jars are obfuscated). Everything else (numeric ids, @NetworkMod, tick handlers, player trackers, Packet250CustomPayload) is the 1.6.4 work and is shared. M0 took about 2 hours.

What differs between 1.4.7 and 1.5.2

Area 1.4.7 Work
Names in the jars notch (obfuscated) names in 96% of the jars (yc, members a, b); the dev sources used flat net.minecraft.src.<Name> (MCP 6.x), the last Forge builds (6.6.2.5xx) already the packaged MCP 7 names, and 20% of the jars mix notch with packaged descriptors Done in M0: legacy/1.4.7/notch.txt (notch to flat MCP/SRG names, from the client jar and joined.srg), forward/1.4.7/flat-names.tsv (1,339 flat classes to their 1.5.2 packages), ForwardRenames.flat, the member lookups walk the flat hierarchy and compare packaged table keys. Open: NotchNames misses about 5% of member references (mod overrides called through a vanilla owner), closed in M1
Version detection no class-name markers: 1.4.7 shares @PreInit/ISidedInventory/ForgeSubscribe with 1.5.2 and 1.6.4 Done: a per-version fingerprint of the obfuscated member references (right version 90 to 100%, wrong ones 0 to 50%), 1.4.7-only FML classes, flat names, declared version, file name; the existing 1.5.2/1.6.4/1.7.10/1.12.2 detection is unchanged (checked on 162 jars)
Packaging .zip is 34% of the mods, ModLoader mods have no @Mod and no mcmod.info Done: mods/1.4.7/ folder (zips accepted there), BaseMod subclasses become mod declarations (LegacyModDecl.modLoader)
Textures integer indices into sprite sheets; see below the largest new item, 1 to 1.5 days
ModLoader BaseMod, ModLoader.registerBlock/addName/addRecipe/addShapedRecipe/registerEntityID/addOverride/getUniqueSpriteIndex/registerTileEntity, MLProp, IBlockRender... as default-package classes of a reobfuscated jar hand-written shim (about 600 to 900 lines; FML's ModLoaderModContainer semantics: load(), modsLoaded(), addRenderer, takenFromCrafting...), 3 to 4 hours
Lifecycle @PreInit/@Init/@PostInit in 81% of the jars (no @EventHandler) shared with 1.5.2
Numeric ids, network, ticks, trackers as 1.6.4 (51 of 65 jars use ids; 43 @NetworkMod; 27 tick handlers) shared with 1.6.4/1.5.2: this is their M1/M2
Liquids net.minecraftforge.liquids.* (LiquidStack(itemID, amount, meta), ITankContainer, LiquidContainerRegistry) in 13 jars (20%) adapter onto fluids (FluidStack, IFluidHandler, capabilities); also used by the 1.5.2 and 1.6.x mods, so it pays three times; 3 to 5 hours
Small deltas RenderEngine (37 jars), AABBPool/Vec3Pool (20/12), ISidedInventory (Forge's own, 18), IArmorTextureProvider (8), SoundPool (7), TexturePackList/ITexturePack (8/7), IClassTransformer coremods (10), StepSound... RenderEngine and the pools are 1.5.2/1.6.4 items; ISidedInventory and the armor provider are a capability adapter and a texture hook; sounds need a SoundPool facade
Jar-mod style Better Than Wolves (and its add-ons) replace vanilla classes out of scope, as in every version

Sprite sheets

The 1.5.2 layer already has to turn string texture paths into ResourceLocations (the RenderEngine.bindTexture(String) family, 37 of 65 jars here), and 1.6.4 has Icons that the shim maps onto IIcon. 1.4.7 needs both of those plus index-based textures. What the measurements say about size (corpus): 41 of 65 jars (63%) use Forge's per-block texture file, 22 (33%) set blockIndexInTexture/iconIndex/setIconIndex by hand, 19 (29%) name the vanilla sheets terrain.png/gui/items.png, 42 reference at least one 256x256 sheet (255 sheets in total, 248 of them 256x256 with a 16-pixel grid), only 3 register animated textures.

Design (all native, no side channels):

  1. A sheet registry in the loader's asset step. For each sheet PNG a mod ships (found by the string constants and setTextureFile/preloadTexture arguments, the same scan this corpus uses; the 256x256 grid is assumed), the pack generator cuts the 256 tiles lazily and writes them as individual sprites legacy147/<mod>/<sheet>/<index> into the generated resource pack, so the vanilla atlas stitches them like any other texture (animations: one .png.mcmeta per tile where a TextureFX updates it, a later item). Cutting only the indices the code can reach would need data-flow analysis; cutting the full 16x16 grid is cheap (a few hundred 16x16 sprites per sheet), and empty (fully transparent) tiles are skipped.
  2. Index to IIcon in the shim. Block.blockIndexInTexture, Block.getBlockTextureFromSideAndMetadata, Item.iconIndex, Item.getIconFromDamage return ints; the shim's getIcon(side, meta) wraps them: (textureFile(), index) to the registered sprite. textureFile() defaults to /terrain.png or /gui/items.png, setTextureFile and ITextureProvider.getTextureFile() override it. Mods that override the int methods keep working; mods that override getIcon do not exist in this era.
  3. The vanilla sheets. Indices into terrain.png and gui/items.png that a mod uses (copying the look of stone, planks, iron ingots) need a 256-entry table index to 1.21 sprite name each (about 500 entries, data; derived from the 1.4.7 TextureMap layout, a few hours). ModLoader.addOverride("/terrain.png", file) and getUniqueSpriteIndex allocate free slots in the vanilla sheets: the registry hands out virtual indices above 255 and maps them to the override file.
  4. Whole-image textures (mobs, GUIs, armor, tile entity renderers: bindTexture("/mods/x/gui.png"), "/gfx/..." paths) go through the 1.5.2 string-path resolver; 1.4.7 only adds the leading-slash resource roots (/gfx/<mod>/, /mods/<mod>/, /mob/, /armor/) and the rule that a mod's file shadows vanilla's of the same path.
  5. Renderers. ISimpleBlockRenderingHandler and tile entity renderers bind sheets and read Tessellator.setColorOpaque/addVertexWithUV with UVs computed from the index ((index % 16) / 16.0): those UVs need the sheet layout of the original sheet, not the atlas. The 1.7.10 shim already rewrites UV math for IIcon; for index-based code the cheap route is to keep the bound sheet as its own texture for tessellator-based rendering (the whole PNG bound to a single texture unit, as FML did) while block/item models use the cut sprites. That is a second path to maintain; 4 to 6 hours.

Total: about 1 to 1.5 days with two agents (the cutter and the index shim; the vanilla index table; the renderer path), most of it after 1.5.2's string-path work is in. This is the main risk: if tessellator-based renderers (BuildCraft pipes, Forestry, RedPower, 20 to 30% of the corpus) need the second path in full, add half a day.

Milestones (after the 1.5.2 layer boots, wall-clock)

Milestone Content State and estimate
M0 Corpus (65 files), scan_147.py, legacy/1.4.7 tables, LegacyVersion.V1_4_7 (forward chain 1.4.7 to 1.5.2 to 1.6.4 to 1.7.10), flat-name relocation, notch-fingerprint detection, mods/1.4.7 + zips, runtime family mapping done (this page's date); 64 of 65 jars detect and translate in checkLegacyMod
M1 Close the notch lookup gap (5%), member forwards for what the 1.4.7 jars call (4,320 synthesized members over 64 jars: the id family, registerBlock, Item.setItemName...), BaseMod/ModLoader emulation, liquids adapter, load without sprite sheets (blocks and items register with a placeholder) 4 to 6 hours; the server test boots the corpus subset
M2 Sprite-sheet registry + index shim + vanilla index table, string-path textures, ISidedInventory/armor provider hooks, entities and world generation as in 1.5.2 1 to 1.5 days; first mods rendering
M3 Client verification (BuildCraft pipes, RedPower, Forestry bees, Twilight Forest, Mystcraft), sounds, GUIs 0.5 to 1 day, in parallel with M2

So 1.4.7 is playable-tier roughly 1.5 to 2.5 days after 1.5.2; with the 1.6.4 and 1.5.2 estimates the 0.4.0 milestone stays at 4 to 5 days (the roadmap said 3 to 4, range 2 to 5; sprite sheets and ModLoader move it to the upper half).

What blocks M1

  • The 1.5.2 forward tables (forward/1.5.2/*: EntityLiving/EntityLivingBase, the 1.5.2 to 1.6.4 class and member deltas, string-path textures) are not written yet; 1.4.7 currently falls back to the 1.6.4 tables only, which is what the synthesized-member numbers measure.
  • BaseMod/ModLoader does not exist in the shim: the inspector finds ModLoader mods, but they would be linked against empty synthesized classes (6 pure ModLoader jars of 65, 18 using the ModLoader class).
  • Sprite sheets (above) for anything that renders; until then blocks and items would have no textures.
  • The 5% of unresolved notch members (TileEntity.a...), best fixed in NotchNames by resolving overrides through the jar's own class hierarchy for 1.4.7 as well.
  • The missing corpus core: IC2, Railcraft, Thermal Expansion, Thaumcraft 3, EE, Natura, Tinkers' Construct, Mo' Creatures, Biomes O' Plenty are not obtainable (no 1.4.7 file reachable). Hexxit/Tekkit-style content (the tech trio plus Thaumcraft) cannot be tested; BuildCraft 3.4, Forestry 2, RedPower 2, Applied Energistics and Twilight Forest are the substitutes.
  • No game run was done in M0 (no instances were started): everything above is offline link/translation evidence, not runtime evidence.
  • Coremods: IClassTransformer-style plugins (CodeChickenCore and 9 more jars here) depend on the coremod API work done in parallel for 1.6.4/1.5.2.

Risks and cost drivers

  • Value: 1.4.7 has the smallest pool of the three old numeric-id versions (about 175 to 410 mods, see the roadmap evidence) and many of its mods have 1.5.2/1.6.4/1.7.10 versions; what exists only here is mostly the Hexxit/Tekkit Lite/Feed The Beast Classic-era tech mods and ModLoader mods. Kept because it is a cheap delta and because the notch-name and sprite-sheet machinery is what 1.2.5 (the next ModLoader-era target) needs too.
  • Sprite sheets and tessellator UVs are the one place where this version can be much more work than the rest (see the 4 to 6 hour renderer path above).
  • Detection of tiny jars (a few hundred bytes, no obfuscated member references) relies on declared versions and the file name; one corpus jar (hopper-1.0.jar) is still not recognised.
  • Shared maintenance: ForwardRenames.flat is the only 1.4.7-specific hook in the shared remapper path; everything else is data or reuses the 1.6.4 classes.

Status 2026-11-07 (M1 done, M2 started)

Server loads of the corpus in batches (./gradlew runServerSubTest, mods in run-subtest/mods/1.4.7) and one client session (Applied Energistics rv9 and RedPower 2, with Sodium, Iris and shaders):

  • Loads and runs (no mod failed): ModLoader mods (mod_SprintKey, mod_Gibbing, Entity Detector, CCTV), Hats, Portal Gun, Gravity Gun, Dragon Mounts, More Swords, Grimoire of Gaia (48 mobs alive), Resource Engineering, BiblioCraft, Custom NPCs, CameraCraft, Extra Buttons, RedPower 2 (all ten modules), Applied Energistics, Mystcraft, Factorization, ComputerCraft, MiscPeripherals, BuildCraft, Forestry, Twilight Forest (dimension generates). Per-mod ratings are in docs/data/mods.json (source "client").
  • Sprite sheets work for the main sheets: tiles are cut by SheetCutter, a sheet that code names without its folder (GfxPath("block.png")) is found by file name, and an index-based block or item now wins over the icon a default registerIcons would register (that placeholder hid every index texture of the item sheet). AE's quartz tools and ore draw correctly in the client.
  • Fixed this round: a default-package mod class (ModLoader mod_X) kept two private roots; items a numeric-id mod never registers are registered (More Swords); constructor adaptation casts narrowed parameters instead of passing null (AI task owners: every Grimoire mob failed to tick); notch member lookup through packaged Forge interfaces (ISidedInventory implementors kept notch method names); one synthesized name per class (flat and packaged TextureFX were two classes, a VerifyError for RedPower's animated textures); BiomeCacheBlock (Twilight Forest chunk generation); the home area on EntityLiving (ghasts).
  • Open: RedPower's own sheets (worlditems1.png, base1.png) are cut but its items name tiles through a path the layer does not read yet (iconIndex stays -1), tessellator renderers (RedPower multipart, AE cables) are untested, texture animations (TextureFXManager) link but do nothing, the liquids API adapter is not written, @PreInit/@Init/@PostInit work (every mod above uses them), Mystcraft's age dimensions, Forestry/Binnie's duplicate genetics API classes, Immibis' mods need IC2/ComputerCraft present.
  • What blocks "supported": the open items above plus client verification of GUIs for more than one mod; the corpus has no IC2, Railcraft, Thermal Expansion or Thaumcraft 3.

Status 2026-11-07 (evening: RedPower renders)

Verified in a real client (Sodium, Iris, Complementary shaders; RedPower 2 all modules in the Core/Digital/Mechanical/Compat zips, Applied Energistics rv9, BuildCraft, ComputerCraft, MiscPeripherals, Entity Detector, CCTV, Old Vein Miner, Block Helper, Hopper, rpcDrive); screenshots in docs/screenshots/old-versions/1.4.7.

  • Item textures of RedPower: the cause was not an unread path. RedPower's tools call Item.setIconCoord(column, row), which the shim lacked (a synthesized no-op), so iconIndex stayed -1; ItemParts-style items (getIconFromDamage(int) overrides) already worked through the bridge. setIconCoord is now a real method; all RedPower items draw.
  • Tessellator and multipart renderers: three defects hid every RedPower block drawn by its own handler. RenderBlocks.overrideBlockTexture is an int (-1 = none) in 1.4.7 and an IIcon in 1.7.10, so the mod's first check (>= 0, draw nothing) always passed; reads of it now go through mcc$overrideIndex() (member-manual G rule). A handler that binds a sprite sheet per part while the Tessellator is drawing (Forge 1.4.7 drew the pending vertices with the old texture before binding) now flushes on bindTexture(String) while a block is captured, and each captured quad remembers the sheet it was drawn under; IsbrhQuads maps its tile-position UVs to the cut tiles of the atlas (vanilla /terrain.png goes through the 256-entry table). ISimpleBlockRenderingHandler.shouldRender3DInInventory() lost its argument in 1.7 (bridge rule added, 1.6.4 table, so it also helps 1.6.4 handlers): block items now show their 3D icons.
  • GUIs: images are bound by getTexture(path) ids; the id is mapped back to the location (the draw code names textures through the render context), so the alloy furnace and deployer GUIs draw. Container slots and clicks sync (items moved into both machines).
  • Other generic fixes: boolean isProvidingWeakPower/StrongPower bridge (1.4.7 returned a boolean), Block.getBlockTextureFromSideAndMetadata, isDefaultTexture, getBlockBrightness, vanilla blocks' /terrain.png index for covers, EntityPickupFX (ComputerCraft's turtle client failed verification), EntityLivingBase.getDropItemId (reflection by name), dirty marks from the server thread no longer assert in Sodium, Synth.dispatch survives a tile class that mentions an absent optional API (a MiscPeripherals tile crashed the world tick on IC2's ic2.api.Direction), and the sheet cutter also cuts a mod's own 256x256 blocks.png/items.png by name (BuildCraft builds those paths at run time).
  • Liquids: net.minecraftforge.liquids resolves to the 1.6.4 shim (fluid capability adapter) through the forward chain; BuildCraft 3.4.6 links; not exercised at run time.
  • Still open: texture animations (TextureFXManager: RedPower's TextureAnimFX, water/lava tiles of mods) link but do nothing; AE cables placed through the item path and AE GUIs were not tried; survival use of wires and gates (power, logic) and RedPower world generation untried; the RedPower Mining module is not in the corpus; Forestry/Binnie duplicate genetics API; Better Than Wolves is a modified-game jar mod (see below).
  • What blocks "supported": animations, a survival session of the RedPower flagship (wire, gate, machine chains; ore generation), GUIs of AE, (the BuildCraft block sheets are cut now and draw). Rating: RedPower works, Entity Detector works, BuildCraft works, AE partial, ComputerCraft partial, CCTV and MiscPeripherals loads.
  • Better Than Wolves 4.65b (old-only, a modified-game jar mod): the loader translates it (475 classes, 253 synthesized API classes for the vanilla classes it replaces, 3 unresolved references) and discovers mod_FCBetterThanWolves, but construction fails with ClassNotFoundException: mod_FCBetterThanWolves. It replaces vanilla classes (mobs, blocks, world generation) rather than adding to them, which the shim cannot express; it would need the vanilla-class-replacement semantics of a patched minecraft.jar (the replaced classes loaded in place of the game's) or a rewrite of its changes as hooks. Not near working; no time spent beyond this check.

Status 2026-11-07 (night: animations, survival)

  • Texture animations work. TextureFX, FMLTextureFX, ITextureFX and TextureFXManager are now real shim classes (v1_6_4 layer, the forward names of the flat 1.4.7 classes) instead of synthesized stubs; ModLoader.addAnimation, TextureFXManager.addAnimation and RenderEngine.registerTextureFX register into Animations147. Each client tick it calls the mod's onTick(), finds the sheet by letting bindImage run against the shim's engine (it records the path of bindTexture/getTexture), maps (sheet, iconIndex) to the cut sprite through SpriteSheets147 and uploads imageData (RGBA, any tile size, with box-filtered mip levels) into the sprite's place in the block atlas. Needed on the loader side: a jar that has a TextureFX subclass also gets its blank sheet tiles cut (the animation draws into tiles that are empty in the sheet). Verified in the client: RedPower's two TextureAnimFX tiles and BuildCraft's oil/fuel effects upload every tick without errors. Not verified visually: which RedPower block shows the animation, and BuildCraft's oil blocks (they render as a hole; their fluid rendering is a separate gap; still and flowing oil name the same tile because the block never sets blockIndexInTexture, which the layer reads as 0).
  • Minecraft.texturePackList/RenderEngine.texturePack (default pack, files read from the mods' class path): RedPower's animation reads its frames through getSelectedTexturePack().getResourceAsStream(path) and failed in its constructor before.
  • StringTranslate.getCurrentLanguage() returns the language code; BuildCraft chooses its lang/buildcraft/<code>.properties by it, so its GUI titles are translated now.
  • RedPower survival: the alloy furnace GUI shift-click moves into its grid, fuel burns, and red alloy comes out; a vanilla lever powers a RedPower lamp. Open: wire and gate chains, deployer/transposer item movement, ore generation in a normal world, pump and tube transport, the project table crafting; BuildCraft's autocrafting table shows no recipe preview; AE GUIs and cables (terminal, drive, controller) and BuildCraft pipes, engines and liquids; Mystcraft ages; Forestry/Extra Bees genetics duplicate; the final corpus load check.
  • Still blocks "supported": the open items of the previous bullet (a survival session of the flagship mods beyond the alloy furnace and lamp, AE and BuildCraft use, a corpus-wide load run with results in docs/data/mods.json).

Status 2026-11-07 (late night: survival round, real client with shaders)

Real client (NeoForge 1.21.1, Sodium, Iris, Complementary shaders), survival actions through the item path (items placed and used like a player does; gives by command only):

  • RedPower 2 works in survival. Logic: a lever on the side of a block next to a red alloy wire, a NOT gate and a lamp: the wire carries the signal (power 255 falling by one per block), the gate inverts, the lamp goes dark and lit again. Machines: the transposer moves items from a chest on its back over two pneumatic tubes into a second chest on a redstone pulse; the deployer places blocks from its inventory; the project table crafts (sticks from planks). World generation in a normal world: the eight ores (ruby, emerald, sapphire, silver, tin, copper, tungsten, nikolite) and marble/basalt generate (about 750 ore blocks per chunk of the area scanned, marble about 430); rubber trees were not found in a 14x14 chunk area (untried further). Screenshots in docs/screenshots/old-versions/1.4.7.
  • Causes found this round (all generic):
    • A tessellator renderer that only binds a sheet (RenderLib.bindTexture("/eloraam/wiring/redpower1.png")) never had that sheet cut, so wires drew with a vanilla tile (copper bulb). SheetCutter now also cuts sheets bound inside block/tile renderer classes (names containing Render, not Gui).
    • Redstone: vanilla blocks answered 0 to isProvidingWeakPower/StrongPower (only blocks of the shim had logic), so no legacy mod could read a lever, button or redstone block. The base Block now reads the modern signal for blocks of the game; the 1.4.7 boolean forms (isProvidingStrongPower(...)Z, a call on a receiver whose class lacks the boolean form) are served by the Block facade (legacyconnector/v1_6_4/facade/.../Block); a redirect rule was wrong (it also caught super calls and recursed through the bridge of the mod's own override).
    • CraftingManager.findMatchingRecipe(inv, null): the client's project table builds its grid from a tile without a world, so the vanilla recipes (looked up in the modern recipe manager) never matched and the result slot stayed empty on the client. A null world now falls back to the client level (or the server's overworld).
    • FurnaceRecipes.smelting().getSmeltingResult(itemId) and getExperience(itemId) (1.4.7 id forms) were stubs returning null; now served through the id table. (RedPower's alloy furnace does not smelt vanilla ores: that is RedPower's own recipe set, only the Blulectric furnace uses the vanilla list.)
    • BuildCraft oil: BlockFluid(id, material) gave the tile 205 (water-like) or 237 (lava-like) of the block's own sheet, which BuildCraft's oil animation draws into; the shim's liquid base class has no tile. Fluid blocks of a flat-name version now get the 205/237 index (loader claim hook IdConstructors, Block.mcc$claimFluidTexture) and BlockLiquid.getIcon reads it (sides the next tile). RenderBlocks.renderBlockFluids is renderBlockLiquid in the shim (a forward rule; without it RenderingOil drew nothing and oil was a hole).
    • Scheduling mods (RedPower gates, timers) use World.getWorldTime(); with the game rule doDaylightCycle off (the screenshot test harness default) the day time stands still and gates never fire. Not a layer defect (1.4.7 had no such rule), noted for test setups.
  • BuildCraft: wooden pipe plus wooden engine (powered by a redstone block) pulls items out of a chest and cobblestone pipes carry them to the second chest; the engine finds its receiver on placement (orientation 4 towards the pump) and runs; oil blocks draw (black pool). The pump did not lower its tube into the oil in the time tried (tank empty), so liquid transport is not verified.
  • Applied Energistics rv9: controller, cables, drive and terminal place through the item path; the ME Terminal and ME Drive screens open and draw (title, search field, sort buttons; drive cell slots); cables still draw as dark cubes, and without power the network cannot be used, so crafting through an ME network was not reached.

Same session: Forestry, Mystcraft, corpus load check, ratings

  • Corpus-wide load check (65 files of test-mods-147, fresh cache, config and world, server port 25906, ./gradlew runServerSubTest): every mod loads except Better Than Wolves (patched-game jar) and the two JInput mods (RawInput, XInput: net.java.games.input is not in the game). The two sprint mods are client-only (they touch client classes, so the dedicated server cannot load them; they load in the client). Ratings are in docs/data/mods.json (source "client", 75 mods: 44 works, 28 loads, 6 partial, 5 fails). Note for test sets: default item ids collide when everything is installed at once with a config left over from an earlier set (RedPower's id 768); a fresh config is clean.
  • Forestry and Extra Bees load. Forestry finds its plugins by listing its own jar for forestry/plugins/Plugin*.class; the shared-package merge moved that package (Extra Bees has copies of the Forestry API and plugin classes) into the shared library and Forestry saw no plugin, so no item existed and the genetics API stayed unset (the "Binnie AlleleManager registry null" symptom: not a second copy of the class, a missing registration). For flat-name (1.4.7) jars SplitPackageResolver now keeps a package whose copies are all in such jars in the jar of the mod that owns its root, strips the others, and adds the classes only the others had to the owner's jar. Other versions keep the old behavior. Result: 16 plugins, 330 alleles, 393 Forestry items and 35 blocks. The Forestry screens do not open: this build's GuiForestry extends the class that is GuiScreen in 1.4.7's mapping (the jar was built against another obfuscation), so it is a corpus limitation.
  • Mystcraft loads (a VerifyError on new TextureCompassFX(): the vanilla texture FX classes were synthesized and not TextureFX subclasses; they are shim classes now) and an age can be created and entered; FMLTextureFX.setup() runs at registration like Forge did (running it in the constructor read fields of the subclass that did not exist yet: Forestry's habitat locator).
  • Other generic fixes: ItemFlintAndSteel shim (CustomNPCs failed in init on the synthesized class), the 1.4.7 misspelling EntityAIMoveTwardsRestriction mapped to the real class (four Grimoire of Gaia mobs failed verification), an item that never sets an icon index draws tile 0 (CCTV's monitor), CraftingManager no longer touches client classes from the server (it broke every mod on a dedicated server).
  • Still blocks "supported": ComputerCraft's terminal draws white rows (its FixedWidthFontRenderer compiles the glyph quads into OpenGL display lists with glNewList, built from a font bitmap it uploads itself, so no computer can be used yet), Forestry's screens (corpus build), an Applied Energistics network (power source and cable drawing), the BuildCraft pump (tube did not extend; liquids unverified), rubber trees of RedPower (none found), Better Than Wolves and the JInput mods, the Mystcraft machines (43% of its self-test errors), and the missing corpus core (IC2, Railcraft, Thermal Expansion, Thaumcraft 3). Rating of the version: alpha (RedPower 2, BuildCraft, Entity Detector, CCTV, MiscPeripherals blocks, AE screens work in a real client).

Next session: ComputerCraft terminal, Applied Energistics network, RedPower world generation

  • ComputerCraft works. The white rows were not a display-list problem (compiled lists, colours and Tessellator draws replay correctly). Two generic causes: (1) RenderEngine.allocateAndSetupTexture(BufferedImage), which FixedWidthFontRenderer uses to upload the font sheet, was an unimplemented stub returning 0, so the glyph quads sampled no texture. It is now implemented in the shim TextureManager (nearest filtered, repeating); the mod builds the renderer while mods load (no GL context), so the call returns a handle and the image is uploaded when the id is first bound (glBindTexture or bindTexture(int)). glBindTexture also resolves the handles getTexture(path) returns for textures that are not loaded yet. (2) The computer's ROM (lua/rom) is mounted with ZipFile.getEntry("lua/rom") on the mod's own jar, and the translated jar had no directory entries (Path doesn't exist inside zip file, the computer never booted). LegacyJarTransformer.write now writes the folder entries and SplitPackageResolver keeps them. Checked in a real client with shaders: help, ls, the Lua prompt; a turtle refuels from coal in its slot and moves; a MiscPeripherals block beside a computer is listed as a peripheral.
  • Applied Energistics works. The cable block draws through RenderBlocks.renderBottomFace/TopFace/East/West/North/SouthFace(Block, x, y, z, int tile) (1.4.7 forms taking a tile index of the bound sheet), which were unimplemented stubs, so cables fell back to the generated full cube. They are shim methods now (an icon covering the tile in sheet space while a block is captured, the cut sprite for items). The cable's renderCableAt also calls markBlockForUpdate from the chunk meshing thread, which reached ClientLevel.sendBlockUpdated and threw in Sodium (the whole renderer failed): from another thread the section rebuild is queued and the level notice skipped. A controller powered by an adjacent wooden BuildCraft engine, a drive with a 1k storage cell and a crafting terminal form a working network: 64 cobblestone put into the C-Terminal stay listed. Open: the ME Access Terminal item (multiblock1 meta 6) does not place (the other terminals do), and a light blue square is drawn on the ground under every cable (not a quad of the block's model: the captured quads are the thin box).
  • RedPower world generation. Ores (about 5000 ore and 6000 deepslate-level ore blocks in an area of 129x129 blocks) and marble/basalt generate in a normal world. Rubber trees only generate in jungle biomes (the mod tests BiomeGenBase.jungle and jungleHills, not forests; earlier forest scans found none): a jungle 2.6 km from spawn had 1735 rubber logs and 2071 leaves. The RedPower pump with tubes was not tried; BuildCraft's pump is unchanged.
  • Still blocks "supported": Forestry's screens (corpus build), the BuildCraft pump (liquids unverified), the RedPower pump, Better Than Wolves and the JInput mods, the Mystcraft machines, the AE ground square and Access Terminal, the missing corpus core (IC2, Railcraft, Thermal Expansion, Thaumcraft 3), Old Vein Miner and CCTV picture-in-picture not exercised.

Status for 0.4.0

What "supported" means for 1.4.7 in 0.4.0: the layer loads 1.4.7 mods (Forge and ModLoader), their blocks, items, entities, recipes, GUIs and world generation work in a real NeoForge 1.21.1 client with Sodium, Iris and shaders, for the flagship mods; mods that need the vanilla game jar replaced or hardware libraries are reported as such. It is alpha, not beta: only a handful of mods were played in survival.

Works in a real client (survival): RedPower 2 (wires, gates, machines, tubes, ore and rubber-tree generation), BuildCraft (pipes, engines, pump and tank with liquids, oil), ComputerCraft (terminal, Lua, turtles), Applied Energistics (powered ME network with controller, cables, drive, crafting terminal, ME Access Terminal), Entity Detector, Twilight Forest (server-side), the corpus of 65 files loads.

Done in this round:

  • AE Access Terminal places and opens (it answers "Unable to communicate with controller" without a controller, as in 1.4.7); the earlier "does not place" was not reproduced.
  • The pale square under cables is not geometry: it is not there without shaders, and a 3x3 block of plain vanilla logs placed by /fill showed the same square-and-hole look under the shader pack until the section meshed, so it is a shader-pack and chunk-update artifact of fast block changes, not a layer defect.
  • BuildCraft pump: water is pumped into a tank (1000 mB). Two causes of the earlier failure, neither a layer defect: the harness has doDaylightCycle off (the pump only searches every 100 world ticks of the clock) and the test world's floor is below y=0 (the pump loops for (y = pumpY - 1; y > 0; y--); legacy mods assume y >= 0, so liquids below y=0 are not found).
  • CCTV monitor now places and draws: Direction.vineGrowth (the side-to-direction table) was missing, a hanging entity of a mod was checked with the wrong, square box (always overlapping the wall), EntityHanging.xPosition/yPosition/zPosition were not the shim's fields (the spawn data wrote zeros), and spawn data written with Guava's ByteArrayDataOutput (Forge for 1.6.4 and older) now goes through the old method form (it was an AbstractMethodError; this helps every old mod with a spawn-data entity).
  • Old Vein Miner loads; the key and left-click events arrive (the test harness has a forcekey verb for Keyboard.isKeyDown), but the mod reaches the game only through reflection on method names (World.getBlockId and so on) that the layer offers to compiled code but not to reflection, so no vein is mined. Partial.
  • Mystcraft writing desk screen opens; Entity Detector drives a lamp.
  • Plain failure reports: Better Than Wolves is reported as "does not start: patched-game jar mod", RawInput and XInput as "needs LWJGL joystick libs (JInput)" (log, docs/data/mods.json).

What does not work or is untested: RedPower pump with fluid pipes (needs a Blulectric power chain; untested), CCTV camera feed (monitor shows no camera; the camera block uses a placeholder tile), Forestry screens (the corpus build's GUI base class is another obfuscation), Mystcraft ages beyond creation, texture-pack-dependent items, Better Than Wolves, the JInput mods, and every mod of the missing corpus core (IC2, Railcraft, Thermal Expansion, Thaumcraft 3, Mo' Creatures). Test-world note: liquids and anything that scans downward fail below y=0.

Ground hole under tubes and cables, pipe textures, tube and chest (2026-11-07)

  • The pale-blue square under RedPower tubes and AE cables was a layer defect, not a shader artifact (the earlier "a 3x3 of logs gave the same look" was never reproduced). Test matrix in a real client: it shows with shaders and without, with Sodium alone it is absent, with Sodium plus MoreCulling it appears, with no performance mods it is absent; vanilla blocks placed the same way (hopper, chest, glass pane, slab) never made it. Cause: MoreCulling reads which faces a block covers from the first model of the state, the generated cube the block handler's model wraps (IsbrhBlockModel), so the tube counted as an opaque full cube and the ground's top face was culled (the hole shows the sky). Fix: for blocks drawn by a handler that are not full cubes (IsbrhBlockModel.Open) the two BakedOpacity methods MoreCulling's mixin puts on BakedModelWrapper answer "no culling shape, no quads on any side, translucent" (state setters by reflection, no dependency).
  • BuildCraft pipes drew as flat lilac boxes: the pipe renderer binds the mod's sheet and draws with RenderBlocks.renderStandardBlock, whose icons are atlas sprites, and IsbrhQuads read their atlas UVs as positions in the bound sheet, so each quad landed on an arbitrary tile (an unused lilac one for most). While a sheet is bound and a block is captured the icon of a cut tile is now the same tile in sheet space (RenderBlocks.mcc$inSheet). The face renderers that take a tile index (renderBottomFace(..., tile), used by the pipe item renderer) fall back to the block's own sheet when none is bound. Open: pipe items in the hand and hotbar draw dark (transparent pipe tiles drawn without a cut-out layer); two item pipes next to each other show a gap in one place.
  • RedPower tubes do connect to chests: RedPower's test is getBlockTileEntity(x,y,z) instanceof IInventory; the layer's view of a vanilla chest implements it (TubeLib.getConnections of a tube between two chests returns the west and east bits), and a transposer moved items from one chest through two tubes into the other (1 cobblestone per pulse). The "tube stops short" look was the hole plus the chest model's own 1/16 inset. No change needed.

Stub pass 2026-11-07 (1.4.7 and 1.5.2)

Offline probe over test-mods-147 / test-mods-152: synthesized members 314 -> 288 (1.4.7) and 209 -> 198 (1.5.2), no new stubs, no verify failures. Done: constructor adapters (EntityPlayerMP with a name, EntityAITempt with an item id and float speed, InventoryBasic(name, slots), Property()), call adapters (Forward152: PathNavigate.tryMoveToEntityLiving(entity, float), World.getAllCollidingBoundingBoxes, static BlockPistonBase.determineOrientation, FMLRelaunchLog.getLogger() as a java.util.logging logger), EntityMinecart.minecartType reads getMinecartType(), Block.getBlockTextureFromSide / getBlockTexture(access, x, y, z, side) redirected again through the re-entry guarded Redirects147, WorldGenerator.setBlock(world, x, y, z, id), TileEntitySkull.getExtraType, TileEntityMobSpawner.getMobID, LanguageRegistry.addStringLocalization(Properties), and real shim classes for ILiquid, LiquidEvent, ServerList (reads/writes servers.dat) and ClientBrandRetriever. Still open: Texture/TextureAtlasSprite (1.5.2 sheet textures), GuiConnecting, NEI GuiContainerManager/API.addKeyBind, ItemData, SoundPool.addSound, TextureFXManager.getTextureDimensions, IClassTransformer.transform, map rendering, capes.

Clone this wiki locally