Add new IFluidHandler for capabilities. (#2942)

Old fluid system is deprecated and slated for removal in the next cleanup cycle.
This commit is contained in:
mezz 2016-06-03 18:26:41 -07:00 committed by LexManos
parent 13ed510fcf
commit 92914f82ae
39 changed files with 2612 additions and 298 deletions

View file

@ -9,3 +9,13 @@
if (raytraceresult == null)
{
@@ -175,4 +177,9 @@
}
}
}
+
+ @Override
+ public net.minecraftforge.common.capabilities.ICapabilityProvider initCapabilities(ItemStack stack, net.minecraft.nbt.NBTTagCompound nbt) {
+ return new net.minecraftforge.fluids.capability.wrappers.FluidBucketWrapper(stack);
+ }
}

View file

@ -9,3 +9,13 @@
}
if (p_77654_3_ instanceof EntityPlayer)
@@ -55,4 +55,9 @@
p_77659_3_.func_184598_c(p_77659_4_);
return new ActionResult(EnumActionResult.SUCCESS, p_77659_1_);
}
+
+ @Override
+ public net.minecraftforge.common.capabilities.ICapabilityProvider initCapabilities(ItemStack stack, net.minecraft.nbt.NBTTagCompound nbt) {
+ return new net.minecraftforge.fluids.capability.wrappers.FluidBucketWrapper(stack);
+ }
}

View file

@ -31,8 +31,10 @@ import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.IFluidContainerItem;
import net.minecraftforge.fluids.capability.IFluidHandler;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function;
@ -237,14 +239,7 @@ public final class ModelDynBucket implements IModel, IModelCustomData, IRetextur
@Override
public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, World world, EntityLivingBase entity)
{
FluidStack fluidStack = FluidContainerRegistry.getFluidForFilledItem(stack);
if (fluidStack == null)
{
if (stack.getItem() instanceof IFluidContainerItem)
{
fluidStack = ((IFluidContainerItem) stack.getItem()).getFluid(stack);
}
}
FluidStack fluidStack = FluidUtil.getFluidContained(stack);
// not a fluid item apparently
if (fluidStack == null)

View file

@ -69,9 +69,10 @@ import net.minecraftforge.common.model.animation.IClip;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.Properties;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.ProgressManager;
import net.minecraftforge.fml.common.ProgressManager.ProgressBar;
@ -355,8 +356,9 @@ public final class ModelLoader extends ModelBakery
{
// can the milk be put into a bucket?
Fluid milk = FluidRegistry.getFluid("milk");
FluidStack milkStack = new FluidStack(milk, FluidContainerRegistry.BUCKET_VOLUME);
if(FluidContainerRegistry.getContainerCapacity(milkStack, new ItemStack(Items.BUCKET)) == FluidContainerRegistry.BUCKET_VOLUME)
FluidStack milkStack = new FluidStack(milk, Fluid.BUCKET_VOLUME);
IFluidHandler bucketHandler = FluidUtil.getFluidHandler(new ItemStack(Items.BUCKET));
if (bucketHandler != null && bucketHandler.fill(milkStack, false) == Fluid.BUCKET_VOLUME)
{
setBucketModel(Items.MILK_BUCKET);
}

View file

@ -36,6 +36,7 @@ import net.minecraftforge.common.config.Property;
import net.minecraftforge.common.model.animation.CapabilityAnimation;
import net.minecraftforge.common.network.ForgeNetworkHandler;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.fluids.UniversalBucket;
import net.minecraftforge.fml.common.registry.GameRegistry;
@ -372,6 +373,7 @@ public class ForgeModContainer extends DummyModContainer implements WorldAccessC
public void preInit(FMLPreInitializationEvent evt)
{
CapabilityItemHandler.register();
CapabilityFluidHandler.register();
CapabilityAnimation.register();
MinecraftForge.EVENT_BUS.register(MinecraftForge.INTERNAL_HANDLER);
ForgeChunkManager.captureConfig(evt.getModConfigurationDirectory());

View file

@ -1,5 +1,6 @@
package net.minecraftforge.common.capabilities;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
@ -66,7 +67,7 @@ public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompou
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing)
public boolean hasCapability(Capability<?> capability, @Nullable EnumFacing facing)
{
for (ICapabilityProvider cap : caps)
{
@ -79,7 +80,7 @@ public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompou
}
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing)
public <T> T getCapability(Capability<T> capability, @Nullable EnumFacing facing)
{
for (ICapabilityProvider cap : caps)
{

View file

@ -1,5 +1,7 @@
package net.minecraftforge.common.capabilities;
import javax.annotation.Nullable;
import net.minecraft.util.EnumFacing;
public interface ICapabilityProvider
@ -19,7 +21,7 @@ public interface ICapabilityProvider
* CAN BE NULL. Null is defined to represent 'internal' or 'self'
* @return True if this object supports the capability.
*/
boolean hasCapability(Capability<?> capability, EnumFacing facing);
boolean hasCapability(Capability<?> capability, @Nullable EnumFacing facing);
/**
* Retrieves the handler for the capability requested on the specific side.
@ -31,5 +33,5 @@ public interface ICapabilityProvider
* CAN BE NULL. Null is defined to represent 'internal' or 'self'
* @return True if this object supports the capability.
*/
<T> T getCapability(Capability<T> capability, EnumFacing facing);
<T> T getCapability(Capability<T> capability, @Nullable EnumFacing facing);
}

View file

@ -24,7 +24,7 @@ public class BlockFluidClassic extends BlockFluidBase
public BlockFluidClassic(Fluid fluid, Material material)
{
super(fluid, material);
stack = new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME);
stack = new FluidStack(fluid, Fluid.BUCKET_VOLUME);
}
public BlockFluidClassic setFluidStack(FluidStack stack)

View file

@ -226,7 +226,7 @@ public class BlockFluidFinite extends BlockFluidBase
@Override
public FluidStack drain(World world, BlockPos pos, boolean doDrain)
{
final FluidStack fluidStack = new FluidStack(getFluid(), MathHelper.floor_float(getQuantaPercentage(world, pos) * FluidContainerRegistry.BUCKET_VOLUME));
final FluidStack fluidStack = new FluidStack(getFluid(), MathHelper.floor_float(getQuantaPercentage(world, pos) * Fluid.BUCKET_VOLUME));
if (doDrain)
{

View file

@ -30,6 +30,8 @@ import net.minecraft.item.EnumRarity;
*/
public class Fluid
{
public static final int BUCKET_VOLUME = 1000;
/** The unique identification name for this fluid. */
protected final String fluidName;

View file

@ -17,10 +17,7 @@ import net.minecraftforge.common.MinecraftForge;
* Register simple items that contain fluids here. Useful for buckets, bottles, and things that have
* ID/metadata mappings.
*
* For more complex items, use {@link IFluidContainerItem} instead.
*
* Deprecated: We will eventually be moving this ALL away from a registry and instead EVERYTHING will use IFluidContainerItem.
* We need to decide a way of swapping Items/Stacks.
* @deprecated This will be removed soon. Create an item like {@link net.minecraftforge.fluids.capability.ItemFluidContainer}
*/
@Deprecated
public abstract class FluidContainerRegistry
@ -70,8 +67,11 @@ public abstract class FluidContainerRegistry
private static Map<ContainerKey, FluidContainerData> filledContainerMap = Maps.newHashMap();
private static Set<ContainerKey> emptyContainers = Sets.newHashSet();
public static final int BUCKET_VOLUME = 1000;
@Deprecated
public static final int BUCKET_VOLUME = Fluid.BUCKET_VOLUME;
@Deprecated
public static final ItemStack EMPTY_BUCKET = new ItemStack(Items.BUCKET);
@Deprecated
public static final ItemStack EMPTY_BOTTLE = new ItemStack(Items.GLASS_BOTTLE);
private static final ItemStack NULL_EMPTYCONTAINER = new ItemStack(Items.BUCKET);
@ -348,6 +348,21 @@ public abstract class FluidContainerRegistry
return container != null && getFluidForFilledItem(container) != null;
}
public static boolean hasNullEmptyContainer(ItemStack container)
{
if (container == null)
{
return false;
}
FluidContainerData data = containerFluidMap.get(new ContainerKey(container));
if (data != null)
{
return data.emptyContainer == NULL_EMPTYCONTAINER;
}
return false;
}
public static FluidContainerData[] getRegisteredFluidContainerData()
{
return containerFluidMap.values().toArray(new FluidContainerData[containerFluidMap.size()]);

View file

@ -174,12 +174,7 @@ public class FluidStack
return false;
}
if (other.getItem() instanceof IFluidContainerItem)
{
return isFluidEqual(((IFluidContainerItem) other.getItem()).getFluid(other));
}
return isFluidEqual(FluidContainerRegistry.getFluidForFilledItem(other));
return isFluidEqual(FluidUtil.getFluidContained(other));
}
@Override

View file

@ -1,26 +1,34 @@
package net.minecraftforge.fluids;
import javax.annotation.Nullable;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.fluids.capability.FluidTankPropertiesWrapper;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
/**
* Reference implementation of {@link IFluidTank}. Use/extend this or implement your own.
*/
public class FluidTank implements IFluidTank
public class FluidTank implements IFluidTank, IFluidHandler
{
@Nullable
protected FluidStack fluid;
protected int capacity;
protected TileEntity tile;
protected boolean canFill = true;
protected boolean canDrain = true;
protected IFluidTankProperties[] tankProperties;
public FluidTank(int capacity)
{
this(null, capacity);
}
public FluidTank(FluidStack stack, int capacity)
public FluidTank(@Nullable FluidStack fluidStack, int capacity)
{
this.fluid = stack;
this.fluid = fluidStack;
this.capacity = capacity;
}
@ -56,23 +64,19 @@ public class FluidTank implements IFluidTank
return nbt;
}
public void setFluid(FluidStack fluid)
{
this.fluid = fluid;
}
public void setCapacity(int capacity)
{
this.capacity = capacity;
}
/* IFluidTank */
@Override
@Nullable
public FluidStack getFluid()
{
return fluid;
}
public void setFluid(@Nullable FluidStack fluid)
{
this.fluid = fluid;
}
@Override
public int getFluidAmount()
{
@ -89,16 +93,36 @@ public class FluidTank implements IFluidTank
return capacity;
}
public void setCapacity(int capacity)
{
this.capacity = capacity;
}
public void setTileEntity(TileEntity tile)
{
this.tile = tile;
}
@Override
public FluidTankInfo getInfo()
{
return new FluidTankInfo(this);
}
@Override
public IFluidTankProperties[] getTankProperties()
{
if (this.tankProperties == null)
{
this.tankProperties = new IFluidTankProperties[] { new FluidTankPropertiesWrapper(this) };
}
return this.tankProperties;
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (resource == null)
if (resource == null || resource.amount <= 0 || !canFillFluidType(resource))
{
return 0;
}
@ -122,6 +146,8 @@ public class FluidTank implements IFluidTank
{
fluid = new FluidStack(resource, Math.min(capacity, resource.amount));
onContentsChanged();
if (tile != null)
{
FluidEvent.fireEvent(new FluidEvent.FluidFillingEvent(fluid, tile.getWorld(), tile.getPos(), this, fluid.amount));
@ -145,6 +171,8 @@ public class FluidTank implements IFluidTank
fluid.amount = capacity;
}
onContentsChanged();
if (tile != null)
{
FluidEvent.fireEvent(new FluidEvent.FluidFillingEvent(fluid, tile.getWorld(), tile.getPos(), this, filled));
@ -152,10 +180,20 @@ public class FluidTank implements IFluidTank
return filled;
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (resource == null || !resource.isFluidEqual(getFluid()))
{
return null;
}
return drain(resource.amount, doDrain);
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (fluid == null)
if (fluid == null || maxDrain <= 0 || !canDrainFluidType(fluid))
{
return null;
}
@ -175,6 +213,8 @@ public class FluidTank implements IFluidTank
fluid = null;
}
onContentsChanged();
if (tile != null)
{
FluidEvent.fireEvent(new FluidEvent.FluidDrainingEvent(fluid, tile.getWorld(), tile.getPos(), this, drained));
@ -182,4 +222,75 @@ public class FluidTank implements IFluidTank
}
return stack;
}
/**
* Whether this tank can be filled with {@link IFluidHandler}
*
* @see IFluidTankProperties#canFill()
*/
public boolean canFill()
{
return canFill;
}
/**
* Whether this tank can be drained with {@link IFluidHandler}
*
* @see IFluidTankProperties#canDrain()
*/
public boolean canDrain()
{
return canDrain;
}
/**
* Set whether this tank can be filled with {@link IFluidHandler}
*
* @see IFluidTankProperties#canFill()
*/
public void setCanFill(boolean canFill)
{
this.canFill = canFill;
}
/**
* Set whether this tank can be drained with {@link IFluidHandler}
*
* @see IFluidTankProperties#canDrain()
*/
public void setCanDrain(boolean canDrain)
{
this.canDrain = canDrain;
}
/**
* Returns true if the tank can be filled with this type of fluid.
* Used as a filter for fluid types.
* Does not consider the current contents or capacity of the tank,
* only whether it could ever fill with this type of fluid.
*
* @see IFluidTankProperties#canFillFluidType(FluidStack)
*/
public boolean canFillFluidType(FluidStack fluid)
{
return canFill();
}
/**
* Returns true if the tank can drain out this type of fluid.
* Used as a filter for fluid types.
* Does not consider the current contents or capacity of the tank,
* only whether it could ever drain out this type of fluid.
*
* @see IFluidTankProperties#canDrainFluidType(FluidStack)
*/
public boolean canDrainFluidType(FluidStack fluid)
{
return canDrain();
}
protected void onContentsChanged()
{
}
}

View file

@ -1,14 +1,17 @@
package net.minecraftforge.fluids;
import javax.annotation.Nullable;
/**
* Wrapper class used to encapsulate information about an IFluidTank.
*/
public final class FluidTankInfo
{
@Nullable
public final FluidStack fluid;
public final int capacity;
public FluidTankInfo(FluidStack fluid, int capacity)
public FluidTankInfo(@Nullable FluidStack fluid, int capacity)
{
this.fluid = fluid;
this.capacity = capacity;

View file

@ -1,118 +1,509 @@
package net.minecraftforge.fluids;
import javax.annotation.Nullable;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraftforge.common.ForgeModContainer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.wrappers.BlockLiquidWrapper;
import net.minecraftforge.fluids.capability.wrappers.FluidBlockWrapper;
import net.minecraftforge.fluids.capability.wrappers.FluidContainerItemWrapper;
import net.minecraftforge.fluids.capability.wrappers.FluidContainerRegistryWrapper;
import net.minecraftforge.fluids.capability.wrappers.FluidHandlerWrapper;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.wrapper.InvWrapper;
import net.minecraftforge.items.wrapper.PlayerMainInvWrapper;
public class FluidUtil
{
private FluidUtil()
{
}
/** Returns true if interaction was successful. */
public static boolean interactWithTank(ItemStack stack, EntityPlayer player, IFluidHandler tank, EnumFacing side)
/**
* Used to handle the common case of a fluid item right-clicking on a fluid handler.
* First it tries to fill the container item from the fluid handler,
* if that action fails then it tries to drain the container item into the fluid handler.
*
* Returns true if interaction was successful.
* Returns false if interaction failed.
*/
public static boolean interactWithFluidHandler(ItemStack stack, IFluidHandler fluidHandler, EntityPlayer player)
{
if (stack == null)
if (stack == null || fluidHandler == null || player == null)
{
return false;
}
IItemHandler playerInventory = new InvWrapper(player.inventory);
return tryFillContainerAndStow(stack, fluidHandler, playerInventory, Integer.MAX_VALUE, player) ||
tryEmptyContainerAndStow(stack, fluidHandler, playerInventory, Integer.MAX_VALUE, player);
}
/**
* Fill a container from the given fluidSource.
*
* @param container The container to be filled. Will not be modified.
* @param fluidSource The fluid handler to be drained.
* @param maxAmount The largest amount of fluid that should be transferred.
* @param player The player to make the filling noise. Pass null for no noise.
* @param doFill true if the container should actually be filled, false if it should be simulated.
* @return The filled container or null if the liquid couldn't be taken from the tank.
*/
public static ItemStack tryFillContainer(ItemStack container, IFluidHandler fluidSource, int maxAmount, @Nullable EntityPlayer player, boolean doFill)
{
container = container.copy(); // do not modify the input
container.stackSize = 1;
IFluidHandler containerFluidHandler = getFluidHandler(container);
if (containerFluidHandler != null)
{
FluidStack simulatedTransfer = tryFluidTransfer(containerFluidHandler, fluidSource, maxAmount, false);
if (simulatedTransfer != null)
{
if (doFill)
{
tryFluidTransfer(containerFluidHandler, fluidSource, maxAmount, true);
if (player != null)
{
SoundEvent soundevent = simulatedTransfer.getFluid().getFillSound(simulatedTransfer);
player.playSound(soundevent, 1f, 1f);
}
}
else
{
containerFluidHandler.fill(simulatedTransfer, true);
}
return container;
}
}
return null;
}
/**
* Takes a filled container and tries to empty it into the given tank.
*
* @param container The filled container. Will not be modified.
* @param fluidDestination The fluid handler to be filled by the container.
* @param maxAmount The largest amount of fluid that should be transferred.
* @param player Player for making the bucket drained sound. Pass null for no noise.
* @param doDrain true if the container should actually be drained, false if it should be simulated.
* @return The empty container if successful, null if the fluid handler couldn't be filled.
* NOTE The empty container will have a stackSize of 0 when a filled container is consumable,
* i.e. it has a "null" empty container but has successfully been emptied.
*/
@Nullable
public static ItemStack tryEmptyContainer(ItemStack container, IFluidHandler fluidDestination, int maxAmount, @Nullable EntityPlayer player, boolean doDrain)
{
container = container.copy(); // do not modify the input
container.stackSize = 1;
IFluidHandler containerFluidHandler = getFluidHandler(container);
if (containerFluidHandler != null)
{
FluidStack simulatedTransfer = tryFluidTransfer(fluidDestination, containerFluidHandler, maxAmount, false);
if (simulatedTransfer != null)
{
if (doDrain)
{
tryFluidTransfer(fluidDestination, containerFluidHandler, maxAmount, true);
if (player != null)
{
SoundEvent soundevent = simulatedTransfer.getFluid().getEmptySound(simulatedTransfer);
player.playSound(soundevent, 1f, 1f);
}
}
else
{
containerFluidHandler.drain(simulatedTransfer, true);
}
return container;
}
}
return null;
}
/**
* Takes an Fluid Container Item and tries to fill it from the given tank.
* If the player is in creative mode, the container will not be modified on success, and no additional items created.
* If the input itemstack has a stacksize > 1 it will stow the filled container in the given inventory.
* If the inventory does not accept it, it will be given to the player or dropped at the players feet.
* If player is null in this case, the action will be aborted.
*
* @param container The Fluid Container Itemstack to fill. This stack WILL be modified on success.
* @param fluidSource The fluid source to fill from
* @param inventory An inventory where any additionally created item (filled container if multiple empty are present) are put
* @param maxAmount Maximum amount of fluid to take from the tank.
* @param player The player that gets the items the inventory can't take. Can be null, only used if the inventory cannot take the filled stack.
* @return True if the container was filled successfully and stowed, false otherwise.
*/
public static boolean tryFillContainerAndStow(ItemStack container, IFluidHandler fluidSource, IItemHandler inventory, int maxAmount, @Nullable EntityPlayer player)
{
if (container == null || container.stackSize < 1)
{
return false;
}
if (player != null && player.capabilities.isCreativeMode)
{
ItemStack filledReal = tryFillContainer(container, fluidSource, maxAmount, player, true);
if (filledReal != null)
{
return true;
}
ItemStack result;
// regular bucket?
int slot = player.inventory.currentItem;
if ((result = FluidUtil.tryFillBucket(stack, tank, side, player)) != null ||
(result = FluidUtil.tryEmptyBucket(stack, tank, side, player)) != null)
{
// "use up" the input item if the player is not in creative
if (!player.capabilities.isCreativeMode)
{
player.inventory.decrStackSize(slot, 1);
ItemHandlerHelper.giveItemToPlayer(player, result, slot);
}
// send inventory updates to client
if (player.inventoryContainer != null)
else if (container.stackSize == 1) // don't need to stow anything, just fill and edit the container stack
{
player.inventoryContainer.detectAndSendChanges();
}
ItemStack filledReal = tryFillContainer(container, fluidSource, maxAmount, player, true);
if (filledReal != null)
{
container.setItem(filledReal.getItem());
container.setTagCompound(filledReal.getTagCompound());
container.setItemDamage(filledReal.getItemDamage());
return true;
}
// IFluidContainerItems
}
else
{
// copy of the original item for creative mode
ItemStack original = stack; // needed for how minecraft manages inventory with interaction
ItemStack copy = stack.copy();
stack = stack.copy(); // needed so we don't affect itemstacks outside of this function
boolean changedBucket = false;
// convert to fluidcontainer-bucket if it's a regular empty bucket
if (ItemStack.areItemsEqual(stack, FluidContainerRegistry.EMPTY_BUCKET) && FluidRegistry.isUniversalBucketEnabled())
ItemStack filledSimulated = tryFillContainer(container, fluidSource, maxAmount, player, false);
if (filledSimulated != null)
{
// try using the forge fluid bucket if it's enabled
stack = new ItemStack(ForgeModContainer.getInstance().universalBucket, copy.stackSize);
changedBucket = true;
// check if we can give the itemStack to the inventory
ItemStack remainder = ItemHandlerHelper.insertItemStacked(inventory, filledSimulated, true);
if (remainder == null || player != null)
{
ItemStack filledReal = tryFillContainer(container, fluidSource, maxAmount, player, true);
remainder = ItemHandlerHelper.insertItemStacked(inventory, filledReal, false);
// give it to the player or drop it at their feet
if (remainder != null && player != null)
{
ItemHandlerHelper.giveItemToPlayer(player, remainder);
}
// try filling an empty fluidcontainer or emptying a filled fluidcontainer
if (FluidUtil.tryFillFluidContainerItem(stack, tank, side, player) ||
FluidUtil.tryEmptyFluidContainerItem(stack, tank, side, player))
{
original.stackSize--; // this tells the player that the item he held was "used up" and the inventory syncing will then play the correct animation
if (player.capabilities.isCreativeMode)
{
// reset the stack that got modified
player.inventory.setInventorySlotContents(slot, copy);
}
else
{
// we passed in multiple stacksize and it changed, that means the new items are in the inventory
// but we have to readjust the old ones back
if (changedBucket && stack.stackSize != copy.stackSize)
{
copy.stackSize = stack.stackSize;
// replace the previously changed buckets that were not used back
player.inventory.setInventorySlotContents(slot, copy);
}
// we have the new stack now, but since we changed it from its original we have to set the contents anew
else
{
// if the original stack was multiple, replace it
if (copy.stackSize > 1)
{
player.inventory.setInventorySlotContents(slot, stack);
}
// otherwise reinsert it into the inventory
else
{
player.inventory.setInventorySlotContents(slot, null);
ItemHandlerHelper.giveItemToPlayer(player, stack, slot);
}
}
}
// send inventory updates to client
if (player.inventoryContainer != null)
{
player.inventoryContainer.detectAndSendChanges();
}
container.stackSize--;
return true;
}
}
}
return false;
}
/**
* Takes an Fluid Container Item, tries to empty it into the fluid handler, and stows it in the given inventory.
* If the player is in creative mode, the container will not be modified on success, and no additional items created.
* If the input itemstack has a stacksize > 1 it will stow the emptied container in the given inventory.
* If the inventory does not accept the emptied container, it will be given to the player or dropped at the players feet.
* If player is null in this case, the action will be aborted.
*
* @param container The Fluid Container Itemstack to fill. This stack WILL be modified on success.
* @param fluidSource The fluid source to fill from
* @param inventory An inventory where any additionally created item (filled container if multiple empty are present) are put
* @param maxAmount Maximum amount of fluid to take from the tank.
* @param player The player that gets the items the inventory can't take. Can be null, only used if the inventory cannot take the filled stack.
* @return True if the container was filled successfully and stowed, false otherwise.
*/
public static boolean tryEmptyContainerAndStow(ItemStack container, IFluidHandler fluidSource, IItemHandler inventory, int maxAmount, @Nullable EntityPlayer player)
{
if (container == null || container.stackSize < 1)
{
return false;
}
if (player != null && player.capabilities.isCreativeMode)
{
ItemStack emptiedReal = tryEmptyContainer(container, fluidSource, maxAmount, player, true);
if (emptiedReal != null)
{
return true;
}
}
else if (container.stackSize == 1) // don't need to stow anything, just fill and edit the container stack
{
ItemStack emptiedReal = tryEmptyContainer(container, fluidSource, maxAmount, player, true);
if (emptiedReal != null)
{
if (emptiedReal.stackSize <= 0)
{
container.stackSize--;
}
else
{
container.setItem(emptiedReal.getItem());
container.setTagCompound(emptiedReal.getTagCompound());
container.setItemDamage(emptiedReal.getItemDamage());
}
return true;
}
}
else
{
ItemStack emptiedSimulated = tryEmptyContainer(container, fluidSource, maxAmount, player, false);
if (emptiedSimulated != null)
{
if (emptiedSimulated.stackSize <= 0)
{
tryEmptyContainer(container, fluidSource, maxAmount, player, true);
container.stackSize--;
return true;
}
else
{
// check if we can give the itemStack to the inventory
ItemStack remainder = ItemHandlerHelper.insertItemStacked(inventory, emptiedSimulated, true);
if (remainder == null || player != null)
{
ItemStack emptiedReal = tryEmptyContainer(container, fluidSource, maxAmount, player, true);
remainder = ItemHandlerHelper.insertItemStacked(inventory, emptiedReal, false);
// give it to the player or drop it at their feet
if (remainder != null && player != null)
{
ItemHandlerHelper.giveItemToPlayer(player, remainder);
}
container.stackSize--;
return true;
}
}
}
}
return false;
}
/**
* Fill a destination fluid handler from a source fluid handler.
*
* @param fluidDestination The fluid handler to be filled.
* @param fluidSource The fluid handler to be drained.
* @param maxAmount The largest amount of fluid that should be transferred.
* @param doTransfer True if the transfer should actually be done, false if it should be simulated.
* @return the fluidStack that was transferred from the source to the destination. null on failure.
*/
@Nullable
public static FluidStack tryFluidTransfer(IFluidHandler fluidDestination, IFluidHandler fluidSource, int maxAmount, boolean doTransfer)
{
FluidStack drainable = fluidSource.drain(maxAmount, false);
if (drainable != null && drainable.amount > 0)
{
int fillableAmount = fluidDestination.fill(drainable, false);
if (fillableAmount > 0)
{
FluidStack drained = fluidSource.drain(fillableAmount, doTransfer);
if (drained != null)
{
drained.amount = fluidDestination.fill(drained, doTransfer);
return drained;
}
}
}
return null;
}
/**
* Helper method to get an IFluidHandler for an itemStack.
*
* The itemStack passed in here WILL be modified, the IFluidHandler acts on it directly.
*
* Note that the itemStack MUST have a stackSize of 1 if you want to fill or drain it.
* You can't fill or drain a whole stack at once, if you do then liquid is multiplied or destroyed.
*
* Vanilla buckets will be converted to universal buckets if they are enabled.
*
* Returns null if the itemStack passed in does not have a fluid handler.
*/
@Nullable
public static IFluidHandler getFluidHandler(ItemStack itemStack)
{
if (itemStack == null)
{
return null;
}
// check for capability
if (itemStack.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, null))
{
return itemStack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, null);
}
// legacy container handling
Item item = itemStack.getItem();
if (item instanceof IFluidContainerItem)
{
return new FluidContainerItemWrapper((IFluidContainerItem) item, itemStack);
}
else if (FluidContainerRegistry.isContainer(itemStack))
{
return new FluidContainerRegistryWrapper(itemStack);
}
else
{
return null;
}
}
/**
* Helper method to get the fluid contained in an itemStack
*/
@Nullable
public static FluidStack getFluidContained(ItemStack container)
{
if (container != null)
{
container = container.copy();
container.stackSize = 1;
IFluidHandler fluidHandler = FluidUtil.getFluidHandler(container);
if (fluidHandler != null)
{
return fluidHandler.drain(Integer.MAX_VALUE, false);
}
}
return null;
}
/**
* Helper method to get an IFluidHandler for at a block position.
*
* Returns null if there is no valid fluid handler.
*/
@Nullable
public static IFluidHandler getFluidHandler(World world, BlockPos blockPos, @Nullable EnumFacing side)
{
IBlockState state = world.getBlockState(blockPos);
Block block = state.getBlock();
if (block.hasTileEntity(state))
{
TileEntity tileEntity = world.getTileEntity(blockPos);
if (tileEntity != null && tileEntity.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side))
{
return tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side);
}
}
else if (block instanceof IFluidBlock)
{
return new FluidBlockWrapper((IFluidBlock) block, world, blockPos);
}
else if (block instanceof BlockLiquid)
{
return new BlockLiquidWrapper((BlockLiquid) block, world, blockPos);
}
return null;
}
/**
* Tries to place a fluid in the world in block form.
* Makes a fluid emptying sound when successful.
* Checks if water-like fluids should vaporize like in the nether.
*
* Modeled after {@link net.minecraft.item.ItemBucket#tryPlaceContainedLiquid(EntityPlayer, World, BlockPos)}
*
* @param player Player who places the fluid. May be null for blocks like dispensers.
* @param worldIn World to place the fluid in
* @param fluid The fluid to place.
* @param pos The position in the world to place the fluid block
* @return true if successful
*/
public static boolean tryPlaceFluid(@Nullable EntityPlayer player, World worldIn, FluidStack fluid, BlockPos pos)
{
if (worldIn == null || fluid == null || fluid.getFluid() == null || pos == null)
{
return false;
}
// check that we can place the fluid at the destination
IBlockState destBlockState = worldIn.getBlockState(pos);
Material destMaterial = destBlockState.getMaterial();
boolean isDestNonSolid = !destMaterial.isSolid();
boolean isDestReplaceable = destBlockState.getBlock().isReplaceable(worldIn, pos);
if (!worldIn.isAirBlock(pos) && !isDestNonSolid && !isDestReplaceable)
{
return false; // Non-air, solid, unreplacable block. We can't put fluid here.
}
IBlockState fluidBlockState = fluid.getFluid().getBlock().getDefaultState();
if (worldIn.provider.doesWaterVaporize() && fluidBlockState.getMaterial() == Material.WATER)
{
worldIn.playSound(player, pos, SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 0.5F, 2.6F + (worldIn.rand.nextFloat() - worldIn.rand.nextFloat()) * 0.8F);
for (int l = 0; l < 8; ++l)
{
worldIn.spawnParticle(EnumParticleTypes.SMOKE_LARGE, (double) pos.getX() + Math.random(), (double) pos.getY() + Math.random(), (double) pos.getZ() + Math.random(), 0.0D, 0.0D, 0.0D);
}
}
else
{
if (!worldIn.isRemote && (isDestNonSolid || isDestReplaceable) && !destMaterial.isLiquid())
{
worldIn.destroyBlock(pos, true);
}
SoundEvent soundevent = fluid.getFluid().getEmptySound(worldIn, pos);
worldIn.playSound(player, pos, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F);
worldIn.setBlockState(pos, fluidBlockState, 11);
}
return true;
}
/**
* Attempts to pick up a fluid in the world and put it in an empty container item.
*
* @param emptyContainer The empty container to fill. Will not be modified.
* @param playerIn The player filling the container. Optional.
* @param worldIn The world the fluid is in.
* @param pos The position of the fluid in the world.
* @param side The side of the fluid that is being drained.
* @return a filled container if it was successful. returns null on failure.
*/
@Nullable
public static ItemStack tryPickUpFluid(ItemStack emptyContainer, @Nullable EntityPlayer playerIn, World worldIn, BlockPos pos, EnumFacing side)
{
if (emptyContainer == null || worldIn == null || pos == null) {
return null;
}
IFluidHandler targetFluidHandler = FluidUtil.getFluidHandler(worldIn, pos, side);
if (targetFluidHandler != null)
{
return FluidUtil.tryFillContainer(emptyContainer, targetFluidHandler, Integer.MAX_VALUE, playerIn, true);
}
return null;
}
/**
* Returns true if interaction was successful.
* @deprecated use {@link #interactWithFluidHandler(ItemStack, IFluidHandler, EntityPlayer)}
*/
@Deprecated
public static ItemStack tryFillBucket(ItemStack bucket, IFluidHandler tank, EnumFacing side)
public static boolean interactWithTank(ItemStack stack, EntityPlayer player, net.minecraftforge.fluids.IFluidHandler tank, EnumFacing side)
{
IFluidHandler fluidHandler = new FluidHandlerWrapper(tank, side);
return interactWithFluidHandler(stack, fluidHandler, player);
}
/**
* @deprecated use {@link #tryFillContainer(ItemStack, IFluidHandler, int, EntityPlayer, boolean)}
*/
@Deprecated
public static ItemStack tryFillBucket(ItemStack bucket, net.minecraftforge.fluids.IFluidHandler tank, EnumFacing side)
{
return tryFillBucket(bucket, tank, side, null);
}
@ -120,47 +511,24 @@ public class FluidUtil
/**
* Fill an empty bucket from the given tank. Uses the FluidContainerRegistry.
*
* @param bucket The empty bucket
* @param bucket The empty bucket. Will not be modified.
* @param tank The tank to fill the bucket from
* @param side Side to access the tank from
* @return The filled bucket or null if the liquid couldn't be taken from the tank.
* @deprecated use {@link #tryFillContainer(ItemStack, IFluidHandler, int, EntityPlayer, boolean)}
*/
public static ItemStack tryFillBucket(ItemStack bucket, IFluidHandler tank, EnumFacing side, EntityPlayer player)
{
FluidTankInfo[] info = tank.getTankInfo(side);
// check for fluid in the tank
if (info == null || info.length == 0)
{
return null;
}
// check if we actually have an empty bucket
if (!FluidContainerRegistry.isEmptyContainer(bucket))
{
return null;
}
// fluid in the tank
FluidStack inTank = info[0].fluid;
// drain one bucket if possible
FluidStack liquid = tank.drain(side, FluidContainerRegistry.getContainerCapacity(inTank, bucket), false);
if (liquid != null && liquid.amount > 0)
{
// play sound
if(player != null)
{
SoundEvent soundevent = liquid.getFluid().getFillSound(liquid);
player.playSound(soundevent, 1f, 1f);
}
// success, return filled bucket
tank.drain(side, FluidContainerRegistry.getContainerCapacity(liquid, bucket), true);
return FluidContainerRegistry.fillFluidContainer(liquid, bucket);
}
return null;
}
@Deprecated
public static ItemStack tryEmptyBucket(ItemStack bucket, IFluidHandler tank, EnumFacing side)
public static ItemStack tryFillBucket(ItemStack bucket, net.minecraftforge.fluids.IFluidHandler tank, EnumFacing side, EntityPlayer player)
{
IFluidHandler newFluidHandler = new FluidHandlerWrapper(tank, side);
return tryFillContainer(bucket, newFluidHandler, Fluid.BUCKET_VOLUME, player, true);
}
/**
* @deprecated use {@link #tryEmptyContainer(ItemStack, IFluidHandler, int, EntityPlayer, boolean)}
*/
@Deprecated
public static ItemStack tryEmptyBucket(ItemStack bucket, net.minecraftforge.fluids.IFluidHandler tank, EnumFacing side)
{
return tryEmptyBucket(bucket, tank, side, null);
}
@ -171,39 +539,15 @@ public class FluidUtil
* @param bucket The filled bucket
* @param tank The tank to fill with the bucket
* @param side Side to access the tank from
* @param player
* @param player Player for making the bucket drained sound.
* @return The empty bucket if successful, null if the tank couldn't be filled.
* @deprecated use {@link #tryFillContainer(ItemStack, IFluidHandler, int, EntityPlayer, boolean)}
*/
public static ItemStack tryEmptyBucket(ItemStack bucket, IFluidHandler tank, EnumFacing side, EntityPlayer player)
@Deprecated
public static ItemStack tryEmptyBucket(ItemStack bucket, net.minecraftforge.fluids.IFluidHandler tank, EnumFacing side, EntityPlayer player)
{
// not a filled bucket
if (!FluidContainerRegistry.isFilledContainer(bucket))
{
return null;
}
// try filling the fluid from the bucket into the tank
FluidStack liquid = FluidContainerRegistry.getFluidForFilledItem(bucket);
if (tank.canFill(side, liquid.getFluid()))
{
// how much can we put into the tank?
int amount = tank.fill(side, liquid, false);
// not everything?
if (amount == liquid.amount)
{
// play sound
if(player != null)
{
SoundEvent soundevent = liquid.getFluid().getEmptySound(liquid);
player.playSound(soundevent, 1f, 1f);
}
// success, fully filled it into the tank, return empty bucket
tank.fill(side, liquid, true);
return FluidContainerRegistry.drainFluidContainer(bucket);
}
}
return null;
IFluidHandler destination = new FluidHandlerWrapper(tank, side);
return tryEmptyContainer(bucket, destination, Fluid.BUCKET_VOLUME, player, true);
}
/**
@ -214,13 +558,19 @@ public class FluidUtil
* @param side Side to access the tank from
* @param player The player that tries to fill the bucket. Needed if the input itemstack has a stacksize > 1 to determine where the filled container goes.
* @return True if the IFluidContainerItem was filled successfully, false otherwise. The passed container will have been modified to accommodate for anything done in this method. New Itemstacks might have been added to the players inventory.
* @deprecated use {@link #tryFillContainerAndStow(ItemStack, IFluidHandler, IItemHandler, int, EntityPlayer)}
*/
public static boolean tryFillFluidContainerItem(ItemStack container, IFluidHandler tank, EnumFacing side, EntityPlayer player)
@Deprecated
public static boolean tryFillFluidContainerItem(ItemStack container, net.minecraftforge.fluids.IFluidHandler tank, EnumFacing side, EntityPlayer player)
{
return tryFillFluidContainerItem(container, tank, side, new PlayerMainInvWrapper(player.inventory), -1, player);
}
public static boolean tryEmptyFluidContainerItem(ItemStack container, IFluidHandler tank, EnumFacing side, EntityPlayer player)
/**
* @deprecated use {@link #tryEmptyContainerAndStow(ItemStack, IFluidHandler, IItemHandler, int, EntityPlayer)}
*/
@Deprecated
public static boolean tryEmptyFluidContainerItem(ItemStack container, net.minecraftforge.fluids.IFluidHandler tank, EnumFacing side, EntityPlayer player)
{
return tryEmptyFluidContainerItem(container, tank, side, new PlayerMainInvWrapper(player.inventory), -1, player);
}
@ -240,8 +590,10 @@ public class FluidUtil
* @param max Maximum amount to take from the tank. Uses IFluidContainerItem capacity if <= 0
* @param player The player that gets the items the inventory can't take. Can be null, only used if the inventory cannot take the filled stack.
* @return True if the IFluidContainerItem was filled successfully, false otherwise. The passed container will have been modified to accommodate for anything done in this method. New Itemstacks might have been added to the players inventory.
* @deprecated use {@link #tryFillContainerAndStow(ItemStack, IFluidHandler, IItemHandler, int, EntityPlayer)}
*/
public static boolean tryFillFluidContainerItem(ItemStack container, IFluidHandler tank, EnumFacing side, IItemHandler inventory, int max, EntityPlayer player)
@Deprecated
public static boolean tryFillFluidContainerItem(ItemStack container, net.minecraftforge.fluids.IFluidHandler tank, EnumFacing side, IItemHandler inventory, int max, @Nullable EntityPlayer player)
{
if (!(container.getItem() instanceof IFluidContainerItem))
{
@ -349,8 +701,10 @@ public class FluidUtil
* @param max Maximum amount to take from the tank. Uses IFluidContainerItem capacity if <= 0
* @param player The player that gets the items the inventory can't take. Can be null, only used if the inventory cannot take the emptied stack.
* @return True if the container successfully emptied at least 1 mb into the tank, false otherwise. The passed container itemstack will be modified to accommodate for the liquid transaction.
* @deprecated use {@link #tryEmptyContainerAndStow(ItemStack, IFluidHandler, IItemHandler, int, EntityPlayer)}
*/
public static boolean tryEmptyFluidContainerItem(ItemStack container, IFluidHandler tank, EnumFacing side, IItemHandler inventory, int max, EntityPlayer player)
@Deprecated
public static boolean tryEmptyFluidContainerItem(ItemStack container, net.minecraftforge.fluids.IFluidHandler tank, EnumFacing side, IItemHandler inventory, int max, EntityPlayer player)
{
if (!(container.getItem() instanceof IFluidContainerItem))
{

View file

@ -1,6 +1,7 @@
package net.minecraftforge.fluids;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.capability.wrappers.FluidContainerItemWrapper;
/**
* Implement this interface on Item classes that support external manipulation of their internal
@ -10,7 +11,10 @@ import net.minecraft.item.ItemStack;
*
* NOTE: Use of NBT data on the containing ItemStack is encouraged.
*
* @deprecated See {@link net.minecraftforge.fluids.capability.ItemFluidContainer} for a CapabilityProvider implementing the Capability {@link net.minecraftforge.fluids.capability.IFluidHandler}
* @see FluidContainerItemWrapper
*/
@Deprecated
public interface IFluidContainerItem
{
/**

View file

@ -1,6 +1,7 @@
package net.minecraftforge.fluids;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.fluids.capability.wrappers.FluidHandlerWrapper;
/**
* Implement this interface on TileEntities which should handle fluids, generally storing them in
@ -8,7 +9,10 @@ import net.minecraft.util.EnumFacing;
*
* A reference implementation is provided {@link TileFluidHandler}.
*
* @deprecated Use the Capability version {@link net.minecraftforge.fluids.capability.IFluidHandler}.
* @see FluidHandlerWrapper
*/
@Deprecated
public interface IFluidHandler
{
/**

View file

@ -1,5 +1,7 @@
package net.minecraftforge.fluids;
import javax.annotation.Nullable;
/**
* A tank is the unit of interaction with Fluid inventories.
*
@ -10,6 +12,7 @@ public interface IFluidTank
/**
* @return FluidStack representing the fluid in the tank, null if the tank is empty.
*/
@Nullable
FluidStack getFluid();
/**
@ -50,5 +53,6 @@ public interface IFluidTank
* If false, the drain will only be simulated.
* @return Amount of fluid that was removed from the tank.
*/
@Nullable
FluidStack drain(int maxDrain, boolean doDrain);
}

View file

@ -3,10 +3,14 @@ package net.minecraftforge.fluids;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fluids.capability.wrappers.FluidContainerItemWrapper;
/**
* Reference implementation of {@link IFluidContainerItem}. Use/extend this or implement your own.
* @deprecated See {@link net.minecraftforge.fluids.capability.ItemFluidContainer}
*/
@Deprecated
public class ItemFluidContainer extends Item implements IFluidContainerItem
{
protected int capacity;
@ -153,4 +157,10 @@ public class ItemFluidContainer extends Item implements IFluidContainerItem
}
return stack;
}
@Override
public ICapabilityProvider initCapabilities(ItemStack stack, NBTTagCompound nbt)
{
return new FluidContainerItemWrapper(this, stack);
}
}

View file

@ -1,16 +1,23 @@
package net.minecraftforge.fluids;
import javax.annotation.Nullable;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.wrappers.FluidHandlerWrapper;
/**
* Reference Tile Entity implementation of {@link IFluidHandler}. Use/extend this or write your own.
* @deprecated see {@link net.minecraftforge.fluids.capability.TileFluidHandler}
*/
@Deprecated
public class TileFluidHandler extends TileEntity implements IFluidHandler
{
protected FluidTank tank = new FluidTank(FluidContainerRegistry.BUCKET_VOLUME);
protected FluidTank tank = new FluidTank(Fluid.BUCKET_VOLUME);
@Override
public void readFromNBT(NBTTagCompound tag)
@ -67,4 +74,20 @@ public class TileFluidHandler extends TileEntity implements IFluidHandler
{
return new FluidTankInfo[] { tank.getInfo() };
}
@Override
public boolean hasCapability(Capability<?> capability, @Nullable EnumFacing facing)
{
return capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY || super.hasCapability(capability, facing);
}
@Override
public <T> T getCapability(Capability<T> capability, @Nullable EnumFacing facing)
{
if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
{
return CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY.cast(new FluidHandlerWrapper(this, facing));
}
return super.getCapability(capability, facing);
}
}

View file

@ -2,11 +2,9 @@ package net.minecraftforge.fluids;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.SoundEvents;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@ -16,7 +14,9 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.text.translation.I18n;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.event.entity.player.FillBucketEvent;
import net.minecraftforge.fluids.capability.wrappers.FluidBucketWrapper;
import net.minecraftforge.fml.common.eventhandler.Event;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@ -38,7 +38,7 @@ public class UniversalBucket extends Item implements IFluidContainerItem
public UniversalBucket()
{
this(FluidContainerRegistry.BUCKET_VOLUME, FluidContainerRegistry.EMPTY_BUCKET, false);
this(Fluid.BUCKET_VOLUME, new ItemStack(Items.BUCKET), false);
}
/**
@ -125,7 +125,7 @@ public class UniversalBucket extends Item implements IFluidContainerItem
if (player.canPlayerEdit(targetPos, mop.sideHit, itemstack))
{
// try placing liquid
if (this.tryPlaceFluid(player, player.getEntityWorld(), fluidStack.getFluid().getBlock(), targetPos)
if (FluidUtil.tryPlaceFluid(player, player.getEntityWorld(), fluidStack, targetPos)
&& !player.capabilities.isCreativeMode)
{
// success!
@ -157,65 +157,21 @@ public class UniversalBucket extends Item implements IFluidContainerItem
@Deprecated
public boolean tryPlaceFluid(Block block, World worldIn, BlockPos pos)
{
return tryPlaceFluid(null, worldIn, block, pos);
if (block instanceof IFluidBlock)
{
IFluidBlock fluidBlock = (IFluidBlock) block;
return FluidUtil.tryPlaceFluid(null, worldIn, new FluidStack(fluidBlock.getFluid(), Fluid.BUCKET_VOLUME), pos);
}
private boolean tryPlaceFluid(EntityPlayer player, World worldIn, Block block, BlockPos pos)
else if (block.getDefaultState().getMaterial() == Material.WATER)
{
if (block == null)
FluidUtil.tryPlaceFluid(null, worldIn, new FluidStack(FluidRegistry.WATER, Fluid.BUCKET_VOLUME), pos);
}
else if (block.getDefaultState().getMaterial() == Material.LAVA)
{
FluidUtil.tryPlaceFluid(null, worldIn, new FluidStack(FluidRegistry.LAVA, Fluid.BUCKET_VOLUME), pos);
}
return false;
}
if(worldIn == null && player != null)
{
worldIn = player.getEntityWorld();
}
Material material = worldIn.getBlockState(pos).getMaterial();
boolean isSolid = material.isSolid();
// can only place in air or non-solid blocks
if (!worldIn.isAirBlock(pos) && isSolid)
{
return false;
}
// water goes poof?
if (worldIn.provider.doesWaterVaporize() && (block == Blocks.FLOWING_WATER || block == Blocks.WATER))
{
int i = pos.getX();
int j = pos.getY();
int k = pos.getZ();
worldIn.playSound(null, pos, SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 0.5F,
2.6F + (worldIn.rand.nextFloat() - worldIn.rand.nextFloat()) * 0.8F);
for (int l = 0; l < 8; ++l)
{
worldIn.spawnParticle(EnumParticleTypes.SMOKE_LARGE,
(double) i + Math.random(),
(double) j + Math.random(), (double) k + Math.random(), 0.0D, 0.0D, 0.0D);
}
}
else
{
if (!worldIn.isRemote && !isSolid && !material.isLiquid())
{
worldIn.destroyBlock(pos, true);
}
if(player != null && block instanceof IFluidBlock)
{
Fluid fluid = ((IFluidBlock) block).getFluid();
if(fluid != null)
{
worldIn.setBlockState(pos, block.getDefaultState(), 3);
SoundEvent soundevent = fluid.getEmptySound(worldIn, pos);
worldIn.playSound(player, pos, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F);
}
}
}
return true;
}
@SubscribeEvent(priority = EventPriority.LOW) // low priority so other mods can handle their stuff first
public void onFillBucket(FillBucketEvent event)
@ -227,48 +183,32 @@ public class UniversalBucket extends Item implements IFluidContainerItem
}
// not for us to handle
if (event.getEmptyBucket() == null ||
!event.getEmptyBucket().isItemEqual(getEmpty()) ||
(isNbtSensitive() && ItemStack.areItemStackTagsEqual(event.getEmptyBucket(), getEmpty())))
ItemStack emptyBucket = event.getEmptyBucket();
if (emptyBucket == null ||
!emptyBucket.isItemEqual(getEmpty()) ||
(isNbtSensitive() && ItemStack.areItemStackTagsEqual(emptyBucket, getEmpty())))
{
return;
}
// needs to target a block
if (event.getTarget() == null || event.getTarget().typeOfHit != RayTraceResult.Type.BLOCK)
RayTraceResult target = event.getTarget();
if (target == null || target.typeOfHit != RayTraceResult.Type.BLOCK)
{
return;
}
World world = event.getWorld();
BlockPos pos = event.getTarget().getBlockPos();
IBlockState state = world.getBlockState(pos);
// Note that water and lava are NOT an instance of IFluidBlock! They are therefore not handled by this code!
if (state.getBlock() instanceof IFluidBlock)
{
IFluidBlock fluidBlock = (IFluidBlock) state.getBlock();
if (fluidBlock.canDrain(world, pos))
{
FluidStack drained = fluidBlock.drain(world, pos, false);
// check if it fits exactly
if (drained != null && drained.amount == getCapacity())
{
// check if the container accepts it
ItemStack filledBucket = new ItemStack(this);
int filled = this.fill(filledBucket, drained, false);
if (filled == drained.amount)
{
// actually transfer the fluid
drained = fluidBlock.drain(world, pos, true);
this.fill(filledBucket, drained, true);
BlockPos pos = target.getBlockPos();
// set it as the result
ItemStack singleBucket = emptyBucket.copy();
singleBucket.stackSize = 1;
ItemStack filledBucket = FluidUtil.tryPickUpFluid(singleBucket, event.getEntityPlayer(), world, pos, target.sideHit);
if (filledBucket != null)
{
event.setResult(Event.Result.ALLOW);
event.setFilledBucket(filledBucket);
// sound!
SoundEvent soundevent = drained.getFluid().getFillSound(drained);
event.getEntityPlayer().playSound(soundevent, 1.0F, 1.0F);
}
else
{
@ -277,9 +217,6 @@ public class UniversalBucket extends Item implements IFluidContainerItem
event.setCanceled(true);
}
}
}
}
}
public static ItemStack getFilledBucket(UniversalBucket item, Fluid fluid)
{
@ -312,15 +249,20 @@ public class UniversalBucket extends Item implements IFluidContainerItem
}
// can only fill exact capacity
if (resource == null || resource.amount != getCapacity())
if (resource == null || resource.amount < getCapacity())
{
return 0;
}
// already contains fluid?
if (getFluid(container) != null)
{
return 0;
}
// registered in the registry?
if (!FluidRegistry.getBucketFluids().contains(resource.getFluid()))
if (FluidRegistry.getBucketFluids().contains(resource.getFluid()))
{
return 0;
}
// fill the container
if (doFill)
{
@ -334,12 +276,39 @@ public class UniversalBucket extends Item implements IFluidContainerItem
}
return getCapacity();
}
else if (resource.getFluid() == FluidRegistry.WATER)
{
if (doFill)
{
container.setItem(Items.WATER_BUCKET);
container.setTagCompound(null);
}
return getCapacity();
}
else if (resource.getFluid() == FluidRegistry.LAVA)
{
if (doFill)
{
container.setItem(Items.LAVA_BUCKET);
container.setTagCompound(null);
}
return getCapacity();
}
return 0;
}
@Override
public FluidStack drain(ItemStack container, int maxDrain, boolean doDrain)
{
// has to be exactly 1, must be handled from the caller
if (container.stackSize != 1)
{
return null;
}
// can only drain everything at once
if (maxDrain < getCapacity())
if (maxDrain < getCapacity(container))
{
return null;
}
@ -375,4 +344,10 @@ public class UniversalBucket extends Item implements IFluidContainerItem
{
return nbtSensitive;
}
@Override
public ICapabilityProvider initCapabilities(ItemStack stack, NBTTagCompound nbt)
{
return new FluidBucketWrapper(stack);
}
}

View file

@ -0,0 +1,65 @@
package net.minecraftforge.fluids.capability;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.IFluidTank;
import java.util.concurrent.Callable;
public class CapabilityFluidHandler
{
@CapabilityInject(IFluidHandler.class)
public static Capability<IFluidHandler> FLUID_HANDLER_CAPABILITY = null;
public static void register()
{
CapabilityManager.INSTANCE.register(IFluidHandler.class, new Capability.IStorage<IFluidHandler>()
{
@Override
public NBTBase writeNBT(Capability<IFluidHandler> capability, IFluidHandler instance, EnumFacing side)
{
if (!(instance instanceof IFluidTank))
throw new RuntimeException("IFluidHandler instance does not implement IFluidTank");
NBTTagCompound nbt = new NBTTagCompound();
IFluidTank tank = (IFluidTank) instance;
FluidStack fluid = tank.getFluid();
if (fluid != null)
{
fluid.writeToNBT(nbt);
}
else
{
nbt.setString("Empty", "");
}
nbt.setInteger("Capacity", tank.getCapacity());
return nbt;
}
@Override
public void readNBT(Capability<IFluidHandler> capability, IFluidHandler instance, EnumFacing side, NBTBase nbt)
{
if (!(instance instanceof IFluidTank))
throw new RuntimeException("IFluidHandler instance is not instance of FluidTank");
NBTTagCompound tags = (NBTTagCompound) nbt;
FluidTank tank = (FluidTank) instance;
tank.setCapacity(tags.getInteger("Capacity"));
tank.readFromNBT(tags);
}
}, new Callable<IFluidHandler>()
{
@Override
public IFluidHandler call() throws Exception
{
return new FluidTank(Fluid.BUCKET_VOLUME);
}
});
}
}

View file

@ -0,0 +1,79 @@
package net.minecraftforge.fluids.capability;
import javax.annotation.Nullable;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;
/**
* Basic implementation of {@link IFluidTankProperties}.
*/
public class FluidTankProperties implements IFluidTankProperties
{
public static FluidTankProperties[] convert(FluidTankInfo[] fluidTankInfos)
{
FluidTankProperties[] properties = new FluidTankProperties[fluidTankInfos.length];
for (int i = 0; i < fluidTankInfos.length; i++)
{
FluidTankInfo info = fluidTankInfos[i];
properties[i] = new FluidTankProperties(info.fluid, info.capacity);
}
return properties;
}
@Nullable
private final FluidStack contents;
private final int capacity;
private final boolean canFill;
private final boolean canDrain;
public FluidTankProperties(@Nullable FluidStack contents, int capacity)
{
this(contents, capacity, true, true);
}
public FluidTankProperties(@Nullable FluidStack contents, int capacity, boolean canFill, boolean canDrain)
{
this.contents = contents;
this.capacity = capacity;
this.canFill = canFill;
this.canDrain = canDrain;
}
@Nullable
@Override
public FluidStack getContents()
{
return contents == null ? null : contents.copy();
}
@Override
public int getCapacity()
{
return capacity;
}
@Override
public boolean canFill()
{
return canFill;
}
@Override
public boolean canDrain()
{
return canDrain;
}
@Override
public boolean canFillFluidType(FluidStack fluidStack)
{
return canFill;
}
@Override
public boolean canDrainFluidType(FluidStack fluidStack)
{
return canDrain;
}
}

View file

@ -0,0 +1,57 @@
package net.minecraftforge.fluids.capability;
import javax.annotation.Nullable;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
/**
* Basic {@link IFluidTankProperties} wrapper for {@link FluidTank}.
*/
public class FluidTankPropertiesWrapper implements IFluidTankProperties
{
protected final FluidTank tank;
public FluidTankPropertiesWrapper(FluidTank tank)
{
this.tank = tank;
}
@Nullable
@Override
public FluidStack getContents()
{
FluidStack contents = tank.getFluid();
return contents == null ? null : contents.copy();
}
@Override
public int getCapacity()
{
return tank.getCapacity();
}
@Override
public boolean canFill()
{
return tank.canFill();
}
@Override
public boolean canDrain()
{
return tank.canDrain();
}
@Override
public boolean canFillFluidType(FluidStack fluidStack)
{
return tank.canFillFluidType(fluidStack);
}
@Override
public boolean canDrainFluidType(FluidStack fluidStack)
{
return tank.canDrainFluidType(fluidStack);
}
}

View file

@ -0,0 +1,55 @@
package net.minecraftforge.fluids.capability;
import javax.annotation.Nullable;
import net.minecraftforge.fluids.*;
/**
* Implement this interface as a capability which should handle fluids, generally storing them in
* one or more internal {@link IFluidTank} objects.
* <p/>
* A reference implementation is provided {@link TileFluidHandler}.
*/
public interface IFluidHandler
{
/**
* Returns an array of objects which represent the internal tanks.
* These objects cannot be used to manipulate the internal tanks.
*
* @return Properties for the relevant internal tanks.
*/
IFluidTankProperties[] getTankProperties();
/**
* Fills fluid into internal tanks, distribution is left entirely to the IFluidHandler.
*
* @param resource FluidStack representing the Fluid and maximum amount of fluid to be filled.
* @param doFill If false, fill will only be simulated.
* @return Amount of resource that was (or would have been, if simulated) filled.
*/
int fill(FluidStack resource, boolean doFill);
/**
* Drains fluid out of internal tanks, distribution is left entirely to the IFluidHandler.
*
* @param resource FluidStack representing the Fluid and maximum amount of fluid to be drained.
* @param doDrain If false, drain will only be simulated.
* @return FluidStack representing the Fluid and amount that was (or would have been, if
* simulated) drained.
*/
@Nullable
FluidStack drain(FluidStack resource, boolean doDrain);
/**
* Drains fluid out of internal tanks, distribution is left entirely to the IFluidHandler.
* <p/>
* This method is not Fluid-sensitive.
*
* @param maxDrain Maximum amount of fluid to drain.
* @param doDrain If false, drain will only be simulated.
* @return FluidStack representing the Fluid and amount that was (or would have been, if
* simulated) drained.
*/
@Nullable
FluidStack drain(int maxDrain, boolean doDrain);
}

View file

@ -0,0 +1,65 @@
package net.minecraftforge.fluids.capability;
import javax.annotation.Nullable;
import net.minecraftforge.fluids.FluidStack;
/**
* Simplified Read-only Information about the internals of an {@link IFluidHandler}.
* This is useful for displaying information, and as hints for interacting with it.
* These properties are constant and do not depend on the fluid contents (except the contents themselves, of course).
*
* The information here may not tell the full story of how the tank actually works,
* for real fluid transactions you must use {@link IFluidHandler} to simulate, check, and then interact.
* None of the information in these properties is required to successfully interact using a {@link IFluidHandler}.
*/
public interface IFluidTankProperties
{
/**
* @return A copy of the fluid contents of this tank. May be null.
* To modify the contents, use {@link IFluidHandler}.
*/
@Nullable
FluidStack getContents();
/**
* @return The maximum amount of fluid this tank can hold, in millibuckets.
*/
int getCapacity();
/**
* Returns true if the tank can be filled at any time (even if it is currently full).
* It does not consider the contents or capacity of the tank.
*
* This value is constant. If the tank behavior is more complicated, returns true.
*/
boolean canFill();
/**
* Returns true if the tank can be drained at any time (even if it is currently empty).
* It does not consider the contents or capacity of the tank.
*
* This value is constant. If the tank behavior is more complicated, returns true.
*/
boolean canDrain();
/**
* Returns true if the tank can be filled with a specific type of fluid.
* Used as a filter for fluid types.
*
* Does not consider the current contents or capacity of the tank,
* only whether it could ever fill with this type of fluid.
* {@link FluidStack} is used here because fluid properties can depend on NBT, the amount is ignored.
*/
boolean canFillFluidType(FluidStack fluidStack);
/**
* Returns true if the tank can drain out this a specific of fluid.
* Used as a filter for fluid types.
*
* Does not consider the current contents or capacity of the tank,
* only whether it could ever drain out this type of fluid.
* {@link FluidStack} is used here because fluid properties can depend on NBT, the amount is ignored.
*/
boolean canDrainFluidType(FluidStack fluidStack);
}

View file

@ -0,0 +1,33 @@
package net.minecraftforge.fluids.capability;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.IFluidContainerItem;
import net.minecraftforge.fluids.capability.templates.FluidHandlerItemStack;
/**
* A simple fluid container, to replace the functionality of {@link FluidContainerRegistry) and {@link IFluidContainerItem}.
* This fluid container may be set so that is can only completely filled or empty. (binary)
* It may also be set so that it gets consumed when it is drained. (consumable)
*/
public class ItemFluidContainer extends Item
{
protected final int capacity;
/**
* @param capacity The maximum capacity of this fluid container.
*/
public ItemFluidContainer(int capacity)
{
this.capacity = capacity;
}
@Override
public ICapabilityProvider initCapabilities(ItemStack stack, NBTTagCompound nbt)
{
return new FluidHandlerItemStack(stack, capacity);
}
}

View file

@ -0,0 +1,43 @@
package net.minecraftforge.fluids.capability;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidTank;
public class TileFluidHandler extends TileEntity
{
protected FluidTank tank = new FluidTank(Fluid.BUCKET_VOLUME);
@Override
public void readFromNBT(NBTTagCompound tag)
{
super.readFromNBT(tag);
tank.readFromNBT(tag);
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound tag)
{
tag = super.writeToNBT(tag);
tank.writeToNBT(tag);
return tag;
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing)
{
return capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY || super.hasCapability(capability, facing);
}
@SuppressWarnings("unchecked")
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing)
{
if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
return (T) tank;
return super.getCapability(capability, facing);
}
}

View file

@ -0,0 +1,69 @@
package net.minecraftforge.fluids.capability.templates;
import javax.annotation.Nullable;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandler;
public class EmptyFluidHandler implements IFluidHandler, IFluidTank
{
public static final EmptyFluidHandler INSTANCE = new EmptyFluidHandler();
public static final FluidTankInfo EMPTY_TANK_INFO = new FluidTankInfo(null, 0);
public static final IFluidTankProperties EMPTY_TANK_PROPERTIES = new FluidTankProperties(null, 0, false, false);
public static final IFluidTankProperties[] EMPTY_TANK_PROPERTIES_ARRAY = new IFluidTankProperties[] { EMPTY_TANK_PROPERTIES };
protected EmptyFluidHandler() {}
@Override
public IFluidTankProperties[] getTankProperties()
{
return EMPTY_TANK_PROPERTIES_ARRAY;
}
@Override
@Nullable
public FluidStack getFluid()
{
return null;
}
@Override
public int getFluidAmount()
{
return 0;
}
@Override
public int getCapacity()
{
return 0;
}
@Override
public FluidTankInfo getInfo()
{
return EMPTY_TANK_INFO;
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
return 0;
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
return null;
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
return null;
}
}

View file

@ -0,0 +1,121 @@
package net.minecraftforge.fluids.capability.templates;
import com.google.common.collect.Lists;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandler;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* FluidHandlerConcatenate is a template class for concatenating multiple handlers into one.
* If each tank is restricted to exactly one type of fluid, then use {@link FluidHandlerFluidMap} as it is more efficient.
*/
public class FluidHandlerConcatenate implements IFluidHandler
{
protected final IFluidHandler[] subHandlers;
public FluidHandlerConcatenate(IFluidHandler... subHandlers)
{
this.subHandlers = subHandlers;
}
public FluidHandlerConcatenate(Collection<IFluidHandler> subHandlers)
{
this.subHandlers = subHandlers.toArray(new IFluidHandler[subHandlers.size()]);
}
@Override
public IFluidTankProperties[] getTankProperties()
{
List<IFluidTankProperties> tanks = Lists.newArrayList();
for (IFluidHandler handler : subHandlers)
{
Collections.addAll(tanks, handler.getTankProperties());
}
return tanks.toArray(new IFluidTankProperties[tanks.size()]);
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (resource == null || resource.amount <= 0)
return 0;
resource = resource.copy();
int totalFillAmount = 0;
for (IFluidHandler handler : subHandlers)
{
int fillAmount = handler.fill(resource, doFill);
totalFillAmount += fillAmount;
resource.amount -= fillAmount;
if (resource.amount <= 0)
break;
}
return totalFillAmount;
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (resource == null || resource.amount <= 0)
return null;
resource = resource.copy();
FluidStack totalDrained = null;
for (IFluidHandler handler : subHandlers)
{
FluidStack drain = handler.drain(resource, doDrain);
if (drain != null)
{
if (totalDrained == null)
totalDrained = drain;
else
totalDrained.amount += drain.amount;
resource.amount -= drain.amount;
if (resource.amount <= 0)
break;
}
}
return totalDrained;
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (maxDrain == 0)
return null;
FluidStack totalDrained = null;
for (IFluidHandler handler : subHandlers)
{
if (totalDrained == null)
{
totalDrained = handler.drain(maxDrain, doDrain);
if (totalDrained != null)
{
maxDrain -= totalDrained.amount;
}
}
else
{
FluidStack copy = totalDrained.copy();
copy.amount = maxDrain;
FluidStack drain = handler.drain(copy, doDrain);
if (drain != null)
{
totalDrained.amount += drain.amount;
maxDrain -= drain.amount;
}
}
if (maxDrain <= 0)
break;
}
return totalDrained;
}
}

View file

@ -0,0 +1,80 @@
package net.minecraftforge.fluids.capability.templates;
import com.google.common.collect.Lists;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandler;
import java.util.*;
/**
* FluidHandlerFluidMap is a template class for concatenating multiple handlers into one,
* where each handler is associated with a different fluid.
*/
public class FluidHandlerFluidMap implements IFluidHandler
{
protected final Map<Fluid, IFluidHandler> handlers;
public FluidHandlerFluidMap()
{
// LinkedHashMap to ensure iteration order is consistent.
this(new LinkedHashMap<Fluid, IFluidHandler>());
}
public FluidHandlerFluidMap(Map<Fluid, IFluidHandler> handlers)
{
this.handlers = handlers;
}
public FluidHandlerFluidMap addHandler(Fluid fluid, IFluidHandler handler)
{
handlers.put(fluid, handler);
return this;
}
@Override
public IFluidTankProperties[] getTankProperties()
{
List<IFluidTankProperties> tanks = Lists.newArrayList();
for (IFluidHandler iFluidHandler : handlers.values())
{
Collections.addAll(tanks, iFluidHandler.getTankProperties());
}
return tanks.toArray(new IFluidTankProperties[tanks.size()]);
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (resource == null)
return 0;
IFluidHandler handler = handlers.get(resource.getFluid());
if (handler == null)
return 0;
return handler.fill(resource, doFill);
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (resource == null)
return null;
IFluidHandler handler = handlers.get(resource.getFluid());
if (handler == null)
return null;
return handler.drain(resource, doDrain);
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
for (IFluidHandler handler : handlers.values())
{
FluidStack drain = handler.drain(maxDrain, doDrain);
if (drain != null)
return drain;
}
return null;
}
}

View file

@ -0,0 +1,229 @@
package net.minecraftforge.fluids.capability.templates;
import javax.annotation.Nullable;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fluids.*;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
/**
* FluidHandlerItemStack is a template capability provider for ItemStacks.
* Data is stored directly in the vanilla NBT, in the same way as the old deprecated {@link ItemFluidContainer}.
*
* This class allows an itemStack to contain any partial level of fluid up to its capacity, unlike {@link FluidHandlerItemStackSimple}
*
* Additional examples are provided to enable consumable fluid containers (see {@link Consumable}),
* fluid containers with different empty and full items (see {@link SwapEmpty},
*/
public class FluidHandlerItemStack implements IFluidHandler, ICapabilityProvider
{
public static final String FLUID_NBT_KEY = "Fluid";
protected final ItemStack container;
protected final int capacity;
/**
* @param container The container itemStack, data is stored on it directly as NBT.
* @param capacity The maximum capacity of this fluid tank.
*/
public FluidHandlerItemStack(ItemStack container, int capacity)
{
this.container = container;
this.capacity = capacity;
}
@Nullable
public FluidStack getFluid()
{
NBTTagCompound tagCompound = container.getTagCompound();
if (tagCompound == null || !tagCompound.hasKey(FLUID_NBT_KEY))
{
return null;
}
return FluidStack.loadFluidStackFromNBT(tagCompound.getCompoundTag(FLUID_NBT_KEY));
}
protected void setFluid(FluidStack fluid)
{
if (!container.hasTagCompound())
{
container.setTagCompound(new NBTTagCompound());
}
NBTTagCompound fluidTag = new NBTTagCompound();
fluid.writeToNBT(fluidTag);
container.getTagCompound().setTag(FLUID_NBT_KEY, fluidTag);
}
@Override
public IFluidTankProperties[] getTankProperties()
{
return new FluidTankProperties[] { new FluidTankProperties(getFluid(), capacity) };
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (container.stackSize != 1 || resource == null || resource.amount <= 0 || !canFillFluidType(resource))
{
return 0;
}
FluidStack contained = getFluid();
if (contained == null)
{
int fillAmount = Math.min(capacity, resource.amount);
if (doFill)
{
FluidStack filled = resource.copy();
filled.amount = fillAmount;
setFluid(filled);
}
return fillAmount;
}
else
{
if (contained.isFluidEqual(resource))
{
int fillAmount = Math.min(capacity - contained.amount, resource.amount);
if (doFill && fillAmount > 0) {
contained.amount += fillAmount;
setFluid(contained);
}
return fillAmount;
}
return 0;
}
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (container.stackSize != 1 || resource == null || resource.amount <= 0 || !resource.isFluidEqual(getFluid()))
{
return null;
}
return drain(resource.amount, doDrain);
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (container.stackSize != 1 || maxDrain <= 0)
{
return null;
}
FluidStack contained = getFluid();
if (contained == null || contained.amount <= 0 || !canDrainFluidType(contained))
{
return null;
}
final int drainAmount = Math.min(contained.amount, maxDrain);
FluidStack drained = contained.copy();
drained.amount = drainAmount;
if (doDrain)
{
contained.amount -= drainAmount;
if (contained.amount == 0)
{
setContainerToEmpty();
}
else
{
setFluid(contained);
}
}
return drained;
}
public boolean canFillFluidType(FluidStack fluid)
{
return true;
}
public boolean canDrainFluidType(FluidStack fluid)
{
return true;
}
/**
* Override this method for special handling.
* Can be used to swap out the container's item for a different one with "container.setItem".
* Can be used to destroy the container with "container.stackSize--"
*/
protected void setContainerToEmpty()
{
container.getTagCompound().removeTag(FLUID_NBT_KEY);
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing)
{
return capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY;
}
@SuppressWarnings("unchecked")
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing)
{
return capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY ? (T) this : null;
}
/**
* Destroys the container item when it's emptied.
*/
public static class Consumable extends FluidHandlerItemStack
{
public Consumable(ItemStack container, int capacity)
{
super(container, capacity);
}
@Override
protected void setContainerToEmpty()
{
super.setContainerToEmpty();
container.stackSize--;
}
}
/**
* Swaps the container item for a different one when it's emptied.
*/
public static class SwapEmpty extends FluidHandlerItemStack
{
protected final ItemStack emptyContainer;
public SwapEmpty(ItemStack container, ItemStack emptyContainer, int capacity)
{
super(container, capacity);
this.emptyContainer = emptyContainer;
}
@Override
protected void setContainerToEmpty()
{
super.setContainerToEmpty();
container.setItem(emptyContainer.getItem());
container.setTagCompound(emptyContainer.getTagCompound());
container.setItemDamage(emptyContainer.getItemDamage());
}
}
}

View file

@ -0,0 +1,206 @@
package net.minecraftforge.fluids.capability.templates;
import javax.annotation.Nullable;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.ItemFluidContainer;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
/**
* FluidHandlerItemStackSimple is a template capability provider for ItemStacks.
* Data is stored directly in the vanilla NBT, in the same way as the old deprecated {@link ItemFluidContainer}.
*
* This implementation only allows item containers to be fully filled or emptied, similar to vanilla buckets.
*/
public class FluidHandlerItemStackSimple implements IFluidHandler, ICapabilityProvider
{
public static final String FLUID_NBT_KEY = "Fluid";
protected final ItemStack container;
protected final int capacity;
/**
* @param container The container itemStack, data is stored on it directly as NBT.
* @param capacity The maximum capacity of this fluid tank.
*/
public FluidHandlerItemStackSimple(ItemStack container, int capacity)
{
this.container = container;
this.capacity = capacity;
}
@Nullable
public FluidStack getFluid()
{
NBTTagCompound tagCompound = container.getTagCompound();
if (tagCompound == null || !tagCompound.hasKey(FLUID_NBT_KEY))
{
return null;
}
return FluidStack.loadFluidStackFromNBT(tagCompound.getCompoundTag(FLUID_NBT_KEY));
}
protected void setFluid(FluidStack fluid)
{
if (!container.hasTagCompound())
{
container.setTagCompound(new NBTTagCompound());
}
NBTTagCompound fluidTag = new NBTTagCompound();
fluid.writeToNBT(fluidTag);
container.getTagCompound().setTag(FLUID_NBT_KEY, fluidTag);
}
@Override
public IFluidTankProperties[] getTankProperties()
{
return new IFluidTankProperties[] { new FluidTankProperties(getFluid(), capacity) };
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (container.stackSize != 1 || resource == null || resource.amount <= 0 || !canFillFluidType(resource))
{
return 0;
}
FluidStack contained = getFluid();
if (contained == null)
{
int fillAmount = Math.min(capacity, resource.amount);
if (fillAmount == capacity) {
if (doFill) {
FluidStack filled = resource.copy();
filled.amount = fillAmount;
setFluid(filled);
}
return fillAmount;
}
}
return 0;
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (container.stackSize != 1 || resource == null || resource.amount <= 0 || !resource.isFluidEqual(getFluid()))
{
return null;
}
return drain(resource.amount, doDrain);
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (container.stackSize != 1 || maxDrain <= 0)
{
return null;
}
FluidStack contained = getFluid();
if (contained == null || contained.amount <= 0 || !canDrainFluidType(contained))
{
return null;
}
final int drainAmount = Math.min(contained.amount, maxDrain);
if (drainAmount == capacity) {
FluidStack drained = contained.copy();
if (doDrain) {
setContainerToEmpty();
}
return drained;
}
return null;
}
public boolean canFillFluidType(FluidStack fluid)
{
return true;
}
public boolean canDrainFluidType(FluidStack fluid)
{
return true;
}
/**
* Override this method for special handling.
* Can be used to swap out the container's item for a different one with "container.setItem".
* Can be used to destroy the container with "container.stackSize--"
*/
protected void setContainerToEmpty()
{
container.getTagCompound().removeTag(FLUID_NBT_KEY);
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing)
{
return capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY;
}
@SuppressWarnings("unchecked")
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing)
{
return capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY ? (T) this : null;
}
/**
* Destroys the container item when it's emptied.
*/
public static class Consumable extends FluidHandlerItemStackSimple
{
public Consumable(ItemStack container, int capacity)
{
super(container, capacity);
}
@Override
protected void setContainerToEmpty()
{
super.setContainerToEmpty();
container.stackSize--;
}
}
/**
* Swaps the container item for a different one when it's emptied.
*/
public static class SwapEmpty extends FluidHandlerItemStackSimple
{
protected final ItemStack emptyContainer;
public SwapEmpty(ItemStack container, ItemStack emptyContainer, int capacity)
{
super(container, capacity);
this.emptyContainer = emptyContainer;
}
@Override
protected void setContainerToEmpty()
{
super.setContainerToEmpty();
container.setItem(emptyContainer.getItem());
container.setTagCompound(emptyContainer.getTagCompound());
container.setItemDamage(emptyContainer.getItemDamage());
}
}
}

View file

@ -0,0 +1,125 @@
package net.minecraftforge.fluids.capability.wrappers;
import javax.annotation.Nullable;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandler;
/**
* Wrapper to handle vanilla Water or Lava as an IFluidHandler.
* Methods are modeled after {@link net.minecraft.item.ItemBucket#onItemRightClick(ItemStack, World, EntityPlayer, EnumHand)}
*/
public class BlockLiquidWrapper implements IFluidHandler
{
protected final BlockLiquid blockLiquid;
protected final World world;
protected final BlockPos blockPos;
public BlockLiquidWrapper(BlockLiquid blockLiquid, World world, BlockPos blockPos)
{
this.blockLiquid = blockLiquid;
this.world = world;
this.blockPos = blockPos;
}
@Override
public IFluidTankProperties[] getTankProperties()
{
FluidStack containedStack = null;
IBlockState blockState = world.getBlockState(blockPos);
if (blockState.getBlock() == blockLiquid)
{
containedStack = getStack(blockState);
}
return new FluidTankProperties[]{new FluidTankProperties(containedStack, Fluid.BUCKET_VOLUME, false, true)};
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
return 0;
}
@Nullable
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (resource == null || resource.amount < Fluid.BUCKET_VOLUME)
{
return null;
}
IBlockState blockState = world.getBlockState(blockPos);
if (blockState.getBlock() == blockLiquid && blockState.getValue(BlockLiquid.LEVEL) == 0)
{
FluidStack containedStack = getStack(blockState);
if (containedStack != null && resource.containsFluid(containedStack))
{
if (doDrain)
{
world.setBlockState(blockPos, Blocks.AIR.getDefaultState(), 11);
}
return containedStack;
}
}
return null;
}
@Nullable
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (maxDrain < Fluid.BUCKET_VOLUME)
{
return null;
}
IBlockState blockState = world.getBlockState(blockPos);
if (blockState.getBlock() == blockLiquid)
{
FluidStack containedStack = getStack(blockState);
if (containedStack != null && containedStack.amount <= maxDrain)
{
if (doDrain)
{
world.setBlockState(blockPos, Blocks.AIR.getDefaultState(), 11);
}
return containedStack;
}
}
return null;
}
@Nullable
private FluidStack getStack(IBlockState blockState)
{
Material material = blockState.getMaterial();
if (material == Material.WATER && blockState.getValue(BlockLiquid.LEVEL) == 0)
{
return new FluidStack(FluidRegistry.WATER, Fluid.BUCKET_VOLUME);
}
else if (material == Material.LAVA && blockState.getValue(BlockLiquid.LEVEL) == 0)
{
return new FluidStack(FluidRegistry.LAVA, Fluid.BUCKET_VOLUME);
}
else
{
return null;
}
}
}

View file

@ -0,0 +1,98 @@
package net.minecraftforge.fluids.capability.wrappers;
import javax.annotation.Nullable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.IFluidBlock;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandler;
/**
* Wrapper to handle {@link IFluidBlock} as an 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 IFluidTankProperties[] getTankProperties()
{
float percentFilled = fluidBlock.getFilledPercentage(world, blockPos);
if (percentFilled < 0)
{
percentFilled *= -1;
}
int amountFilled = Math.round(Fluid.BUCKET_VOLUME * percentFilled);
FluidStack fluid = amountFilled > 0 ? new FluidStack(fluidBlock.getFluid(), amountFilled) : null;
return new FluidTankProperties[]{ new FluidTankProperties(fluid, Fluid.BUCKET_VOLUME, false, true)};
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
return 0;
}
@Nullable
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (resource == null || !fluidBlock.canDrain(world, blockPos))
{
return null;
}
FluidStack simulatedDrain = fluidBlock.drain(world, blockPos, false);
if (resource.containsFluid(simulatedDrain))
{
if (doDrain)
{
return fluidBlock.drain(world, blockPos, true);
}
else
{
return simulatedDrain;
}
}
return null;
}
@Nullable
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (maxDrain <= 0 || !fluidBlock.canDrain(world, blockPos))
{
return null;
}
FluidStack simulatedDrain = fluidBlock.drain(world, blockPos, false);
if (simulatedDrain != null && simulatedDrain.amount <= maxDrain)
{
if (doDrain)
{
return fluidBlock.drain(world, blockPos, true);
}
else
{
return simulatedDrain;
}
}
return null;
}
}

View file

@ -0,0 +1,184 @@
package net.minecraftforge.fluids.capability.wrappers;
import javax.annotation.Nullable;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.ForgeModContainer;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.UniversalBucket;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
/**
* Wrapper for vanilla and forge buckets.
* Swaps between empty bucket and filled bucket of the correct type.
*/
public class FluidBucketWrapper implements IFluidHandler, ICapabilityProvider
{
protected final ItemStack container;
public FluidBucketWrapper(ItemStack container)
{
this.container = container;
}
public boolean canFillFluidType(FluidStack fluid)
{
if (fluid.getFluid() == FluidRegistry.WATER || fluid.getFluid() == FluidRegistry.LAVA || fluid.getFluid().getName().equals("milk"))
{
return true;
}
return FluidRegistry.isUniversalBucketEnabled() && FluidRegistry.getBucketFluids().contains(fluid.getFluid());
}
@Nullable
public FluidStack getFluid()
{
Item item = container.getItem();
if (item == Items.WATER_BUCKET)
{
return new FluidStack(FluidRegistry.WATER, Fluid.BUCKET_VOLUME);
}
else if (item == Items.LAVA_BUCKET)
{
return new FluidStack(FluidRegistry.LAVA, Fluid.BUCKET_VOLUME);
}
else if (item == Items.MILK_BUCKET)
{
return FluidRegistry.getFluidStack("milk", Fluid.BUCKET_VOLUME);
}
else if (item == ForgeModContainer.getInstance().universalBucket)
{
return ForgeModContainer.getInstance().universalBucket.getFluid(container);
}
else
{
return null;
}
}
protected void setFluid(Fluid fluid) {
if (fluid == null)
{
container.setItem(Items.BUCKET);
container.setTagCompound(null);
container.setItemDamage(0);
}
else if (fluid == FluidRegistry.WATER)
{
container.setItem(Items.WATER_BUCKET);
container.setTagCompound(null);
container.setItemDamage(0);
}
else if (fluid == FluidRegistry.LAVA)
{
container.setItem(Items.LAVA_BUCKET);
container.setTagCompound(null);
container.setItemDamage(0);
}
else if (fluid.getName().equals("milk"))
{
container.setItem(Items.MILK_BUCKET);
container.setTagCompound(null);
container.setItemDamage(0);
}
else if (FluidRegistry.isUniversalBucketEnabled() && FluidRegistry.getBucketFluids().contains(fluid))
{
ItemStack filledBucket = UniversalBucket.getFilledBucket(ForgeModContainer.getInstance().universalBucket, fluid);
container.setItem(filledBucket.getItem());
container.setTagCompound(filledBucket.getTagCompound());
container.setItemDamage(filledBucket.getItemDamage());
}
}
@Override
public IFluidTankProperties[] getTankProperties()
{
return new FluidTankProperties[] { new FluidTankProperties(getFluid(), Fluid.BUCKET_VOLUME) };
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (container.stackSize != 1 || resource == null || resource.amount < Fluid.BUCKET_VOLUME || getFluid() != null || !canFillFluidType(resource))
{
return 0;
}
if (doFill)
{
setFluid(resource.getFluid());
}
return Fluid.BUCKET_VOLUME;
}
@Nullable
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (container.stackSize != 1 || resource == null || resource.amount < Fluid.BUCKET_VOLUME)
{
return null;
}
FluidStack fluidStack = getFluid();
if (fluidStack != null && fluidStack.isFluidEqual(resource))
{
if (doDrain)
{
setFluid(null);
}
return fluidStack;
}
return null;
}
@Nullable
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (container.stackSize != 1 || maxDrain < Fluid.BUCKET_VOLUME)
{
return null;
}
FluidStack fluidStack = getFluid();
if (fluidStack != null)
{
if (doDrain)
{
setFluid(null);
}
return fluidStack;
}
return null;
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing)
{
return capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY;
}
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing)
{
if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
{
return CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY.cast(this);
}
return null;
}
}

View file

@ -0,0 +1,90 @@
package net.minecraftforge.fluids.capability.wrappers;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.IFluidContainerItem;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
/**
* FluidContainerItemWrapper converts an old {@link IFluidContainerItem} to IFluidHandler.
* Note that successful operations WILL modify the container itemStack.
* @deprecated will be removed along with {@link IFluidContainerItem}
*/
@Deprecated
public class FluidContainerItemWrapper implements IFluidHandler, ICapabilityProvider
{
protected final IFluidContainerItem handler;
protected final ItemStack container;
public FluidContainerItemWrapper(IFluidContainerItem handler, ItemStack container)
{
this.handler = handler;
this.container = container;
}
@Override
public FluidTankProperties[] getTankProperties()
{
return new FluidTankProperties[] { new FluidTankProperties(handler.getFluid(container), handler.getCapacity(container)) };
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (container.stackSize != 1)
{
return 0;
}
return handler.fill(container, resource, doFill);
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (container.stackSize != 1 || resource == null)
{
return null;
}
FluidStack canDrain = drain(resource.amount, false);
if (canDrain != null)
{
if (canDrain.isFluidEqual(resource))
{
return drain(resource.amount, doDrain);
}
}
return null;
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (container.stackSize != 1)
{
return null;
}
return handler.drain(container, maxDrain, doDrain);
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing)
{
return capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY;
}
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing)
{
if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
{
return CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY.cast(this);
}
return null;
}
}

View file

@ -0,0 +1,141 @@
package net.minecraftforge.fluids.capability.wrappers;
import javax.annotation.Nullable;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
/**
* Wraps a liquid container that uses the {@link FluidContainerRegistry}
* Note that successful operations WILL modify the container itemStack.
* @deprecated will be removed along with {@link FluidContainerRegistry}
*/
@Deprecated
public class FluidContainerRegistryWrapper implements IFluidHandler, ICapabilityProvider
{
protected final ItemStack container;
public FluidContainerRegistryWrapper(ItemStack container)
{
this.container = container;
}
private void updateContainer(ItemStack newContainerData)
{
container.setItem(newContainerData.getItem());
container.setTagCompound(newContainerData.getTagCompound());
container.setItemDamage(newContainerData.getItemDamage());
container.stackSize = newContainerData.stackSize;
}
@Override
public IFluidTankProperties[] getTankProperties()
{
FluidStack fluid = FluidContainerRegistry.getFluidForFilledItem(container);
int capacity = FluidContainerRegistry.getContainerCapacity(fluid, container);
return new FluidTankProperties[] { new FluidTankProperties(fluid, capacity) };
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (container.stackSize != 1 || resource == null)
{
return 0;
}
FluidStack originalContained = FluidContainerRegistry.getFluidForFilledItem(container);
ItemStack result = FluidContainerRegistry.fillFluidContainer(resource, container);
if (result == null)
{
return 0;
}
if (doFill)
{
updateContainer(result);
}
FluidStack newContained = FluidContainerRegistry.getFluidForFilledItem(result);
int originalAmount = originalContained == null ? 0 : originalContained.amount;
int newAmount = newContained == null ? 0 : newContained.amount;
return newAmount - originalAmount;
}
@Nullable
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (container.stackSize != 1 || resource == null)
{
return null;
}
FluidStack contained = FluidContainerRegistry.getFluidForFilledItem(container);
if (contained != null && contained.isFluidEqual(resource))
{
return drain(resource.amount, doDrain);
}
return null;
}
@Nullable
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (container.stackSize != 1)
{
return null;
}
FluidStack contained = FluidContainerRegistry.getFluidForFilledItem(container);
if (contained != null)
{
if (contained.amount <= maxDrain)
{
ItemStack emptyContainer = FluidContainerRegistry.drainFluidContainer(container);
if (emptyContainer != null)
{
if (doDrain)
{
if (FluidContainerRegistry.hasNullEmptyContainer(container))
{
emptyContainer.stackSize = 0;
}
updateContainer(emptyContainer);
}
return contained;
}
}
}
return null;
}
@Override
public boolean hasCapability(Capability<?> capability, @Nullable EnumFacing facing)
{
return capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY;
}
@Override
public <T> T getCapability(Capability<T> capability, @Nullable EnumFacing facing)
{
if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
{
return CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY.cast(this);
}
return null;
}
}

View file

@ -0,0 +1,52 @@
package net.minecraftforge.fluids.capability.wrappers;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandler;
/**
* FluidHandlerWrapper automatically converts the old {@link net.minecraftforge.fluids.IFluidHandler} to the new version.
* @deprecated will be removed along with {@link net.minecraftforge.fluids.IFluidHandler}
*/
@Deprecated
public class FluidHandlerWrapper implements IFluidHandler
{
protected final net.minecraftforge.fluids.IFluidHandler handler;
protected final EnumFacing side;
public FluidHandlerWrapper(net.minecraftforge.fluids.IFluidHandler handler, EnumFacing side)
{
this.handler = handler;
this.side = side;
}
@Override
public IFluidTankProperties[] getTankProperties()
{
return FluidTankProperties.convert(handler.getTankInfo(side));
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (resource == null || !handler.canFill(side, resource.getFluid()))
return 0;
return handler.fill(side, resource, doFill);
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (resource == null || !handler.canDrain(side, resource.getFluid()))
return null;
return handler.drain(side, resource, doDrain);
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
return handler.drain(side, maxDrain, doDrain);
}
}