Skip to content

Prefab loading

A prefab is a JSON file at data/<namespace>/prefabs/<id>.json describing a reusable in-world structure — block volumes, anchors, lobby zones, sub-prefab references, screens, labels. The Prefab record is the typed shape after parsing; PrefabElement is the sealed list of element kinds; PrefabMigrations runs forward-migration steps on older files so the codec only ever sees the current schema.

  • You want game geometry defined in data files, not Java.
  • You want one prefab template to spawn at many sites with different bindings.
  • You want /reload to re-instantiate edited prefabs without restarting.
package me.zlex.conduit.prefab;
public record Prefab(int schema, Map<String, Integer> params, List<PrefabElement> elements) {
public static final int SCHEMA_VERSION_CURRENT = 2;
public record Id(Identifier identifier) {
public static Id of(String namespace, String path);
}
public static final Codec<Prefab> CODEC;
}
public sealed interface PrefabElement {
String type();
record BlockVolume(BlockVolumeShape shape, String blockState, IntVec3 from, IntVec3 to)
implements PrefabElement {}
// Anchor, Zone, Screen, Label, SubPrefab — see PrefabElement source.
}
public final class PrefabMigrations {
public static JsonObject upgrade(JsonObject root);
}

SceneStore is the loader — it discovers, parses, and registers every prefab on server start and on /reload. You don’t usually call the codec yourself.

A minimal prefab JSON:

{
"schema": 2,
"params": { "xMin": -8, "xMax": 8, "zMin": -8, "zMax": 8, "yFloor": 100, "yCeiling": 105 },
"elements": [
{
"type": "block-volume",
"shape": "cuboid",
"block": "minecraft:barrier",
"from": ["@xMin", "@yFloor", "@zMin"],
"to": ["@xMax", "@yFloor", "@zMax"]
},
{
"type": "block-volume",
"shape": "walls",
"block": "minecraft:barrier",
"from": ["@xMin", "@yFloor + 1", "@zMin"],
"to": ["@xMax", "@yCeiling", "@zMax"]
}
]
}

Loaded by the engine via:

import me.zlex.conduit.prefab.Prefab;
import me.zlex.conduit.prefab.SceneStore;
Prefab.Id id = Prefab.Id.of("my-mod", "arena-room");
Prefab prefab = SceneStore.prefab(id); // null if not loaded
  • schema is a required integer field; the engine refuses files with a schema newer than SCHEMA_VERSION_CURRENT.
  • Migration v1 → v2 swapped the cardinal facing string on screen/label elements for an integer yawDegrees field. The scaffold runs in order so future migrations don’t have to be v1 → vN jumps.
  • The codec validates ordering — from/to corners are normalised at instantiation time, not at parse time.