519 lines
23 KiB
Java
519 lines
23 KiB
Java
package net.minecraft.world.level.material;
|
|
|
|
import com.google.common.collect.Maps;
|
|
import it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap;
|
|
import it.unimi.dsi.fastutil.shorts.Short2BooleanMap;
|
|
import it.unimi.dsi.fastutil.shorts.Short2BooleanOpenHashMap;
|
|
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
|
|
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.tags.BlockTags;
|
|
import net.minecraft.world.level.BlockGetter;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.LevelAccessor;
|
|
import net.minecraft.world.level.LevelReader;
|
|
import net.minecraft.world.level.block.Block;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.DoorBlock;
|
|
import net.minecraft.world.level.block.IceBlock;
|
|
import net.minecraft.world.level.block.LiquidBlockContainer;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.block.state.StateDefinition;
|
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
|
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraft.world.phys.shapes.Shapes;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
|
|
public abstract class FlowingFluid extends Fluid {
|
|
public static final BooleanProperty FALLING = BlockStateProperties.FALLING;
|
|
public static final IntegerProperty LEVEL = BlockStateProperties.LEVEL_FLOWING;
|
|
private static final int CACHE_SIZE = 200;
|
|
private static final ThreadLocal<Object2ByteLinkedOpenHashMap<FlowingFluid.BlockStatePairKey>> OCCLUSION_CACHE = ThreadLocal.withInitial(
|
|
() -> {
|
|
Object2ByteLinkedOpenHashMap<FlowingFluid.BlockStatePairKey> object2bytelinkedopenhashmap = new Object2ByteLinkedOpenHashMap<FlowingFluid.BlockStatePairKey>(
|
|
200
|
|
) {
|
|
@Override
|
|
protected void rehash(int p_76102_) {
|
|
}
|
|
};
|
|
object2bytelinkedopenhashmap.defaultReturnValue((byte)127);
|
|
return object2bytelinkedopenhashmap;
|
|
}
|
|
);
|
|
private final Map<FluidState, VoxelShape> shapes = Maps.newIdentityHashMap();
|
|
|
|
@Override
|
|
protected void createFluidStateDefinition(StateDefinition.Builder<Fluid, FluidState> p_76046_) {
|
|
p_76046_.add(FALLING);
|
|
}
|
|
|
|
@Override
|
|
public Vec3 getFlow(BlockGetter p_75987_, BlockPos p_75988_, FluidState p_75989_) {
|
|
double d0 = 0.0;
|
|
double d1 = 0.0;
|
|
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
|
|
|
|
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
|
blockpos$mutableblockpos.setWithOffset(p_75988_, direction);
|
|
FluidState fluidstate = p_75987_.getFluidState(blockpos$mutableblockpos);
|
|
if (this.affectsFlow(fluidstate)) {
|
|
float f = fluidstate.getOwnHeight();
|
|
float f1 = 0.0F;
|
|
if (f == 0.0F) {
|
|
if (!p_75987_.getBlockState(blockpos$mutableblockpos).blocksMotion()) {
|
|
BlockPos blockpos = blockpos$mutableblockpos.below();
|
|
FluidState fluidstate1 = p_75987_.getFluidState(blockpos);
|
|
if (this.affectsFlow(fluidstate1)) {
|
|
f = fluidstate1.getOwnHeight();
|
|
if (f > 0.0F) {
|
|
f1 = p_75989_.getOwnHeight() - (f - 0.8888889F);
|
|
}
|
|
}
|
|
}
|
|
} else if (f > 0.0F) {
|
|
f1 = p_75989_.getOwnHeight() - f;
|
|
}
|
|
|
|
if (f1 != 0.0F) {
|
|
d0 += direction.getStepX() * f1;
|
|
d1 += direction.getStepZ() * f1;
|
|
}
|
|
}
|
|
}
|
|
|
|
Vec3 vec3 = new Vec3(d0, 0.0, d1);
|
|
if (p_75989_.getValue(FALLING)) {
|
|
for (Direction direction1 : Direction.Plane.HORIZONTAL) {
|
|
blockpos$mutableblockpos.setWithOffset(p_75988_, direction1);
|
|
if (this.isSolidFace(p_75987_, blockpos$mutableblockpos, direction1) || this.isSolidFace(p_75987_, blockpos$mutableblockpos.above(), direction1)) {
|
|
vec3 = vec3.normalize().add(0.0, -6.0, 0.0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return vec3.normalize();
|
|
}
|
|
|
|
private boolean affectsFlow(FluidState p_76095_) {
|
|
return p_76095_.isEmpty() || p_76095_.getType().isSame(this);
|
|
}
|
|
|
|
protected boolean isSolidFace(BlockGetter p_75991_, BlockPos p_75992_, Direction p_75993_) {
|
|
BlockState blockstate = p_75991_.getBlockState(p_75992_);
|
|
FluidState fluidstate = p_75991_.getFluidState(p_75992_);
|
|
if (fluidstate.getType().isSame(this)) {
|
|
return false;
|
|
} else if (p_75993_ == Direction.UP) {
|
|
return true;
|
|
} else {
|
|
return blockstate.getBlock() instanceof IceBlock ? false : blockstate.isFaceSturdy(p_75991_, p_75992_, p_75993_);
|
|
}
|
|
}
|
|
|
|
protected void spread(ServerLevel p_361853_, BlockPos p_76012_, BlockState p_370035_, FluidState p_76013_) {
|
|
if (!p_76013_.isEmpty()) {
|
|
BlockPos blockpos = p_76012_.below();
|
|
BlockState blockstate = p_361853_.getBlockState(blockpos);
|
|
FluidState fluidstate = blockstate.getFluidState();
|
|
if (this.canMaybePassThrough(p_361853_, p_76012_, p_370035_, Direction.DOWN, blockpos, blockstate, fluidstate)) {
|
|
FluidState fluidstate1 = this.getNewLiquid(p_361853_, blockpos, blockstate);
|
|
Fluid fluid = fluidstate1.getType();
|
|
if (fluidstate.canBeReplacedWith(p_361853_, blockpos, fluid, Direction.DOWN) && canHoldSpecificFluid(p_361853_, blockpos, blockstate, fluid)) {
|
|
this.spreadTo(p_361853_, blockpos, blockstate, Direction.DOWN, fluidstate1);
|
|
if (this.sourceNeighborCount(p_361853_, p_76012_) >= 3) {
|
|
this.spreadToSides(p_361853_, p_76012_, p_76013_, p_370035_);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (p_76013_.isSource() || !this.isWaterHole(p_361853_, p_76012_, p_370035_, blockpos, blockstate)) {
|
|
this.spreadToSides(p_361853_, p_76012_, p_76013_, p_370035_);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void spreadToSides(ServerLevel p_367610_, BlockPos p_76016_, FluidState p_76017_, BlockState p_76018_) {
|
|
int i = p_76017_.getAmount() - this.getDropOff(p_367610_);
|
|
if (p_76017_.getValue(FALLING)) {
|
|
i = 7;
|
|
}
|
|
|
|
if (i > 0) {
|
|
Map<Direction, FluidState> map = this.getSpread(p_367610_, p_76016_, p_76018_);
|
|
|
|
for (Entry<Direction, FluidState> entry : map.entrySet()) {
|
|
Direction direction = entry.getKey();
|
|
FluidState fluidstate = entry.getValue();
|
|
BlockPos blockpos = p_76016_.relative(direction);
|
|
this.spreadTo(p_367610_, blockpos, p_367610_.getBlockState(blockpos), direction, fluidstate);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected FluidState getNewLiquid(ServerLevel p_369574_, BlockPos p_76037_, BlockState p_76038_) {
|
|
int i = 0;
|
|
int j = 0;
|
|
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
|
|
|
|
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
|
BlockPos blockpos = blockpos$mutableblockpos.setWithOffset(p_76037_, direction);
|
|
BlockState blockstate = p_369574_.getBlockState(blockpos);
|
|
FluidState fluidstate = blockstate.getFluidState();
|
|
if (fluidstate.getType().isSame(this) && canPassThroughWall(direction, p_369574_, p_76037_, p_76038_, blockpos, blockstate)) {
|
|
if (fluidstate.isSource()) {
|
|
j++;
|
|
}
|
|
|
|
i = Math.max(i, fluidstate.getAmount());
|
|
}
|
|
}
|
|
|
|
if (j >= 2 && this.canConvertToSource(p_369574_)) {
|
|
BlockState blockstate1 = p_369574_.getBlockState(blockpos$mutableblockpos.setWithOffset(p_76037_, Direction.DOWN));
|
|
FluidState fluidstate1 = blockstate1.getFluidState();
|
|
if (blockstate1.isSolid() || this.isSourceBlockOfThisType(fluidstate1)) {
|
|
return this.getSource(false);
|
|
}
|
|
}
|
|
|
|
BlockPos blockpos1 = blockpos$mutableblockpos.setWithOffset(p_76037_, Direction.UP);
|
|
BlockState blockstate2 = p_369574_.getBlockState(blockpos1);
|
|
FluidState fluidstate2 = blockstate2.getFluidState();
|
|
if (!fluidstate2.isEmpty() && fluidstate2.getType().isSame(this) && canPassThroughWall(Direction.UP, p_369574_, p_76037_, p_76038_, blockpos1, blockstate2)) {
|
|
return this.getFlowing(8, true);
|
|
} else {
|
|
int k = i - this.getDropOff(p_369574_);
|
|
return k <= 0 ? Fluids.EMPTY.defaultFluidState() : this.getFlowing(k, false);
|
|
}
|
|
}
|
|
|
|
private static boolean canPassThroughWall(Direction p_76062_, BlockGetter p_76063_, BlockPos p_76064_, BlockState p_76065_, BlockPos p_76066_, BlockState p_76067_) {
|
|
VoxelShape voxelshape = p_76067_.getCollisionShape(p_76063_, p_76066_);
|
|
if (voxelshape == Shapes.block()) {
|
|
return false;
|
|
} else {
|
|
VoxelShape voxelshape1 = p_76065_.getCollisionShape(p_76063_, p_76064_);
|
|
if (voxelshape1 == Shapes.block()) {
|
|
return false;
|
|
} else if (voxelshape1 == Shapes.empty() && voxelshape == Shapes.empty()) {
|
|
return true;
|
|
} else {
|
|
Object2ByteLinkedOpenHashMap<FlowingFluid.BlockStatePairKey> object2bytelinkedopenhashmap;
|
|
if (!p_76065_.getBlock().hasDynamicShape() && !p_76067_.getBlock().hasDynamicShape()) {
|
|
object2bytelinkedopenhashmap = OCCLUSION_CACHE.get();
|
|
} else {
|
|
object2bytelinkedopenhashmap = null;
|
|
}
|
|
|
|
FlowingFluid.BlockStatePairKey flowingfluid$blockstatepairkey;
|
|
if (object2bytelinkedopenhashmap != null) {
|
|
flowingfluid$blockstatepairkey = new FlowingFluid.BlockStatePairKey(p_76065_, p_76067_, p_76062_);
|
|
byte b0 = object2bytelinkedopenhashmap.getAndMoveToFirst(flowingfluid$blockstatepairkey);
|
|
if (b0 != 127) {
|
|
return b0 != 0;
|
|
}
|
|
} else {
|
|
flowingfluid$blockstatepairkey = null;
|
|
}
|
|
|
|
boolean flag = !Shapes.mergedFaceOccludes(voxelshape1, voxelshape, p_76062_);
|
|
if (object2bytelinkedopenhashmap != null) {
|
|
if (object2bytelinkedopenhashmap.size() == 200) {
|
|
object2bytelinkedopenhashmap.removeLastByte();
|
|
}
|
|
|
|
object2bytelinkedopenhashmap.putAndMoveToFirst(flowingfluid$blockstatepairkey, (byte)(flag ? 1 : 0));
|
|
}
|
|
|
|
return flag;
|
|
}
|
|
}
|
|
}
|
|
|
|
public abstract Fluid getFlowing();
|
|
|
|
public FluidState getFlowing(int p_75954_, boolean p_75955_) {
|
|
return this.getFlowing().defaultFluidState().setValue(LEVEL, p_75954_).setValue(FALLING, p_75955_);
|
|
}
|
|
|
|
public abstract Fluid getSource();
|
|
|
|
public FluidState getSource(boolean p_76069_) {
|
|
return this.getSource().defaultFluidState().setValue(FALLING, p_76069_);
|
|
}
|
|
|
|
protected abstract boolean canConvertToSource(ServerLevel p_369955_);
|
|
|
|
protected void spreadTo(LevelAccessor p_76005_, BlockPos p_76006_, BlockState p_76007_, Direction p_76008_, FluidState p_76009_) {
|
|
if (p_76007_.getBlock() instanceof LiquidBlockContainer liquidblockcontainer) {
|
|
liquidblockcontainer.placeLiquid(p_76005_, p_76006_, p_76007_, p_76009_);
|
|
} else {
|
|
if (!p_76007_.isAir()) {
|
|
this.beforeDestroyingBlock(p_76005_, p_76006_, p_76007_);
|
|
}
|
|
|
|
p_76005_.setBlock(p_76006_, p_76009_.createLegacyBlock(), 3);
|
|
}
|
|
}
|
|
|
|
protected abstract void beforeDestroyingBlock(LevelAccessor p_76002_, BlockPos p_76003_, BlockState p_76004_);
|
|
|
|
protected int getSlopeDistance(LevelReader p_76027_, BlockPos p_76028_, int p_76029_, Direction p_76030_, BlockState p_76031_, FlowingFluid.SpreadContext p_361884_) {
|
|
int i = 1000;
|
|
|
|
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
|
if (direction != p_76030_) {
|
|
BlockPos blockpos = p_76028_.relative(direction);
|
|
BlockState blockstate = p_361884_.getBlockState(blockpos);
|
|
FluidState fluidstate = blockstate.getFluidState();
|
|
if (this.canPassThrough(p_76027_, this.getFlowing(), p_76028_, p_76031_, direction, blockpos, blockstate, fluidstate)) {
|
|
if (p_361884_.isHole(blockpos)) {
|
|
return p_76029_;
|
|
}
|
|
|
|
if (p_76029_ < this.getSlopeFindDistance(p_76027_)) {
|
|
int j = this.getSlopeDistance(p_76027_, blockpos, p_76029_ + 1, direction.getOpposite(), blockstate, p_361884_);
|
|
if (j < i) {
|
|
i = j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
boolean isWaterHole(BlockGetter p_75957_, BlockPos p_75959_, BlockState p_75960_, BlockPos p_75961_, BlockState p_75962_) {
|
|
if (!canPassThroughWall(Direction.DOWN, p_75957_, p_75959_, p_75960_, p_75961_, p_75962_)) {
|
|
return false;
|
|
} else {
|
|
return p_75962_.getFluidState().getType().isSame(this) ? true : canHoldFluid(p_75957_, p_75961_, p_75962_, this.getFlowing());
|
|
}
|
|
}
|
|
|
|
private boolean canPassThrough(
|
|
BlockGetter p_75964_,
|
|
Fluid p_75965_,
|
|
BlockPos p_75966_,
|
|
BlockState p_75967_,
|
|
Direction p_75968_,
|
|
BlockPos p_75969_,
|
|
BlockState p_75970_,
|
|
FluidState p_75971_
|
|
) {
|
|
return this.canMaybePassThrough(p_75964_, p_75966_, p_75967_, p_75968_, p_75969_, p_75970_, p_75971_) && canHoldSpecificFluid(p_75964_, p_75969_, p_75970_, p_75965_);
|
|
}
|
|
|
|
private boolean canMaybePassThrough(
|
|
BlockGetter p_366439_, BlockPos p_366289_, BlockState p_368603_, Direction p_367727_, BlockPos p_366544_, BlockState p_366635_, FluidState p_362443_
|
|
) {
|
|
return !this.isSourceBlockOfThisType(p_362443_) && canHoldAnyFluid(p_366635_) && canPassThroughWall(p_367727_, p_366439_, p_366289_, p_368603_, p_366544_, p_366635_);
|
|
}
|
|
|
|
private boolean isSourceBlockOfThisType(FluidState p_76097_) {
|
|
return p_76097_.getType().isSame(this) && p_76097_.isSource();
|
|
}
|
|
|
|
protected abstract int getSlopeFindDistance(LevelReader p_76074_);
|
|
|
|
private int sourceNeighborCount(LevelReader p_76020_, BlockPos p_76021_) {
|
|
int i = 0;
|
|
|
|
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
|
BlockPos blockpos = p_76021_.relative(direction);
|
|
FluidState fluidstate = p_76020_.getFluidState(blockpos);
|
|
if (this.isSourceBlockOfThisType(fluidstate)) {
|
|
i++;
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
protected Map<Direction, FluidState> getSpread(ServerLevel p_367926_, BlockPos p_76081_, BlockState p_76082_) {
|
|
int i = 1000;
|
|
Map<Direction, FluidState> map = Maps.newEnumMap(Direction.class);
|
|
FlowingFluid.SpreadContext flowingfluid$spreadcontext = null;
|
|
|
|
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
|
BlockPos blockpos = p_76081_.relative(direction);
|
|
BlockState blockstate = p_367926_.getBlockState(blockpos);
|
|
FluidState fluidstate = blockstate.getFluidState();
|
|
if (this.canMaybePassThrough(p_367926_, p_76081_, p_76082_, direction, blockpos, blockstate, fluidstate)) {
|
|
FluidState fluidstate1 = this.getNewLiquid(p_367926_, blockpos, blockstate);
|
|
if (canHoldSpecificFluid(p_367926_, blockpos, blockstate, fluidstate1.getType())) {
|
|
if (flowingfluid$spreadcontext == null) {
|
|
flowingfluid$spreadcontext = new FlowingFluid.SpreadContext(p_367926_, p_76081_);
|
|
}
|
|
|
|
int j;
|
|
if (flowingfluid$spreadcontext.isHole(blockpos)) {
|
|
j = 0;
|
|
} else {
|
|
j = this.getSlopeDistance(p_367926_, blockpos, 1, direction.getOpposite(), blockstate, flowingfluid$spreadcontext);
|
|
}
|
|
|
|
if (j < i) {
|
|
map.clear();
|
|
}
|
|
|
|
if (j <= i) {
|
|
if (fluidstate.canBeReplacedWith(p_367926_, blockpos, fluidstate1.getType(), direction)) {
|
|
map.put(direction, fluidstate1);
|
|
}
|
|
|
|
i = j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
private static boolean canHoldAnyFluid(BlockState p_366747_) {
|
|
Block block = p_366747_.getBlock();
|
|
if (block instanceof LiquidBlockContainer) {
|
|
return true;
|
|
} else {
|
|
return p_366747_.blocksMotion()
|
|
? false
|
|
: !(block instanceof DoorBlock)
|
|
&& !p_366747_.is(BlockTags.SIGNS)
|
|
&& !p_366747_.is(Blocks.LADDER)
|
|
&& !p_366747_.is(Blocks.SUGAR_CANE)
|
|
&& !p_366747_.is(Blocks.BUBBLE_COLUMN)
|
|
&& !p_366747_.is(Blocks.NETHER_PORTAL)
|
|
&& !p_366747_.is(Blocks.END_PORTAL)
|
|
&& !p_366747_.is(Blocks.END_GATEWAY)
|
|
&& !p_366747_.is(Blocks.STRUCTURE_VOID);
|
|
}
|
|
}
|
|
|
|
private static boolean canHoldFluid(BlockGetter p_75973_, BlockPos p_75974_, BlockState p_75975_, Fluid p_75976_) {
|
|
return canHoldAnyFluid(p_75975_) && canHoldSpecificFluid(p_75973_, p_75974_, p_75975_, p_75976_);
|
|
}
|
|
|
|
private static boolean canHoldSpecificFluid(BlockGetter p_368745_, BlockPos p_367421_, BlockState p_366623_, Fluid p_365745_) {
|
|
return p_366623_.getBlock() instanceof LiquidBlockContainer liquidblockcontainer
|
|
? liquidblockcontainer.canPlaceLiquid(null, p_368745_, p_367421_, p_366623_, p_365745_)
|
|
: true;
|
|
}
|
|
|
|
protected abstract int getDropOff(LevelReader p_76087_);
|
|
|
|
protected int getSpreadDelay(Level p_75998_, BlockPos p_75999_, FluidState p_76000_, FluidState p_76001_) {
|
|
return this.getTickDelay(p_75998_);
|
|
}
|
|
|
|
@Override
|
|
public void tick(ServerLevel p_362527_, BlockPos p_75996_, BlockState p_369266_, FluidState p_75997_) {
|
|
if (!p_75997_.isSource()) {
|
|
FluidState fluidstate = this.getNewLiquid(p_362527_, p_75996_, p_362527_.getBlockState(p_75996_));
|
|
int i = this.getSpreadDelay(p_362527_, p_75996_, p_75997_, fluidstate);
|
|
if (fluidstate.isEmpty()) {
|
|
p_75997_ = fluidstate;
|
|
p_369266_ = Blocks.AIR.defaultBlockState();
|
|
p_362527_.setBlock(p_75996_, p_369266_, 3);
|
|
} else if (fluidstate != p_75997_) {
|
|
p_75997_ = fluidstate;
|
|
p_369266_ = fluidstate.createLegacyBlock();
|
|
p_362527_.setBlock(p_75996_, p_369266_, 3);
|
|
p_362527_.scheduleTick(p_75996_, fluidstate.getType(), i);
|
|
}
|
|
}
|
|
|
|
this.spread(p_362527_, p_75996_, p_369266_, p_75997_);
|
|
}
|
|
|
|
protected static int getLegacyLevel(FluidState p_76093_) {
|
|
return p_76093_.isSource() ? 0 : 8 - Math.min(p_76093_.getAmount(), 8) + (p_76093_.getValue(FALLING) ? 8 : 0);
|
|
}
|
|
|
|
private static boolean hasSameAbove(FluidState p_76089_, BlockGetter p_76090_, BlockPos p_76091_) {
|
|
return p_76089_.getType().isSame(p_76090_.getFluidState(p_76091_.above()).getType());
|
|
}
|
|
|
|
@Override
|
|
public float getHeight(FluidState p_76050_, BlockGetter p_76051_, BlockPos p_76052_) {
|
|
return hasSameAbove(p_76050_, p_76051_, p_76052_) ? 1.0F : p_76050_.getOwnHeight();
|
|
}
|
|
|
|
@Override
|
|
public float getOwnHeight(FluidState p_76048_) {
|
|
return p_76048_.getAmount() / 9.0F;
|
|
}
|
|
|
|
@Override
|
|
public abstract int getAmount(FluidState p_164509_);
|
|
|
|
@Override
|
|
public VoxelShape getShape(FluidState p_76084_, BlockGetter p_76085_, BlockPos p_76086_) {
|
|
return p_76084_.getAmount() == 9 && hasSameAbove(p_76084_, p_76085_, p_76086_)
|
|
? Shapes.block()
|
|
: this.shapes.computeIfAbsent(p_76084_, p_76073_ -> Shapes.box(0.0, 0.0, 0.0, 1.0, p_76073_.getHeight(p_76085_, p_76086_), 1.0));
|
|
}
|
|
|
|
record BlockStatePairKey(BlockState first, BlockState second, Direction direction) {
|
|
@Override
|
|
public boolean equals(Object p_364864_) {
|
|
return p_364864_ instanceof FlowingFluid.BlockStatePairKey flowingfluid$blockstatepairkey
|
|
&& this.first == flowingfluid$blockstatepairkey.first
|
|
&& this.second == flowingfluid$blockstatepairkey.second
|
|
&& this.direction == flowingfluid$blockstatepairkey.direction;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
int i = System.identityHashCode(this.first);
|
|
i = 31 * i + System.identityHashCode(this.second);
|
|
return 31 * i + this.direction.hashCode();
|
|
}
|
|
}
|
|
|
|
protected class SpreadContext {
|
|
private final BlockGetter level;
|
|
private final BlockPos origin;
|
|
private final Short2ObjectMap<BlockState> stateCache = new Short2ObjectOpenHashMap<>();
|
|
private final Short2BooleanMap holeCache = new Short2BooleanOpenHashMap();
|
|
|
|
SpreadContext(final BlockGetter p_369304_, final BlockPos p_362233_) {
|
|
this.level = p_369304_;
|
|
this.origin = p_362233_;
|
|
}
|
|
|
|
public BlockState getBlockState(BlockPos p_366261_) {
|
|
return this.getBlockState(p_366261_, this.getCacheKey(p_366261_));
|
|
}
|
|
|
|
private BlockState getBlockState(BlockPos p_361123_, short p_365944_) {
|
|
return this.stateCache.computeIfAbsent(p_365944_, p_365254_ -> this.level.getBlockState(p_361123_));
|
|
}
|
|
|
|
public boolean isHole(BlockPos p_370165_) {
|
|
return this.holeCache.computeIfAbsent(this.getCacheKey(p_370165_), p_365811_ -> {
|
|
BlockState blockstate = this.getBlockState(p_370165_, p_365811_);
|
|
BlockPos blockpos = p_370165_.below();
|
|
BlockState blockstate1 = this.level.getBlockState(blockpos);
|
|
return FlowingFluid.this.isWaterHole(this.level, p_370165_, blockstate, blockpos, blockstate1);
|
|
});
|
|
}
|
|
|
|
private short getCacheKey(BlockPos p_363365_) {
|
|
int i = p_363365_.getX() - this.origin.getX();
|
|
int j = p_363365_.getZ() - this.origin.getZ();
|
|
return (short)((i + 128 & 0xFF) << 8 | j + 128 & 0xFF);
|
|
}
|
|
}
|
|
} |