13 KiB
ForgeMultipart Java API
Start here when integrating with ForgeMultipart for Minecraft 1.7.10 / Forge. This describes the algent/java
migration branch. Its new APIs are implemented and tested but do not yet have a minimum published dependency version.
Use a dev artifact containing the methods you need; source Javadocs are packaged with the sources artifact.
Consumers can use the Java surface without importing Scala types. FMP still retains Scala storage, runtime and compatibility bridges, and some extension contracts still need migration. A Scala-authored mod can adopt the Java API without converting the rest of its code to Java.
Direct calls and optional integration
The intended consumer API uses direct typed public calls, without reflection, private-field mixins or Scala companion lookup. Reuse existing entry points where they cover the task. For optional support, isolate FMP-typed code in a compatibility class loaded only after mod-presence and supported-version checks; test absent and present mod loading. Reflection snippets in older guides are legacy interoperability options, not the migration target. Existing reflective binaries remain supported until consumer release and pack adoption.
Choose a guide
| Task | API and guide |
|---|---|
| Register block converters | registerConverter(IPartConverter) — registration, state ownership and committed lifecycle |
| Register part factories during mod initialization | registerPartFactory(IPartFactory2, String...) — factory timing, payload ownership and migration |
| Find the factory registered for a part type | getPartFactory(String) — lookup ownership and Schematica reflection migration |
| Enumerate microblock materials by numeric ID | materialCount(), materialName(int), getMaterial(int) — material enumeration |
| Read a microblock material's block and metadata | BlockMicroMaterial.block(), meta() — typed GuideNH query, identity and overrides |
| Create a microblock with the requested material and side | MicroblockGenerator.create(MicroblockClass, int, boolean) — construction, material traits and GuideNH migration |
| Call generated tile capabilities from Java | TileMultipart, IRedstoneTile and ordinary interfaces — safe compilation and raw-trait pitfalls |
| Add aggregate or lifecycle behavior to generated multipart tiles | registerTrait(marker, trait) — custom Java tile traits, stable capabilities and transformer constraints |
| Refresh slots after a stored part changes shape | refreshPartSlots(TMultiPart) — ownership, equality and notification responsibilities |
| Add material-specific behavior to generated microblocks | registerTrait(String) and IGeneratedMaterial — illuminated Java extension, compilation and side contracts |
| Change an existing FMP saw's cutting strength | ItemSaw.setHarvestLevel(int) — state, lifecycle and Iguana migration |
| Read/index/search a tile's parts | jPartList() — part collection ownership and order |
| Run callbacks while skipping detached parts | forEachPart(Consumer) — callback and override behavior |
| Rebuild parts on an already prepared composite tile | loadPartList(Collection) — part loading |
| Select client/server tile capabilities before preparing state and loading | MultipartGenerator.generateCompositeTile(TileEntity, Iterable, boolean) — staged generation and reflection migration |
| Assign stored parts during reconstruction, without binding or notifications | setPartList(List) — storage assignment |
| Test a candidate against a selected collection of parts | testOcclusion(Collection, candidate) — occlusion queries and generated hooks |
| Test two groups of bounding boxes directly | NormalOcclusionTest.testBoxes(Iterable, Iterable) — box-versus-box queries |
| Read FMP's global render registration ID | TileMultipart.getRenderID() — render-ID meaning, lifecycle and setter |
| Inspect an existing tile or converted placeholder with a named result | getOrConvertTileResult(World, BlockCoord) — conversion outcomes and placement lifecycle |
| Add or remap multipart button attachment orientations | ButtonPart.setOrientation(int, ForgeDirection) — metadata, face mapping and Et Futurum migration |
Each guide explains ownership, lifecycle, legacy replacements and limitations, and links to a compiling Java example exercised by the test suite. The loading/setter APIs are advanced reconstruction operations; ordinary placement and removal should use the existing world APIs below.
Existing Java entry points
These entry points already exist. The links lead to their source/Javadocs; detailed migration guides and checks for compilation without Scala are still pending in these areas. A Java-typed overload can still require Scala on the compile classpath for overload resolution, as the loading guide explains.
| Area | Starting points |
|---|---|
| Define a custom part | Extend TMultiPart; implement the required capability interfaces. The built-in parts show Java implementations |
| Find, place and remove parts | TileMultipart: getTile, canPlacePart, addPart, remPart. Retain the tile returned by changes because generated capabilities can replace the instance |
| Construct a server composite tile from parts, or restore saved multipart NBT | MultipartHelper: createTileFromParts(Iterable), createTileFromNBT(World, NBTTagCompound) |
| Register microblock materials | MicroMaterialRegistry and BlockMicroMaterial |
| Register generated tile traits or pass-through interfaces | MultipartGenerator; see custom tile-trait authoring and safe capability access |
New API examples use Java 8 language/library features. The source path src/main/scala also contains Java classes
because of the current joint-compilation layout; it does not imply that those APIs require Scala source in a consumer.
Supported API and internal hooks
Public visibility alone does not make a method a consumer entry point. Scala's former package-private methods are public in bytecode. Source Javadocs now mark the following audited implementation hooks Internal FMP; keep consumer code on the public operations in the right column. These markers change no visibility, descriptor or behavior and do not deprecate or authorize removing a method. Trait callbacks and generated overrides still run.
| Internal hooks | Consumer operation or responsibility |
|---|---|
TileMultipart.addPart_impl, addPart_do, writeAddPart |
Place through TileMultipart.addPart(world, pos, part); use part loading for prepared reconstruction |
TileMultipart.remPart_impl |
Remove through tile.remPart(part) on the server and retain the returned tile |
TileMultipart.partAdded, partRemoved |
Lifecycle callbacks for trait overrides; callers use placement/removal APIs |
TileMultipart.from, copyFrom, loadFrom, setValid |
FMP composite transitions; use staged generation and loading for consumer reconstruction |
MicroMaterialRegistry.setupIDMap, calcMaxCuttingStrength |
FMP initializes IDs and cutting strength; register materials at initialization and read the resulting values |
MicroMaterialRegistry.loadIcons |
FMP dispatches client texture callbacks; override the supported IMicroMaterial.loadIcons() material callback |
MicroMaterialRegistry.writeIDMap, readIDMap |
FMP's whole-map handshake; part packets use writeMaterialID / readMaterialID for individual IDs |
The registry's matching companion methods carry the same internal marker. This is the bounded Phase 9.2 audit, not a claim that every other public member is a supported API. See TileMultipart's Javadocs and registry Javadocs for method-specific details.
Three advanced methods remain supported because consumers use them directly:
bindPart(part)updates capability caches through generated overrides. It does not insert the part, change its tile binding or perform placement/notifications. The legacy OpenComputers integration clears a print part's old slot entries before calling it to populate a changed slot mask. A repeated call does not clear obsolete slots and may append entries in other trait caches. UserefreshPartSlotsfor that migration; full reconstruction usesloadPartList.refreshPartSlots(part)replaces OpenComputers' direct generated-array mutation. Generated slotted tiles clear equal cached entries and invoke the virtual bind chain once; base tiles do nothing. It leaves ownership, storage, validation and notifications to the caller. See the slot-refresh contract.internalPartChange(part)sends localonPartChangedcallbacks through the retainedoperatehook. The base traversal captures list order, skips parts whose binding is null at callback time, and excludes parts equal to the changed part usingpart.equals(p). Null broadcasts to all eligible parts. A non-null binding to another tile still qualifies. Callback failures stop traversal and propagate. ProjectRed deliberately handles dirty state, packets and external neighbors separately; this method does none of those.notifyPartChangealso performs world update/neighbor/lighting notifications when needed.
No reflection is needed to call any of these methods. operate and getOrConvertTile2 retain their documented legacy
contracts and Java replacements; neither receives an internal-only marker. Removing those bridges still requires
consumer and internal migration gates. The consumer audit
records the checked source calls and validation.
Compatibility and remaining work
Deprecated Scala-facing entry points remain callable, with their descriptors and supported override dispatch retained. Follow the method-specific guide: a Java sibling is not automatically a replacement override hook, and reflection must select the intended parameter types when a method is overloaded.
An illuminated Java microblock extension now covers registration, material traits, light aggregation and halo geometry, with compiling examples and Forge coverage. Its physical-client rendering and ProjectRed adoption remain open. Converter registration and lifecycle are documented and tested. Stable tile capability access covers safe Java calls, ProjectRed redstone queries and OpenComputers slot refresh. Custom Java tile-trait authoring covers registration, stable capabilities, lifecycle/state rules and transformer constraints with generated Forge coverage. Supported button orientation mapping replaces Et Futurum's reflective array mutation. Supported saw-strength mutation replaces Iguana's private-field access. ProjectRed's existing Scala traits remain supported until adoption.
All ten entries in the plan's Phase 9.1 API table have Java replacements. That table is a bounded list of signatures; the broader API, extension and consumer adoption work above remains open.
FMP-side implementation is separate from consumer releases and target-pack adoption. Retiring legacy bridges or the Scala dependency requires those gates and removal of FMP's remaining internal Scala users.
| Need | Document |
|---|---|
| What is complete and what comes next? | Working handoff, migration plan |
| Which consumers need changes, releases and pack adoption? | Consumer adoption ledger |
| Which binary names, reflective lookups and runtime contracts must survive? | ABI inventory, source consumer audit |
| What has been tested and what still needs a client/pack run? | Migration history, manual release checks |
| Why is some Scala or older Java syntax retained? | Modern Java policy, compiler/toolchain handoff |