Skip to content
This repository was archived by the owner on Feb 16, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/main/resources/forge-1.20.1/block.definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -477,5 +477,12 @@ tags:

- tag: BLOCKS:minecraft:replaceable
condition: isReplaceable
- tag: BLOCKS:minecraft:climbable
condition: isLadder

field_exclusions: [sensitiveToVibration, vibrationalEvents, vibrationSensitivityRadius, canReceiveVibrationCondition, onReceivedVibration]
- tag: GAME_EVENTS:minecraft:@registryname_can_listen
condition:
- hasInventory
- sensitiveToVibration
- "${data.vibrationalEvents?has_content}"
entryprovider: data.getVibrationalEvents()
59 changes: 22 additions & 37 deletions src/main/resources/forge-1.20.1/templates/block/block.java.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public class ${name}Block extends
() -> ForgeRegistries.SOUND_EVENTS.getValue(ResourceLocation.parse("${data.hitSound}")),
() -> ForgeRegistries.SOUND_EVENTS.getValue(ResourceLocation.parse("${data.fallSound}"))
))
<#else>
<#elseif data.soundOnStep != "STONE">
.sound(SoundType.${data.soundOnStep})
</#if>
<#if data.unbreakable>
Expand Down Expand Up @@ -162,6 +162,9 @@ public class ${name}Block extends
<#if (!data.isNotColidable && data.offsetType != "NONE")>
.dynamicShape()
</#if>
<#if data.isReplaceable>
.replaceable()
</#if>
<#if data.offsetType != "NONE">
.offsetType(Block.OffsetType.${data.offsetType})
</#if>
Expand Down Expand Up @@ -190,12 +193,10 @@ public class ${name}Block extends
<#if data.blockBase?has_content>
<#if data.blockBase == "Stairs">
super(() -> Blocks.AIR.defaultBlockState(), <@blockProperties/>);
<#elseif data.blockBase == "PressurePlate">
super(Sensitivity.<#if data.blockSetType == "OAK">EVERYTHING<#else>MOBS</#if>, <@blockProperties/>, BlockSetType.${data.blockSetType});
<#elseif data.blockBase == "PressurePlate" || data.blockBase == "TrapDoor" || data.blockBase == "Door">
super(<#if data.blockBase == "PressurePlate">Sensitivity.<#if data.blockSetType == "OAK">EVERYTHING<#else>MOBS</#if>, </#if><@blockProperties/>, BlockSetType.${data.blockSetType});
<#elseif data.blockBase == "Button">
super(<@blockProperties/>, BlockSetType.${data.blockSetType}, <#if data.blockSetType == "OAK">30, true<#else>20, false</#if>);
<#elseif (data.blockBase == "TrapDoor" || data.blockBase == "Door")>
super(<@blockProperties/>, BlockSetType.${data.blockSetType});
super(<@blockProperties/>, BlockSetType.${data.blockSetType}, <#if data.blockSetType == "OAK">30, true<#else>20, false</#if>);
<#elseif data.blockBase == "FenceGate">
super(<@blockProperties/>, WoodType.OAK);
<#else>
Expand Down Expand Up @@ -389,14 +390,7 @@ public class ${name}Block extends
}
<#else>
@Override public BlockState rotate(BlockState state, Rotation rot) {
if(rot == Rotation.CLOCKWISE_90 || rot == Rotation.COUNTERCLOCKWISE_90) {
if (state.getValue(AXIS) == Direction.Axis.X) {
return state.setValue(AXIS, Direction.Axis.Z);
} else if (state.getValue(AXIS) == Direction.Axis.Z) {
return state.setValue(AXIS, Direction.Axis.X);
}
}
return state;
return RotatedPillarBlock.rotatePillar(state, rot);
}
</#if>

Expand Down Expand Up @@ -447,12 +441,6 @@ public class ${name}Block extends
}
</#if>

<#if data.isReplaceable>
@Override public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
return context.getItemInHand().getItem() != this.asItem();
}
</#if>

<#if data.canProvidePower && data.emittedRedstonePower??>
@Override public boolean isSignalSource(BlockState state) {
return true;
Expand Down Expand Up @@ -506,12 +494,6 @@ public class ${name}Block extends
}
</#if>

<#if data.isLadder>
@Override public boolean isLadder(BlockState state, LevelReader world, BlockPos pos, LivingEntity entity) {
return true;
}
</#if>

<#if data.canRedstoneConnect>
@Override
public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) {
Expand Down Expand Up @@ -552,16 +534,7 @@ public class ${name}Block extends
}
</#if>

<#if hasProcedure(data.onRandomUpdateEvent)>
@OnlyIn(Dist.CLIENT) @Override public void animateTick(BlockState blockstate, Level world, BlockPos pos, RandomSource random) {
super.animateTick(blockstate, world, pos, random);
Player entity = Minecraft.getInstance().player;
int x = pos.getX();
int y = pos.getY();
int z = pos.getZ();
<@procedureOBJToCode data.onRandomUpdateEvent/>
}
</#if>
<@onAnimateTick data.onRandomUpdateEvent/>

<@onDestroyedByPlayer data.onDestroyedByPlayer/>

Expand Down Expand Up @@ -635,7 +608,7 @@ public class ${name}Block extends
public boolean triggerEvent(BlockState state, Level world, BlockPos pos, int eventID, int eventParam) {
super.triggerEvent(state, world, pos, eventID, eventParam);
BlockEntity blockEntity = world.getBlockEntity(pos);
return blockEntity == null ? false : blockEntity.triggerEvent(eventID, eventParam);
return blockEntity != null && blockEntity.triggerEvent(eventID, eventParam);
}

<#if data.inventoryDropWhenDestroyed>
Expand Down Expand Up @@ -667,6 +640,18 @@ public class ${name}Block extends
</#if>
</#if>

<#if data.sensitiveToVibration && data.hasInventory>
@Override @Nullable public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState blockState, BlockEntityType<T> blockEntityType) {
if (!level.isClientSide && blockEntityType == ${JavaModName}BlockEntities.${REGISTRYNAME}.get()) {
return (_level, pos, state, blockEntity) -> {
if (blockEntity instanceof ${name}BlockEntity be)
VibrationSystem.Ticker.tick(_level, be.getVibrationData(), be.getVibrationUser());
};
}
return null;
}
</#if>

<#if data.tintType != "No tint">
@OnlyIn(Dist.CLIENT) public static void blockColorLoad(RegisterColorHandlersEvent.Block event) {
event.getBlockColors().register((bs, world, pos, index) -> {
Expand Down
118 changes: 116 additions & 2 deletions src/main/resources/forge-1.20.1/templates/block/blockentity.java.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,19 @@
package ${package}.block.entity;

<#compress>
public class ${name}BlockEntity extends RandomizableContainerBlockEntity implements WorldlyContainer {
public class ${name}BlockEntity extends RandomizableContainerBlockEntity implements WorldlyContainer
<#if data.sensitiveToVibration>, GameEventListener.Holder<VibrationSystem.Listener>, VibrationSystem</#if> {

private NonNullList<ItemStack> stacks = NonNullList.<ItemStack>withSize(${data.inventorySize}, ItemStack.EMPTY);
private NonNullList<ItemStack> stacks = NonNullList.withSize(${data.inventorySize}, ItemStack.EMPTY);

private final LazyOptional<? extends IItemHandler>[] handlers = SidedInvWrapper.create(this, Direction.values());

<#if data.sensitiveToVibration>
private final VibrationSystem.Listener vibrationListener = new VibrationSystem.Listener(this);
private final VibrationSystem.User vibrationUser = new VibrationUser(this.getBlockPos());
private VibrationSystem.Data vibrationData = new VibrationSystem.Data();
</#if>

<#if data.renderType() == 4>
<#list data.animations as animation>
public final AnimationState animationState${animation?index} = new AnimationState();
Expand Down Expand Up @@ -67,6 +74,14 @@ public class ${name}BlockEntity extends RandomizableContainerBlockEntity impleme
if(compound.get("fluidTank") instanceof CompoundTag compoundTag)
fluidTank.readFromNBT(compoundTag);
</#if>

<#if data.sensitiveToVibration>
if (compound.contains("listener", 10)) {
VibrationSystem.Data.CODEC.parse(new Dynamic<>(NbtOps.INSTANCE, compound.getCompound("listener")))
.resultOrPartial(e -> ${JavaModName}.LOGGER.error("Failed to parse vibration listener for ${data.name}: '{}'", e))
.ifPresent(data -> this.vibrationData = data);
}
</#if>
}

@Override public void saveAdditional(CompoundTag compound) {
Expand All @@ -83,6 +98,12 @@ public class ${name}BlockEntity extends RandomizableContainerBlockEntity impleme
<#if data.isFluidTank>
compound.put("fluidTank", fluidTank.writeToNBT(new CompoundTag()));
</#if>

<#if data.sensitiveToVibration>
VibrationSystem.Data.CODEC.encodeStart(NbtOps.INSTANCE, this.vibrationData)
.resultOrPartial(e -> ${JavaModName}.LOGGER.error("Failed to encode vibration listener for ${data.name}: '{}'", e))
.ifPresent(listener -> compound.put("listener", listener));
</#if>
}

@Override public ClientboundBlockEntityDataPacket getUpdatePacket() {
Expand All @@ -108,9 +129,11 @@ public class ${name}BlockEntity extends RandomizableContainerBlockEntity impleme
return Component.literal("${registryname}");
}

<#if data.inventoryStackSize != 99>
@Override public int getMaxStackSize() {
return ${data.inventoryStackSize};
}
</#if>

@Override public AbstractContainerMenu createMenu(int id, Inventory inventory) {
<#if !data.guiBoundTo?has_content>
Expand Down Expand Up @@ -245,6 +268,97 @@ public class ${name}BlockEntity extends RandomizableContainerBlockEntity impleme
handler.invalidate();
}

<#if data.sensitiveToVibration>
@Override public VibrationSystem.Data getVibrationData() {
return this.vibrationData;
}

@Override public VibrationSystem.User getVibrationUser() {
return this.vibrationUser;
}

@Override public VibrationSystem.Listener getListener() {
return this.vibrationListener;
}

private class VibrationUser implements VibrationSystem.User {

private final int x;
private final int y;
private final int z;
private final PositionSource positionSource;

public VibrationUser(BlockPos blockPos) {
this.x = blockPos.getX();
this.y = blockPos.getY();
this.z = blockPos.getZ();
this.positionSource = new BlockPositionSource(blockPos);
}

@Override public PositionSource getPositionSource() {
return this.positionSource;
}

<#if data.vibrationalEvents?has_content>
@Override public TagKey<GameEvent> getListenableEvents() {
return TagKey.create(Registries.GAME_EVENT, ResourceLocation.parse("${registryname}_can_listen"));
}
</#if>

@Override public int getListenerRadius() {
<#if hasProcedure(data.vibrationSensitivityRadius)>
Level world = ${name}BlockEntity.this.getLevel();
BlockState blockstate = ${name}BlockEntity.this.getBlockState();
return (int) <@procedureOBJToNumberCode data.vibrationSensitivityRadius/>;
<#else>
return ${data.vibrationSensitivityRadius.getFixedValue()};
</#if>
}

@Override public boolean canReceiveVibration(ServerLevel world, BlockPos vibrationPos, GameEvent holder, GameEvent.Context context) {
<#if hasProcedure(data.canReceiveVibrationCondition)>
return <@procedureCode data.canReceiveVibrationCondition {
"x": "x",
"y": "y",
"z": "z",
"vibrationX": "vibrationPos.getX()",
"vibrationY": "vibrationPos.getY()",
"vibrationZ": "vibrationPos.getZ()",
"world": "world",
"entity": "context.sourceEntity()",
"blockstate": "${name}BlockEntity.this.getBlockState()"
}/>
<#else>
return true;
</#if>
}

@Override public void onReceiveVibration(ServerLevel world, BlockPos vibrationPos, GameEvent holder, Entity entity, Entity projectileShooter, float distance) {
<#if hasProcedure(data.onReceivedVibration)>
<@procedureCode data.onReceivedVibration {
"x": "x",
"y": "y",
"z": "z",
"vibrationX": "vibrationPos.getX()",
"vibrationY": "vibrationPos.getY()",
"vibrationZ": "vibrationPos.getZ()",
"world": "world",
"blockstate": "${name}BlockEntity.this.getBlockState()",
"entity": "entity",
"sourceentity": "projectileShooter"
}/>
</#if>
}

@Override public void onDataChanged() {
${name}BlockEntity.this.setChanged();
}

@Override public boolean requiresAdjacentChunksToBeTicking() {
return true;
}
}
</#if>
}
</#compress>
<#-- @formatter:on -->
Loading