package com.minelittlepony.unicopia.block; import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.util.SoundEmitter; import net.minecraft.block.*; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.ai.pathing.NavigationType; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.fluid.FluidState; import net.minecraft.fluid.Fluids; import net.minecraft.item.*; import net.minecraft.particle.ParticleTypes; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; import net.minecraft.stat.Stats; import net.minecraft.state.StateManager; import net.minecraft.state.property.*; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.*; import net.minecraft.util.math.random.Random; import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShapes; import net.minecraft.world.*; import net.minecraft.world.event.GameEvent; public class PieBlock extends Block implements Waterloggable { public static final int MAX_BITES = 3; public static final IntProperty BITES = IntProperty.of("bites", 0, MAX_BITES); public static final BooleanProperty STOMPED = BooleanProperty.of("stomped"); public static final BooleanProperty WATERLOGGED = Properties.WATERLOGGED; private static final VoxelShape[] SHAPES; static { final int PIE_HEIGHT = 4; final VoxelShape WEDGE = Block.createCuboidShape(2, 0, 2, 8, PIE_HEIGHT, 8); final float OFFSET_AMOUNT = 6F/16F; SHAPES = new VoxelShape[] { Block.createCuboidShape(2, 0, 2, 14, PIE_HEIGHT, 14), VoxelShapes.union(WEDGE, WEDGE.offset(OFFSET_AMOUNT, 0, 0), WEDGE.offset(OFFSET_AMOUNT, 0, OFFSET_AMOUNT)), VoxelShapes.union(WEDGE, WEDGE.offset(OFFSET_AMOUNT, 0, 0)), WEDGE }; } private final ItemConvertible sliceItem; private final ItemConvertible normalItem; private final ItemConvertible stompedItem; public PieBlock(Settings settings, ItemConvertible sliceItem, ItemConvertible normalItem, ItemConvertible stompedItem) { super(settings); setDefaultState(getDefaultState().with(STOMPED, false).with(WATERLOGGED, false)); this.sliceItem = sliceItem; this.normalItem = normalItem; this.stompedItem = stompedItem; } @Deprecated @Override public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { return SHAPES[state.get(BITES)]; } @Deprecated @Override public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { ItemStack itemStack = player.getStackInHand(hand); if (world.isClient) { if (itemStack.isIn(UTags.CAN_CUT_PIE)) { return ActionResult.SUCCESS; } if (tryEat(world, pos, state, player).isAccepted()) { return ActionResult.SUCCESS; } if (itemStack.isEmpty()) { return ActionResult.CONSUME; } } if (itemStack.isIn(UTags.CAN_CUT_PIE)) { SoundEmitter.playSoundAt(player, USounds.BLOCK_PIE_SLICE, SoundCategory.NEUTRAL, 1, 1); removeSlice(world, pos, state, player); itemStack.damage(1, player, p -> p.sendToolBreakStatus(hand)); SoundEmitter.playSoundAt(player, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.NEUTRAL, 0.5F, world.getRandom().nextFloat() * 0.1F + 0.9F); Block.dropStack(world, pos, sliceItem.asItem().getDefaultStack()); return ActionResult.SUCCESS; } return tryEat(world, pos, state, player); } protected ActionResult tryEat(WorldAccess world, BlockPos pos, BlockState state, PlayerEntity player) { if (!player.canConsume(false)) { return ActionResult.PASS; } player.incrementStat(Stats.EAT_CAKE_SLICE); player.getHungerManager().add(state.get(STOMPED) ? 1 : 2, 0.1f); world.emitGameEvent(player, GameEvent.EAT, pos); SoundEmitter.playSoundAt(player, SoundEvents.ENTITY_GENERIC_EAT, 0.5F, world.getRandom().nextFloat() * 0.1F + 0.9F); if (world instanceof World ww && (!player.canConsume(false) || world.getRandom().nextInt(10) == 0)) { AwaitTickQueue.scheduleTask(ww, w -> { SoundEmitter.playSoundAt(player, SoundEvents.ENTITY_PLAYER_BURP, 0.5F, world.getRandom().nextFloat() * 0.1F + 0.9F); }, 5); } removeSlice(world, pos, state, player); return ActionResult.SUCCESS; } protected void removeSlice(WorldAccess world, BlockPos pos, BlockState state, PlayerEntity player) { int bites = state.get(BITES); if (bites < MAX_BITES) { world.setBlockState(pos, state.with(BITES, bites + 1), Block.NOTIFY_ALL); } else { world.removeBlock(pos, false); world.emitGameEvent(player, GameEvent.BLOCK_DESTROY, pos); } } @Override public ItemStack getPickStack(BlockView world, BlockPos pos, BlockState state) { return (state.get(STOMPED) ? stompedItem : normalItem).asItem().getDefaultStack(); } @Override public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) { if (state.get(STOMPED)) { Vec3d center = Vec3d.ofCenter(pos); world.addParticle(ParticleTypes.SNEEZE, random.nextTriangular(center.getX(), 0.9), random.nextTriangular(center.getY(), 0.9), random.nextTriangular(center.getZ(), 0.9), 0, 0, 0 ); } else { if (world.random.nextInt(10) == 0) { Vec3d center = Vec3d.ofCenter(pos); world.addParticle(ParticleTypes.SNEEZE, random.nextTriangular(center.getX(), 0.2), random.nextTriangular(center.getY(), 0.2), random.nextTriangular(center.getZ(), 0.2), 0, 0.01F, 0 ); } } } @Override public void onSteppedOn(World world, BlockPos pos, BlockState state, Entity entity) { if (!state.get(STOMPED) && entity instanceof LivingEntity && !entity.bypassesSteppingEffects()) { world.setBlockState(pos, state.cycle(STOMPED)); world.syncWorldEvent(WorldEvents.BLOCK_BROKEN, pos, Block.getRawIdFromState(state)); world.emitGameEvent(UGameEvents.PIE_STOMP, pos, GameEvent.Emitter.of(entity, state)); } } @Deprecated @Override public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) { if (direction == Direction.DOWN && !state.canPlaceAt(world, pos)) { return Blocks.AIR.getDefaultState(); } if (state.get(WATERLOGGED)) { world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world)); } return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos); } @Deprecated @Override public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) { return world.getBlockState(pos.down()).isSideSolidFullSquare(world, pos, Direction.UP); } @Deprecated @Override public BlockState getPlacementState(ItemPlacementContext ctx) { return super.getDefaultState() .with(WATERLOGGED, ctx.getWorld().getFluidState(ctx.getBlockPos()).getFluid() == Fluids.WATER) .with(STOMPED, ctx.getStack().isOf(UItems.APPLE_PIE_HOOF)); } @Deprecated @Override public FluidState getFluidState(BlockState state) { if (state.get(WATERLOGGED)) { return Fluids.WATER.getStill(false); } return super.getFluidState(state); } @Override protected void appendProperties(StateManager.Builder builder) { builder.add(BITES, STOMPED, WATERLOGGED); } @Override public int getComparatorOutput(BlockState state, World world, BlockPos pos) { return (5 - state.get(BITES)) * 2; } @Override public boolean hasComparatorOutput(BlockState state) { return true; } @Override public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) { return false; } }