Repository navigation
Mimic Blocks
A mimic block stores another block and shows it. There are two kinds:
- Retexture: the block takes on the texture of the applied block (Timber Frames, Fireplace Cornice).
- Held: the block draws the stored block as well (Rope Knot on a fence).
Foundation handles saving, syncing, drops and the models on Fabric and NeoForge. You register your block entity type and say which blocks use which model.
Available since Foundation 1.0.5.
Register your own type with MimicBlockEntity. The ID stays in your mod, so existing worlds keep working.
public static final RegistrySupplier<BlockEntityType<MimicBlockEntity>> FRAME = BLOCK_ENTITY_TYPES.register("timber_frame",
() -> BlockEntityType.Builder.of((pos, state) -> new MimicBlockEntity(FRAME.get(), pos, state), TIMBER_FRAME.get()).build(null));| Method | Does |
|---|---|
getMimicState() |
the stored block, null when empty |
hasMimic() |
true when something is stored |
setMimicState(state) |
stores the block, syncs to clients and re-renders; null or air clears it |
Saved under Mimic. The old Held key (Rope Knot) is still read.
public class FrameBlock extends Block implements EntityBlock {
public static final BooleanProperty APPLIED = MimicBlock.APPLIED;
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new MimicBlockEntity(MyBlockEntities.FRAME.get(), pos, state);
}
@Override
public @NotNull ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
return MimicBlock.use(stack, state, level, pos, player, mimic -> true);
}
@Override
protected @NotNull List<ItemStack> getDrops(BlockState state, LootParams.Builder builder) {
return MimicBlock.addDrops(super.getDrops(state, builder), builder);
}
}MimicBlock.use covers everything the player does:
-
Right-click with a full block: applies it, uses up one item (not in creative), sets
APPLIED. -
Right-click with a pickaxe: gives the block back and clears
APPLIED. - The last argument filters which blocks are allowed.
MimicBlock.canAcceptalready only allows full, normally rendered blocks without a block entity.
addDrops drops the stored block when the mimic block is broken, also through explosions.
Other helpers: MimicBlock.apply(level, pos, state, mimic) and MimicBlock.remove(level, pos, state, drop).
APPLIED is optional. Blocks without it (Rope Knot) always show their stored block.
Register once, early. Use preInitClient, not onInitializeClient, because models are baked before client setup on NeoForge.
MimicModels.retexture(MimicModels.ALL, TIMBER_FOUNDATION);
MimicModels.retexture(MimicModels.placeholder(MimicModels.Mode.UNDERLAY), TIMBER_FRAME);
MimicModels.retexture(MimicModels.tintIndex(1), FIREPLACE_CORNICE);
MimicModels.held(ROPE_KNOT);A QuadRule decides per quad what happens:
| Mode | Result |
|---|---|
KEEP |
quad stays as it is |
REPLACE |
quad gets the texture of the stored block |
UNDERLAY |
quad gets the texture and the original is drawn on top (frame beams over the filling) |
Ready-made rules:
| Rule | Replaces |
|---|---|
MimicModels.ALL |
every quad |
MimicModels.tintIndex(i) |
quads with tint index i, keeps the rest |
MimicModels.placeholder(others) |
quads whose texture name contains placeholder, others for the rest |
Write your own as a lambda: (quad, state) -> ....
Models are matched by block, so all blockstate variants and multipart parts are covered on both loaders. Nothing else to register, no mixin and no ModelLoadingPlugin / ModifyBakingResult in your mod.
- Delete the own block entity, textured models (Fabric and NeoForge) and the NeoForge
getModelDatamixin. - Keep the block entity type ID and register it with
MimicBlockEntity. - Point
APPLIEDtoMimicBlock.APPLIED(same nameapplied, blockstates stay valid). - Replace
useItemOnandplayerWillDestroywithMimicBlock.useandgetDropsas above. - Register the model rule in
preInitClient.