Skip to content

Entity Processor Framework

finnsetchell edited this page Aug 15, 2026 · 2 revisions

Entity processor framework

Most structure processors work on blocks. This one works on entities, letting a processor change or equip the mobs and armor stands saved into a piece as it is placed. equip_armor_stand_processor is the only one MSL ships.

This page is for mod developers writing their own entity processor in Java. If you only write datapacks, you want the processor page instead.

Ported and adapted from YUNG's API.

Known issue: entity processors only run on Fabric. On NeoForge they are silently skipped, so anything built on this framework does nothing there. Detail below.

Writing one

Extend StructureEntityProcessor and implement processEntity, plus codec() as with any other processor:

public class MyProcessor extends StructureEntityProcessor {
    public static final MapCodec<MyProcessor> MAP_CODEC = /* ... */;

    @Override
    public StructureTemplate.StructureEntityInfo processEntity(
            ServerLevelAccessor level,
            BlockPos piecePos,
            BlockPos pieceBottomCenterPos,
            StructureTemplate.StructureEntityInfo localInfo,
            StructureTemplate.StructureEntityInfo globalInfo,
            StructurePlaceSettings settings) {
        // return globalInfo unchanged to leave the entity alone
    }

    @Override
    public MapCodec<MyProcessor> codec() {
        return MAP_CODEC;
    }
}

Register the codec in the structure processor registry, the same way as a block processor.

The contract

  • localInfo carries piece-local coordinates. Do not modify its pos or blockPos.
  • globalInfo carries real world coordinates and already reflects any processor that ran before yours. Do not modify its pos or blockPos either.
  • Return a new StructureEntityInfo to change the entity, globalInfo to leave it alone, or null to delete it entirely.
  • Whatever you return becomes the globalInfo seen by the next processor in the list, so order in the processor list matters.

Identify the entity by reading the id string from its NBT. Use globalInfo.blockPos as a per-entity random seed if you need one to be stable.

You can also override processBlock on the same class if a processor needs to touch both.

Loader support

On Fabric a mixin runs the entity processors during entity placement and spawns the results itself. It only activates for pieces whose processor list actually contains an entity processor, so it costs nothing elsewhere.

On NeoForge nothing runs them. NeoForge does provide its own entity hook, but it takes different parameters from MSL's method, so MSL's is a separate overload that the loader never calls. Vanilla has no entity hook at all. The result is a silent no-op rather than a crash or a log line.

If you are writing an entity processor today, treat it as Fabric-only and test there.

Gotchas

  • Failures during entity placement are swallowed on Fabric. A malformed entity produces no log line, just a missing or unmodified entity. Check results in game rather than trusting a clean log.
  • A gametest that calls your processor directly will pass even if the framework never invokes it. Testing the method body proves the logic, not the wiring. Verify by generating a real structure.

See also

Clone this wiki locally