/*
* Copyright (c) CovertJaguar, 2015 http://railcraft.info
*
* This code is the property of CovertJaguar
* and may only be used with explicit written
* permission unless otherwise specified on the
* license page at http://railcraft.info/wiki/info:license.
*/
package mods.railcraft.common.carts;
import mods.railcraft.api.carts.IFluidCart;
import mods.railcraft.api.carts.IItemCart;
import mods.railcraft.api.carts.ITrainTransferHelper;
import mods.railcraft.api.core.items.IStackFilter;
import mods.railcraft.common.fluids.FluidHelper;
import mods.railcraft.common.util.inventory.InvTools;
import net.minecraft.entity.item.EntityMinecart;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;
import net.minecraftforge.fluids.IFluidHandler;
import java.util.Set;
/**
* Created by CovertJaguar on 5/9/2015.
*/
public class TrainTransferHelper implements mods.railcraft.api.carts.ITrainTransferHelper {
public static final ITrainTransferHelper INSTANCE = new TrainTransferHelper();
private static final int NUM_SLOTS = 8;
private static final int TANK_CAPACITY = 8 * FluidHelper.BUCKET_VOLUME;
private TrainTransferHelper() {
}
// ***************************************************************************************************************************
// Items
// ***************************************************************************************************************************
@Override
public ItemStack pushStack(EntityMinecart requester, ItemStack stack) {
Iterable<EntityMinecart> carts = LinkageManager.instance().getLinkedCarts(requester, LinkageManager.LinkType.LINK_A);
stack = _pushStack(requester, carts, stack);
if (stack == null)
return null;
if (LinkageManager.instance().hasLink(requester, LinkageManager.LinkType.LINK_B)) {
carts = LinkageManager.instance().getLinkedCarts(requester, LinkageManager.LinkType.LINK_B);
stack = _pushStack(requester, carts, stack);
}
return stack;
}
private ItemStack _pushStack(EntityMinecart requester, Iterable<EntityMinecart> carts, ItemStack stack) {
for (EntityMinecart cart : carts) {
if (canAcceptPushedItem(requester, cart, stack))
stack = InvTools.moveItemStack(stack, (IInventory) cart);
if (stack == null || !canPassItemRequests(cart))
break;
}
return stack;
}
@Override
public ItemStack pullStack(EntityMinecart requester, IStackFilter filter) {
Iterable<EntityMinecart> carts = LinkageManager.instance().getLinkedCarts(requester, LinkageManager.LinkType.LINK_A);
ItemStack stack = _pullStack(requester, carts, filter);
if (stack != null)
return stack;
carts = LinkageManager.instance().getLinkedCarts(requester, LinkageManager.LinkType.LINK_B);
return _pullStack(requester, carts, filter);
}
private ItemStack _pullStack(EntityMinecart requester, Iterable<EntityMinecart> carts, IStackFilter filter) {
for (EntityMinecart cart : carts) {
if (cart instanceof IInventory) {
Set<ItemStack> items = InvTools.findMatchingItems((IInventory) cart, filter);
for (ItemStack stack : items) {
if (stack != null && canProvidePulledItem(requester, cart, stack)) {
ItemStack removed = InvTools.removeOneItem((IInventory) cart, stack);
if (removed != null)
return removed;
}
}
}
if (!canPassItemRequests(cart))
break;
}
return null;
}
private boolean canAcceptPushedItem(EntityMinecart requester, EntityMinecart cart, ItemStack stack) {
if (!(cart instanceof IInventory))
return false;
if (cart instanceof IItemCart)
return ((IItemCart) cart).canAcceptPushedItem(requester, stack);
return true;
}
private boolean canProvidePulledItem(EntityMinecart requester, EntityMinecart cart, ItemStack stack) {
if (!(cart instanceof IInventory))
return false;
if (cart instanceof IItemCart)
return ((IItemCart) cart).canProvidePulledItem(requester, stack);
return true;
}
private boolean canPassItemRequests(EntityMinecart cart) {
if (cart instanceof IItemCart)
return ((IItemCart) cart).canPassItemRequests();
if (cart instanceof IInventory)
return ((IInventory) cart).getSizeInventory() >= NUM_SLOTS;
return false;
}
// ***************************************************************************************************************************
// Fluids
// ***************************************************************************************************************************
@Override
public FluidStack pushFluid(EntityMinecart requester, FluidStack fluidStack) {
Iterable<EntityMinecart> carts = LinkageManager.instance().getLinkedCarts(requester, LinkageManager.LinkType.LINK_A);
fluidStack = _pushFluid(requester, carts, fluidStack);
if (fluidStack == null)
return null;
if (LinkageManager.instance().hasLink(requester, LinkageManager.LinkType.LINK_B)) {
carts = LinkageManager.instance().getLinkedCarts(requester, LinkageManager.LinkType.LINK_B);
fluidStack = _pushFluid(requester, carts, fluidStack);
}
return fluidStack;
}
private FluidStack _pushFluid(EntityMinecart requester, Iterable<EntityMinecart> carts, FluidStack fluidStack) {
if (fluidStack == null)
return null;
for (EntityMinecart cart : carts) {
if (canAcceptPushedFluid(requester, cart, fluidStack.getFluid())) {
fluidStack.amount -= ((IFluidHandler) cart).fill(ForgeDirection.UP, fluidStack, true);
}
if (fluidStack.amount <= 0 || !canPassFluidRequests(cart, fluidStack.getFluid()))
break;
}
if (fluidStack.amount <= 0)
return null;
return fluidStack;
}
@Override
public FluidStack pullFluid(EntityMinecart requester, FluidStack fluidStack) {
Iterable<EntityMinecart> carts = LinkageManager.instance().getLinkedCarts(requester, LinkageManager.LinkType.LINK_A);
FluidStack pulled = _pullFluid(requester, carts, fluidStack);
if (pulled != null)
return pulled;
carts = LinkageManager.instance().getLinkedCarts(requester, LinkageManager.LinkType.LINK_B);
return _pullFluid(requester, carts, fluidStack);
}
private FluidStack _pullFluid(EntityMinecart requester, Iterable<EntityMinecart> carts, FluidStack fluidStack) {
for (EntityMinecart cart : carts) {
if (canProvidePulledFluid(requester, cart, fluidStack.getFluid())) {
IFluidHandler fluidHandler = (IFluidHandler) cart;
if (fluidHandler.canDrain(ForgeDirection.DOWN, fluidStack.getFluid())) {
FluidStack drained = fluidHandler.drain(ForgeDirection.DOWN, fluidStack, true);
if (drained != null)
return drained;
}
}
if (!canPassFluidRequests(cart, fluidStack.getFluid()))
break;
}
return null;
}
private boolean canAcceptPushedFluid(EntityMinecart requester, EntityMinecart cart, Fluid fluid) {
if (!(cart instanceof IFluidHandler))
return false;
if (cart instanceof IFluidCart)
return ((IFluidCart) cart).canAcceptPushedFluid(requester, fluid);
return ((IFluidHandler) cart).canFill(ForgeDirection.UP, fluid);
}
private boolean canProvidePulledFluid(EntityMinecart requester, EntityMinecart cart, Fluid fluid) {
if (!(cart instanceof IFluidHandler))
return false;
if (cart instanceof IFluidCart)
return ((IFluidCart) cart).canProvidePulledFluid(requester, fluid);
return ((IFluidHandler) cart).canDrain(ForgeDirection.DOWN, fluid);
}
private boolean canPassFluidRequests(EntityMinecart cart, Fluid fluid) {
if (cart instanceof IFluidCart)
return ((IFluidCart) cart).canPassFluidRequests(fluid);
if (cart instanceof IFluidHandler) {
if (hasMatchingTank((IFluidHandler) cart, fluid))
return true;
}
return false;
}
private boolean hasMatchingTank(IFluidHandler handler, Fluid fluid) {
FluidTankInfo[] tankInfo = handler.getTankInfo(ForgeDirection.UP);
for (FluidTankInfo info : tankInfo) {
if (info.capacity >= TANK_CAPACITY) {
if (info.fluid == null || info.fluid.amount == 0 || info.fluid.getFluid() == fluid)
return true;
}
}
return false;
}
}