From b181f5d9b5b7fe38bba7261780d46eb485c7836d Mon Sep 17 00:00:00 2001 From: Kli Kli Date: Thu, 11 Apr 2024 14:13:51 +0200 Subject: [PATCH] feat: rotatable bowls (#1111) * feat: allow sacrificial bowls to be rotated * feat: make item bob in facing direction * fix: improve item bobbing location * fix: final fix to item bobbing location --- .../blockstates/sacrificial_bowl.json | 30 ++++++++ .../blockentity/SacrificialBowlRenderer.java | 27 ++++++- .../common/block/DirectionalBlockShape.java | 74 +++++++++++++++++++ .../common/block/SacrificialBowlBlock.java | 28 ++++++- .../datagen/StandardBlockStateProvider.java | 2 + .../blockstates/sacrificial_bowl.json | 7 -- 6 files changed, 157 insertions(+), 11 deletions(-) create mode 100644 src/generated/resources/assets/occultism/blockstates/sacrificial_bowl.json create mode 100644 src/main/java/com/klikli_dev/occultism/common/block/DirectionalBlockShape.java delete mode 100644 src/main/resources/assets/occultism/blockstates/sacrificial_bowl.json diff --git a/src/generated/resources/assets/occultism/blockstates/sacrificial_bowl.json b/src/generated/resources/assets/occultism/blockstates/sacrificial_bowl.json new file mode 100644 index 000000000..d5c055258 --- /dev/null +++ b/src/generated/resources/assets/occultism/blockstates/sacrificial_bowl.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=down": { + "model": "occultism:block/sacrificial_bowl", + "x": 180 + }, + "facing=east": { + "model": "occultism:block/sacrificial_bowl", + "x": 90, + "y": 90 + }, + "facing=north": { + "model": "occultism:block/sacrificial_bowl", + "x": 90 + }, + "facing=south": { + "model": "occultism:block/sacrificial_bowl", + "x": 90, + "y": 180 + }, + "facing=up": { + "model": "occultism:block/sacrificial_bowl" + }, + "facing=west": { + "model": "occultism:block/sacrificial_bowl", + "x": 90, + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/main/java/com/klikli_dev/occultism/client/render/blockentity/SacrificialBowlRenderer.java b/src/main/java/com/klikli_dev/occultism/client/render/blockentity/SacrificialBowlRenderer.java index 77b140053..a5ee0bd71 100644 --- a/src/main/java/com/klikli_dev/occultism/client/render/blockentity/SacrificialBowlRenderer.java +++ b/src/main/java/com/klikli_dev/occultism/client/render/blockentity/SacrificialBowlRenderer.java @@ -32,9 +32,13 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.phys.Vec3; +import org.joml.Vector3f; public class SacrificialBowlRenderer implements BlockEntityRenderer { @@ -57,12 +61,29 @@ public void render(SacrificialBowlBlockEntity blockEntity, float partialTicks, P blockEntity.itemStackHandler.ifPresent(handler -> { ItemStack stack = handler.getStackInSlot(0); long time = blockEntity.getLevel().getGameTime(); + + var facing = blockEntity.getBlockState().hasProperty(BlockStateProperties.FACING) ? + blockEntity.getBlockState().getValue(BlockStateProperties.FACING) : Direction.UP; + + poseStack.pushPose(); + + //TODO: Currently the items bob up and down, instead of away from the bowl facing and back + poseStack.pushPose(); //slowly bob up and down following a sine double offset = Math.sin((time - blockEntity.lastChangeTime + partialTicks) / 16) * 0.5f + 0.5f; // * 0.5f + 0.5f; move sine between 0.0-1.0 offset = offset / 4.0f; //reduce amplitude - poseStack.translate(0.5, 0.6 + offset, 0.5); + + // Fixed offset to push the item away from the bowl + double fixedOffset = 0.2; + + // Adjust the translation based on the facing direction + double xOffset = facing.getAxis() == Direction.Axis.X ? (facing.getAxisDirection() == Direction.AxisDirection.POSITIVE ? offset + fixedOffset : -offset - fixedOffset) : 0.0; + double yOffset = facing.getAxis() == Direction.Axis.Y ? (facing.getAxisDirection() == Direction.AxisDirection.POSITIVE ? offset + fixedOffset : -offset - fixedOffset) : 0.0; + double zOffset = facing.getAxis() == Direction.Axis.Z ? (facing.getAxisDirection() == Direction.AxisDirection.POSITIVE ? offset + fixedOffset : -offset - fixedOffset) : 0.0; + + poseStack.translate(0.5 + xOffset, 0.5 + yOffset, 0.5 + zOffset); //use system time to become independent of game time long systemTime = System.currentTimeMillis(); @@ -80,6 +101,10 @@ public void render(SacrificialBowlBlockEntity blockEntity, float partialTicks, P combinedLight, combinedOverlay, model); poseStack.popPose(); + + poseStack.mulPose(facing.getRotation()); + + poseStack.popPose(); }); } //endregion Static Methods diff --git a/src/main/java/com/klikli_dev/occultism/common/block/DirectionalBlockShape.java b/src/main/java/com/klikli_dev/occultism/common/block/DirectionalBlockShape.java new file mode 100644 index 000000000..02cdf137b --- /dev/null +++ b/src/main/java/com/klikli_dev/occultism/common/block/DirectionalBlockShape.java @@ -0,0 +1,74 @@ +package com.klikli_dev.occultism.common.block; + +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class DirectionalBlockShape { + + protected final float length; + protected final float width; + protected final float height; + protected final float center; + protected final VoxelShape up; + protected final VoxelShape down; + protected final VoxelShape west; + protected final VoxelShape east; + protected final VoxelShape north; + protected final VoxelShape south; + + + public DirectionalBlockShape(float length, float width, float height) { + this(length, width, height, 8.0F); + } + + public DirectionalBlockShape(float length, float width, float height, float center) { + this.length = length; + this.width = width; + this.height = height; + this.center = center; + + this.up = Block.box(center - width / 2, 0.0F, center - length / 2, center + width / 2, height, center + length / 2); + this.down = Block.box(center - width / 2, 16.0F - height, center - length / 2, center + width / 2, 16.0F, center + length / 2); + this.west = Block.box(16.0F - height, center - width / 2, center - length / 2, 16.0F, center + width / 2, center + length / 2); + this.east = Block.box(0.0F, center - width / 2, center - length / 2, height, center + width / 2, center + length / 2); + this.north = Block.box(center - width / 2, center - length / 2, 16.0F - height, center + width / 2, center + length / 2, 16.0F); + this.south = Block.box(center - width / 2, center - length / 2, 0.0F, center + width / 2, center + length / 2, height); + } + + public VoxelShape getShape(Direction direction) { + return switch (direction) { + case UP -> this.up; + case DOWN -> this.down; + case WEST -> this.west; + case EAST -> this.east; + case NORTH -> this.north; + case SOUTH -> this.south; + }; + } + + public VoxelShape up() { + return this.up; + } + + public VoxelShape down() { + return this.down; + } + + public VoxelShape west() { + return this.west; + } + + public VoxelShape east() { + return this.east; + } + + public VoxelShape north() { + return this.north; + } + + public VoxelShape south() { + return this.south; + } + +} diff --git a/src/main/java/com/klikli_dev/occultism/common/block/SacrificialBowlBlock.java b/src/main/java/com/klikli_dev/occultism/common/block/SacrificialBowlBlock.java index c68e5a31d..20041eafd 100644 --- a/src/main/java/com/klikli_dev/occultism/common/block/SacrificialBowlBlock.java +++ b/src/main/java/com/klikli_dev/occultism/common/block/SacrificialBowlBlock.java @@ -26,18 +26,22 @@ import com.klikli_dev.occultism.registry.OccultismTiles; import com.klikli_dev.occultism.util.StorageUtil; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; 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.block.Block; +import net.minecraft.world.level.block.DirectionalBlock; import net.minecraft.world.level.block.EntityBlock; 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.pathfinder.PathComputationType; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.CollisionContext; @@ -47,12 +51,16 @@ import javax.annotation.Nullable; -public class SacrificialBowlBlock extends Block implements EntityBlock { +public class SacrificialBowlBlock extends DirectionalBlock implements EntityBlock { - private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 2.3, 12); + private static final DirectionalBlockShape SHAPE = new DirectionalBlockShape(12, 12, 2.3f); + + //TODO Rotate renderer public SacrificialBowlBlock(Properties properties) { super(properties); + + this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.UP)); } @Override @@ -108,7 +116,21 @@ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player @Override @SuppressWarnings("deprecation") public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { - return SHAPE; + return SHAPE.getShape(state.getValue(FACING)); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder pBuilder) { + pBuilder.add(FACING); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext pContext) { + Direction direction = pContext.getClickedFace(); + BlockState blockstate = pContext.getLevel().getBlockState(pContext.getClickedPos().relative(direction.getOpposite())); + return blockstate.is(this) && blockstate.getValue(FACING) == direction + ? this.defaultBlockState().setValue(FACING, direction.getOpposite()) + : this.defaultBlockState().setValue(FACING, direction); } @Nullable diff --git a/src/main/java/com/klikli_dev/occultism/datagen/StandardBlockStateProvider.java b/src/main/java/com/klikli_dev/occultism/datagen/StandardBlockStateProvider.java index 25db59a7d..e7588f812 100644 --- a/src/main/java/com/klikli_dev/occultism/datagen/StandardBlockStateProvider.java +++ b/src/main/java/com/klikli_dev/occultism/datagen/StandardBlockStateProvider.java @@ -60,6 +60,8 @@ protected void registerStatesAndModels() { this.models().getExistingFile(this.modLoc("block/storage_controller_base"))); this.models().withExistingParent("item/storage_controller_base", this.modLoc("block/storage_controller_base")); this.generateStableWormholeState(OccultismBlocks.STABLE_WORMHOLE.get()); + this.directionalBlock(OccultismBlocks.SACRIFICIAL_BOWL.get(), + this.models().getExistingFile(this.modLoc("block/sacrificial_bowl"))); this.directionalBlock(OccultismBlocks.STORAGE_STABILIZER_TIER1.get(), this.models().getExistingFile(this.modLoc("block/storage_stabilizer_tier1"))); this.directionalBlock(OccultismBlocks.STORAGE_STABILIZER_TIER2.get(), diff --git a/src/main/resources/assets/occultism/blockstates/sacrificial_bowl.json b/src/main/resources/assets/occultism/blockstates/sacrificial_bowl.json deleted file mode 100644 index 84ae56a41..000000000 --- a/src/main/resources/assets/occultism/blockstates/sacrificial_bowl.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "variants": { - "": { - "model": "occultism:block/sacrificial_bowl" - } - } -} \ No newline at end of file