mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-12 16:27:47 +00:00
Fix a few FluidUtil issues that were causing DispenseFluidContainer to not function properly (#7422)
This commit is contained in:
1 parent
0340664dbf
commit
d97f28141c
6 files changed
+353
-20
No files matched your search
@@ -24,6 +24,8 @@ import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.IBucketPickupHandler;
|
||||
import net.minecraft.block.ILiquidContainer;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
@@ -31,7 +33,6 @@ import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.fluid.Fluids;
|
||||
import net.minecraft.item.BlockItemUseContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemUseContext;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.*;
|
||||
@@ -44,6 +45,8 @@ import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
|
||||
import net.minecraftforge.fluids.capability.wrappers.BlockWrapper;
|
||||
import net.minecraftforge.fluids.capability.wrappers.BucketPickupHandlerWrapper;
|
||||
import net.minecraftforge.fluids.capability.wrappers.FluidBlockWrapper;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
@@ -435,8 +438,12 @@ public class FluidUtil
|
||||
if (!container.isEmpty())
|
||||
{
|
||||
container = ItemHandlerHelper.copyStackWithSize(container, 1);
|
||||
return getFluidHandler(container)
|
||||
Optional<FluidStack> fluidContained = getFluidHandler(container)
|
||||
.map(handler -> handler.drain(Integer.MAX_VALUE, IFluidHandler.FluidAction.SIMULATE));
|
||||
if (fluidContained.isPresent() && !fluidContained.get().isEmpty())
|
||||
{
|
||||
return fluidContained;
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
@@ -481,20 +488,29 @@ public class FluidUtil
|
||||
|
||||
BlockState state = worldIn.getBlockState(pos);
|
||||
Block block = state.getBlock();
|
||||
|
||||
IFluidHandler targetFluidHandler;
|
||||
if (block instanceof IFluidBlock)
|
||||
{
|
||||
IFluidHandler targetFluidHandler = getFluidHandler(worldIn, pos, side).orElse(null);
|
||||
if (targetFluidHandler != null)
|
||||
{
|
||||
return tryFillContainer(emptyContainer, targetFluidHandler, Integer.MAX_VALUE, playerIn, true);
|
||||
}
|
||||
targetFluidHandler = new FluidBlockWrapper((IFluidBlock) block, worldIn, pos);
|
||||
}
|
||||
return FluidActionResult.FAILURE;
|
||||
else if (block instanceof IBucketPickupHandler)
|
||||
{
|
||||
targetFluidHandler = new BucketPickupHandlerWrapper((IBucketPickupHandler) block, worldIn, pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
Optional<IFluidHandler> fluidHandler = getFluidHandler(worldIn, pos, side).resolve();
|
||||
if (!fluidHandler.isPresent())
|
||||
{
|
||||
return FluidActionResult.FAILURE;
|
||||
}
|
||||
targetFluidHandler = fluidHandler.get();
|
||||
}
|
||||
return tryFillContainer(emptyContainer, targetFluidHandler, Integer.MAX_VALUE, playerIn, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* ItemStack version of {@link #tryPlaceFluid(PlayerEntity, World, BlockPos, IFluidHandler, FluidStack)}.
|
||||
* ItemStack version of {@link #tryPlaceFluid(PlayerEntity, World, Hand, BlockPos, IFluidHandler, FluidStack)}.
|
||||
* Use the returned {@link FluidActionResult} to update the container ItemStack.
|
||||
*
|
||||
* @param player Player who places the fluid. May be null for blocks like dispensers.
|
||||
@@ -522,7 +538,7 @@ public class FluidUtil
|
||||
* Honors the amount of fluid contained by the used container.
|
||||
* Checks if water-like fluids should vaporize like in the nether.
|
||||
*
|
||||
* Modeled after {@link ItemBucket#tryPlaceContainedLiquid(PlayerEntity, World, BlockPos)}
|
||||
* Modeled after {@link net.minecraft.item.BucketItem#tryPlaceContainedLiquid(PlayerEntity, World, BlockPos, BlockRayTraceResult)}
|
||||
*
|
||||
* @param player Player who places the fluid. May be null for blocks like dispensers.
|
||||
* @param world World to place the fluid in
|
||||
@@ -540,7 +556,7 @@ public class FluidUtil
|
||||
}
|
||||
|
||||
Fluid fluid = resource.getFluid();
|
||||
if (fluid == null || !fluid.getAttributes().canBePlacedInWorld(world, pos, resource))
|
||||
if (fluid == Fluids.EMPTY || !fluid.getAttributes().canBePlacedInWorld(world, pos, resource))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -550,14 +566,15 @@ public class FluidUtil
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockItemUseContext context = new BlockItemUseContext(new ItemUseContext(player, hand, new BlockRayTraceResult(Vector3d.ZERO, Direction.UP, pos, false))); //TODO: This neds proper context...
|
||||
BlockItemUseContext context = new BlockItemUseContext(world, player, hand, player == null ? ItemStack.EMPTY : player.getHeldItem(hand), new BlockRayTraceResult(Vector3d.ZERO, Direction.UP, pos, false));
|
||||
|
||||
// check that we can place the fluid at the destination
|
||||
BlockState destBlockState = world.getBlockState(pos);
|
||||
Material destMaterial = destBlockState.getMaterial();
|
||||
boolean isDestNonSolid = !destMaterial.isSolid();
|
||||
boolean isDestReplaceable = destBlockState.isReplaceable(context);
|
||||
if (!world.isAirBlock(pos) && !isDestNonSolid && !isDestReplaceable)
|
||||
boolean canDestContainFluid = destBlockState.getBlock() instanceof ILiquidContainer && ((ILiquidContainer) destBlockState.getBlock()).canContainFluid(world, pos, destBlockState, fluid);
|
||||
if (!world.isAirBlock(pos) && !isDestNonSolid && !isDestReplaceable && !canDestContainFluid)
|
||||
{
|
||||
return false; // Non-air, solid, unreplacable block. We can't put fluid here.
|
||||
}
|
||||
@@ -574,7 +591,15 @@ public class FluidUtil
|
||||
else
|
||||
{
|
||||
// This fluid handler places the fluid block when filled
|
||||
IFluidHandler handler = getFluidBlockHandler(fluid, world, pos);
|
||||
IFluidHandler handler;
|
||||
if (canDestContainFluid)
|
||||
{
|
||||
handler = new BlockWrapper.LiquidContainerBlockWrapper((ILiquidContainer) destBlockState.getBlock(), world, pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
handler = getFluidBlockHandler(fluid, world, pos);
|
||||
}
|
||||
FluidStack result = tryFluidTransfer(handler, fluidSource, resource, true);
|
||||
if (!result.isEmpty())
|
||||
{
|
||||
@@ -589,8 +614,8 @@ public class FluidUtil
|
||||
/**
|
||||
* Internal method for getting a fluid block handler for placing a fluid.
|
||||
*
|
||||
* Modders: Instead of this method, use {@link #tryPlaceFluid(PlayerEntity, World, BlockPos, ItemStack, FluidStack)}
|
||||
* or {@link #tryPlaceFluid(PlayerEntity, World, BlockPos, IFluidHandler, FluidStack)}
|
||||
* Modders: Instead of this method, use {@link #tryPlaceFluid(PlayerEntity, World, Hand, BlockPos, ItemStack, FluidStack)}
|
||||
* or {@link #tryPlaceFluid(PlayerEntity, World, Hand, BlockPos, IFluidHandler, FluidStack)}
|
||||
*/
|
||||
private static IFluidHandler getFluidBlockHandler(Fluid fluid, World world, BlockPos pos)
|
||||
{
|
||||
@@ -600,9 +625,9 @@ public class FluidUtil
|
||||
|
||||
/**
|
||||
* Destroys a block when a fluid is placed in the same position.
|
||||
* Modeled after {@link ItemBucket#tryPlaceContainedLiquid(PlayerEntity, World, BlockPos)}
|
||||
* Modeled after {@link net.minecraft.item.BucketItem#tryPlaceContainedLiquid(PlayerEntity, World, BlockPos, BlockRayTraceResult)}
|
||||
*
|
||||
* This is a helper method for implementing {@link IFluidBlock#place(World, BlockPos, FluidStack, boolean)}.
|
||||
* This is a helper method for implementing {@link IFluidBlock#place(World, BlockPos, FluidStack, IFluidHandler.FluidAction)}.
|
||||
*
|
||||
* @param world the world that the fluid will be placed in
|
||||
* @param pos the location that the fluid will be placed
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
package net.minecraftforge.fluids.capability.wrappers;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.ILiquidContainer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.Constants;
|
||||
@@ -62,4 +62,37 @@ public class BlockWrapper extends VoidFluidHandler
|
||||
}
|
||||
return FluidAttributes.BUCKET_VOLUME;
|
||||
}
|
||||
|
||||
public static class LiquidContainerBlockWrapper extends VoidFluidHandler
|
||||
{
|
||||
protected final ILiquidContainer liquidContainer;
|
||||
protected final World world;
|
||||
protected final BlockPos blockPos;
|
||||
|
||||
public LiquidContainerBlockWrapper(ILiquidContainer liquidContainer, World world, BlockPos blockPos)
|
||||
{
|
||||
this.liquidContainer = liquidContainer;
|
||||
this.world = world;
|
||||
this.blockPos = blockPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fill(FluidStack resource, FluidAction action)
|
||||
{
|
||||
// NOTE: "Filling" means placement in this context!
|
||||
if (resource.getAmount() >= FluidAttributes.BUCKET_VOLUME)
|
||||
{
|
||||
BlockState state = world.getBlockState(blockPos);
|
||||
if (liquidContainer.canContainFluid(world, blockPos, state, resource.getFluid()))
|
||||
{
|
||||
//If we are executing try to actually fill the container, if it failed return that we failed
|
||||
if (action.simulate() || liquidContainer.receiveFluid(world, blockPos, state, resource.getFluid().getAttributes().getStateForPlacement(world, blockPos, resource)))
|
||||
{
|
||||
return FluidAttributes.BUCKET_VOLUME;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fluids.capability.wrappers;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import net.minecraft.block.IBucketPickupHandler;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.fluid.Fluids;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fluids.FluidAttributes;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class BucketPickupHandlerWrapper implements IFluidHandler
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
protected final IBucketPickupHandler bucketPickupHandler;
|
||||
protected final World world;
|
||||
protected final BlockPos blockPos;
|
||||
|
||||
public BucketPickupHandlerWrapper(IBucketPickupHandler bucketPickupHandler, World world, BlockPos blockPos)
|
||||
{
|
||||
this.bucketPickupHandler = bucketPickupHandler;
|
||||
this.world = world;
|
||||
this.blockPos = blockPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTanks()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public FluidStack getFluidInTank(int tank)
|
||||
{
|
||||
if (tank == 0)
|
||||
{
|
||||
//Best guess at stored fluid
|
||||
FluidState fluidState = world.getFluidState(blockPos);
|
||||
if (!fluidState.isEmpty())
|
||||
{
|
||||
return new FluidStack(fluidState.getFluid(), FluidAttributes.BUCKET_VOLUME);
|
||||
}
|
||||
}
|
||||
return FluidStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTankCapacity(int tank)
|
||||
{
|
||||
return FluidAttributes.BUCKET_VOLUME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFluidValid(int tank, @Nonnull FluidStack stack)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fill(FluidStack resource, FluidAction action)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public FluidStack drain(FluidStack resource, FluidAction action)
|
||||
{
|
||||
if (!resource.isEmpty() && FluidAttributes.BUCKET_VOLUME <= resource.getAmount())
|
||||
{
|
||||
FluidState fluidState = world.getFluidState(blockPos);
|
||||
if (!fluidState.isEmpty() && resource.getFluid() == fluidState.getFluid())
|
||||
{
|
||||
if (action.execute())
|
||||
{
|
||||
Fluid fluid = bucketPickupHandler.pickupFluid(world, blockPos, world.getBlockState(blockPos));
|
||||
if (fluid != Fluids.EMPTY)
|
||||
{
|
||||
FluidStack extracted = new FluidStack(fluid, FluidAttributes.BUCKET_VOLUME);
|
||||
if (!resource.isFluidEqual(extracted))
|
||||
{
|
||||
//Be loud if something went wrong
|
||||
LOGGER.error("Fluid removed without successfully being picked up. Fluid {} at {} in {} matched requested type, but after performing pickup was {}.",
|
||||
fluidState.getFluid().getRegistryName(), blockPos, world.getDimensionKey().getLocation(), fluid.getRegistryName());
|
||||
return FluidStack.EMPTY;
|
||||
}
|
||||
return extracted;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FluidStack extracted = new FluidStack(fluidState.getFluid(), FluidAttributes.BUCKET_VOLUME);
|
||||
if (resource.isFluidEqual(extracted))
|
||||
{
|
||||
//Validate NBT matches
|
||||
return extracted;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return FluidStack.EMPTY;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public FluidStack drain(int maxDrain, FluidAction action)
|
||||
{
|
||||
if (FluidAttributes.BUCKET_VOLUME <= maxDrain)
|
||||
{
|
||||
FluidState fluidState = world.getFluidState(blockPos);
|
||||
if (!fluidState.isEmpty())
|
||||
{
|
||||
if (action.simulate())
|
||||
{
|
||||
return new FluidStack(fluidState.getFluid(), FluidAttributes.BUCKET_VOLUME);
|
||||
}
|
||||
Fluid fluid = bucketPickupHandler.pickupFluid(world, blockPos, world.getBlockState(blockPos));
|
||||
if (fluid != Fluids.EMPTY)
|
||||
{
|
||||
return new FluidStack(fluid, FluidAttributes.BUCKET_VOLUME);
|
||||
}
|
||||
}
|
||||
}
|
||||
return FluidStack.EMPTY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2020.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fluids.capability.wrappers;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fluids.FluidAttributes;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.IFluidBlock;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
|
||||
public class FluidBlockWrapper implements IFluidHandler
|
||||
{
|
||||
protected final IFluidBlock fluidBlock;
|
||||
protected final World world;
|
||||
protected final BlockPos blockPos;
|
||||
|
||||
public FluidBlockWrapper(IFluidBlock fluidBlock, World world, BlockPos blockPos)
|
||||
{
|
||||
this.fluidBlock = fluidBlock;
|
||||
this.world = world;
|
||||
this.blockPos = blockPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTanks()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public FluidStack getFluidInTank(int tank)
|
||||
{
|
||||
return tank == 0 ? fluidBlock.drain(world, blockPos, FluidAction.SIMULATE) : FluidStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTankCapacity(int tank)
|
||||
{
|
||||
FluidStack stored = getFluidInTank(tank);
|
||||
if (!stored.isEmpty())
|
||||
{
|
||||
float filledPercentage = fluidBlock.getFilledPercentage(world, blockPos);
|
||||
if (filledPercentage > 0)
|
||||
{
|
||||
return (int) (stored.getAmount() / filledPercentage);
|
||||
}
|
||||
}
|
||||
return FluidAttributes.BUCKET_VOLUME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFluidValid(int tank, @Nonnull FluidStack stack)
|
||||
{
|
||||
return stack.getFluid() == fluidBlock.getFluid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fill(FluidStack resource, FluidAction action)
|
||||
{
|
||||
return fluidBlock.place(world, blockPos, resource, action);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public FluidStack drain(FluidStack resource, FluidAction action)
|
||||
{
|
||||
if (!resource.isEmpty() && fluidBlock.canDrain(world, blockPos) && resource.getFluid() == fluidBlock.getFluid())
|
||||
{
|
||||
FluidStack simulatedDrained = fluidBlock.drain(world, blockPos, FluidAction.SIMULATE);
|
||||
if (simulatedDrained.getAmount() <= resource.getAmount() && resource.isFluidEqual(simulatedDrained))
|
||||
{
|
||||
if (action.execute())
|
||||
{
|
||||
return fluidBlock.drain(world, blockPos, FluidAction.EXECUTE).copy();
|
||||
}
|
||||
return simulatedDrained.copy();
|
||||
}
|
||||
}
|
||||
return FluidStack.EMPTY;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public FluidStack drain(int maxDrain, FluidAction action)
|
||||
{
|
||||
if (maxDrain <= 0 && fluidBlock.canDrain(world, blockPos))
|
||||
{
|
||||
FluidStack simulatedDrained = fluidBlock.drain(world, blockPos, FluidAction.SIMULATE);
|
||||
if (simulatedDrained.getAmount() <= maxDrain)
|
||||
{
|
||||
if (action.execute())
|
||||
{
|
||||
return fluidBlock.drain(world, blockPos, FluidAction.EXECUTE).copy();
|
||||
}
|
||||
return simulatedDrained.copy();
|
||||
}
|
||||
}
|
||||
return FluidStack.EMPTY;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user