2026-09-05 00:21:08 +02:00
|
|
|
# Loading and assigning multipart parts from Java
|
|
|
|
|
|
|
|
|
|
[API index](../API.md)
|
|
|
|
|
|
2026-10-15 16:39:36 +02:00
|
|
|
`TileMultipart.loadPartList(Collection<TMultiPart>)` and `setPartList(List<TMultiPart>)` adapt to the existing
|
|
|
|
|
virtual Scala-parameter hooks. Both legacy entries are deprecated for callers and remain supported for existing
|
|
|
|
|
binaries, subclasses and reflection.
|
2026-09-05 00:21:08 +02:00
|
|
|
|
|
|
|
|
These are reconstruction operations, not normal placement/removal. Use `TileMultipart.addPart` / `remPart` for world
|
|
|
|
|
changes. Use `MultipartHelper.createTileFromParts(Iterable<TMultiPart>)` to construct a new server composite tile; the
|
|
|
|
|
loader itself does not choose traits, promote a tile or install it in the world.
|
|
|
|
|
|
2026-09-05 14:00:24 +02:00
|
|
|
For separate client/server generation before world/NBT setup and loading, use the
|
|
|
|
|
[staged composite-generation API](COMPOSITE_GENERATION.md).
|
2026-09-16 12:44:33 +02:00
|
|
|
For an uninstalled client tile reconstructed from saved multipart NBT, use the complete
|
|
|
|
|
[client preview helper](CLIENT_PREVIEW.md) instead of assembling these steps.
|
2026-09-05 14:00:24 +02:00
|
|
|
|
2026-09-05 00:21:08 +02:00
|
|
|
## Loading a prepared tile
|
|
|
|
|
|
|
|
|
|
To rebuild a tile using its existing parts, capture them before the loader clears the tile:
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
public static void reloadParts(TileMultipart tile) {
|
|
|
|
|
List<TMultiPart> parts = new ArrayList<>(tile.jPartList());
|
|
|
|
|
tile.loadPartList(parts);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
For a supplied collection, call `preparedTile.loadPartList(parts)`. The tile must already have all capabilities required
|
|
|
|
|
by those parts. An arbitrary `new TileMultipart()` does not acquire slot, inventory or other generated traits by loading.
|
|
|
|
|
|
|
|
|
|
The default implementation:
|
|
|
|
|
|
|
|
|
|
1. Calls the virtual `clearParts()` hook to clear stored parts and trait caches that implement that hook.
|
|
|
|
|
2. Reads the supplied collection in its iteration order. For each part, appends it to stored state, calls `bindPart`,
|
|
|
|
|
then `part.bind(tile)`, and enables ticking if needed. It retains the existing 250-part limit.
|
|
|
|
|
3. With a client world, visits bound parts through the legacy `operate` hook to call `onWorldJoin`.
|
|
|
|
|
4. With either kind of world, calls `notifyPartChange(null)`, which notifies parts, marks the block for update,
|
|
|
|
|
notifies neighboring blocks and recalculates lighting. Without a world, neither world step runs.
|
|
|
|
|
|
|
|
|
|
Loading does not call `onAdded`, call old parts' removal/separation callbacks, unbind old parts, reset an already-set
|
|
|
|
|
ticking flag, check occlusion/duplicates, or send a complete multipart description packet. It is not a general live-tile
|
|
|
|
|
replacement transaction. Reconstruction callers remain responsible for their world/position setup, render updates,
|
|
|
|
|
tile notifications and any full description synchronization required by their existing flow.
|
|
|
|
|
|
|
|
|
|
The Java collection is viewed during the call, not copied first. Its iterator determines the order and mutation
|
|
|
|
|
behavior; do not structurally modify it from callbacks. Replacing a pending list entry during a binding callback can
|
|
|
|
|
change which part is loaded next. After successful loading, normal stored sequence snapshots no longer track later
|
|
|
|
|
edits to the input collection. Part objects remain shared.
|
|
|
|
|
|
|
|
|
|
Call on the game thread. Failures propagate without rollback: clearing happens before iteration, and each part is
|
|
|
|
|
published before binding. A null collection fails after clearing; a null part can remain in partially loaded storage
|
|
|
|
|
before binding fails. A callback exception likewise leaves changes already performed. Supply valid parts rather than
|
|
|
|
|
using these failures to validate a proposed live-world change.
|
|
|
|
|
|
|
|
|
|
## Storage assignment
|
|
|
|
|
|
|
|
|
|
`preparedTile.setPartList(parts)` takes a shallow immutable copy of a non-null Java list, then passes that sequence to
|
|
|
|
|
the virtual legacy setter. It preserves order, duplicates, null entries and object identities. Editing the original
|
|
|
|
|
list later does not alter the stored sequence; parts themselves are not copied.
|
|
|
|
|
|
|
|
|
|
The setter performs storage assignment only. It does not bind parts, rebuild slot/inventory/render caches, update
|
|
|
|
|
ticking, validate parts or notify anything. Existing legacy setter overrides can customize that behavior. Use it only
|
|
|
|
|
where a reconstruction flow specifically needs to stage stored state before its separate loading/binding step.
|
|
|
|
|
|
|
|
|
|
A null list preserves the legacy unset-state sentinel. The generated client render-cache code handles that sentinel;
|
|
|
|
|
most ordinary part queries do not. Use an empty list for ordinary empty storage. The old Scala setter still retains
|
|
|
|
|
the exact supplied sequence, including mutable aliasing; the new Java setter deliberately copies a non-null list.
|
|
|
|
|
|
|
|
|
|
Both operations appear in the [compiling Java example](../../src/test/java/codechicken/multipart/examples/PartLoadingExample.java).
|
2026-10-15 16:39:36 +02:00
|
|
|
Its staging method illustrates assignment only, not a complete tile-promotion procedure.
|
2026-09-05 00:21:08 +02:00
|
|
|
|
|
|
|
|
## Overrides and reflection
|
|
|
|
|
|
|
|
|
|
Dispatch is `setPartList(List)` → virtual `partList_$eq(Seq)` and `loadPartList(Collection)` → virtual
|
|
|
|
|
`loadParts(scala.collection.Iterable)`. Internal reconstruction and storage writes continue using the legacy hooks.
|
|
|
|
|
Keep existing overrides there; overriding just the new Java sibling does not intercept all internal calls.
|
|
|
|
|
|
2026-10-15 16:39:36 +02:00
|
|
|
GuideNH calls the Scala loader directly; older releases select it with assignability-based reflection.
|
|
|
|
|
Schematica's exact `loadParts(scala.collection.Iterable)` lookup also remains valid. Java reflection can now request
|
2026-09-05 00:21:08 +02:00
|
|
|
`getMethod("setPartList", List.class)` or `getMethod("loadPartList", Collection.class)`. Select by parameter type, not
|
|
|
|
|
by the first method with the right name.
|
|
|
|
|
|
|
|
|
|
The Java loader has a distinct name deliberately: the initially planned `loadParts(Collection)` overload made
|
|
|
|
|
`javac --release 8` require `scala.collection.Iterable` during overload resolution even with a Java list argument.
|
|
|
|
|
`loadPartList` lets the example compile without Scala on the consumer compile classpath, while retaining the legacy
|
|
|
|
|
hook and its name. This changes the planned Java name, not any existing entry point.
|
|
|
|
|
|
2026-09-16 12:44:33 +02:00
|
|
|
For an older GuideNH-compatible path, use a Java list of the promoted client parts, retain its existing world/position setup,
|
2026-09-05 00:21:08 +02:00
|
|
|
replace the raw setter with `setPartList`, and call the Collection loader. Preserve its following `notifyTileChange`
|
2026-09-21 23:30:12 +02:00
|
|
|
and `markRender` steps. Current GuideNH no longer uses the raw setter or reflection, but still needs to migrate its
|
|
|
|
|
Scala parts and companion generator to the [static Java replacement](COMPOSITE_GENERATION.md).
|
|
|
|
|
Schematica can select the Collection loader and pass its existing Java list directly.
|
2026-09-16 12:44:33 +02:00
|
|
|
New versions of both integrations should use the [client preview helper](CLIENT_PREVIEW.md).
|