Commit Graph
64 Commits
Author SHA1 Message Date
Algent 911e73291f test: characterize hollow microblocks 2026-09-02 01:15:59 +02:00
Algent 0f3a8c2097 test: characterize edge and post microblocks 2026-09-02 00:51:28 +02:00
Algent 44fb151828 test: characterize corner microblocks 2026-09-02 00:28:11 +02:00
Algent 2f638b1e79 test: characterize face microblocks 2026-09-01 20:04:52 +02:00
Algent 30925fbddd test: characterize microblock base 2026-09-01 19:45:44 +02:00
Algent ee75f86e02 test: characterize microblock classes 2026-09-01 19:28:19 +02:00
Algent 7a031e6cb4 test: characterize microblock renderer 2026-09-01 19:09:21 +02:00
Algent c6ce881aa7 test: characterize saw item and renderer 2026-09-01 18:54:55 +02:00
Algent a932f47dc1 test: characterize Angelica compat 2026-09-01 18:41:29 +02:00
Algent 53751101d2 test: characterize config content 2026-09-01 14:00:50 +02:00
Algent 87a1c23f54 test: characterize block micro material 2026-09-01 13:41:08 +02:00
Algent 2549bfdffb test: characterize placement grids 2026-09-01 10:16:01 +02:00
Algent e286de3401 test: characterize microblock placement 2026-09-01 09:53:09 +02:00
Algent 9ac0a5e409 test: characterize ItemMicroPart 2026-09-01 08:28:14 +02:00
Algent bed000cacf test: characterize multipart packet handlers 2026-09-01 00:42:10 +02:00
Algent 36a0e9c865 test: characterize microblock proxy 2026-09-01 00:22:01 +02:00
Algent e6278a8d14 test: characterize multipart proxy 2026-08-31 23:54:41 +02:00
Algent a1ab154f4c test: characterize grass micro materials 2026-08-31 20:01:13 +02:00
Algent f9724b9d93 test: characterize default content
Pin the singleton ABI and exact built-in factory, material, and remap registrations.
2026-08-31 19:36:36 +02:00
Algent e1ca4fba53 test: characterize missing micro material
Pin the singleton ABI, inert defaults, registration, and client stripping.
2026-08-31 19:04:10 +02:00
Algent 3cdc62455c test: characterize multipart save/load 2026-08-31 14:33:56 +02:00
Algent 7152b5e394 test: characterize microblock packet handlers
Pin the packet-handler ABI, client registry handling, and server handshake payload before the Java port.
2026-08-31 13:38:00 +02:00
Algent cd84c140ae test: characterize microblock event handler
Pin the client-only ABI and dedicated-server side stripping before the Java port.
2026-08-30 21:55:54 +02:00
Algent dbe617ed46 test: characterize microblock mod lifecycle
Pin the Scala mod instance, handler surface, and mutable compatibility hook before the Java port.
2026-08-30 21:37:09 +02:00
Algent e9f244fefa test: characterize multipart event handler
Pin event annotations, bus identity, and server dispatch before the Java port.
2026-08-30 21:15:20 +02:00
Algent 6dbdb74559 test: characterize multipart mod lifecycle
Pin the Scala singleton identity and FML event surface before the Java port.
2026-08-30 16:14:00 +02:00
Algent 53e5901360 test: characterize multipart compatibility
Pin the Scala Function4 callback surface and MCPC fallback behavior before the Java port.
2026-08-30 15:29:59 +02:00
Algent bde3445488 test: characterize multipart raytrace index production
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.
2026-08-28 18:31:33 +03:00
Algent 85c2c4d15c test: characterize multipart read paths 2026-08-28 16:54:50 +03:00
Algent 2b04a2e52b test: characterize partial occlusion tile trait 2026-08-28 11:19:44 +03:00
Algent df21e4041c test: characterize microblock recipes 2026-08-28 10:59:04 +03:00
Algent 28c90189a6 test: characterize redstone interaction unit 2026-08-27 23:15:56 +03:00
Algent dffc65a894 test: characterize multipart traversal mutations 2026-08-27 22:49:00 +03:00
Algent 6410cc0028 test: characterize multipart ordering and move lifecycle 2026-08-27 18:02:41 +03:00
Algent 4616b5834c test: guard source-only consumer reflection contracts 2026-08-27 14:11:53 +03:00
Algent 49ed6fd751 fix: restore Schematica registry reflection compatibility 2026-08-27 14:02:47 +03:00
Algent da472f1fd3 test: characterize MultipartRenderer
Everything this class does needs a client, so nothing here can run it. What is
pinned is the contract two other parties depend on and the ABI diff cannot see.

guidenh reflects on both MultipartRenderer and MultipartRenderer$ by name,
calling renderWorldBlock as a static first and falling back to the companion's
MODULE$, so both the static's exact signature and the singleton field are
pinned. Forge needs that singleton to be both a TileEntitySpecialRenderer and
an ISimpleBlockRenderingHandler or it rejects the registration. Both classes
carry class-level @SideOnly(CLIENT) and are stripped on a dedicated server.

Every lookup uses initialize = false: initialising the companion runs its
constructor, which claims a render id from Forge's RenderingRegistry.

125 plain-JVM tests, 22 Forge server tests.
2026-08-15 20:09:49 +02:00
Algent d224ce116d refactor: remove the package objects instead of porting them
A Scala package object compiles to a class literally named 'package', and that
is a Java keyword, so no Java source can declare or even name it. The
characterization had to reach both through Class.forName, which is the argument
in one line. There is no Java form to port to.

Each held exactly one member, a logger alias for its proxy, so the indirection
is inlined at its eight call sites: ConfigContent (7) and MultipartGenerator
(1). The functional characterization asserted beforehand that each alias
returned the very instance its proxy holds, so the substitution is an identity;
both classes are descriptor-identical afterwards.

Exactly four classes leave the jar and nothing else changes. No consumer
referenced them, and no Java consumer could have.

120 plain-JVM tests and 22 Forge server tests pass. PackageObjectCharacterization
went with its subject; ProxyLoggerFunctionalTest keeps the assertion worth
having, that both proxies publish a logger during preInit.
2026-08-15 20:04:55 +02:00
Algent d6bba7ff46 test: characterize the package objects
Each holds one member, a logger alias for its proxy's logger. Everything goes
through reflection because 'package' is a Java keyword and cannot appear as a
type name in Java source, which is also why these two classes have no Java
form at all.

The plain-JVM half pins the shape and that the alias reads the proxy's var
rather than holding anything, so it reports null before preInit. The Forge
server half pins the part that matters for what comes next: after preInit each
alias returns the very instance its proxy holds, adding nothing.

123 plain-JVM tests, 23 Forge server tests.
2026-08-15 20:02:42 +02:00
Algent 8f73a693cc test: characterize ControlKeyModifer
Plain-JVM coverage is structural: the Java-facing isControlDown(EntityPlayer)
static that the reference scaladoc calls out as existing for Java callers, and
the typo in the class name, which is the published name.

Forge server coverage for the behavior. isControlDown branches on whether the
player's world is remote, so it needs a real player; a Forge FakePlayer on a
dedicated server world takes the server branch and reads the map the client
keeps in sync through packet 1. Unknown players default to not holding, the map
reflects the last recorded value, and clearing resets it.

The client branch reads isClientPressing instead and no harness has a client.

120 plain-JVM tests, 21 Forge server tests.
2026-08-15 19:42:38 +02:00
Algent 40bb1b71b7 refactor: port PacketScheduler to Java
IScheduledPacketPart is descriptor-identical and schedulePacket is unchanged.
TScheduledPacketPart.read stays abstract: TMultiPart declares read, so a
default would be shadowed and a part would silently read a description instead
of a mask. The dispatch that lived in the $class helper is now the interface
static readMask, with the one-line forwarder documented on read.

writeScheduled and readScheduled became defaults. TMultiPart declares neither,
and empty bodies are what mixing the Scala trait in already gave a Scala
implementor -- only Java implementors ever had to write them out.

sendScheduled is public because the reference's private[multipart] reaches the
handler package and Java has no equivalent scope. An unsupported mask width now
throws IllegalArgumentException rather than scala.MatchError; both are
RuntimeException and the map is still left uncleared on that path, as before.

Dropped PacketScheduler$, TScheduledPacketPart$class and two closure classes,
none referenced in bytecode or by reflective name.

118 plain-JVM tests and 18 Forge server tests pass.
2026-08-15 17:04:41 +02:00
Algent 3ad25f56cb test: characterize PacketScheduler
Plain-JVM coverage is structural: the shapes of IScheduledPacketPart and
TScheduledPacketPart, and the fact that read must stay abstract. TMultiPart
declares read, so a superclass method would beat any default the interface
tried to supply, and a part that does not declare it resolves to TMultiPart's,
which reads a description rather than a mask.

Forge server coverage for the behavior, which needs a part bound to a tile in a
non-remote world and a real write stream: masks OR-ing into one write, the map
clearing after a send, a part that lost its tile being skipped, all four
documented mask widths being accepted, and an undocumented one being rejected
rather than silently writing nothing.

117 plain-JVM tests, 18 Forge server tests.
2026-08-15 17:01:18 +02:00
Algent 31ec83f91b refactor: port TileCache to Java
The first port free to change shape rather than preserve it: TileCache has zero
downstream references in bytecode and does not appear in guidenh's reflective
names. map() became a java.util.Map, add/remove became void, and apply returns
a nullable FlaggedTile instead of a scala.Option. No internal caller used any
of the discarded return values.

Dropped TileCache$, TileCache$FlaggedTile$ and FlaggedTile's case-class
machinery. It is only ever a map value, never compared, hashed, printed or
destructured.

findTile is unchanged, including the branch the reference obscures: its
trailing 'case _ => null' is unreachable because Some(FlaggedTile(t, rem))
matches whatever the flag holds, so a tile flagged removed is returned like any
other and only the warning is suppressed. That is pinned by a functional test
written before the port.

114 plain-JVM tests and 13 Forge server tests pass; the only test change is the
two-line adapter that stopped unwrapping a scala.Option.
2026-08-15 16:23:47 +02:00
Algent b92d4b7af4 test: characterize TileCache
Plain-JVM coverage for the map half: add stores the tile unflagged, remove
replaces the entry rather than dropping it, entries are keyed by coordinate
value rather than identity, and clear empties everything.

Forge server coverage for findTile, which needs a world. It pins the branch
that is easy to misread: the removed flag only suppresses the warning, and a
tile flagged removed is still returned, because the Some pattern matches
regardless of the flag and the reference's trailing null case is unreachable.
The empty-cache path throws with a message starting 'DC: Client multipart @'.

114 plain-JVM tests, 13 Forge server tests.
2026-08-15 16:21:14 +02:00
Algent 0fdf9e5e75 test: characterize MultipartHelper
Plain-JVM coverage for the half that needs no world: the id guard on
createTileFromNBT and the whole of IPartTileConverter. MultipartSaveLoad
cannot class-initialize headless, which makes it a usable probe -- returning
null rather than raising a LinkageError is what proves the guard short-circuits
before the loadingWorld assignment.

Forge server coverage for the rest, none of which is reachable headless:
createTileFromParts runs the ASM generator, the NBT round trip needs the
save/load hooks, registerTileConverter appends to a Scala MutableList, and
sendDescPacket needs a loaded chunk.

Also pins the two static descriptors other jars link against and the
MultipartHelper/MultipartHelper$ names guidenh reflects on, which the ABI diff
cannot see.

107 plain-JVM tests, 10 Forge server tests.
2026-08-15 15:43:18 +02:00
Algent 3e68e67599 test: characterize the marker interfaces
TSlottedPart, IRandomDisplayTick, INeighborTileChange, TRandomUpdateTick,
ISidedHollowConnect and IMicroMaterialRender carry no implementation, so their
characterization is their shape: every member abstract and public, no
superinterface, and the exact member names.

Two of them extend TMultiPart in Scala source but emit a bare interface, and
IMicroMaterialRender is satisfied entirely by TMultiPart's Scala-style
world/x/y/z accessors, so the names are load-bearing.

TRandomUpdateTick's onWorldJoin auto-registration lives in its $class helper.
A part that does not declare onWorldJoin resolves it to TMultiPart's no-op;
that is pinned so the port cannot quietly turn it into an interface default,
which the superclass would shadow.
2026-08-15 15:28:17 +02:00
Algent beb0995e60 test: characterize TileMultipart part storage and predicates
Gate step before converting the central tile. Covers the surface that does
not need a world: the part list is replaced rather than mutated so a
previously published Seq never changes under a caller, jPartList reflects
the current parts, operate skips parts whose tile has been cleared,
getLightValue is the maximum and zero when empty while
getExplosionResistance is the maximum but throws when empty, occlusionTest
needs agreement in both directions, canReplacePart excludes the outgoing
part but still rejects a part already present, and solidity falls back to
partMap being null on a bare tile.

One assumption was wrong and the test caught it: TMultiPart.doesTick
defaults to true, so a default part starts the tile ticking and a part has
to opt out to leave it idle. The case now records the real behavior.

Anything touching worldObj, the registry or packets stays out of this
layer because it cannot run headless; the Forge server suite covers that
side.

90 plain-JVM tests, all passing against the untouched Scala.
2026-08-15 10:49:57 +02:00
Algent ff380ee3bc test: characterize MultiPartRegistry
Splits the characterization across both layers, because part registration
needs FML's active mod container and throws without one, so it cannot run
headless at all.

Plain JVM covers what is reachable: converters are dispatched per block,
a converter returning null does not stop the scan, converters registered
for another block are never consulted, a converter claiming several blocks
is registered for each, and an unknown mod container throws rather than
returning null.

The Forge server suite covers registration itself, and deliberately
exercises both overloads downstream depends on. Content registers through
the deprecated IPartFactory array form that seven jars use, and each
microblock class registers through the IPartFactory2 varargs form that
ProjRed uses, so resolving mc_torch and mcr_face proves both paths. Part
ids also round trip through the shared IDWriter carrier.

78 plain-JVM tests and 5 server tests, all passing against the untouched
Scala.
2026-08-15 10:31:59 +02:00
Algent edd6136354 refactor: port MicroMaterialRegistry to Java
Replaces MicroMaterialRegistry.scala with a Java registry, its companion
singleton and the two nested interfaces. Both nested interfaces are
descriptor-identical to the reference and MODULE$ keeps every instance
method ProjRed links against. Ten jars reference this type and three more
reach it reflectively, so the surface was checked member by member rather
than by descriptor count.

getIdMap keeps its scala.Tuple2 array because extrautilities links against
it, so the registry still stores tuples internally. readIDMap moves from
scala.collection.Seq to java.util.List, which no jar references; the one
in-repo caller moved from mkString to String.join. That clears one of the
five Scala-typed descriptors the inventory identified.

Three removals, all verified unreferenced: the mangled public accessors
Scala emitted so its closure classes could reach private state,
IMicroMaterial$class, and the MissingMicroMaterial forwarders for the two
members it does not override. The last of those was caught by the
characterization failing to compile, not by inspection.

IMicroMaterial's loadIcons, canRenderInPass and isSolid become real Java
defaults, so implementors can inherit rather than restate them. Eleven
anonfun classes are gone.

Validated with 73 plain-JVM tests passing against both the Scala baseline
and the port, a clean build, and the Java 8 Forge dedicated-server suite,
which exercises setupIDMap and calcMaxCuttingStrength during real startup.
2026-08-14 22:08:30 +02:00
Algent dc758d4310 test: characterize MicroMaterialRegistry
Freezes the registry lifecycle before the port: setupIDMap sorts the type
map by name into the id array, ids are the index into it, materialID and
materialName round trip, remapName resolves on both getMaterial(String)
and materialID, getMissingId points at the registered placeholder rather
than falling back to zero, ids round trip through the shared IDWriter, and
a highlight renderer that claims the highlight short-circuits the default
client renderer.

Also freezes the two members IMicroMaterial supplies. A Java class cannot
inherit them today, so they are observed through MissingMicroMaterial,
which overrides only isTransparent and loadIcons.

Two limits are deliberate and recorded in the test. The registry is global
mutable state, so both test classes guard their registrations and assert
only relative facts. The error paths are not covered at all: they call the
microblock logger, which is null until MicroblockProxy.preInit runs.

Adds a frozen Scala 2.11.5 consumer compiled against the reference dev jar
at 52ff8ff, reading MODULE$ and the raw scala.Tuple2 array.

73 plain-JVM tests, all passing against the untouched Scala.
2026-08-14 22:03:04 +02:00