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.Property; public class DoubleBlockCombiner { public static DoubleBlockCombiner.NeighborCombineResult combineWithNeigbour( final BlockEntityType entityType, final Function typeResolver, final Function connectionResolver, final Property facingProperty, final BlockState state, final LevelAccessor level, final BlockPos pos, final BiPredicate blockedChecker ) { S blockEntity = entityType.getBlockEntity(level, pos); if (blockEntity == null) { return DoubleBlockCombiner.Combiner::acceptNone; } else if (blockedChecker.test(level, pos)) { return DoubleBlockCombiner.Combiner::acceptNone; } else { DoubleBlockCombiner.BlockType type = (DoubleBlockCombiner.BlockType)typeResolver.apply(state); boolean single = type == DoubleBlockCombiner.BlockType.SINGLE; boolean isFirst = type == DoubleBlockCombiner.BlockType.FIRST; if (single) { return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity); } else { BlockPos neighborPos = pos.relative((Direction)connectionResolver.apply(state)); BlockState neighbourState = level.getBlockState(neighborPos); if (neighbourState.is(state.getBlock())) { DoubleBlockCombiner.BlockType neighbourType = (DoubleBlockCombiner.BlockType)typeResolver.apply(neighbourState); if (neighbourType != DoubleBlockCombiner.BlockType.SINGLE && type != neighbourType && neighbourState.getValue(facingProperty) == state.getValue(facingProperty)) { if (blockedChecker.test(level, neighborPos)) { return DoubleBlockCombiner.Combiner::acceptNone; } S neighbour = entityType.getBlockEntity(level, neighborPos); if (neighbour != null) { S first = isFirst ? blockEntity : neighbour; S second = isFirst ? neighbour : blockEntity; return new DoubleBlockCombiner.NeighborCombineResult.Double<>(first, second); } } } 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 callback); public static final class Double implements DoubleBlockCombiner.NeighborCombineResult { private final S first; private final S second; public Double(final S first, final S second) { this.first = first; this.second = second; } @Override public T apply(final DoubleBlockCombiner.Combiner callback) { return callback.acceptDouble(this.first, this.second); } } public static final class Single implements DoubleBlockCombiner.NeighborCombineResult { private final S single; public Single(final S single) { this.single = single; } @Override public T apply(final DoubleBlockCombiner.Combiner callback) { return callback.acceptSingle(this.single); } } } }