Files
ForgeMultipart/docs/api/MICROBLOCK_CREATION.md
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

92 lines
6.4 KiB
Markdown
Raw Normal View History

# Creating and recreating microblocks
[Java API index](../API.md)
Use the existing `MicroblockGenerator.create(MicroblockClass, int material, boolean client)` static Java entry.
It delegates to the retained companion implementation. This guide describes `algent/java`; it does not establish a
minimum published dependency version. No additional creation API or production behavior change is introduced here.
```java
Microblock part = MicroblockGenerator.create(microClass, materialId, client);
```
`microClass.create(client, materialId)` uses the same generator; note its different parameter order. To find a factory
by part type, use [registered factory lookup](FACTORY_LOOKUP.md) and verify that it is a `MicroblockClass`.
## Construction and ownership
Creation chooses the factory's base trait and, for the client path, its client trait. It then resolves the material
from the active numeric ID map and invokes `IGeneratedMaterial.addTraits` when implemented. Finally it constructs a
fresh instance of the resulting generated class with the material ID as its constructor argument. Generated classes
are cached; part instances are not reused. Trait initializers execute during construction.
The generator does not copy an existing part, assign a requested shape, load NBT, bind the part or install a tile.
Stock face microblocks begin with shape zero, which is not a completed placement shape. Restore shape/NBT before
using geometry or rendering and before [preparing/loading a composite tile](COMPOSITE_GENERATION.md).
Resolve the intended material before construction. A later `part.load(tag)` or `material_$eq` updates stored material
but does not regenerate the class's material traits. For NBT reconstruction, resolve `tag.getString("material")`,
create the correctly sided part with that ID, then call `load(tag)`. Ordinary `MultiPartRegistry.loadPart` selects the
server/NBT path; it does not provide client preview construction.
Call after factory/trait registration and material-map initialization, on the initialization/game thread. Numeric IDs
belong to the active map and may change across sessions or a multiplayer handshake; persist material names, not IDs.
See [material enumeration and ownership](MATERIAL_ENUMERATION.md). Invalid/unresolved IDs, null factories, callback
exceptions and constructor failures propagate; there is no new fallback or rollback.
## Material-provided traits
`IGeneratedMaterial.addTraits(BitSet, MicroblockClass, boolean)` receives the exact factory and side supplied by the
caller. Its borrowed mutable bit set already contains the selected base/client traits. Add registered trait IDs;
do not remove required traits. The generator consumes the modified set immediately after the callback.
Do not retain the set or recursively call this generator from the callback: the next creation on that thread clears
and reuses it. On failure, already-performed callback side effects and scratch mutations remain; a later creation
clears scratch again. Thread-local scratch does not make registry changes or the complete generator thread-safe.
ProjectRed's existing external Scala trait path remains supported. The Forge fixture confirms material-driven trait
injection and generated behavior; this does not replace the planned representative external Java extension example
or authorize removing Scala-signature support before consumer release/adoption.
## GuideNH migration
GuideNH `7d8fb44e77b9` explicitly resolves the companion's `create(MicroblockClass, int, boolean)` and invokes it on
2026-09-05 14:58:24 +02:00
`MODULE$`. It does not automatically discover the existing static method. Prefer the direct typed creation example
below, with [gated optional integration](../API.md#direct-calls-and-optional-integration). The following cache is only
a temporary interoperability option for consumers retaining reflection:
```java
Class<?> generator = Class.forName("codechicken.microblock.MicroblockGenerator");
Class<?> factoryType = Class.forName("codechicken.microblock.MicroblockClass");
Method create = generator.getMethod("create", factoryType, int.class, boolean.class);
Object promoted = create.invoke(null, microClass, materialId, true);
```
Keep the exact parameter types and order. The old companion class, singleton, descriptor and behavior remain
unchanged for existing releases.
GuideNH's promotion recreates the source family and material on the client, then copies the encoded shape byte.
The [compiling Java example](../../src/functionalTest/java/codechicken/multipart/examples/MicroblockCreationExample.java)
implements that core-data policy through `setShape(size, slot)`, preserving all eight shape bits. `getShape()` alone
is only the slot nibble, while `shape()` returns the complete byte. The example leaves source bindings untouched and
returns an unbound replacement. It is not a clone of arbitrary custom-part state or a shape-validity check.
Factory, material and shape are captured before construction, as in GuideNH. Material callbacks can have side effects;
capturing shape after creation could copy a callback-modified value instead of the original one.
Public `setShape` uses the virtual shape setter; GuideNH's old private-field write bypassed that dispatch. Validate
custom traits overriding these hooks before adopting the change. Preserve its existing missing/failed-promotion
handling, part order, Java collection migration, tile state setup and subsequent loading/notifications. Do not copy
2026-09-05 14:58:24 +02:00
the source tile binding to the new part. Private material-field access has a separate [typed query guide](MATERIAL_ACCESS.md).
## Side and validation limits
Use `client=true` on the physical client for client variants. Unlike generating a client tile container, normal client
microblock construction cannot run in the dedicated-server harness: Forge strips `MicroblockClass.clientTrait()`.
The side parameter selects traits; it does not infer a world side or bypass Forge's side-only filtering.
Server Forge tests cover both exact reflective entries, factory/material identity, fresh instances, shape/NBT
ownership, material trait injection, callback failures and scratch reuse. The Java example tests all 256 shape-byte
values without copying bindings or altering the source and compiles without Scala. Archived callers, existing APIs,
method bodies and generated dumps are checked separately. Physical-client creation and GuideNH preview/GPU output
remain [manual release checks](../../JAVA_MIGRATION_MANUAL_CHECKS.md); reference checkouts and adoption status are unchanged.