/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids;
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, 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(@Nullable FluidStack fluidStack, int capacity)
{
this.fluid = fluidStack;
this.capacity = capacity;
}
public FluidTank(Fluid fluid, int amount, int capacity)
{
this(new FluidStack(fluid, amount), capacity);
}
public FluidTank readFromNBT(NBTTagCompound nbt)
{
if (!nbt.hasKey("Empty"))
{
FluidStack fluid = FluidStack.loadFluidStackFromNBT(nbt);
setFluid(fluid);
}
else
{
setFluid(null);
}
return this;
}
public NBTTagCompound writeToNBT(NBTTagCompound nbt)
{
if (fluid != null)
{
fluid.writeToNBT(nbt);
}
else
{
nbt.setString("Empty", "");
}
return nbt;
}
/* IFluidTank */
@Override
@Nullable
public FluidStack getFluid()
{
return fluid;
}
public void setFluid(@Nullable FluidStack fluid)
{
this.fluid = fluid;
}
@Override
public int getFluidAmount()
{
if (fluid == null)
{
return 0;
}
return fluid.amount;
}
@Override
public int getCapacity()
{
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 (!canFillFluidType(resource))
{
return 0;
}
return fillInternal(resource, doFill);
}
/**
* Use this method to bypass the restrictions from {@link #canFillFluidType(FluidStack)}
* Meant for use by the owner of the tank when they have {@link #canFill() set to false}.
*/
public int fillInternal(FluidStack resource, boolean doFill)
{
if (resource == null || resource.amount <= 0)
{
return 0;
}
if (!doFill)
{
if (fluid == null)
{
return Math.min(capacity, resource.amount);
}
if (!fluid.isFluidEqual(resource))
{
return 0;
}
return Math.min(capacity - fluid.amount, resource.amount);
}
if (fluid == null)
{
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));
}
return fluid.amount;
}
if (!fluid.isFluidEqual(resource))
{
return 0;
}
int filled = capacity - fluid.amount;
if (resource.amount < filled)
{
fluid.amount += resource.amount;
filled = resource.amount;
}
else
{
fluid.amount = capacity;
}
onContentsChanged();
if (tile != null)
{
FluidEvent.fireEvent(new FluidEvent.FluidFillingEvent(fluid, tile.getWorld(), tile.getPos(), this, filled));
}
return filled;
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (!canDrainFluidType(getFluid()))
{
return null;
}
return drainInternal(resource, doDrain);
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (!canDrainFluidType(fluid))
{
return null;
}
return drainInternal(maxDrain, doDrain);
}
/**
* Use this method to bypass the restrictions from {@link #canDrainFluidType(FluidStack)}
* Meant for use by the owner of the tank when they have {@link #canDrain()} set to false}.
*/
@Nullable
public FluidStack drainInternal(FluidStack resource, boolean doDrain)
{
if (resource == null || !resource.isFluidEqual(getFluid()))
{
return null;
}
return drainInternal(resource.amount, doDrain);
}
/**
* Use this method to bypass the restrictions from {@link #canDrainFluidType(FluidStack)}
* Meant for use by the owner of the tank when they have {@link #canDrain()} set to false}.
*/
@Nullable
public FluidStack drainInternal(int maxDrain, boolean doDrain)
{
if (fluid == null || maxDrain <= 0)
{
return null;
}
int drained = maxDrain;
if (fluid.amount < drained)
{
drained = fluid.amount;
}
FluidStack stack = new FluidStack(fluid, drained);
if (doDrain)
{
fluid.amount -= drained;
if (fluid.amount <= 0)
{
fluid = null;
}
onContentsChanged();
if (tile != null)
{
FluidEvent.fireEvent(new FluidEvent.FluidDrainingEvent(fluid, tile.getWorld(), tile.getPos(), this, drained));
}
}
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(@Nullable FluidStack fluid)
{
return fluid != null && canDrain();
}
protected void onContentsChanged()
{
}
}