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.
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.
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.
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.
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.
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.
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.
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.
Replaces TFacePart.scala with a Java interface and retains the
TFacePart$class bridge for OpenComputers, ProjRed and ProjectBlue. The
interface is descriptor-identical to the reference; the bridge adds only a
private constructor.
This is the first converted trait where Java default methods are safe.
TMultiPart declares neither solid nor redstoneConductionMap, and neither
does anything in the microblock superclass chain, so there is no
superclass method for a default to lose to. Both members therefore become
real defaults rather than staying abstract with explicit forwarders, and
no in-repo Scala needed changing. The rule for the remaining traits is to
check that condition before choosing.
A side effect is that Java classes can now inherit these members;
McSidedMetaPart previously had to declare both just to accept the
defaults, and stays descriptor-identical.
Adds the first functional coverage of runtime class generation against a
ported type. Microblock classes are built by ASM at run time, so the
server suite now checks that a generated FaceMicroblock resolves the
inherited default and that a generated HollowMicroblock still returns its
own overrides.
Validated with 43 plain-JVM tests, a clean build, and the Java 8 Forge
dedicated-server suite at 3 tests.