move most block code into SimpleBlockWithEntity.java to simplify creation of custom blocks

This commit is contained in:
Robin Bärtschi 2024-06-26 10:51:00 +02:00
parent 079370e208
commit d90374272e
8 changed files with 116 additions and 157 deletions

View File

@ -99,10 +99,7 @@ configurations["junitImplementation"].extendsFrom(configurations.implementation.
//minecraft.accessTransformers.entry public net.minecraft.client.Minecraft textureManager # textureManager
// Default run configurations.
// These can be tweaked, removed, or duplicated as needed.
runs {
// applies to all the run configs below
configureEach {
// Recommended logging data for an userdev environment
@ -112,9 +109,6 @@ runs {
// "REGISTRYDUMP": For getting the contents of all registries.
systemProperty ("forge.logging.markers", "REGISTRIES")
// Recommended logging level for the console
// You can set various levels here.
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
systemProperty ("forge.logging.console.level", "debug")
modSource (project.sourceSets["main"])
@ -136,9 +130,6 @@ runs {
programArgument ("--nogui")
}
// This run config launches GameTestServer and runs all registered gametests, then exits.
// By default, the server will crash when no gametests are provided.
// The gametest system is also enabled by default for other run configs under the /test command.
create("gameTestServer") {
systemProperty ("forge.enabledGameTestNamespaces", modId)
@ -146,22 +137,12 @@ runs {
create("data") {
// example of overriding the workingDirectory set in configureEach above, uncomment if you want to use it
// workingDirectory project.file("run-data")
// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
programArguments.addAll ("--mod", modId, "--all", "--output", file("src/generated/resources/").absolutePath, "--existing", file("src/main/resources/").absolutePath)
}
}
dependencies {
// Specify the version of Minecraft to use.
// Depending on the plugin applied there are several options. We will assume you applied the userdev plugin as shown above.
// The group for userdev is net.neoforge, the module name is neoforge, and the version is the same as the neoforge version.
// You can however also use the vanilla plugin (net.neoforged.gradle.vanilla) to use a version of Minecraft without the neoforge loader.
// And its provides the option to then use net.minecraft as the group, and one of; client, server or joined as the module name, plus the game version as version.
// For all intends and purposes: You can treat this dependency as if it is a normal library you would use.
implementation ("net.neoforged:neoforge:${neoVersion}")
implementation("mcjty.theoneprobe:theoneprobe:${topVersion}")
@ -179,9 +160,9 @@ dependencies {
// Example mod dependency with JEI
// The JEI API is declared for compile time use, while the full JEI artifact is used at runtime
// compileOnly("mezz.jei:jei-${jeiMcVersion}-common-api:${jeiVersion}")
// compileOnly("mezz.jei:jei-${jeiMcVersion}-neoforge-api:${jeiVersion}")
// runtimeOnly("mezz.jei:jei-${jeiMcVersion}-neoforge:${jeiVersion}")
compileOnly("mezz.jei:jei-${jeiMcVersion}-common-api:${jeiVersion}")
compileOnly("mezz.jei:jei-${jeiMcVersion}-neoforge-api:${jeiVersion}")
runtimeOnly("mezz.jei:jei-${jeiMcVersion}-neoforge:${jeiVersion}")
// Example mod dependency using a mod jar from ./libs with a flat dir repository
// This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar

View File

@ -46,5 +46,5 @@ junitVersion=5.10.2
assertjVersion=3.25.1
topVersion=1.21_neo-12.0.0-1
reiVersion=16.0.729
jeiVersion=19.0.0.9
jeiVersion=19.0.0.11
jeiMcVersion=1.21

View File

@ -3,25 +3,17 @@ package robaertschi.environmenttech.level.block;
import com.mojang.serialization.MapCodec;
import lombok.extern.slf4j.Slf4j;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.*;
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.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.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.CollisionContext;
@ -36,15 +28,13 @@ import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault()
@Slf4j
public class EnvCollectorBlock extends BaseEntityBlock {
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
public class EnvCollectorBlock extends SimpleBlockWithEntity<EnvCollectorBlockEntity> {
public static final MapCodec<EnvCollectorBlock> CODEC = simpleCodec(EnvCollectorBlock::new);
public EnvCollectorBlock(Properties properties) {
super(properties);
super(properties, ETBlockEntities.ENV_COLLECTOR_BLOCK_ENTITY);
}
public static VoxelShape makeShape(){
VoxelShape shape = Shapes.empty();
shape = Shapes.join(shape, Shapes.box(0, 0, 0, 1, 0.125, 1), BooleanOp.OR);
@ -69,45 +59,11 @@ public class EnvCollectorBlock extends BaseEntityBlock {
return CODEC;
}
@SuppressWarnings("deprecation")
@Override
protected @NotNull RenderShape getRenderShape(BlockState pState) {
return RenderShape.MODEL;
}
@Override
protected @NotNull VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
return SHAPE;
}
@Override
public @NotNull BlockState rotate(BlockState state, LevelAccessor level, BlockPos pos, Rotation direction) {
return state.setValue(FACING, direction.rotate(state.getValue(FACING)));
}
@SuppressWarnings("deprecation")
@Override
protected @NotNull BlockState mirror(BlockState pState, Mirror pMirror) {
return pState.rotate(pMirror.getRotation(pState.getValue(FACING)));
}
@Nullable
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
return this.defaultBlockState().setValue(FACING, pContext.getHorizontalDirection().getOpposite());
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> pBuilder) {
pBuilder.add(FACING);
}
@Override
protected void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pMovedByPiston) {
pLevel.updateNeighborsAt(pPos, this);
super.onRemove(pState, pLevel, pPos, pNewState, pMovedByPiston);
}
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) {
@ -138,19 +94,4 @@ public class EnvCollectorBlock extends BaseEntityBlock {
return ItemInteractionResult.SUCCESS;
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level pLevel, BlockState pState, BlockEntityType<T> pBlockEntityType) {
return createTickerHelper(pBlockEntityType, ETBlockEntities.ENV_COLLECTOR_BLOCK_ENTITY.get(), this::tick);
}
public void tick(Level level, BlockPos blockPos, BlockState blockState, EnvCollectorBlockEntity envCollectorBlockEntity) {
if (!level.isClientSide()) {
if (level instanceof ServerLevel serverLevel) {
envCollectorBlockEntity.serverTick(serverLevel, blockPos, blockState);
} else {
log.error("level.isClientSide() returned false, but is not a ServerLevel, not ticking EnvCollector");
}
}
}
}

View File

@ -4,37 +4,23 @@ import com.mojang.serialization.MapCodec;
import lombok.extern.slf4j.Slf4j;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.*;
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.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;
import robaertschi.environmenttech.level.block.entity.ETBlockEntities;
import robaertschi.environmenttech.level.block.entity.EnvDistributorBlockEntity;
import javax.annotation.ParametersAreNonnullByDefault;
@SuppressWarnings("deprecation")
@Slf4j
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class EnvDistributorBlock extends BaseEntityBlock {
public static final DirectionProperty FACING = BlockStateProperties.FACING;
public class EnvDistributorBlock extends SimpleBlockWithEntity<EnvDistributorBlockEntity> {
public static final MapCodec<EnvDistributorBlock> CODEC = simpleCodec(EnvDistributorBlock::new);
public EnvDistributorBlock(Properties pProperties) {
super(pProperties);
super(pProperties, ETBlockEntities.ENV_DISTRIBUTOR_BLOCK_ENTITY);
}
@Override
@ -42,60 +28,10 @@ public class EnvDistributorBlock extends BaseEntityBlock {
return CODEC;
}
@Override
protected RenderShape getRenderShape(BlockState pState) {
return RenderShape.MODEL;
}
@Override
public BlockState rotate(BlockState state, LevelAccessor level, BlockPos pos, Rotation direction) {
return state.setValue(FACING, direction.rotate(state.getValue(FACING)));
}
@Override
protected @NotNull BlockState mirror(BlockState pState, Mirror pMirror) {
return pState.rotate(pMirror.getRotation(pState.getValue(FACING)));
}
@Nullable
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
return this.defaultBlockState().setValue(FACING, pContext.getHorizontalDirection().getOpposite());
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> pBuilder) {
pBuilder.add(FACING);
}
@Override
protected void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pMovedByPiston) {
pLevel.updateNeighborsAt(pPos, this);
super.onRemove(pState, pLevel, pPos, pNewState, pMovedByPiston);
}
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) {
return new EnvDistributorBlockEntity(pPos, pState);
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(@NotNull Level pLevel, @NotNull BlockState pState, @NotNull BlockEntityType<T> pBlockEntityType) {
return createTickerHelper(pBlockEntityType, ETBlockEntities.ENV_DISTRIBUTOR_BLOCK_ENTITY.get(), this::tick);
}
public void tick(Level level, BlockPos blockPos, BlockState blockState, EnvDistributorBlockEntity envDistributorBlockEntity) {
if (!level.isClientSide()) {
if (level instanceof ServerLevel serverLevel) {
envDistributorBlockEntity.serverTick(serverLevel, blockPos, blockState);
} else {
log.error("level.isClientSide() returned false, but is not a ServerLevel, not ticking EnvCollector");
}
}
}
}

View File

@ -0,0 +1,95 @@
package robaertschi.environmenttech.level.block;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.*;
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.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.neoforged.neoforge.registries.DeferredHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import robaertschi.environmenttech.level.block.entity.ITickableBlockEntity;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public abstract class SimpleBlockWithEntity<T extends BlockEntity & ITickableBlockEntity> extends BaseEntityBlock {
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
private static final Logger log = LoggerFactory.getLogger(SimpleBlockWithEntity.class);
protected final DeferredHolder<BlockEntityType<?>, BlockEntityType<T>> blockEntityType;
protected SimpleBlockWithEntity(Properties pProperties, DeferredHolder<BlockEntityType<?>, BlockEntityType<T>> beType) {
super(pProperties);
blockEntityType = beType;
}
// Always model
@SuppressWarnings("deprecation")
@Override
protected RenderShape getRenderShape(BlockState pState) {
return RenderShape.MODEL;
}
@Override
public BlockState rotate(BlockState state, LevelAccessor level, BlockPos pos, Rotation direction) {
return state.setValue(FACING, direction.rotate(state.getValue(FACING)));
}
@SuppressWarnings("deprecation")
@Override
protected @NotNull BlockState mirror(BlockState pState, Mirror pMirror) {
return pState.rotate(pMirror.getRotation(pState.getValue(FACING)));
}
@Nullable
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
return this.defaultBlockState().setValue(FACING, pContext.getHorizontalDirection().getOpposite());
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> pBuilder) {
pBuilder.add(FACING);
}
@Override
protected void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pMovedByPiston) {
pLevel.updateNeighborsAt(pPos, this);
super.onRemove(pState, pLevel, pPos, pNewState, pMovedByPiston);
}
@Override
public StateDefinition<Block, BlockState> getStateDefinition() {
return super.getStateDefinition();
}
@Nullable
@Override
public <BT extends BlockEntity> BlockEntityTicker<BT> getTicker(Level pLevel, BlockState pState, BlockEntityType<BT> pBlockEntityType) {
return createTickerHelper(pBlockEntityType, blockEntityType.get(), this::tick);
}
public void tick(Level level, BlockPos blockPos, BlockState blockState, T blockEntity) {
if (!level.isClientSide()) {
if (level instanceof ServerLevel serverLevel) {
blockEntity.serverTick(serverLevel, blockPos, blockState);
} else {
log.error("level.isClientSide() returned false, but is not a ServerLevel. Can not tick block entity.");
}
}
}
}

View File

@ -17,7 +17,6 @@ import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeInput;
import net.minecraft.world.item.crafting.SingleRecipeInput;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
@ -27,7 +26,6 @@ import net.neoforged.neoforge.items.IItemHandler;
import net.neoforged.neoforge.items.IItemHandlerModifiable;
import net.neoforged.neoforge.items.ItemStackHandler;
import net.neoforged.neoforge.items.wrapper.CombinedInvWrapper;
import net.neoforged.neoforge.items.wrapper.RecipeWrapper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import robaertschi.environmenttech.data.attachments.ETAttachments;
@ -40,7 +38,7 @@ import robaertschi.environmenttech.menu.EnvCollectorMenu;
import static robaertschi.environmenttech.EnvironmentTech.MODID;
public class EnvCollectorBlockEntity extends BlockEntity implements MenuProvider {
public class EnvCollectorBlockEntity extends BlockEntity implements MenuProvider, ITickableBlockEntity {
public static final int SLOT_INPUT = 0;
public static final int SLOT_INPUT_COUNT = 1;
@ -207,6 +205,7 @@ public class EnvCollectorBlockEntity extends BlockEntity implements MenuProvider
}
@Override
public void serverTick(ServerLevel level, BlockPos blockPos, @SuppressWarnings("unused") BlockState blockState) {
if (takeEnv <= 0) {

View File

@ -5,16 +5,13 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
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.minecraft.world.level.chunk.ChunkAccess;
import org.jetbrains.annotations.NotNull;
import robaertschi.environmenttech.data.attachments.ETAttachments;
import robaertschi.environmenttech.data.capabilities.EnvStorage;
import robaertschi.environmenttech.data.capabilities.EnvType;
import robaertschi.environmenttech.data.components.ETComponents;
import javax.annotation.ParametersAreNonnullByDefault;
@ -22,7 +19,7 @@ import static robaertschi.environmenttech.EnvironmentTech.MODID;
@Getter
@ParametersAreNonnullByDefault
public class EnvDistributorBlockEntity extends BlockEntity {
public class EnvDistributorBlockEntity extends BlockEntity implements ITickableBlockEntity {
public static final String ENV_TAG = "Env";
private final EnvStorage envStorage = new EnvStorage(EnvType.Chunk, 64) {
@ -55,6 +52,7 @@ public class EnvDistributorBlockEntity extends BlockEntity {
pTag.put(MODID, modData);
}
@Override
public void serverTick(ServerLevel level, BlockPos blockPos, BlockState blockState) {
if (envStorage.getEnvStored() > 0) {
ChunkAccess chunk = level.getChunk(blockPos);

View File

@ -0,0 +1,9 @@
package robaertschi.environmenttech.level.block.entity;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.state.BlockState;
public interface ITickableBlockEntity {
void serverTick(ServerLevel level, BlockPos blockPos, BlockState blockState);
}