From 4e9553774ec588797308555aedc439f994148f2f Mon Sep 17 00:00:00 2001 From: Kli Kli Date: Thu, 11 Apr 2024 14:16:49 +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 | 26 ++++++- .../common/block/DirectionalBlockShape.java | 74 +++++++++++++++++++ .../common/block/SacrificialBowlBlock.java | 34 ++++++++- .../datagen/StandardBlockStateProvider.java | 2 + .../blockstates/sacrificial_bowl.json | 7 -- 6 files changed, 160 insertions(+), 13 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 c013fe6e6..d8470d2ff 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,11 @@ 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; public class SacrificialBowlRenderer implements BlockEntityRenderer { @@ -54,15 +56,29 @@ public static float getScale(ItemStack stack) { public void render(SacrificialBowlBlockEntity blockEntity, float partialTicks, PoseStack poseStack, MultiBufferSource buffer, int combinedLight, int combinedOverlay) { var handler = blockEntity.itemStackHandler; - 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(); + 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(); @@ -73,12 +89,16 @@ public void render(SacrificialBowlBlockEntity blockEntity, float partialTicks, P //Fixed scale float scale = getScale(stack) * 0.5f; poseStack.scale(scale, scale, scale); - + ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); BakedModel model = itemRenderer.getModel(stack, blockEntity.getLevel(), null, 0); itemRenderer.render(stack, ItemDisplayContext.FIXED, true, poseStack, buffer, combinedLight, combinedOverlay, model); poseStack.popPose(); + + poseStack.mulPose(facing.getRotation()); + + poseStack.popPose(); } } 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 123bf7f74..e3daa7abf 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 @@ -25,19 +25,24 @@ import com.klikli_dev.occultism.common.blockentity.SacrificialBowlBlockEntity; import com.klikli_dev.occultism.registry.OccultismBlockEntities; import com.klikli_dev.occultism.util.StorageUtil; +import com.mojang.serialization.MapCodec; 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; @@ -46,12 +51,21 @@ 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); + public static final MapCodec CODEC = simpleCodec(SacrificialBowlBlock::new); + + private static final DirectionalBlockShape SHAPE = new DirectionalBlockShape(12, 12, 2.3f); public SacrificialBowlBlock(Properties properties) { super(properties); + + this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.UP)); + } + + @Override + protected MapCodec codec() { + return CODEC; } @Override @@ -106,7 +120,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 795770285..9e5b46725 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