BasicEntityBlock and TickableBlockEntity added to simplify block entity creation

This commit is contained in:
XevianLight
2026-02-03 20:00:52 -07:00
parent 012985441f
commit df344034a6
11 changed files with 275 additions and 27 deletions

View File

@@ -4,33 +4,29 @@ import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.xevianlight.aphelion.block.custom.base.BasicEntityBlock;
import net.xevianlight.aphelion.block.entity.custom.OxygenTestBlockEntity;
import net.xevianlight.aphelion.block.entity.custom.TestBlockEntity;
import net.xevianlight.aphelion.core.init.ModBlockEntities;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class OxygenTestBlock extends BaseEntityBlock {
public class OxygenTestBlock extends BasicEntityBlock {
public OxygenTestBlock(Properties properties) {
super(properties);
super(properties, true);
}
public static final MapCodec<OxygenTestBlock> CODEC = simpleCodec(OxygenTestBlock::new);
@Override
protected MapCodec<? extends BaseEntityBlock> codec() {
protected @NotNull MapCodec<? extends BaseEntityBlock> codec() {
return CODEC;
}
@Override
public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
public @Nullable BlockEntity newBlockEntity(@NotNull BlockPos blockPos, @NotNull BlockState blockState) {
return new OxygenTestBlockEntity(blockPos, blockState);
}
@@ -39,21 +35,13 @@ public class OxygenTestBlock extends BaseEntityBlock {
}
@Override
public @Nullable <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
if (level.isClientSide) {
return null;
}
return createTickerHelper(blockEntityType, ModBlockEntities.OXYGEN_TEST_BLOCK_ENTITY.get(), (level1, blockPos, blockState, oxygenTestBlockEntity) -> oxygenTestBlockEntity.tick(level1, blockPos, blockState));
}
@Override
public RenderShape getRenderShape(BlockState pState) {
@NotNull
public RenderShape getRenderShape(@NotNull BlockState pState) {
return RenderShape.MODEL;
}
@Override
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
protected void onRemove(BlockState state, @NotNull Level level, @NotNull BlockPos pos, BlockState newState, boolean movedByPiston) {
if (state.getBlock() != newState.getBlock()) {
BlockEntity blockEntity= level.getBlockEntity(pos);
if (blockEntity instanceof OxygenTestBlockEntity oxygenTestBlockEntity) {

View File

@@ -0,0 +1,44 @@
package net.xevianlight.aphelion.block.custom;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.xevianlight.aphelion.block.custom.base.BasicHorizontalEntityBlock;
import net.xevianlight.aphelion.block.entity.custom.RocketAssemblerBlockEntity;
import org.jetbrains.annotations.Nullable;
public class RocketAssemblerBlock extends BasicHorizontalEntityBlock {
public RocketAssemblerBlock(Properties properties) {
super(properties, true);
}
public static final MapCodec<RocketAssemblerBlock> CODEC = simpleCodec(RocketAssemblerBlock::new);
@Override
protected MapCodec<? extends BaseEntityBlock> codec() {
return CODEC;
}
public static Properties getProperties() {
return Properties
.of()
.sound(SoundType.METAL)
.destroyTime(2f)
.explosionResistance(10f)
.requiresCorrectToolForDrops();
}
@Override
public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new RocketAssemblerBlockEntity(blockPos, blockState);
}
}

View File

@@ -0,0 +1,61 @@
package net.xevianlight.aphelion.block.custom.base;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class BasicEntityBlock extends BaseEntityBlock {
private final boolean shouldTick;
private BlockEntityType<?> entity;
protected BasicEntityBlock(Properties properties, boolean shouldTick) {
super(properties);
this.shouldTick = shouldTick;
}
@Override
protected @NotNull RenderShape getRenderShape(@NotNull BlockState state) {
return RenderShape.MODEL;
}
public static Item.Properties getItemProperties() {
return new Item.Properties();
}
@Override
public @Nullable <T extends BlockEntity> BlockEntityTicker<T> getTicker(@NotNull Level level, @NotNull BlockState state, @NotNull BlockEntityType<T> blockEntityType) {
return !shouldTick ? null : (entityLevel, pos, blockState, blockEntity) -> {
if (blockEntity instanceof TickableBlockEntity tickable) {
long time = level.getGameTime() - pos.hashCode();
tickable.tick(entityLevel, time, blockState, pos);
if (level.isClientSide()) {
tickable.clientTick((ClientLevel) level, time, state, pos);
} else {
tickable.serverTick((ServerLevel) level, time, state, pos);
}
if (!tickable.isInitialized()) tickable.firstTick(level, state, pos);
}
};
}
@Override
protected void onRemove(BlockState state, @NotNull Level level, @NotNull BlockPos pos, BlockState newState, boolean movedByPiston) {
if (state.getBlock() != newState.getBlock()) {
if (level.getBlockEntity(pos) instanceof TickableBlockEntity tickable) {
tickable.onRemoved();
}
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
}

View File

@@ -0,0 +1,42 @@
package net.xevianlight.aphelion.block.custom.base;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class BasicHorizontalEntityBlock extends BasicEntityBlock {
protected BasicHorizontalEntityBlock(Properties properties, boolean shouldTick) {
super(properties, shouldTick);
this.registerDefaultState(this.getStateDefinition().any());
}
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
@Override
protected @NotNull BlockState rotate(BlockState state, Rotation rotation) {
return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
}
@Override
protected @NotNull BlockState mirror(BlockState state, Mirror mirror) {
return state.rotate(mirror.getRotation(state.getValue(FACING)));
}
@Override
public @Nullable BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING);
}
}

View File

@@ -0,0 +1,23 @@
package net.xevianlight.aphelion.block.custom.base;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
public interface TickableBlockEntity {
void tick(Level entityLevel, long time, BlockState blockState, BlockPos pos);
void clientTick(ClientLevel level, long time, BlockState state, BlockPos pos);
void serverTick(ServerLevel level, long time, BlockState state, BlockPos pos);
default boolean isInitialized() {
return true;
};
void firstTick(Level level, BlockState state, BlockPos pos);
default void onRemoved() {}
}

View File

@@ -2,13 +2,16 @@ package net.xevianlight.aphelion.block.entity.custom;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import static net.xevianlight.aphelion.Aphelion.LOGGER;
import net.minecraft.world.level.chunk.LevelChunk;
import net.xevianlight.aphelion.block.custom.base.TickableBlockEntity;
import net.xevianlight.aphelion.core.init.ModBlockEntities;
import net.xevianlight.aphelion.core.saveddata.EnvironmentSavedData;
import net.xevianlight.aphelion.util.FloodFill3D;
@@ -16,13 +19,20 @@ import org.openjdk.nashorn.internal.runtime.regexp.joni.exception.ValueException
import java.util.*;
public class OxygenTestBlockEntity extends BlockEntity {
public class OxygenTestBlockEntity extends BlockEntity implements TickableBlockEntity {
public OxygenTestBlockEntity(BlockPos pos, BlockState blockState) {
super(ModBlockEntities.OXYGEN_TEST_BLOCK_ENTITY.get(), pos, blockState);
}
public boolean isInitialized;
@Override
public boolean isInitialized() {
return this.isInitialized;
}
private LevelChunk lastChunk;
private int lastChunkX = Integer.MIN_VALUE, lastChunkZ = Integer.MIN_VALUE;
@@ -231,9 +241,8 @@ public class OxygenTestBlockEntity extends BlockEntity {
int refreshAfter = 20;
public void tick(Level level, BlockPos pos, BlockState blockState) {
if (level.isClientSide) return;
@Override
public void serverTick(ServerLevel level, long time, BlockState blockState, BlockPos pos) {
ticks++;
if (ticks >= refreshAfter) {
getEnclosedBlocks();
@@ -244,4 +253,18 @@ public class OxygenTestBlockEntity extends BlockEntity {
}
}
@Override
public void clientTick(ClientLevel level, long time, BlockState state, BlockPos pos) {
}
@Override
public void tick(Level entityLevel, long time, BlockState blockState, BlockPos pos) {
}
@Override
public void firstTick(Level level, BlockState state, BlockPos pos) {
this.isInitialized = true;
}
}

View File

@@ -0,0 +1,60 @@
package net.xevianlight.aphelion.block.entity.custom;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.xevianlight.aphelion.block.custom.base.TickableBlockEntity;
import net.xevianlight.aphelion.core.init.ModBlockEntities;
import net.xevianlight.aphelion.util.RocketStructure;
import org.apache.commons.lang3.NotImplementedException;
public class RocketAssemblerBlockEntity extends BlockEntity implements TickableBlockEntity {
public boolean isInitialized;
@Override
public boolean isInitialized() {
return isInitialized;
}
public RocketAssemblerBlockEntity(BlockPos pos, BlockState blockState) {
super(ModBlockEntities.ROCKET_ASSEMBLER_BLOCK_ENTITY.get(), pos, blockState);
}
public void tick(Level level1, BlockPos blockPos, BlockState blockState) {
}
public boolean getPlatform() {
// TODO
throw new NotImplementedException();
}
public RocketStructure scan() {
// TODO
throw new NotImplementedException();
}
@Override
public void tick(Level entityLevel, long time, BlockState blockState, BlockPos pos) {
}
@Override
public void clientTick(ClientLevel level, long time, BlockState state, BlockPos pos) {
}
@Override
public void serverTick(ServerLevel level, long time, BlockState state, BlockPos pos) {
}
@Override
public void firstTick(Level level, BlockState state, BlockPos pos) {
this.isInitialized = true;
}
}