Add Phase 9 and Phase 10 to the migration plan.
Phase 9 is a deprecation pass, not a redesign. The published API is already
largely Java-shaped; nine public entries still carry Scala types, two of which
already have a Java sibling. It also covers a second problem: private[multipart]
compiles to public, so seventeen implementation hooks are advertised as API.
Phase 10 covers upstream consumer cleanup, where consumer-side reflection and
Scala-trait registration constrain FMP internals. It is unsequenced and parts of
it can land before this port merges. ProjectRed's is not one of them, so its two
blockers are recorded as Phase 7 prerequisites.
Phase 8 now notes that removing Scala from FMP has no pack-level payoff.
Preserve the exact generated client interfaces, render-cache behavior, and ordered display ticks.
Teach Java mixin generation to linearize a registered parent and exclude transient runtime caches from copying.
Keep TIInventoryTile as AE2's public rebuild API and JInventoryTile as the registered mixin input, preserving both generated interfaces and flattened sided-slot behavior.
Preserve the exact generated interface and ordered fluid behavior.
Isolate FluidStack.amount access outside the transformed class. The transformer treats every field read as trait-owned state.
Freeze ordered tank state and fluid distribution behavior.
Pin capability short-circuiting and the exact generated interface. All checks run against the untouched Scala trait.
The fourth generated tile written directly in Java, and the first with
both mutable state and inherited member access. The eight characterization
tests pass unchanged, and the runtime interface keeps the exact thirteen
methods. INeighborTileChange, the surface shipping jars link against, is
byte-identical between the reference and ported dev jars, and no consumer
references the removed $class or closure classes.
Two transformer constraints turned up, both now in the handoff gotchas.
registerJavaTrait rejects a trait with a non-empty InnerClasses attribute
outright, so the anonymous AbstractFunction1 for the operate callback
could not stay in the trait; it is a named class in the access shim.
The shim's parameters are Object rather than the trait type. Typing them
as the trait let javac elide the cast to TileMultipart, since the
untransformed trait extends it, and the verifier then rejected the
getfield once Forge rewrote the trait to an interface.
TRedstoneTileAccess only escapes this because IRedstoneTile is unrelated
to TileMultipart and forces a real checkcast.
Seven behavioral tests and a generated-interface freeze, both against the
untouched Scala trait. Nothing in the frozen consumer baseline references
TTileChangeTile or a $class helper for it, so there is no binary fixture
to take: the load-bearing surface is INeighborTileChange, which is already
Java and unchanged.
The behavior pinned is the flag lifecycle and the coordinate filter.
bindPart only ever ors the flag in, copyFrom takes it from another change
tile but leaves it alone for a plain source, clearParts resets it, and
partRemoved recomputes from the remaining list rather than from the part
handed to it. onNeighborTileChange dispatches only for an axial offset of
one or two blocks, and marks the two-block case weak.
The runtime interface is the exact thirteen methods: six overrides, the
field getter and setter, and five super accessors.
rayTraceAll was the one method the read-path cleanup restructured, moving
from an indexed loop over a copied list to an iterator with a manual
counter, and nothing covered it. The index it writes into ExtendedMOP.data
is what reduceMOP hands back to every click, activate, harvest and pick
block, so an off-by-one there would misroute interactions silently.
Six tests pin the index production: a part that misses still consumes its
index, sorting by distance happens after the indices are assigned, the
part's own data is nested underneath rather than replaced, subHit keeps
its default because data is assigned directly, and an index taken from a
hit still selects the part that produced it. harvestPart's indexing and
collisionRayTrace's nearest-or-null are covered alongside.
All six also pass against the pre-cleanup implementation at 370b353^,
which is the evidence that the restructure preserved behavior.