|
| 1 | +package com.ishland.c2me.rewrites.chunksystem.common.quirks; |
| 2 | + |
| 3 | +import com.ishland.c2me.base.mixin.access.IFlowableFluid; |
| 4 | +import it.unimi.dsi.fastutil.shorts.Short2BooleanFunction; |
| 5 | +import it.unimi.dsi.fastutil.shorts.Short2BooleanMap; |
| 6 | +import it.unimi.dsi.fastutil.shorts.Short2BooleanOpenHashMap; |
| 7 | +import it.unimi.dsi.fastutil.shorts.Short2ObjectFunction; |
| 8 | +import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; |
| 9 | +import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; |
| 10 | +import net.minecraft.block.BlockState; |
| 11 | +import net.minecraft.fluid.FlowableFluid; |
| 12 | +import net.minecraft.fluid.Fluid; |
| 13 | +import net.minecraft.fluid.FluidState; |
| 14 | +import net.minecraft.fluid.Fluids; |
| 15 | +import net.minecraft.util.math.BlockPos; |
| 16 | +import net.minecraft.util.math.Direction; |
| 17 | +import net.minecraft.world.BlockView; |
| 18 | +import net.minecraft.world.WorldView; |
| 19 | + |
| 20 | +public class FlowableFluidUtils { |
| 21 | + |
| 22 | + public static boolean needsPostProcessing(WorldView world, BlockPos pos, BlockState blockState, FluidState fluidState) { |
| 23 | + if (!fluidState.isStill()) { |
| 24 | + return true; |
| 25 | + } |
| 26 | + return canFlowNormally(world, pos, blockState, fluidState); |
| 27 | + } |
| 28 | + |
| 29 | + private static boolean canFlowNormally(WorldView world, BlockPos pos, BlockState blockState, FluidState fluidState) { |
| 30 | + if (fluidState.isEmpty()) return false; |
| 31 | + |
| 32 | + BlockPos belowPos = pos.down(); |
| 33 | + BlockState belowBlockState = world.getBlockState(belowPos); |
| 34 | + FluidState belowFluidState = belowBlockState.getFluidState(); |
| 35 | + // very rough filtering |
| 36 | + if (((IFlowableFluid) fluidState.getFluid()).invokeCanFlowThrough(world, pos, blockState, Direction.DOWN, belowPos, belowBlockState, belowFluidState)) { |
| 37 | + FluidState fluidState3 = getUpdatedState(((FlowableFluid) fluidState.getFluid()), world, belowPos, belowBlockState); |
| 38 | + if (fluidState3 == null) { |
| 39 | + return true; // shortcut |
| 40 | + } |
| 41 | + Fluid fluid = fluidState3.getFluid(); |
| 42 | + if (belowFluidState.canBeReplacedWith(world, belowPos, fluid, Direction.DOWN) && IFlowableFluid.invokeCanFillWithFluid(world, belowPos, belowBlockState, fluid)) { |
| 43 | + return true; |
| 44 | + } |
| 45 | + } |
| 46 | + if ((fluidState.isStill() || !(((IFlowableFluid) fluidState.getFluid()).invokeCanFlowDownTo(world, pos, blockState, belowPos, belowBlockState))) && |
| 47 | + canSpreadToSidesNormally(world, pos, blockState, fluidState)) { |
| 48 | + return true; |
| 49 | + } |
| 50 | + |
| 51 | + return false; |
| 52 | + } |
| 53 | + |
| 54 | + private static boolean canSpreadToSidesNormally(WorldView world, BlockPos pos, BlockState blockState, FluidState fluidState) { |
| 55 | + int nextFluidLevel = fluidState.getLevel() - ((IFlowableFluid) fluidState.getFluid()).invokeGetLevelDecreasePerBlock(world); |
| 56 | + if (fluidState.get(FlowableFluid.FALLING)) { |
| 57 | + nextFluidLevel = 7; |
| 58 | + } |
| 59 | + if (nextFluidLevel > 0) { |
| 60 | + // getSpread |
| 61 | +// int i = 1000; |
| 62 | +// Map<Direction, FluidState> map = Maps.newEnumMap(Direction.class); |
| 63 | +// SpreadCache spreadCache = null; |
| 64 | + |
| 65 | + for (Direction direction : Direction.Type.HORIZONTAL) { |
| 66 | + BlockPos offsetPos = pos.offset(direction); |
| 67 | + BlockState offsetBlockState = world.getBlockState(offsetPos); |
| 68 | + FluidState offsetFluidState = offsetBlockState.getFluidState(); |
| 69 | + if (((IFlowableFluid) fluidState.getFluid()).invokeCanFlowThrough(world, pos, blockState, direction, offsetPos, offsetBlockState, offsetFluidState)) { |
| 70 | + FluidState fluidState2 = getUpdatedState((FlowableFluid) fluidState.getFluid(), world, offsetPos, offsetBlockState); |
| 71 | + if (fluidState2 == null) { |
| 72 | + return true; // shortcut |
| 73 | + } |
| 74 | + if (IFlowableFluid.invokeCanFillWithFluid(world, offsetPos, offsetBlockState, fluidState2.getFluid())) { |
| 75 | + return true; // shortcut |
| 76 | + } |
| 77 | + } |
| 78 | + } |
| 79 | + } |
| 80 | + |
| 81 | + return false; |
| 82 | + } |
| 83 | + |
| 84 | + private static FluidState getUpdatedState(FlowableFluid receiver, WorldView world, BlockPos pos, BlockState state) { |
| 85 | + int i = 0; |
| 86 | + int j = 0; |
| 87 | + BlockPos.Mutable mutable = new BlockPos.Mutable(); |
| 88 | + |
| 89 | + for (Direction direction : Direction.Type.HORIZONTAL) { |
| 90 | + BlockPos blockPos = mutable.set(pos, direction); |
| 91 | + BlockState blockState = world.getBlockState(blockPos); |
| 92 | + FluidState fluidState = blockState.getFluidState(); |
| 93 | + if (fluidState.getFluid().matchesType(receiver) && IFlowableFluid.invokeReceivesFlow(direction, world, pos, state, blockPos, blockState)) { |
| 94 | + if (fluidState.isStill()) { |
| 95 | + j++; |
| 96 | + } |
| 97 | + |
| 98 | + i = Math.max(i, fluidState.getLevel()); |
| 99 | + } |
| 100 | + } |
| 101 | + |
| 102 | +// if (j >= 2 && this.isInfinite(world)) { |
| 103 | +// BlockState blockState2 = world.getBlockState(mutable.set(pos, Direction.DOWN)); |
| 104 | +// FluidState fluidState2 = blockState2.getFluidState(); |
| 105 | +// if (blockState2.isSolid() || receiver.isMatchingAndStill(fluidState2)) { |
| 106 | +// return receiver.getStill(false); |
| 107 | +// } |
| 108 | +// } |
| 109 | + if (j >= 2) { |
| 110 | + return null; // to not filter this |
| 111 | + } |
| 112 | + |
| 113 | + BlockPos blockPos2 = mutable.set(pos, Direction.UP); |
| 114 | + BlockState blockState3 = world.getBlockState(blockPos2); |
| 115 | + FluidState fluidState3 = blockState3.getFluidState(); |
| 116 | + if (!fluidState3.isEmpty() && fluidState3.getFluid().matchesType(receiver) && IFlowableFluid.invokeReceivesFlow(Direction.UP, world, pos, state, blockPos2, blockState3)) { |
| 117 | + return receiver.getFlowing(8, true); |
| 118 | + } else { |
| 119 | + int k = i - ((IFlowableFluid) receiver).invokeGetLevelDecreasePerBlock(world); |
| 120 | + return k <= 0 ? Fluids.EMPTY.getDefaultState() : receiver.getFlowing(k, false); |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + private static class SpreadCache { |
| 125 | + private final FlowableFluid flowableFluid; |
| 126 | + private final BlockView world; |
| 127 | + private final BlockPos startPos; |
| 128 | + private final Short2ObjectMap<BlockState> stateCache = new Short2ObjectOpenHashMap<>(); |
| 129 | + private final Short2BooleanMap flowDownCache = new Short2BooleanOpenHashMap(); |
| 130 | + |
| 131 | + SpreadCache(final FlowableFluid flowableFluid, final BlockView world, final BlockPos startPos) { |
| 132 | + this.flowableFluid = flowableFluid; |
| 133 | + this.world = world; |
| 134 | + this.startPos = startPos; |
| 135 | + } |
| 136 | + |
| 137 | + public BlockState getBlockState(BlockPos pos) { |
| 138 | + return this.getBlockState(pos, this.pack(pos)); |
| 139 | + } |
| 140 | + |
| 141 | + private BlockState getBlockState(BlockPos pos, short packed) { |
| 142 | + return this.stateCache.computeIfAbsent(packed, (Short2ObjectFunction<? extends BlockState>)(packedPos -> this.world.getBlockState(pos))); |
| 143 | + } |
| 144 | + |
| 145 | + public boolean canFlowDownTo(BlockPos pos) { |
| 146 | + return this.flowDownCache.computeIfAbsent(this.pack(pos), (Short2BooleanFunction)(packed -> { |
| 147 | + BlockState blockState = this.getBlockState(pos, packed); |
| 148 | + BlockPos blockPos2 = pos.down(); |
| 149 | + BlockState blockState2 = this.world.getBlockState(blockPos2); |
| 150 | + return ((IFlowableFluid) this.flowableFluid).invokeCanFlowDownTo(this.world, pos, blockState, blockPos2, blockState2); |
| 151 | + })); |
| 152 | + } |
| 153 | + |
| 154 | + private short pack(BlockPos pos) { |
| 155 | + int i = pos.getX() - this.startPos.getX(); |
| 156 | + int j = pos.getZ() - this.startPos.getZ(); |
| 157 | + return (short)((i + 128 & 0xFF) << 8 | j + 128 & 0xFF); |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | +} |
0 commit comments