mirror of
https://github.com/GTNewHorizons/ForgeMultipart.git
synced 2026-11-14 01:14:19 +00:00
docs: audit ForgeMultipart downstream consumers
This commit is contained in:
1 parent
fa976c2002
commit
16dd5f3dee
4 files changed
+496
-4
No files matched your search
+1
-1
@@ -467,7 +467,7 @@ These ranges were formed before designing the characterization suite and should
|
||||
- Replaced `TPartialOcclusion.scala` with Java implementations of `PartialOcclusionTest` and `JPartialOcclusion`. The interface keeps its name and method descriptors, while `allowCompleteOcclusion()` is now a Java default method and the deprecated `$class` helper remains for old Scala binaries.
|
||||
- Passed all ten partial-occlusion behavior/API cases, the frozen Scala binary consumer, all 27 plain-JVM tests, a clean build, and both Java 8 Forge server checks. The existing marker-interface registration remains unchanged and continues to drive runtime tile generation.
|
||||
- Completed the downstream ABI inventory by constant-pool scan of 240 mod jars in GTNH daily `2026-08-14+678`, recorded in `JAVA_MIGRATION_ABI_INVENTORY.md` with the scanner in `tools/AbiScan.java` and the frozen baseline in `src/test/fixtures/abi/`. GitHub code search was rejected as an oracle because it indexes default branches only and cannot see reflection strings or closed-source consumers.
|
||||
- Found 28 consumer jars referencing 35 inherited types, 255 exact member descriptors, 76 other types, and 20 reflective string constants.
|
||||
- Found 27 consumer jars referencing 35 inherited types, 255 exact member descriptors, 76 other types, and 20 reflective string constants.
|
||||
- Answered open decision 2: third-party Scala traits are registered externally. ProjRed passes its own `LightMicroblock` Scala trait to `MicroblockGenerator.registerTrait`, so `registerScalaTrait` and ScalaSignature decoding must survive Phase 7.
|
||||
- Answered open decision 4: Scala runtime removal is not achievable for the first Java release. ProjRed, OpenComputers, ProjectBlue, and ForgeRelocationFMP link against 16 static methods on 8 trait `$class` helpers plus 17 companion `MODULE$` singletons.
|
||||
- Found only five referenced descriptors containing Scala types, and `TileMultipart.jPartList()` already outweighs `partList()` in downstream use. The Scala bridge surface is much smaller than the initial audit assumed.
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# Downstream ABI inventory
|
||||
|
||||
For runtime behavior, data formats, lifecycle use, and member-level reflection found in consumer source, see
|
||||
[`JAVA_MIGRATION_CONSUMER_AUDIT.md`](JAVA_MIGRATION_CONSUMER_AUDIT.md).
|
||||
|
||||
Completes the Phase 0 item "Inventory downstream mods that compile against or reflect into ForgeMultipart".
|
||||
|
||||
Method: constant-pool scan of every mod jar in a real pack, not a source search. Bytecode is the only oracle that
|
||||
@@ -20,7 +23,7 @@ any member that disappears from the port but appears in the baseline is a linkag
|
||||
|
||||
| Category | Count |
|
||||
| --- | ---: |
|
||||
| Consumer jars | 28 of 240 |
|
||||
| Consumer jars | 27 of 240 |
|
||||
| Types extended or implemented downstream | 35 |
|
||||
| Referenced members with exact descriptors | 255 |
|
||||
| Other referenced types | 76 |
|
||||
@@ -57,7 +60,7 @@ Two distinct consumer shapes:
|
||||
|
||||
### 1. Which existing downstream binaries must keep working without recompilation?
|
||||
|
||||
The 28 jars above. The compatibility budget is dominated by four: ProjRed, extrautilities, OpenComputers, ProjectBlue.
|
||||
The 27 jars above. The compatibility budget is dominated by four: ProjRed, extrautilities, OpenComputers, ProjectBlue.
|
||||
ProjRed alone accounts for 141 of the touching classes and is the only consumer exercising the trait-generation path.
|
||||
|
||||
### 2. Are third-party Scala traits registered through `registerScalaTrait`?
|
||||
|
||||
@@ -0,0 +1,489 @@
|
||||
# Source-level downstream consumer audit
|
||||
|
||||
Status: 2026-08-27. This is the source-level companion to
|
||||
[`JAVA_MIGRATION_ABI_INVENTORY.md`](JAVA_MIGRATION_ABI_INVENTORY.md).
|
||||
|
||||
The ABI inventory answers "what must still link?" This audit answers the harder question: "what behavior do real
|
||||
consumers expect after they have linked?" It covers all 27 ForgeMultipart consumers in the supplied GTNH daily
|
||||
`2026-08-25+700` instance, plus UtilitiesInExcess as the planned Extra Utilities replacement.
|
||||
|
||||
## Bottom line
|
||||
|
||||
The Java conversion cannot be treated as a set of independent class translations. Downstream code depends on five
|
||||
connected contracts:
|
||||
|
||||
1. **The generated composite tile architecture.** Parts cause `TileMultipart` subclasses to acquire Scala traits,
|
||||
Java traits, and arbitrary pass-through interfaces. AE2, ProjectRed, Extra Utilities, WR-CBE,
|
||||
WitchingGadgets, ForgeRelocationFMP, and UtilitiesInExcess all exercise this architecture.
|
||||
2. **Scala-emitted binary shapes.** ProjectRed, OpenComputers, ProjectBlue, and ForgeRelocationFMP call generated
|
||||
trait `$class` helpers and companion `MODULE$` objects. Java consumers also use Scala-shaped APIs such as
|
||||
`partList(): scala.collection.Seq` and `getIdMap(): scala.Tuple2[]`.
|
||||
3. **Multipart state and lifecycle.** Consumers do more than add parts. They inspect `partMap`, mutate/rebuild slot
|
||||
maps, move the live tile object, call `onMoved`, remove and reload parts, trigger part/tile notifications, and
|
||||
make deliberate choices about description packets.
|
||||
4. **World, NBT, and packet formats.** The container `parts` list, each part's `id`, core microblock fields and part
|
||||
type strings are an interchange format used by builders, schematic tools, movers, HUD mods, and save/load code.
|
||||
Material numeric IDs and their packet encoding are also shared outside FMP.
|
||||
5. **Names that are not in ordinary linkage.** Schematica reaches a private Scala-mangled field, Et Futurum mutates
|
||||
static arrays, GuideNH mixes into private fields, Iguana reflects a saw field, and several mods load FMP classes
|
||||
and companions by string. A clean ABI diff alone will miss these breaks.
|
||||
|
||||
The safest first Java release is therefore **Java-maintainable implementation with the bounded Scala compatibility
|
||||
shell retained**. Removing the Scala runtime is a separate coordinated migration, not the end of this source port.
|
||||
|
||||
## Coverage and method
|
||||
|
||||
The supplied instance was rescanned with `tools/AbiScan.java` before reading source:
|
||||
|
||||
- scanner visited 241 mod JARs, one of which was excluded as ForgeMultipart itself;
|
||||
- 27 consumer JARs;
|
||||
- 35 downstream-extended or implemented FMP types;
|
||||
- 255 referenced FMP members with exact descriptors;
|
||||
- 76 other referenced FMP types;
|
||||
- 20 class-name/reflection strings.
|
||||
|
||||
Those structural totals are unchanged from the frozen `+678` inventory. The consumer versions changed, but no new
|
||||
binary API family appeared. The source audit then searched every clone and the Extra Utilities jar for direct
|
||||
imports, fully qualified names, reflection strings, factories, converters, part subclasses, tile access, registry
|
||||
access, NBT, packet, rendering, occlusion, redstone, and movement paths. Important call sites were traced through the
|
||||
owning code instead of counting imports.
|
||||
|
||||
This gives full coverage of the current pack's known source and binary consumers. It does not claim that an arbitrary
|
||||
future mod, a runtime-generated script, or an unpublished patched JAR cannot contain another reflective use. The ABI
|
||||
scanner should remain a release gate for exactly that reason.
|
||||
|
||||
### Source provenance
|
||||
|
||||
| Installed consumer | Source used | Match to installed code |
|
||||
| --- | --- |-----------------------------------------------------------|
|
||||
| ProjRed `4.12.43-GTNH` | `ProjectRed` at `4.12.43-GTNH` (`e173952e96a4`) | Exact |
|
||||
| Extra Utilities `1.2.12` | `extrautilities-1.2.12` | Exacted JAR; not original source |
|
||||
| OpenComputers `1.12.56-GTNH` | `OpenComputers`; installed tag plus HEAD `1.12.57-GTNH` | FMP files unchanged after installed tag |
|
||||
| ProjectBlue `1.2.10-GTNH` | `ProjectBlue` at `1.2.10-GTNH` (`c01a5e769643`) | Exact |
|
||||
| AE2 `rv3-beta-1041-GTNH` | `Applied-Energistics-2-Unofficial`; installed tag plus HEAD `1042` | FMP files unchanged after installed tag |
|
||||
| BuildCraftCompat `7.1.22` | `BuildCraftCompat` at `7.1.22` (`79e02803be32`) | Exact |
|
||||
| ForgeRelocationFMP `0.2.0` | `ForgeRelocationFMP` at `0.2.0` (`49a810b8c63b`) | Exact; installed JAR also disassembled as a cross-check |
|
||||
| Galacticraft `3.4.33-GTNH` | `Galacticraft` at `3.4.33-GTNH` (`26a472f9c7ae`) | Exact |
|
||||
| ThaumicTinkerer `2.12.30` | `ThaumicTinkerer` at `2.12.30` (`18c787153c96`) | Exact |
|
||||
| WR-CBE `1.7.12` | `WirelessRedstone-CBE` at `1.7.12` (`9dfb913b4880`) | Exact |
|
||||
| Chisel `2.17.32-GTNH` | `Chisel` at `2.17.32-GTNH` (`ff70c8b2e3cd`) | Exact |
|
||||
| IguanaTweaksTConstruct `2.7.12` | `IguanaTweaksTConstruct` at `2.7.12` (`2bc09889d3e2`) | Exact |
|
||||
| WitchingGadgets `1.8.50-GTNH` | `WitchingGadgets` at `1.8.50-GTNH` (`f82988693af3`) | Exact |
|
||||
| GuideNH `1.3.22` | `GuideNH` at `1.3.22` (`7d8fb44e77b9`) | Exact |
|
||||
| BloodArsenal `1.5.12` | `BloodArsenal` at `1.5.12` (`890824be106a`) | Exact |
|
||||
| Botania `1.13.33-GTNH` | `Botania`; installed tag plus HEAD `1.13.34-GTNH` | FMP files unchanged after installed tag |
|
||||
| Waila `1.19.34` | `waila` at `1.19.34` (`f998f9ebfe09`) | Exact |
|
||||
| MatterManipulator `0.1.54-GTNH` | `MatterManipulator` at `0.1.54-GTNH` (`897ffbf17a02`) | Exact |
|
||||
| Biomes O' Plenty `2.1.0.2308` | `BiomesOPlenty`, branch `BOP-1.7.10-2.1.x` | No exact tag; historical source plus exact binary surface |
|
||||
| BloodMagic `1.9.13` | `BloodMagic` at `1.9.13` (`6776676ef209`) | Exact |
|
||||
| Natura `2.8.24` | `Natura` at `2.8.24` (`4f88c0665928`) | Exact |
|
||||
| Schematica `1.12.6-GTNH` | `Schematica` at `1.12.6-GTNH` (`3b03ee937953`) | Exact |
|
||||
| TConstruct `1.14.103-GTNH` | `TinkersConstruct`; installed tag plus HEAD `1.14.104-GTNH` | FMP file unchanged after installed tag |
|
||||
| AE2 Fluid Craft `1.5.105-gtnh` | `AE2FluidCraft-Rework` at `1.5.105-gtnh` (`1706b5a8daf2`) | Exact |
|
||||
| EnderCore `0.5.14` | `EnderCore` at `0.5.14` (`075609240fa7`) | Exact |
|
||||
| Et Futurum Requiem `2.6.56-GTNH` | `Et-Futurum-Requiem`; installed tag plus HEAD `2.6.57-GTNH` | FMP file unchanged after installed tag |
|
||||
| GT5U `5.09.54.108` | `GT5-Unofficial`; installed tag plus HEAD after `5.09.54.112` | FMP file unchanged after installed tag |
|
||||
| Future: UtilitiesInExcess | `UtilitiesInExcess` HEAD `3e107a1fe9bc` | Not installed; audited as forward compatibility scope |
|
||||
|
||||
`ForgeRelocation` itself is not the source of `ForgeRelocationFMP`; both repositories are needed and both are now
|
||||
present. Only the plugin is one of the 27 FMP consumers.
|
||||
|
||||
## Cross-cutting compatibility map
|
||||
|
||||
| Contract | Consumers that make it load-bearing | What must survive |
|
||||
| --- | --- | --- |
|
||||
| Part factory/converter registration | ProjectRed, Extra Utilities, OpenComputers, AE2, BuildCraftCompat, ForgeRelocationFMP, Chisel, ThaumicTinkerer, WR-CBE, WitchingGadgets, ProjectBlue, UtilitiesInExcess | Java `IPartFactory`/`IPartFactory2`, converters, the Scala `Function2` and `Seq` overloads, stable type strings, client/server construction |
|
||||
| Dynamic composite tiles | ProjectRed, Extra Utilities, AE2, ForgeRelocationFMP, WR-CBE, WitchingGadgets, UtilitiesInExcess; GuideNH and Schematica reconstruct them | Trait-bit selection, generated subclass caching, pass-through interfaces, client/server selection, promotion of an existing tile |
|
||||
| External Scala trait generation | ProjectRed illuminated microblocks | `MicroblockGenerator.registerTrait`, ScalaSignature decoding, `$class` helper handling, correct trait initialization and dispatch |
|
||||
| Tile collections and slot state | ProjectRed, Extra Utilities, OpenComputers, AE2, ProjectBlue, GT5U, BuildCraftCompat, WitchingGadgets, MatterManipulator, GuideNH | `partList(): Seq`, `jPartList(): List`, ordering, `partMap(int)`, mutable `TSlottedTile.v_partMap`, `bindPart`, slot-map rebuilds |
|
||||
| Placement/removal/replacement | Most custom-part mods | `getTile`/`getOrConvertTile`, `canPlacePart`, `canAddPart`, `canReplacePart`, `addPart`, `remPart`, binding and notifications in their current order |
|
||||
| Move lifecycle | ForgeRelocationFMP, MatterManipulator | A live `TileMultipart` can be detached/reinserted, coordinates rewritten, then `onMoved`; render, dirty, lighting, and description synchronization remain coherent |
|
||||
| Occlusion and geometry | ProjectRed, Extra Utilities, OpenComputers, AE2, ForgeRelocationFMP, Chisel, WR-CBE, WitchingGadgets, UtilitiesInExcess | Normal and partial occlusion, collision/subpart boxes, `PartMap` numbering, Java iterable adapters, Scala `Traversable` overload |
|
||||
| Redstone and connectivity | ProjectRed, Extra Utilities, OpenComputers, ProjectBlue, AE2, WR-CBE | `IRedstonePart` family, `TRedstoneTile`, `RedstoneInteractions`, face/edge/center maps, neighbor and part-change propagation |
|
||||
| Micro-material registry | Extra Utilities, ProjectRed, ProjectBlue, AE2, BuildCraftCompat, Chisel, material-only integrations, UtilitiesInExcess | Stable material names, integer IDs, remapping, packet ID encoding, `getIdMap(): Tuple2[]`, block/meta access, material behavior hooks |
|
||||
| Multipart save/load | Extra Utilities, ProjectRed, OpenComputers, BuildCraftCompat, MatterManipulator, GuideNH, Schematica, Waila, UtilitiesInExcess | Tile `parts` list, per-part `id`, factory lookup, `save`/`load` ordering, microblock fields, unknown/invalid-part behavior |
|
||||
| Description/update packets | Every substantial custom part integration | `writeDesc`/`readDesc`, keyed part packets, `sendDescUpdate`, `sendDescPacket`, material packet IDs, render and neighbor notification behavior |
|
||||
| Reflection/mixins | GuideNH, Schematica, Et Futurum, Galacticraft, Waila, AE2/AE2FC, Iguana | Exact class/companion/member/field names and, where stated below, exact parameter and field types |
|
||||
|
||||
## Consumer findings
|
||||
|
||||
### ProjectRed — deepest current consumer
|
||||
|
||||
ProjectRed is not merely an optional integration. Wires, framed wires, bundled wires, gates, lamps, buttons, pipes,
|
||||
solar panels, and fabricated gates are FMP parts. Its 141 touching classes dominate the installed binary surface.
|
||||
|
||||
- Its parts mix `TMultiPart` with `TCuboidPart`, `TFacePart`, `TSlottedPart`, `TNormalOcclusion`,
|
||||
`TIconHitEffects`, redstone interfaces, and microblock hollow-connect interfaces. The emitted classes directly call
|
||||
Scala trait `$class` helpers.
|
||||
- Item placement uses `TItemMultiPart`; registries use both `IPartFactory` and `IPartFactory2`, including the
|
||||
Scala-`Seq` registration descriptor.
|
||||
- Connectivity is built on exact `PartMap` face/edge/center numbering and repeated `partMap` queries across the same
|
||||
and neighboring tiles. Redstone propagation uses `RedstoneInteractions` and casts generated tiles to
|
||||
`scalatraits.TRedstoneTile` for `openConnections`.
|
||||
- Parts rely on lifecycle callbacks and their ordering: `onAdded`, `onRemoved`, `onPartChanged`,
|
||||
`onNeighborChanged`, `onChunkLoad`, `onWorldJoin`, scheduled ticks, `notifyPartChange`, `markDirty`, and
|
||||
`markRender`.
|
||||
- Framed wires persist material names and use `materialID`, `materialName`, `getMaterial`, packet material IDs, and
|
||||
`ItemMicroPart.create`. Their fit calculation temporarily changes their own occlusion bounds and calls
|
||||
`tile.canReplacePart(this, this)`.
|
||||
- Part-owned NBT and packet fields include `connMap`, `side`, `orient`, `shape`, `mat`, and type-specific data. FMP
|
||||
must keep treating these tags as opaque and must continue calling part save/load and packet hooks exactly once in
|
||||
the established order.
|
||||
- `LightMicroMaterial` implements `MicroblockGenerator.IGeneratedMaterial` and registers the third-party Scala trait
|
||||
`LightMicroblock` with `MicroblockGenerator.registerTrait`. Generated microblocks must actually acquire that trait;
|
||||
it supplies dynamic halo rendering and computes light from `tile.partList`.
|
||||
- ProjectRed also uses `MultipartSaveLoad.loadingWorld`, `MultipartProxy.block`, vanilla multipart part classes,
|
||||
microblock class companions, saw traits, and the material highlight renderer extension.
|
||||
|
||||
**Migration consequence:** ProjectRed is the acceptance test for the complete architecture: Scala trait ingestion,
|
||||
trait linearization, tile and microblock code generation, redstone tile traits, core lifecycle, rendering, packets,
|
||||
and the micro-material system. A launch-only smoke test is inadequate; illuminated microblocks, gates, face/framed
|
||||
wires, and routed pipes need functional fixtures.
|
||||
|
||||
### Extra Utilities 1.2.12 — broad Java consumer with Scala-shaped registry access
|
||||
|
||||
The code shows several separate FMP subsystems, not one compatibility class:
|
||||
|
||||
- It registers generated-tile pass-through interfaces for `IAntiMobTorch`, pipe/cosmetic/filter pipe interfaces,
|
||||
node, inventory, liquid, and energy node interfaces, plus CoFH `IEnergyHandler`. Composite tiles must expose these
|
||||
interfaces and dispatch to the correct part.
|
||||
- Transfer pipes and nodes are multipart factories/converters. They use face/slot traits, neighbor-tile callbacks,
|
||||
hollow connections, `TRedstoneTile`, `RedstoneInteractions`, part lists/maps, and part-change notifications.
|
||||
- Custom parts include the magnum torch, fence, wall, sphere, pipe jackets, and several microblock-derived shapes.
|
||||
They exercise normal/partial occlusion, icon hit effects, `PartMetaAccess`, `MicroblockRender`, and client/server
|
||||
factories.
|
||||
- Connected-texture and colored/full-bright micro-materials subclass `BlockMicroMaterial` and participate in
|
||||
material rendering. Fences and walls add their own pass-through interfaces.
|
||||
- NEI recipes and item enumeration consume `MicroMaterialRegistry.getIdMap()` as `scala.Tuple2[]`, use
|
||||
`MicroRecipe`, saw cutting strength, material names, and `ItemMicroPart` creation.
|
||||
- Some paths use `jPartList`; others use `partList().toIterator()`. Both collection views and stable ordering are
|
||||
required even though the mod's implementation language is Java.
|
||||
|
||||
The jar is sufficient to establish behavior, while the exact JAR's constant pool remains the authority for
|
||||
names and descriptors. Obfuscated Minecraft method names should not be treated as source-quality naming evidence.
|
||||
|
||||
**Migration consequence:** Extra Utilities covers almost every Java-facing extension seam and is the strongest test
|
||||
that Java wrappers still compose into the same generated tile. UtilitiesInExcess does not make this compatibility
|
||||
burden disappear until existing worlds and the old mod have been retired.
|
||||
|
||||
### OpenComputers — generated slot state is part of the effective API
|
||||
|
||||
OpenComputers converts its cable and 3D print blocks to parts and registers `oc` cable/print factories.
|
||||
|
||||
- `CablePart` mixes cuboid, slotted, hollow-connect, normal-occlusion, icon-effect, and OC network-environment
|
||||
behavior. Network join/separate is driven from part lifecycle callbacks.
|
||||
- Network traversal locates cable parts through `TileMultipart.partList`. Connection checks combine FMP normal
|
||||
occlusion boxes, solid face parts, and exact `PartMap.face(...).mask` values.
|
||||
- `PrintPart` mixes cuboid, edge, face, slotted, normal occlusion, and redstone traits. Its shape and slot mask change
|
||||
at runtime.
|
||||
- When a print toggles shape, it casts the generated tile to `scalatraits.TSlottedTile`, directly clears every
|
||||
matching entry in `v_partMap`, and calls `tile.bindPart(this)` to rebuild its slots. `v_partMap` field shape and
|
||||
`bindPart` behavior are therefore externally load-bearing, not private implementation details in practice.
|
||||
- Placement uses `getOrConvertTile`, `canAddPart`, and `addPart`; complexity limits are calculated across the Scala
|
||||
`partList`. Print redstone input also folds over that list.
|
||||
|
||||
**Migration consequence:** a Java slot-map rewrite must retain a binary and behavioral bridge for `TSlottedTile`,
|
||||
including its public generated state. Test a print whose on/off shapes occupy different slots next to a cable and a
|
||||
face part.
|
||||
|
||||
### ProjectBlue — Java parts built on Scala shim bases
|
||||
|
||||
ProjectBlue defines tiny Scala bridge bases (`JFacePart`, `JCuboidFacePart`, `JCenterPart`) so most of its FMP code
|
||||
can be Java. Its active multipart is the bundled-redstone control panel.
|
||||
|
||||
- The bridge bases inherit `TFacePart`, `TCuboidPart`, and `TSlottedPart`, so their generated `$class` calls remain
|
||||
binary dependencies.
|
||||
- Control panels register an `IPartFactory`, place through `canPlacePart`/`addPart`, remove through `remPart`, and
|
||||
send part description updates.
|
||||
- Bundled/redwire connectivity repeatedly queries `partMap` using exact face, edge, and center indices and uses
|
||||
`RedstoneInteractions` for vanilla/FMP power.
|
||||
- The panel resolves its cover material by stable micro-material name and item representation. Its own persistent
|
||||
fields are opaque part data.
|
||||
- Its edit network identifies a target part by world coordinates plus index in `jPartList`; list order is therefore
|
||||
observable over the network.
|
||||
|
||||
**Migration consequence:** preserve trait bridges, part ordering, `PartMap`, redstone semantics, and stable material
|
||||
name lookup. A control-panel edit packet is a useful ordering regression test.
|
||||
|
||||
### Applied Energistics 2
|
||||
|
||||
AE2's cable bus is a full multipart integration, not just visual compatibility.
|
||||
|
||||
- `CableBusPart` is a Java cuboid part with normal occlusion, masked redstone, and `AEMultiTile`; AE2 dynamically
|
||||
registers `AEMultiTile` and layer interfaces as pass-through interfaces.
|
||||
- `PartRegistry` constructs registered AE2 parts through AE2's combined-instance helper. The FMP integration acts as
|
||||
both part factory and block converter.
|
||||
- Placement/conversion uses `getOrConvertTile`, `canAddPart`, and `addPart`. Code traverses the Scala `partList`
|
||||
iterator.
|
||||
- Occlusion is checked both directly with `NormalOcclusionTest` and by asking `tile.canAddPart` with an AE2
|
||||
`NormallyOccludedPart` probe.
|
||||
- When a generated tile implements `TIInventoryTile`, AE2 calls `rebuildSlotMap()` after changes.
|
||||
- AE2's Waila path and AE2 Fluid Craft load `TileMultipart` by name to register multipart HUD providers.
|
||||
|
||||
**Migration consequence:** preserve dynamic pass-through interfaces and generated tile inventory traits, not only
|
||||
the `CableBusPart` class ABI. Test a cable bus sharing a block with an inventory-bearing part and an occluding cover.
|
||||
|
||||
### BuildCraftCompat
|
||||
|
||||
BuildCraftCompat serializes multipart blocks for builders and reconstructs them later.
|
||||
|
||||
- It identifies `MultipartProxy.block`, walks `jPartList`, calls each part's `save`, and records the part type.
|
||||
- Restore calls `MultiPartRegistry.loadPart(type, tag)`, then uses `canPlacePart`/`addPart`.
|
||||
- Its microblock schematic validates the saved material name through `MicroMaterialRegistry.getMaterial`.
|
||||
- It understands and rotates FMP's own saved type IDs for face, corner, edge, post, hollow, torch, lever, button,
|
||||
and redstone-torch parts.
|
||||
|
||||
**Migration consequence:** registry lookup, part `save`/`load`, core type IDs, material names, and placement validation
|
||||
are a world-data contract. A builder round trip containing every built-in Minecraft part and microblock shape should
|
||||
be a golden test.
|
||||
|
||||
### ForgeRelocationFMP
|
||||
|
||||
The plugin registers `rfmp_frame`, a frame-block converter, an `IFrame` pass-through interface, and an FMP tile
|
||||
mover.
|
||||
|
||||
- `FramePart` mixes `TCuboidPart`, `TNormalOcclusion`, and `TIconHitEffects`. Its special fit test temporarily exposes
|
||||
one face occlusion box, calls `canReplacePart(this, this)`, and combines another part's normal boxes, partial boxes,
|
||||
and collision boxes through the Scala `NormalOcclusionTest` overload.
|
||||
- Frame placement requires an existing multipart tile and uses `canPlacePart`/`addPart`.
|
||||
- The mover removes the live `TileMultipart`, moves the original block and tile object, rewrites `xCoord/yCoord/zCoord`,
|
||||
reinserts it, and calls `onMoved()` in the post-move hook.
|
||||
|
||||
**Migration consequence:** this is a direct test of Scala trait helpers, Scala factory overloads, mixed occlusion,
|
||||
pass-through interfaces, and live tile movement. `onMoved` must reestablish every coordinate-sensitive/generated-tile
|
||||
invariant without replacing the tile object.
|
||||
|
||||
### Chisel
|
||||
|
||||
Chisel registers its blocks as micro-materials and adds a `chisel_torch` factory/converter. `PartChiselTorch`
|
||||
subclasses FMP's `TorchPart`, including its constructors, load/read/write behavior and static side mapping. Placement
|
||||
uses tile conversion, fit checks, and `addPart`; Chisel also supplies a full-bright material implementation.
|
||||
|
||||
**Migration consequence:** the Minecraft-part classes are extension bases, not internal examples. Keep protected
|
||||
state, constructors, packet/NBT hooks, and static orientation tables source- and binary-compatible.
|
||||
|
||||
### ThaumicTinkerer
|
||||
|
||||
ThaumicTinkerer registers block micro-materials and factories/converters for candle and nitor parts. The parts extend
|
||||
`McMetaPart`; the candle participates in random display ticks. They rely on FMP meta-part persistence, placement,
|
||||
render hooks, and factory type dispatch.
|
||||
|
||||
**Migration consequence:** preserve `McMetaPart` subclass semantics and random-display capability composition.
|
||||
|
||||
### Wireless Redstone CBE
|
||||
|
||||
WR-CBE registers transmitter, receiver, and jammer parts and pass-through interfaces for wireless tile APIs.
|
||||
|
||||
- Its Java parts use `JItemMultiPart`, `JCuboidPart`, face/redstone, normal/partial occlusion, icon effects, and
|
||||
micro-shrink rendering interfaces.
|
||||
- It uses `partMap`, `RedstoneInteractions`, `IRedstonePart`, `NormalOcclusionTest`, `MicroOcclusion.recalcBounds`,
|
||||
`onPartChanged`, `remPart`, and tile item drops.
|
||||
|
||||
**Migration consequence:** Java compatibility bases must retain the same trait defaults and generated composite
|
||||
behavior. Test wireless interface dispatch through a composite tile, not just direct calls on the part.
|
||||
|
||||
### WitchingGadgets
|
||||
|
||||
WitchingGadgets registers multipart essentia tubes and buffers, with block converters and factories.
|
||||
|
||||
- Parts extend `McMetaPart`; the tube is slotted, and parts implement Thaumcraft transport/wand interfaces.
|
||||
- Those external APIs are registered as pass-through interfaces, including the overload carrying client/server
|
||||
generation flags.
|
||||
- Connection logic walks `jPartList` and directly consumes other parts' normal and partial occlusion boxes.
|
||||
- Rendering goes through `PartMetaAccess`; placement uses `canAddPart`/`addPart`.
|
||||
|
||||
**Migration consequence:** preserve flag-sensitive pass-through registration, Java occlusion iterables, slotted part
|
||||
semantics, and `PartMetaAccess` behavior.
|
||||
|
||||
### MatterManipulator
|
||||
|
||||
MatterManipulator is the broadest external editor of multipart state.
|
||||
|
||||
- Analysis records each part's `getType`, calls `save` into NBT containing `id`, and captures `getDrops`.
|
||||
- Application removes current parts with `remPart`, sorts microblocks before other parts, reconstructs through
|
||||
`MultiPartRegistry.loadPart(type, nbt)`, calls `part.load(nbt)`, and adds through `TileMultipart.addPart`.
|
||||
- It interprets core microblock type prefixes and NBT fields `material`, `shape`, `side`, `orient`, and `connMap`, and
|
||||
transforms exact `PartMap` edge/corner numbering.
|
||||
- Its mover detaches and reinserts the same tile object, rewrites coordinates, validates it, calls `onMoved`, then
|
||||
performs dirty, render, block-update, lighting, and description-packet synchronization.
|
||||
- Its apply path intentionally does **not** send a redundant description packet: rebuilding the tile a second time
|
||||
previously produced null bounds. Packet timing and reconstruction side effects therefore matter.
|
||||
|
||||
**Migration consequence:** add capture/apply/move golden tests. This consumer will expose changes in part ordering,
|
||||
factory semantics, core NBT, movement lifecycle, and over-eager network synchronization.
|
||||
|
||||
### GuideNH
|
||||
|
||||
GuideNH reconstructs and renders multipart tiles for guide scenes and exports part statistics. Most access is
|
||||
reflective to keep the integration optional.
|
||||
|
||||
- It reflects `MultipartHelper.createTileFromNBT`, `MultipartRenderer.renderWorldBlock`, material registration and
|
||||
construction, registry lookup, tile part-list getters/setters, `loadParts`, `notifyTileChange`, `markRender`,
|
||||
microblock properties, and part drops.
|
||||
- `MultipartGenerator$.MODULE$.generateCompositeTile(TileEntity, Iterable, boolean)` is companion-only.
|
||||
- `MicroblockGenerator$.create(MicroblockClass, int, boolean)` is companion-only and matched by exact parameter
|
||||
classes.
|
||||
- Client preview promotion replaces parts with client microblock instances, assigns
|
||||
`partList_$eq(scala.collection.Seq)`, loads/binds them, then triggers tile/render notifications.
|
||||
- A late mixin targets `BlockMicroMaterial` fields named exactly `block: Block` and `meta: int`. Method reflection is
|
||||
only a fallback if an object is not mixin-transformed.
|
||||
|
||||
**Migration consequence:** keep both companion entry points, the Scala `partList` setter descriptor, and the private
|
||||
field names/types unless GuideNH is updated in lockstep. Failures may appear only as missing guide previews or export
|
||||
data rather than a startup crash.
|
||||
|
||||
### Schematica
|
||||
|
||||
Schematica's optional integration reconstructs multipart tiles from schematic NBT, especially on the client. It is
|
||||
more invasive than its small binary footprint suggests.
|
||||
|
||||
- It reflects `MultiPartRegistry$.MODULE$` and the **private Scala-mangled field**
|
||||
`codechicken$multipart$MultiPartRegistry$$typeMap`, casting it to `scala.collection.mutable.Map`.
|
||||
- It resolves material IDs, obtains the registered microblock class from that map, and invokes
|
||||
`MicroblockClass.create(boolean, int)`.
|
||||
- It reflects part `load`, `onPartChanged`, `TileMultipart.loadParts`, `TileMultipart.createFromNBT`, and
|
||||
`MultipartGenerator$.generateCompositeTile(TileEntity, scala.collection.Iterable, boolean)`.
|
||||
- It parses tile NBT `parts`, each part's `id`, and microblock `material`; it rejects a preview if any part fails to
|
||||
reconstruct.
|
||||
|
||||
**Migration consequence:** the registry's private field name **and Scala mutable-map representation are currently
|
||||
effective public API**. A Java `Map` replacement will silently disable Schematica unless an exact compatibility field
|
||||
is retained or Schematica is patched and deployed first. This is a higher-risk constraint than the constant-pool
|
||||
inventory alone shows.
|
||||
|
||||
### UtilitiesInExcess — future replacement, already a substantial consumer
|
||||
|
||||
UtilitiesInExcess is not in the `+700` JAR scan but is in scope because it is intended to replace Extra Utilities.
|
||||
|
||||
- `Content` implements `IPartFactory2` for `ue_fence`, `ue_wall`, and `ue_sphere`, with legacy Extra Utilities type
|
||||
aliases when the old mod is absent.
|
||||
- Parts extend `TMultiPart`, implement Java icon/normal-occlusion interfaces, call the normal occlusion protocol, and
|
||||
render through microblock material helpers.
|
||||
- Placement and connectivity use `canPlacePart`, `addPart`, `BlockMultipart`, neighboring `TileMultipart` instances,
|
||||
`jPartList`, and part sub-boxes.
|
||||
- Recipes and item enumeration consume `MicroMaterialRegistry.getIdMap()` as `scala.Tuple2[]` and use microblock
|
||||
class IDs plus `ItemMicroPart.create`.
|
||||
- Materials use name/ID lookup, packet material ID helpers, remapping, sounds, icons, drops, and rendering. Legacy
|
||||
Extra Utilities material names are explicitly remapped for world conversion.
|
||||
- At audited HEAD, the server factory reads NBT key `material` while `MaterialBasedPart.save` writes `mat`. That is a
|
||||
UtilitiesInExcess-side inconsistency to resolve before relying on save/load round trips; FMP should not special-case
|
||||
it.
|
||||
|
||||
**Migration consequence:** replacing Extra Utilities does not permit early removal of `IPartFactory2`, the Scala
|
||||
`Tuple2[]` registry view, legacy material remapping, or the Java part/occlusion bridges. UtilitiesInExcess should be
|
||||
added to compatibility CI before it enters the pack.
|
||||
|
||||
## Narrow consumers, still real contracts
|
||||
|
||||
| Consumer | Actual use | Compatibility requirement |
|
||||
| --- | --- | --- |
|
||||
| BloodArsenal | Registers decorative blocks/metas as `BlockMicroMaterial` instances | Constructor and `registerMaterial`; stable chosen names |
|
||||
| Botania | Registers decorative blocks/metas as micro-materials | Same material registration API and block/meta behavior |
|
||||
| Biomes O' Plenty | Registers historical BOP block/metas as micro-materials | Constructor, registry, and its dot-separated material names |
|
||||
| Natura | Registers single/ranged block metas, using both `createAndRegister` and direct registration | Static helper plus registry API and generated material keys |
|
||||
| TConstruct | Optional init plugin registers many smeltery/metal/glass blocks with `createAndRegister` | Helper availability and init-time registration behavior |
|
||||
| Galacticraft | Reflectively constructs `BlockMicroMaterial` and chooses the first public method named `registerMaterial`; separately rejects `TileMultipart` as an energy receiver | Exact class/constructor names; compatible public registration method; tile class identity. Avoid incompatible same-name overloads because it does not check the signature |
|
||||
| BloodMagic | Teleposer reconstructs multipart tiles with `MultipartHelper.createTileFromNBT` and sends a description packet after placement | NBT reconstruction, placement lifecycle, and `sendDescPacket` |
|
||||
| Waila | Reflects `BlockMultipart`, reads tile NBT `parts`, then dispatches providers using each part tag's `id` | Block class name and tile/part NBT layout |
|
||||
| AE2 Fluid Craft | Reflects `TileMultipart` and registers Waila part providers | Tile class name and `jPartList`/provider behavior reached by AE2 |
|
||||
| GT5U | Detects `TileMultipart`, iterates `jPartList`, and finds a ProjectRed `GatePart` to expose its screwdriver slot | Tile identity, Java list view/order, part instance identity |
|
||||
| EnderCore | Tests items with `instanceof ItemSaw` for durability display | `ItemSaw` class identity and inheritance |
|
||||
| IguanaTweaksTConstruct | Creates saws through `MicroblockProxy`, reads saw methods, accesses proxy companions, and reflectively mutates private `ItemSaw.harvestLevel` | Proxy methods and `MODULE$`, `Saw`/`ItemSaw` identity, exact `harvestLevel: int` field name/type |
|
||||
| Et Futurum Requiem | Reflectively gets and mutates static `int[] ButtonPart.metaSideMap` and `sideMetaMap` to repair button orientation | Exact class and mutable static field names/types; array index meanings |
|
||||
|
||||
## Source-only hazards that must be added to the compatibility checklist
|
||||
|
||||
The original constant-pool inventory identified reflective class names, but source inspection adds exact member-level
|
||||
requirements:
|
||||
|
||||
| Consumer | Hidden requirement | Likely symptom if broken |
|
||||
| --- | --- | --- |
|
||||
| Schematica | `MultiPartRegistry$.MODULE$`; field `codechicken$multipart$MultiPartRegistry$$typeMap` of Scala mutable-map shape; exact generator/load methods | FMP schematic tile reconstruction disables itself or returns no preview |
|
||||
| GuideNH | Companion-only generator methods; `partList_$eq(Seq)`; `BlockMicroMaterial.block` and `.meta` mixin fields | Missing/incorrect guide preview, material export, or part statistics |
|
||||
| Et Futurum | Static mutable `ButtonPart.metaSideMap` and `sideMetaMap`, both `int[]` | FMP buttons attach with pre-fix orientation behavior |
|
||||
| Iguana | Private `ItemSaw.harvestLevel` field | Existing saw cutting strengths are not adjusted |
|
||||
| Galacticraft | Reflection by method name only for `registerMaterial` | Galacticraft micro-material registration is skipped after a caught exception |
|
||||
| Waila | `BlockMultipart` string plus tile NBT `parts`/part `id` | No multipart HUD data |
|
||||
|
||||
These need targeted runtime tests or explicit downstream patches. They cannot be proven safe by `javap` ABI diffing.
|
||||
|
||||
## Data and ordering contracts
|
||||
|
||||
### Core NBT and identity
|
||||
|
||||
The following are read by code outside FMP and must be treated as serialized API:
|
||||
|
||||
- the tile's `parts` compound list;
|
||||
- the `id` string in every part compound;
|
||||
- built-in multipart type strings and registry lookup behavior;
|
||||
- microblock `material`, `shape`, and orientation fields used by schematic/editor code;
|
||||
- material names and remapping, including legacy Extra Utilities names;
|
||||
- invalid/unknown part handling during `loadPart`, tile creation, and preview reconstruction.
|
||||
|
||||
Consumer-specific fields such as ProjectRed's `connMap` and UtilitiesInExcess's `mat` belong to their parts. FMP's
|
||||
obligation is to invoke each part's hooks with the same tag and ordering, not to interpret or rewrite those fields.
|
||||
|
||||
### Observable part order
|
||||
|
||||
Part list order is not an internal detail:
|
||||
|
||||
- ProjectBlue identifies an edited part by its `jPartList` index;
|
||||
- rendering code in ProjectRed and Extra Utilities indexes `partList` from hit data;
|
||||
- MatterManipulator deliberately sorts placement, with microblocks first;
|
||||
- GuideNH and Schematica build an ordered list before generating/loading a composite tile;
|
||||
- Waila preserves tile NBT order when dispatching part providers.
|
||||
|
||||
The Java port may add faster indexed storage, but all published views, serialization, binding, ray-hit indices, and
|
||||
packet consumers must observe one consistent order.
|
||||
|
||||
### Material IDs and packets
|
||||
|
||||
Numeric material IDs are runtime registry identities used in descriptions and custom-part packets. Names are the
|
||||
persistent identity. Preserve:
|
||||
|
||||
- deterministic name-to-ID lookup for one runtime;
|
||||
- remap behavior for renamed materials;
|
||||
- `writeMaterialID`/`readMaterialID` wire agreement;
|
||||
- `materialName`/`materialID` round trips;
|
||||
- the legacy `getIdMap(): scala.Tuple2[]` view until Extra Utilities and UtilitiesInExcess are migrated.
|
||||
|
||||
## Migration gates derived from the audit
|
||||
|
||||
Before converting or materially changing each subsystem, add the smallest test that freezes its consumer-visible
|
||||
behavior:
|
||||
|
||||
1. **Registry:** Java `IPartFactory`, `IPartFactory2`, Scala function factory, converter priority, `loadPart`, unknown
|
||||
type behavior, stable type strings, and Schematica's compatibility view.
|
||||
2. **Tile storage:** `partList`, `jPartList`, `partMap`, exact order, slot rebinding, `TIInventoryTile.rebuildSlotMap`,
|
||||
add/remove/replace callback and notification order.
|
||||
3. **Generator:** generated class caching; Java and Scala traits; ProjectRed `LightMicroblock`; pass-through interfaces
|
||||
representative of AE2, Extra Utilities, WR-CBE, WitchingGadgets, ForgeRelocationFMP, and UtilitiesInExcess;
|
||||
client/server generation and promotion of an existing tile.
|
||||
4. **Save/load:** a mixed tile golden fixture containing a built-in microblock, ProjectRed part, Extra Utilities or
|
||||
UtilitiesInExcess part, AE2 cable bus, OpenComputers part, and a Minecraft meta part. Exercise normal world load,
|
||||
BuildCraft builder, MatterManipulator, Schematica client preview, and GuideNH preview.
|
||||
5. **Movement:** move the same live tile through both ForgeRelocationFMP-style and MatterManipulator-style flows;
|
||||
verify coordinates, part tile references, generated interfaces, scheduled state, render/lighting, dirty state, and
|
||||
client synchronization after `onMoved`.
|
||||
6. **Occlusion:** mixed Java/Scala normal and partial occlusion parts, collision-only boxes, `canReplacePart(this,
|
||||
this)`, face/edge/center `PartMap`, and the Scala `NormalOcclusionTest` descriptor.
|
||||
7. **Redstone:** ProjectRed face/framed wire, OpenComputers print, ProjectBlue panel, AE2 cable bus, and WR-CBE part in
|
||||
composite tiles; verify neighbor/part-change propagation and generated `TRedstoneTile` behavior.
|
||||
8. **Reflection:** launch focused checks for Schematica, GuideNH, Et Futurum, Iguana, Galacticraft, Waila, AE2, and
|
||||
AE2 Fluid Craft. Assert the exact names and types listed above.
|
||||
9. **Binary gate:** rebuild and diff all 27 installed JAR consumers against the frozen inventory after every public
|
||||
API, trait, generator, registry, or tile change. Add UtilitiesInExcess as a compile/runtime fixture now even though
|
||||
it is not yet in the pack.
|
||||
|
||||
## Practical priority for the current branch
|
||||
|
||||
1. Keep the existing `+678` ABI fixture as the exact binary floor and correct failures before source cleanup.
|
||||
2. Add the hidden-member reflection checks, especially Schematica's `typeMap` compatibility and GuideNH's mixin
|
||||
fields, before converting their owners.
|
||||
3. Characterize `TileMultipart` list/map/slot behavior and move lifecycle before optimizing storage or iteration.
|
||||
4. Characterize pass-through interfaces and ProjectRed's external Scala trait before changing either generator.
|
||||
5. Add mixed NBT/packet fixtures before converting microblocks and Minecraft part implementations.
|
||||
6. Treat Scala runtime removal as downstream coordination work after the Java port, not as a requirement of it.
|
||||
|
||||
With these gates, the source audit is actionable: the port can simplify internals freely where no listed observation
|
||||
changes, while each externally observed behavior has a named consumer and a focused way to prove compatibility.
|
||||
@@ -90,7 +90,7 @@ java tools/AbiScan.java "<instance>/.minecraft/mods" ForgeMultipart
|
||||
```
|
||||
|
||||
Needs JDK 17+. The frozen baseline is `src/test/fixtures/abi/gtnh-daily-678-consumers.txt`, from GTNH daily
|
||||
`2026-08-14+678` (241 jars, 28 consumers). Diff against it; anything present there but absent from the port is a
|
||||
`2026-08-14+678` (241 jars, 27 consumers). Diff against it; anything present there but absent from the port is a
|
||||
linkage break in a shipping mod.
|
||||
|
||||
### Building a frozen Scala consumer fixture
|
||||
|
||||
Reference in new issue
Block a user