Files
ForgeMultipart/docs/api/COMPOSITE_GENERATION.md
Algent ed861b6ca5 docs: trim audit noise from API guides
- drop per-guide Validation sections; manual gates stay in MANUAL_CHECKS
- drop audit/provenance lines (reference checkouts, dated refreshes, commit pins)
- state version status and Scala-free compile check once in API.md
- replace API.md status prose with link to migration status
- fix RELEASE_NOTES dangling sentence
- rewrite README for GTNH fork and Java port
2026-10-15 16:39:36 +02:00

5.6 KiB

Staged composite-tile generation

Java API index

MultipartGenerator.generateCompositeTile(TileEntity, java.lang.Iterable<TMultiPart>, boolean) selects a tile's generated capabilities without loading its parts. The compiling example then assigns world/position and loads the same parts, leaving installation to its caller.

TileMultipart prepared = MultipartGenerator.generateCompositeTile(candidate, parts, client);
// Prepare world, coordinates and any required tile NBT before loading.
prepared.loadPartList(parts);

Use a List<TMultiPart> or another repeatable collection when the same parts will subsequently be loaded. Generation accepts Iterable<TMultiPart>; loading accepts Collection<TMultiPart>. A one-shot iterable can select traits, but cannot then supply the same parts again. The generator reads the input once on every call, including candidate reuse, without copying it. Do not mutate it during generation or change the required capabilities between generation and loading.

Selection and ownership

Candidate and required traits Result
Null or a non-multipart tile A fresh empty generated tile
Registered multipart class with exactly the required trait set The same tile, with all existing state untouched
Registered multipart class with a different trait set or side A fresh empty replacement; the candidate remains untouched
Multipart class unknown to the generator NoSuchElementException, after reading the parts

An empty iterable is valid and chooses the side's base tile. Order and duplicate parts do not add extra copies of a trait, but each input entry is visited. The generator caches constructed classes; fresh tiles are still distinct objects.

Generation does not load or bind parts, assign world/position, copy source state, invalidate an old tile, install a replacement or send notifications. New tiles have empty part storage and caches. Existing part-to-tile bindings remain until the caller loads/rebinds them; loading a replacement does not clear the old tile's stored list.

Call after trait registration on the initialization/game thread. Trait selection uses existing caches and scratch state. Iterator exceptions, null inputs/elements and unregistered-class failures propagate without rollback of that internal state. Generation is neither a placement check nor a transaction for replacing a live tile.

Side and loading lifecycle

client=true selects client tile capabilities. It does not turn server parts into client part variants; supply the correctly constructed parts yourself. The world assigned for loading must agree with the intended side. The example also allows null for explicitly worldless staging, which omits world-dependent loading callbacks.

Prepare position, world and any required tile NBT before loading. With a world, the default loader notifies parts and neighbors and updates lighting; a client world also triggers onWorldJoin. Preserve the integration's subsequent installation, tile/render notifications and synchronization. Do not add them blindly to a worldless preview.

For ordinary world placement use TileMultipart.canPlacePart / addPart. For immediate server construction and loading, the existing MultipartHelper.createTileFromParts remains supported. It is not a substitute for consumers that must set state between generation and loading.

Schematica and GuideNH migration

For saved-NBT client previews, prefer the complete client preview helper. It owns client part construction, generation, loading and local render preparation. Use this lower-level generator for reconstruction flows that need to prepare or reuse a candidate tile themselves.

Prefer the direct call MultipartGenerator.generateCompositeTile(candidate, parts, client), as in the compiling example. Gate optional typed integration code as described in the API index. For temporary interoperability with an existing reflective integration, the method can also be resolved with:

Method generate = MultipartGenerator.class.getMethod(
    "generateCompositeTile", TileEntity.class, java.lang.Iterable.class, boolean.class);
TileMultipart tile = (TileMultipart) generate.invoke(null, candidate, parts, client);

An optional integration can obtain the owner through Class.forName("codechicken.multipart.MultipartGenerator"). Pass a Java list directly and cache the method during integration initialization.

  • Older Schematica integrations: remove JavaConversions.collectionAsScalaIterable from generation; keep material resolution, factory lookup, side-specific microblock construction, per-part NBT loading and rejection when any part is missing. Preserve its following tile readFromNBT, loadPartList(parts) and per-part notification order.
  • Older GuideNH integrations: keep promotion of parts to their client variants, then use a Java list for generation. Preserve its same-instance branch, copying of coordinates/world/block state, storage assignment where required, loading, notifyTileChange and markRender. Generation does not perform any of those steps automatically.

The old companion's generateCompositeTile(TileEntity, scala.collection.Iterable, boolean) keeps its descriptor and body, deprecated for callers in favor of the static Java entry. Existing direct calls and Schematica's exact reflective lookup remain valid. GuideNH's separate microblock-generator call has an existing Java replacement.