diff options
author | Martin Robertz <dream-master@gmx.net> | 2021-07-15 16:50:25 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-15 16:50:25 +0200 |
commit | b0b591089c9ae646506770e92efeee074598b49b (patch) | |
tree | 95393d3bcbb39e3bb52307b3abec66ea6cbe0584 /src/main/java/gregtech/api/gui | |
parent | f2b07a2872a1c3a1825a9dad0b52e6588fef9ac0 (diff) | |
parent | 6f8016367d6f278f7a39206ff7f9dc73c719c807 (diff) | |
download | GT5-Unofficial-b0b591089c9ae646506770e92efeee074598b49b.tar.gz GT5-Unofficial-b0b591089c9ae646506770e92efeee074598b49b.tar.bz2 GT5-Unofficial-b0b591089c9ae646506770e92efeee074598b49b.zip |
Merge pull request #593 from GTNewHorizons/gui-manipulate-fluid
Extended GUI fluid manipulation support to GT_MetaTileEntity_BasicTank
Diffstat (limited to 'src/main/java/gregtech/api/gui')
-rw-r--r-- | src/main/java/gregtech/api/gui/GT_Container_BasicMachine.java | 150 | ||||
-rw-r--r-- | src/main/java/gregtech/api/gui/GT_Container_BasicTank.java | 226 |
2 files changed, 235 insertions, 141 deletions
diff --git a/src/main/java/gregtech/api/gui/GT_Container_BasicMachine.java b/src/main/java/gregtech/api/gui/GT_Container_BasicMachine.java index 28fd2983f4..5d2a9321c4 100644 --- a/src/main/java/gregtech/api/gui/GT_Container_BasicMachine.java +++ b/src/main/java/gregtech/api/gui/GT_Container_BasicMachine.java @@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicTank; import gregtech.api.util.GT_Utility; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; @@ -11,7 +12,6 @@ import net.minecraft.inventory.ICrafting; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.IFluidContainerItem; import static gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine.OTHER_SLOT_COUNT; @@ -195,154 +195,22 @@ public class GT_Container_BasicMachine extends GT_Container_BasicTank { if (mTileEntity.getMetaTileEntity() == null) return null; machine.mItemTransfer = !machine.mItemTransfer; return null; - case 2: - if (aMouseclick > 1) - return null; - tResultStack = pickupFluid(machine.getDrainableStack(), aPlayer, aMouseclick == 0); - if (machine.getDrainableStack() != null && machine.getDrainableStack().amount == 0) - machine.setDrainableStack(null); - return tResultStack; default: - if (aSlotIndex == OTHER_SLOT_COUNT + 1 + machine.mInputSlotCount + machine.mOutputItems.length) { - if (aMouseclick > 1) - return null; - // input fluid slot - ItemStack tStackHeld = aPlayer.inventory.getItemStack(); - ItemStack tStackSizedOne = GT_Utility.copyAmount(1, tStackHeld); - if (tStackSizedOne == null || tStackHeld.stackSize == 0) return null; - FluidStack tInputFluid = machine.getFillableStack(); - FluidStack tFluidHeld = GT_Utility.getFluidForFilledItem(tStackSizedOne, true); - if (tFluidHeld != null && tFluidHeld.amount <= 0) - tFluidHeld = null; - if (tInputFluid == null) { - if (tFluidHeld == null) - // both null -> no op - return null; - return fillFluid(machine, aPlayer, tFluidHeld, aMouseclick == 0); - } else { - if (tFluidHeld != null && tInputFluid.amount < machine.getCapacity()) { - // both nonnull and have space left for filling. - // actually both pickup and fill is reasonable, but I'll go with fill here - return fillFluid(machine, aPlayer, tFluidHeld, aMouseclick == 0); - } else { - tResultStack = pickupFluid(tInputFluid, aPlayer, aMouseclick == 0); - if (tInputFluid.amount == 0) - machine.setFillableStack(null); - return tResultStack; - } + if (aSlotIndex == OTHER_SLOT_COUNT + 1 + machine.mInputSlotCount + machine.mOutputItems.length && aMouseclick < 2) { + if (mTileEntity.isClientSide()) { + // see parent class slotClick for an explanation on why doing this + GT_MetaTileEntity_BasicTank tTank = (GT_MetaTileEntity_BasicTank) mTileEntity.getMetaTileEntity(); + tTank.setFillableStack(GT_Utility.getFluidFromDisplayStack(tTank.getStackInSlot(2))); } + GT_MetaTileEntity_BasicTank tTank = (GT_MetaTileEntity_BasicTank) mTileEntity.getMetaTileEntity(); + IFluidAccess tFillableAccess = IFluidAccess.from(tTank, true); + return handleFluidSlotClick(tFillableAccess, aPlayer, aMouseclick == 0, true, true); } else { return super.slotClick(aSlotIndex, aMouseclick, aShifthold, aPlayer); } } } - private ItemStack pickupFluid(FluidStack aTankStack, EntityPlayer aPlayer, boolean aProcessFullStack) { - if (aTankStack == null) return null; - ItemStack tStackHeld = aPlayer.inventory.getItemStack(); - ItemStack tStackSizedOne = GT_Utility.copyAmount(1, tStackHeld); - if (tStackSizedOne == null || tStackHeld.stackSize == 0) return null; - int tOriginalFluidAmount = aTankStack.amount; - ItemStack tFilled = GT_Utility.fillFluidContainer(aTankStack, tStackSizedOne, true, false); - if (tFilled == null && tStackSizedOne.getItem() instanceof IFluidContainerItem) { - IFluidContainerItem tContainerItem = (IFluidContainerItem) tStackSizedOne.getItem(); - int tFilledAmount = tContainerItem.fill(tStackSizedOne, aTankStack, true); - if (tFilledAmount > 0) { - tFilled = tStackSizedOne; - aTankStack.amount -= tFilledAmount; - } - } - if (tFilled != null) { - if (aProcessFullStack) { - int tFilledAmount = tOriginalFluidAmount - aTankStack.amount; - /* - work out how many more items we can fill - one cell is already used, so account for that - the round down behavior will left over a fraction of a cell worth of fluid - the user then get to decide what to do with it - it will not be too fancy if it spills out partially filled cells - */ - int tAdditionalParallel = Math.min(tStackHeld.stackSize - 1, aTankStack.amount / tFilledAmount); - aTankStack.amount -= tFilledAmount * tAdditionalParallel; - tFilled.stackSize += tAdditionalParallel; - } - replaceCursorItemStack(aPlayer, tFilled); - } - return tFilled; - } - - private ItemStack fillFluid(GT_MetaTileEntity_BasicMachine aMachine, EntityPlayer aPlayer, FluidStack aFluidHeld, boolean aProcessFullStack) { - // we are not using aMachine.fill() here any more, so we need to check for fluid type here ourselves - if (aMachine.getFillableStack() != null && !aMachine.getFillableStack().isFluidEqual(aFluidHeld)) - return null; - ItemStack tStackHeld = aPlayer.inventory.getItemStack(); - ItemStack tStackSizedOne = GT_Utility.copyAmount(1, tStackHeld); - if (tStackSizedOne == null) - return null; - - int tFreeSpace = aMachine.getCapacity() - (aMachine.getFillableStack() != null ? aMachine.getFillableStack().amount : 0); - if (tFreeSpace <= 0) - // no space left - return null; - - // find out how much fluid can be taken - // some cells cannot be partially filled - ItemStack tStackEmptied = null; - int tAmountTaken = 0; - if (tFreeSpace >= aFluidHeld.amount) { - // fully accepted - try take it from item now - // IFluidContainerItem is intentionally not checked here. it will be checked later - tStackEmptied = GT_Utility.getContainerForFilledItem(tStackSizedOne, false); - tAmountTaken = aFluidHeld.amount; - } - if (tStackEmptied == null && tStackSizedOne.getItem() instanceof IFluidContainerItem) { - // either partially accepted, or is IFluidContainerItem - IFluidContainerItem container = (IFluidContainerItem) tStackSizedOne.getItem(); - FluidStack tDrained = container.drain(tStackSizedOne, tFreeSpace, true); - if (tDrained != null && tDrained.amount > 0) { - // something is actually drained - change the cell and drop it to player - tStackEmptied = tStackSizedOne; - tAmountTaken = tDrained.amount; - } - } - if (tStackEmptied == null) - // somehow the cell refuse to give out that amount of fluid, no op then - return null; - - // find out how many fill can we do - // same round down behavior as above - // however here the fluid stack is not changed at all, so the exact code will slightly differ - int tParallel = aProcessFullStack ? Math.min(tFreeSpace / tAmountTaken, tStackHeld.stackSize) : 1; - if (aMachine.getFillableStack() == null) { - FluidStack tNewFillableStack = aFluidHeld.copy(); - tNewFillableStack.amount = tAmountTaken * tParallel; - aMachine.setFillableStack(tNewFillableStack); - } else { - aMachine.getFillableStack().amount += tAmountTaken * tParallel; - } - tStackEmptied.stackSize = tParallel; - replaceCursorItemStack(aPlayer, tStackEmptied); - return tStackEmptied; - } - - private void replaceCursorItemStack(EntityPlayer aPlayer, ItemStack tStackResult) { - int tStackResultMaxStackSize = tStackResult.getMaxStackSize(); - while (tStackResult.stackSize > tStackResultMaxStackSize) { - aPlayer.inventory.getItemStack().stackSize -= tStackResultMaxStackSize; - GT_Utility.addItemToPlayerInventory(aPlayer, tStackResult.splitStack(tStackResultMaxStackSize)); - } - if (aPlayer.inventory.getItemStack().stackSize == tStackResult.stackSize) { - // every cell is mutated. it could just stay on the cursor. - aPlayer.inventory.setItemStack(tStackResult); - } else { - // some cells not mutated. The mutated cells must go into the inventory - // or drop into the world if there isn't enough space. - ItemStack tStackHeld = aPlayer.inventory.getItemStack(); - tStackHeld.stackSize -= tStackResult.stackSize; - GT_Utility.addItemToPlayerInventory(aPlayer, tStackResult); - } - } - @Override public void detectAndSendChanges() { super.detectAndSendChanges(); diff --git a/src/main/java/gregtech/api/gui/GT_Container_BasicTank.java b/src/main/java/gregtech/api/gui/GT_Container_BasicTank.java index c80874eef4..0ce9ab9232 100644 --- a/src/main/java/gregtech/api/gui/GT_Container_BasicTank.java +++ b/src/main/java/gregtech/api/gui/GT_Container_BasicTank.java @@ -4,9 +4,15 @@ import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicTank; +import gregtech.api.util.GT_Utility; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.ICrafting; import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ChatComponentText; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidContainerItem; /** * NEVER INCLUDE THIS FILE IN YOUR MOD!!! @@ -29,6 +35,189 @@ public class GT_Container_BasicTank extends GT_ContainerMetaTile_Machine { } @Override + public ItemStack slotClick(int aSlotIndex, int aMouseclick, int aShifthold, EntityPlayer aPlayer) { + if (aSlotIndex == 2 && aMouseclick < 2) { + if (mTileEntity.isClientSide()) { + /* + * While a logical client don't really need to process fluid cells upon click (it could have just wait + * for server side to send the result), doing so would result in every fluid interaction having a + * noticeable delay between clicking and changes happening even on single player. + * I'd imagine this delay to get only more severe when playing MP over ethernet, which would have much more latency + * than a memory connection + */ + GT_MetaTileEntity_BasicTank tTank = (GT_MetaTileEntity_BasicTank) mTileEntity.getMetaTileEntity(); + tTank.setDrainableStack(GT_Utility.getFluidFromDisplayStack(tTank.getStackInSlot(2))); + } + GT_MetaTileEntity_BasicTank tTank = (GT_MetaTileEntity_BasicTank) mTileEntity.getMetaTileEntity(); + IFluidAccess tDrainableAccess = IFluidAccess.from(tTank, false); + return handleFluidSlotClick(tDrainableAccess, aPlayer, aMouseclick == 0, true, !tTank.isDrainableStackSeparate()); + } + if (mTileEntity.isServerSide()) { + aPlayer.addChatComponentMessage(new ChatComponentText(String.format("Slot Index: %d, aMouseClick: %d, Shift Hold: %d", aShifthold, aMouseclick, aShifthold))); + } + return super.slotClick(aSlotIndex, aMouseclick, aShifthold, aPlayer); + } + + /** + * Expected to be called on client side only. Load fluid stacks from fluid display items as they were not sent + * over the network. + * Override this if you have more than one fluid display stack. This implementation will set drainable stack according to items + * in slot indexed 2. + * + */ + protected void syncFluidFromFluidDisplayItems() { + GT_MetaTileEntity_BasicTank tTank = (GT_MetaTileEntity_BasicTank) mTileEntity.getMetaTileEntity(); + tTank.setDrainableStack(GT_Utility.getFluidFromDisplayStack(tTank.getStackInSlot(2))); + } + + protected static ItemStack handleFluidSlotClick(IFluidAccess aFluidAccess, EntityPlayer aPlayer, boolean aProcessFullStack, boolean aCanDrain, boolean aCanFill) { + ItemStack tStackHeld = aPlayer.inventory.getItemStack(); + ItemStack tStackSizedOne = GT_Utility.copyAmount(1, tStackHeld); + if (tStackSizedOne == null || tStackHeld.stackSize == 0) return null; + FluidStack tInputFluid = aFluidAccess.get(); + FluidStack tFluidHeld = GT_Utility.getFluidForFilledItem(tStackSizedOne, true); + if (tFluidHeld != null && tFluidHeld.amount <= 0) + tFluidHeld = null; + if (tInputFluid == null) { + // tank empty, consider fill only from now on + if (!aCanFill) + // cannot fill and nothing to take, bail out + return null; + if (tFluidHeld == null) + // no fluid to fill + return null; + return fillFluid(aFluidAccess, aPlayer, tFluidHeld, aProcessFullStack); + } + // tank not empty, both action possible + if (tFluidHeld != null && tInputFluid.amount < aFluidAccess.getCapacity()) { + // both nonnull and have space left for filling. + if (aCanFill) + // actually both pickup and fill is reasonable, but I'll go with fill here + return fillFluid(aFluidAccess, aPlayer, tFluidHeld, aProcessFullStack); + if (!aCanDrain) + // cannot take AND cannot fill, why make this call then? + return null; + // the slot does not allow filling, so try take some + return drainFluid(aFluidAccess.get(), aPlayer, aProcessFullStack); + } else { + // cannot fill and there is something to take + if (!aCanDrain) + // but the slot does not allow taking, so bail out + return null; + ItemStack tResultStack = drainFluid(tInputFluid, aPlayer, aProcessFullStack); + if (tInputFluid.amount == 0) + aFluidAccess.set(null); + return tResultStack; + } + } + + protected static ItemStack drainFluid(FluidStack aTankStack, EntityPlayer aPlayer, boolean aProcessFullStack) { + if (aTankStack == null) return null; + ItemStack tStackHeld = aPlayer.inventory.getItemStack(); + ItemStack tStackSizedOne = GT_Utility.copyAmount(1, tStackHeld); + if (tStackSizedOne == null || tStackHeld.stackSize == 0) return null; + int tOriginalFluidAmount = aTankStack.amount; + ItemStack tFilled = GT_Utility.fillFluidContainer(aTankStack, tStackSizedOne, true, false); + if (tFilled == null && tStackSizedOne.getItem() instanceof IFluidContainerItem) { + IFluidContainerItem tContainerItem = (IFluidContainerItem) tStackSizedOne.getItem(); + int tFilledAmount = tContainerItem.fill(tStackSizedOne, aTankStack, true); + if (tFilledAmount > 0) { + tFilled = tStackSizedOne; + aTankStack.amount -= tFilledAmount; + } + } + if (tFilled != null) { + if (aProcessFullStack) { + int tFilledAmount = tOriginalFluidAmount - aTankStack.amount; + /* + work out how many more items we can fill + one cell is already used, so account for that + the round down behavior will left over a fraction of a cell worth of fluid + the user then get to decide what to do with it + it will not be too fancy if it spills out partially filled cells + */ + int tAdditionalParallel = Math.min(tStackHeld.stackSize - 1, aTankStack.amount / tFilledAmount); + aTankStack.amount -= tFilledAmount * tAdditionalParallel; + tFilled.stackSize += tAdditionalParallel; + } + replaceCursorItemStack(aPlayer, tFilled); + } + return tFilled; + } + + protected static ItemStack fillFluid(IFluidAccess aFluidAccess, EntityPlayer aPlayer, FluidStack aFluidHeld, boolean aProcessFullStack) { + // we are not using aMachine.fill() here any more, so we need to check for fluid type here ourselves + if (aFluidAccess.get() != null && !aFluidAccess.get().isFluidEqual(aFluidHeld)) + return null; + ItemStack tStackHeld = aPlayer.inventory.getItemStack(); + ItemStack tStackSizedOne = GT_Utility.copyAmount(1, tStackHeld); + if (tStackSizedOne == null) + return null; + + int tFreeSpace = aFluidAccess.getCapacity() - (aFluidAccess.get() != null ? aFluidAccess.get().amount : 0); + if (tFreeSpace <= 0) + // no space left + return null; + + // find out how much fluid can be taken + // some cells cannot be partially filled + ItemStack tStackEmptied = null; + int tAmountTaken = 0; + if (tFreeSpace >= aFluidHeld.amount) { + // fully accepted - try take it from item now + // IFluidContainerItem is intentionally not checked here. it will be checked later + tStackEmptied = GT_Utility.getContainerForFilledItem(tStackSizedOne, false); + tAmountTaken = aFluidHeld.amount; + } + if (tStackEmptied == null && tStackSizedOne.getItem() instanceof IFluidContainerItem) { + // either partially accepted, or is IFluidContainerItem + IFluidContainerItem container = (IFluidContainerItem) tStackSizedOne.getItem(); + FluidStack tDrained = container.drain(tStackSizedOne, tFreeSpace, true); + if (tDrained != null && tDrained.amount > 0) { + // something is actually drained - change the cell and drop it to player + tStackEmptied = tStackSizedOne; + tAmountTaken = tDrained.amount; + } + } + if (tStackEmptied == null) + // somehow the cell refuse to give out that amount of fluid, no op then + return null; + + // find out how many fill can we do + // same round down behavior as above + // however here the fluid stack is not changed at all, so the exact code will slightly differ + int tParallel = aProcessFullStack ? Math.min(tFreeSpace / tAmountTaken, tStackHeld.stackSize) : 1; + if (aFluidAccess.get() == null) { + FluidStack tNewFillableStack = aFluidHeld.copy(); + tNewFillableStack.amount = tAmountTaken * tParallel; + aFluidAccess.set(tNewFillableStack); + } else { + aFluidAccess.get().amount += tAmountTaken * tParallel; + } + tStackEmptied.stackSize = tParallel; + replaceCursorItemStack(aPlayer, tStackEmptied); + return tStackEmptied; + } + + private static void replaceCursorItemStack(EntityPlayer aPlayer, ItemStack tStackResult) { + int tStackResultMaxStackSize = tStackResult.getMaxStackSize(); + while (tStackResult.stackSize > tStackResultMaxStackSize) { + aPlayer.inventory.getItemStack().stackSize -= tStackResultMaxStackSize; + GT_Utility.addItemToPlayerInventory(aPlayer, tStackResult.splitStack(tStackResultMaxStackSize)); + } + if (aPlayer.inventory.getItemStack().stackSize == tStackResult.stackSize) { + // every cell is mutated. it could just stay on the cursor. + aPlayer.inventory.setItemStack(tStackResult); + } else { + // some cells not mutated. The mutated cells must go into the inventory + // or drop into the world if there isn't enough space. + ItemStack tStackHeld = aPlayer.inventory.getItemStack(); + tStackHeld.stackSize -= tStackResult.stackSize; + GT_Utility.addItemToPlayerInventory(aPlayer, tStackResult); + } + } + + @Override public void detectAndSendChanges() { super.detectAndSendChanges(); if (mTileEntity.isClientSide() || mTileEntity.getMetaTileEntity() == null) return; @@ -66,4 +255,41 @@ public class GT_Container_BasicTank extends GT_ContainerMetaTile_Machine { public int getShiftClickSlotCount() { return 1; } + + protected interface IFluidAccess { + void set(FluidStack stack); + FluidStack get(); + int getCapacity(); + static IFluidAccess from(GT_MetaTileEntity_BasicTank aTank, boolean aIsFillableStack) { + return new BasicTankFluidAccess(aTank, aIsFillableStack); + } + } + + static class BasicTankFluidAccess implements IFluidAccess { + private final GT_MetaTileEntity_BasicTank mTank; + private final boolean mIsFillableStack; + + public BasicTankFluidAccess(GT_MetaTileEntity_BasicTank aTank, boolean aIsFillableStack) { + this.mTank = aTank; + this.mIsFillableStack = aIsFillableStack; + } + + @Override + public void set(FluidStack stack) { + if (mIsFillableStack) + mTank.setFillableStack(stack); + else + mTank.setDrainableStack(stack); + } + + @Override + public FluidStack get() { + return mIsFillableStack ? mTank.getFillableStack() : mTank.getDrainableStack(); + } + + @Override + public int getCapacity() { + return mTank.getCapacity(); + } + } } |