package net.minecraft.world.level.block; import java.util.function.BiPredicate; import java.util.function.Function; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.LevelAccessor; 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.block.state.properties.DirectionProperty; public class DoubleBlockCombiner { public static DoubleBlockCombiner.NeighborCombineResult combineWithNeigbour( BlockEntityType blockEntityType, Function doubleBlockTypeGetter, Function directionGetter, DirectionProperty directionProperty, BlockState state, LevelAccessor level, BlockPos pos, BiPredicate blockedChestTest ) { S blockEntity = blockEntityType.getBlockEntity(level, pos); if (blockEntity == null) { return DoubleBlockCombiner.Combiner::acceptNone; } else if (blockedChestTest.test(level, pos)) { return DoubleBlockCombiner.Combiner::acceptNone; } else { DoubleBlockCombiner.BlockType blockType = (DoubleBlockCombiner.BlockType)doubleBlockTypeGetter.apply(state); boolean bl = blockType == DoubleBlockCombiner.BlockType.SINGLE; boolean bl2 = blockType == DoubleBlockCombiner.BlockType.FIRST; if (bl) { return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity); } else { BlockPos blockPos = pos.relative((Direction)directionGetter.apply(state)); BlockState blockState = level.getBlockState(blockPos); if (blockState.is(state.getBlock())) { DoubleBlockCombiner.BlockType blockType2 = (DoubleBlockCombiner.BlockType)doubleBlockTypeGetter.apply(blockState); if (blockType2 != DoubleBlockCombiner.BlockType.SINGLE && blockType != blockType2 && blockState.getValue(directionProperty) == state.getValue(directionProperty)) { if (blockedChestTest.test(level, blockPos)) { return DoubleBlockCombiner.Combiner::acceptNone; } S blockEntity2 = blockEntityType.getBlockEntity(level, blockPos); if (blockEntity2 != null) { S blockEntity3 = bl2 ? blockEntity : blockEntity2; S blockEntity4 = bl2 ? blockEntity2 : blockEntity; return new DoubleBlockCombiner.NeighborCombineResult.Double<>(blockEntity3, blockEntity4); } } } return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity); } } } public static enum BlockType { SINGLE, FIRST, SECOND; } public interface Combiner { T acceptDouble(S first, S second); T acceptSingle(S single); T acceptNone(); } public interface NeighborCombineResult { T apply(DoubleBlockCombiner.Combiner combiner); public static final class Double implements DoubleBlockCombiner.NeighborCombineResult { private final S first; private final S second; public Double(S first, S second) { this.first = first; this.second = second; } @Override public T apply(DoubleBlockCombiner.Combiner combiner) { return combiner.acceptDouble(this.first, this.second); } } public static final class Single implements DoubleBlockCombiner.NeighborCombineResult { private final S single; public Single(S single) { this.single = single; } @Override public T apply(DoubleBlockCombiner.Combiner combiner) { return combiner.acceptSingle(this.single); } } } }