package net.shadowfacts.extrahoppers.block.grate import net.fabricmc.fabric.api.block.FabricBlockSettings import net.minecraft.block.* import net.minecraft.block.enums.BlockHalf import net.minecraft.entity.EntityContext import net.minecraft.entity.EntityType import net.minecraft.fluid.Fluid import net.minecraft.fluid.FluidState import net.minecraft.fluid.Fluids import net.minecraft.item.ItemPlacementContext import net.minecraft.sound.BlockSoundGroup import net.minecraft.state.StateManager import net.minecraft.state.property.Properties import net.minecraft.util.Identifier import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction import net.minecraft.util.shape.VoxelShape import net.minecraft.world.BlockView import net.minecraft.world.IWorld import net.minecraft.world.World import net.shadowfacts.extrahoppers.block.base.BlockWithEntity import net.shadowfacts.extrahoppers.util.DynamicFluidStateProvider /** * @author shadowfacts */ class GrateBlock: BlockWithEntity( FabricBlockSettings.of(Material.METAL, MaterialColor.AIR) .strength(5f, 6f) .sounds(BlockSoundGroup.METAL) .nonOpaque() .build() ), DynamicFluidStateProvider, FluidFillable, FluidDrainable { companion object { val ID = Identifier("extrahoppers", "grate") val HALF = Properties.BLOCK_HALF val TOP_SHAPE = createCuboidShape(0.0, 14.0, 0.0, 16.0, 16.0, 16.0) val BOTTOM_SHAPE = createCuboidShape(0.0, 0.0, 0.0, 16.0, 2.0, 16.0) } init { defaultState = stateManager.defaultState.with(HALF, BlockHalf.BOTTOM) } override fun appendProperties(builder: StateManager.Builder) { builder.add(HALF) } override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, entityContext: EntityContext): VoxelShape { return when (state.get(HALF)) { BlockHalf.TOP -> TOP_SHAPE BlockHalf.BOTTOM -> BOTTOM_SHAPE } } override fun getRayTraceShape(state: BlockState, world: BlockView, pos: BlockPos): VoxelShape { return when (state.get(HALF)) { BlockHalf.TOP -> TOP_SHAPE BlockHalf.BOTTOM -> BOTTOM_SHAPE } } override fun getPlacementState(context: ItemPlacementContext): BlockState { val half = when (context.side) { Direction.DOWN -> BlockHalf.TOP Direction.UP -> BlockHalf.BOTTOM else -> if (context.hitPos.y - context.blockPos.y > 0.5) BlockHalf.TOP else BlockHalf.BOTTOM } return defaultState.with(HALF, half) } override fun createBlockEntity(world: BlockView) = GrateBlockEntity() override fun isTranslucent(state: BlockState, world: BlockView, pos: BlockPos): Boolean { return true } override fun isSimpleFullBlock(state: BlockState, world: BlockView, pos: BlockPos): Boolean { return false } override fun allowsSpawning(state: BlockState, world: BlockView, pos: BlockPos, entityType: EntityType<*>): Boolean { return false } override fun getFluidState(state: BlockState, world: BlockView, pos: BlockPos): FluidState { return getBlockEntity(world, pos)?.fluidState ?: Fluids.EMPTY.defaultState } override fun setEmptyFluid(world: World, pos: BlockPos) { val be = getBlockEntity(world, pos) ?: return be.fluidState = null if (!world.isClient) { be.sync() } triggerFluidUpdate(world, pos, world.getBlockState(pos)) } override fun allowsFlow(toSide: Direction, state: BlockState, world: BlockView, pos: BlockPos): DynamicFluidStateProvider.FlowResult { return DynamicFluidStateProvider.FlowResult.ALLOW } override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, block: Block, neighborPos: BlockPos, bl: Boolean) { val fluidState = getFluidState(state, world, pos) if (!fluidState.isEmpty) { world.fluidTickScheduler.schedule(pos, fluidState.fluid, fluidState.fluid.getTickRate(world)) } } private fun triggerFluidUpdate(world: World, pos: BlockPos, state: BlockState) { world.updateListeners(pos, state, state, 3) world.updateNeighbors(pos, state.block) } // Fluid Fillable override fun canFillWithFluid(world: BlockView, pos: BlockPos, state: BlockState, fluid: Fluid): Boolean { val be = getBlockEntity(world, pos) return be != null && be.fluidState == null } override fun tryFillWithFluid(world: IWorld, pos: BlockPos, state: BlockState, fluidState: FluidState): Boolean { val be = getBlockEntity(world, pos) return if (be != null) { be.fluidState = fluidState if (!world.isClient) { world.fluidTickScheduler.schedule(pos, fluidState.fluid, fluidState.fluid.getTickRate(world)) be.sync() } if (world is World) { triggerFluidUpdate(world, pos, state) } true } else { false } } override fun tryDrainFluid(world: IWorld, pos: BlockPos, state: BlockState): Fluid { val be = getBlockEntity(world, pos) ?: return Fluids.EMPTY val fluidState = be.fluidState ?: return Fluids.EMPTY return if (fluidState.isStill) { be.fluidState = null if (!world.isClient) { be.sync() } if (world is World) { triggerFluidUpdate(world, pos, state) } fluidState.fluid } else { Fluids.EMPTY } } }