mirror of
https://github.com/GTNewHorizons/AE2FluidCraft-Rework.git
synced 2026-11-11 15:57:55 +00:00
Fix fluid terminal interactions (#111)
Now the math is properly calculated.
This commit is contained in:
1 parent
e1b3f20078
commit
c174db3f15
1 file changed
+251
-108
+251
-108
@@ -15,8 +15,6 @@ import net.minecraftforge.common.util.ForgeDirection;
|
||||
import net.minecraftforge.fluids.FluidContainerRegistry;
|
||||
import net.minecraftforge.fluids.IFluidContainerItem;
|
||||
|
||||
import org.apache.commons.lang3.tuple.MutablePair;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.implementations.tiles.IViewCellStorage;
|
||||
@@ -194,122 +192,267 @@ public class ContainerFluidMonitor extends FCContainerMonitor<IAEFluidStack> {
|
||||
this.dropItem(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Two operations, insert and extract.
|
||||
*
|
||||
* @param slotIndex The slot. If index == -1, the cursor held itemstack. Else, slotIndex indicates which slot was
|
||||
* shift clicked on.
|
||||
*/
|
||||
public void postChange(Iterable<IAEFluidStack> change, ItemStack fluidContainer, EntityPlayer player,
|
||||
int slotIndex) {
|
||||
int cursorItems;
|
||||
if (slotIndex == -1) {
|
||||
cursorItems = player.inventory.getItemStack().stackSize;
|
||||
} else {
|
||||
cursorItems = player.inventory.getStackInSlot(slotIndex).stackSize;
|
||||
}
|
||||
for (IAEFluidStack fluid : change) {
|
||||
IAEFluidStack nfluid = this.monitor.getStorageList().findPrecise(fluid);
|
||||
ItemStack out = fluidContainer.copy();
|
||||
out.stackSize = 1;
|
||||
// The primary output itemstack
|
||||
if (Util.FluidUtil.isEmpty(fluidContainer) && fluid != null) {
|
||||
// add fluid to tanks
|
||||
if (nfluid.getStackSize() <= 0) continue;
|
||||
final IAEFluidStack toExtract = nfluid.copy();
|
||||
MutablePair<Integer, ItemStack> fillStack = Util.FluidUtil.fillStack(out, toExtract.getFluidStack());
|
||||
if (fillStack.right == null || fillStack.left <= 0) continue;
|
||||
toExtract.setStackSize((long) fillStack.left * fluidContainer.stackSize);
|
||||
// The real result may don't match simulation result.
|
||||
if (fillStack.right.getItem() instanceof IFluidContainerItem) {
|
||||
IAEFluidStack real = this.host.getFluidInventory()
|
||||
.extractItems(toExtract, Actionable.MODULATE, this.getActionSource());
|
||||
if (real == null) continue;
|
||||
// Refill the container
|
||||
out = fluidContainer.copy();
|
||||
out.stackSize = 1;
|
||||
fillStack = Util.FluidUtil.fillStack(out, real.getFluidStack());
|
||||
fillStack.right.stackSize = (int) (real.getStackSize() / fillStack.left);
|
||||
out.stackSize = fillStack.right.stackSize;
|
||||
if ((int) (real.getStackSize() % fillStack.left) > 0) {
|
||||
this.dropItem(
|
||||
Util.FluidUtil.setFluidContainerAmount(
|
||||
fillStack.right,
|
||||
(int) (real.getStackSize() % fillStack.left)),
|
||||
1);
|
||||
out.stackSize++;
|
||||
}
|
||||
} else if (FluidContainerRegistry.isContainer(fillStack.right)) {
|
||||
IAEFluidStack real = this.host.getFluidInventory()
|
||||
.extractItems(toExtract, Actionable.MODULATE, this.getActionSource());
|
||||
if (real == null) continue;
|
||||
// Refill the container
|
||||
out = fluidContainer.copy();
|
||||
out.stackSize = 1;
|
||||
fillStack = Util.FluidUtil.fillStack(out, real.getFluidStack());
|
||||
fillStack.right.stackSize = (int) (real.getStackSize() / fillStack.left);
|
||||
out.stackSize = fillStack.right.stackSize;
|
||||
toExtract.setStackSize((long) fillStack.right.stackSize * fillStack.left);
|
||||
}
|
||||
this.dropItem(fillStack.right);
|
||||
// Situation 1.a: Empty fluid container, and nonnull slot
|
||||
extractFluid(fluid, fluidContainer, player, cursorItems);
|
||||
} else if (!Util.FluidUtil.isEmpty(fluidContainer)) {
|
||||
// add fluid to ae network
|
||||
AEFluidStack fluidStack = Util.getAEFluidFromItem(fluidContainer);
|
||||
final IAEFluidStack aeFluidStack = fluidStack.copy();
|
||||
// simulate result is incorrect. so I'm using other solution and ec2 both mod have same issues
|
||||
final IAEFluidStack notInserted = this.host.getFluidInventory()
|
||||
.injectItems(aeFluidStack, Actionable.MODULATE, this.getActionSource());
|
||||
MutablePair<Integer, ItemStack> drainStack = Util.FluidUtil
|
||||
.drainStack(out.copy(), aeFluidStack.getFluidStack());
|
||||
if (notInserted != null && notInserted.getStackSize() > 0) {
|
||||
if (fluidStack.getStackSize() == notInserted.getStackSize()) continue;
|
||||
aeFluidStack.decStackSize(notInserted.getStackSize());
|
||||
|
||||
if (drainStack.left > aeFluidStack.getStackSize()
|
||||
&& FluidContainerRegistry.isContainer(drainStack.right)) {
|
||||
aeFluidStack.setStackSize(drainStack.left - aeFluidStack.getStackSize());
|
||||
this.host.getFluidInventory()
|
||||
.extractItems(aeFluidStack, Actionable.MODULATE, this.getActionSource());
|
||||
continue;
|
||||
}
|
||||
|
||||
this.dropItem(drainStack.right, (int) (aeFluidStack.getStackSize() / drainStack.left)); // drop
|
||||
// empty
|
||||
// item
|
||||
out.stackSize = (int) (notInserted.getStackSize() / drainStack.left);
|
||||
if (drainStack.right.getItem() instanceof IFluidContainerItem) {
|
||||
if (notInserted.getStackSize() % drainStack.left > 0) {
|
||||
fluidStack.setStackSize((notInserted.getStackSize() % drainStack.left));
|
||||
((IFluidContainerItem) drainStack.right.getItem())
|
||||
.fill(drainStack.right, fluidStack.getFluidStack(), true);
|
||||
this.dropItem(drainStack.right, 1);
|
||||
}
|
||||
} else if (FluidContainerRegistry.isContainer(drainStack.right)) {
|
||||
if (notInserted.getStackSize() % drainStack.left > 0) {
|
||||
aeFluidStack.setStackSize(aeFluidStack.getStackSize() % drainStack.left);
|
||||
this.host.getFluidInventory()
|
||||
.extractItems(aeFluidStack, Actionable.MODULATE, this.getActionSource());
|
||||
out.stackSize++;
|
||||
}
|
||||
}
|
||||
if (slotIndex == -1) out.stackSize = fluidContainer.stackSize - out.stackSize;
|
||||
} else {
|
||||
if (slotIndex == -1) {
|
||||
out.stackSize = fluidContainer.stackSize;
|
||||
} else {
|
||||
out.stackSize = (int) (fluidContainer.stackSize
|
||||
- (aeFluidStack.getStackSize() / drainStack.left));
|
||||
}
|
||||
this.dropItem(drainStack.right, fluidContainer.stackSize); // drop empty item
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (slotIndex == -1) {
|
||||
player.inventory.getItemStack().stackSize = player.inventory.getItemStack().stackSize - out.stackSize;
|
||||
if (player.inventory.getItemStack().stackSize > 0) {
|
||||
FluidCraft.proxy.netHandler.sendTo(
|
||||
new SPacketFluidUpdate(new HashMap<>(), player.inventory.getItemStack()),
|
||||
(EntityPlayerMP) player);
|
||||
} else {
|
||||
player.inventory.setItemStack(null);
|
||||
FluidCraft.proxy.netHandler
|
||||
.sendTo(new SPacketFluidUpdate(new HashMap<>()), (EntityPlayerMP) player);
|
||||
}
|
||||
} else {
|
||||
player.inventory.setInventorySlotContents(slotIndex, out.stackSize > 0 ? out : null);
|
||||
// Situation 2.a: We are holding a non-empty container.
|
||||
insertFluid(fluidContainer, player, slotIndex, cursorItems);
|
||||
// End of situation 2.a
|
||||
}
|
||||
// No op (Any other situation)
|
||||
}
|
||||
this.detectAndSendChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* The insert operation. For input, we have an filled container stack. For outputs, we have the following: 1.
|
||||
* Leftover filled container stack - primary output. 2. Empty containers 3. Partially filled container x1 In order
|
||||
* above, the itemstack at `slotIndex` is transformed into the output.
|
||||
*/
|
||||
private void insertFluid(ItemStack fluidContainer, EntityPlayer player, int slotIndex, int heldContainers) {
|
||||
IAEFluidStack fluid;
|
||||
int fluidInTank;
|
||||
if (fluidContainer.getItem() instanceof IFluidContainerItem) {
|
||||
fluid = AEFluidStack.create(((IFluidContainerItem) fluidContainer.getItem()).getFluid(fluidContainer));
|
||||
fluidInTank = (int) fluid.getStackSize();
|
||||
} else if (FluidContainerRegistry.isContainer(fluidContainer)) {
|
||||
fluid = AEFluidStack.create(FluidContainerRegistry.getFluidForFilledItem(fluidContainer));
|
||||
fluidInTank = (int) fluid.getStackSize();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
// Simulate to know how much will not be inserted
|
||||
IAEFluidStack canSend = fluid.copy();
|
||||
canSend.setStackSize((long) fluidInTank * fluidContainer.stackSize);
|
||||
final IAEFluidStack notInserted = this.host.getFluidInventory()
|
||||
.injectItems(canSend, Actionable.MODULATE, this.getActionSource());
|
||||
int emptyTanks = fluidContainer.stackSize;
|
||||
ItemStack partialStack = fluidContainer.copy();
|
||||
if (notInserted != null && notInserted.getStackSize() > 0) {
|
||||
// Here, we cannot insert everything into the system.
|
||||
if (canSend.getStackSize() == notInserted.getStackSize()) return; // System was full, no op
|
||||
// Now "refill" the buckets that couldn't enter the system
|
||||
int refilled = (int) (notInserted.getStackSize() / fluidInTank); // # of full tanks left
|
||||
emptyTanks -= refilled;
|
||||
final int remainder = (int) (notInserted.getStackSize() % fluidInTank); // partial tank
|
||||
// Now handle remaining if applicable
|
||||
if (remainder > 0) {
|
||||
notInserted.setStackSize(remainder);
|
||||
partialStack.stackSize = 1;
|
||||
if (partialStack.getItem() instanceof IFluidContainerItem) {
|
||||
((IFluidContainerItem) partialStack.getItem()).drain(partialStack, fluidInTank - remainder, true);
|
||||
} else if (FluidContainerRegistry.isContainer(fluidContainer)) {
|
||||
// For "whole containers" (need to round down, no remainders)
|
||||
ItemStack container = FluidContainerRegistry
|
||||
.fillFluidContainer(notInserted.getFluidStack(), fluidContainer);
|
||||
if (container == null) {
|
||||
// whatever, lets just not have the ME system get filled with any of its fluid
|
||||
emptyTanks++;
|
||||
notInserted.setStackSize(fluidInTank - remainder);
|
||||
this.host.getFluidInventory()
|
||||
.extractItems(notInserted, Actionable.MODULATE, this.getActionSource());
|
||||
partialStack.stackSize = 0;
|
||||
} else {
|
||||
partialStack = container;
|
||||
}
|
||||
}
|
||||
emptyTanks -= partialStack.stackSize;
|
||||
} else {
|
||||
partialStack.stackSize = 0;
|
||||
}
|
||||
} else {
|
||||
partialStack.stackSize = 0;
|
||||
}
|
||||
// Now that the 3 outputs are handled, we can now actually put the fluids in
|
||||
ItemStack emptyStack = fluidContainer.copy();
|
||||
emptyStack.stackSize = 1;
|
||||
if (emptyStack.getItem() instanceof IFluidContainerItem) {
|
||||
((IFluidContainerItem) emptyStack.getItem()).drain(emptyStack, fluidInTank, true);
|
||||
} else {
|
||||
emptyStack = FluidContainerRegistry.drainFluidContainer(emptyStack);
|
||||
}
|
||||
emptyStack.stackSize = emptyTanks;
|
||||
int extraTanks = heldContainers - emptyTanks - partialStack.stackSize;
|
||||
// Done. Put the output in the inventory or ground, and update stack size.
|
||||
boolean shouldSendStack = true;
|
||||
if (slotIndex == -1) {
|
||||
if (extraTanks > 0) {
|
||||
ItemStack stack = player.inventory.getItemStack();
|
||||
stack.stackSize = extraTanks;
|
||||
adjustStack(stack);
|
||||
dropItem(emptyStack);
|
||||
dropItem(partialStack);
|
||||
} else if (emptyTanks != 0) {
|
||||
adjustStack(emptyStack);
|
||||
player.inventory.setItemStack(emptyStack);
|
||||
dropItem(partialStack);
|
||||
} else if (partialStack.stackSize != 0) {
|
||||
player.inventory.setItemStack(partialStack);
|
||||
} else {
|
||||
player.inventory.setItemStack(null);
|
||||
shouldSendStack = false;
|
||||
}
|
||||
} else {
|
||||
ItemStack stack = player.inventory.getStackInSlot(slotIndex);
|
||||
if (extraTanks > 0) {
|
||||
stack.stackSize = extraTanks;
|
||||
adjustStack(stack);
|
||||
dropItem(emptyStack);
|
||||
dropItem(partialStack);
|
||||
} else if (emptyTanks != 0) {
|
||||
adjustStack(emptyStack);
|
||||
player.inventory.setInventorySlotContents(slotIndex, emptyStack);
|
||||
dropItem(partialStack);
|
||||
} else if (partialStack.stackSize != 0) {
|
||||
player.inventory.setInventorySlotContents(slotIndex, partialStack);
|
||||
} else {
|
||||
player.inventory.setItemStack(null);
|
||||
shouldSendStack = false;
|
||||
}
|
||||
}
|
||||
if (shouldSendStack) {
|
||||
FluidCraft.proxy.netHandler.sendTo(
|
||||
new SPacketFluidUpdate(new HashMap<>(), player.inventory.getItemStack()),
|
||||
(EntityPlayerMP) player);
|
||||
} else {
|
||||
FluidCraft.proxy.netHandler.sendTo(new SPacketFluidUpdate(new HashMap<>()), (EntityPlayerMP) player);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The extract operation. For input, we have an empty container stack. For outputs, we have the following: 1.
|
||||
* Leftover empty container stack - primary output. 2. Filled containers (full) 3. Partially filled container x1 In
|
||||
* order above, the itemstack at `slotIndex` is transformed into the output.
|
||||
*/
|
||||
private void extractFluid(IAEFluidStack fluid, ItemStack fluidContainer, EntityPlayer player, int heldContainers) {
|
||||
IAEFluidStack storedFluid = this.monitor.getStorageList().findPrecise(fluid);
|
||||
if (storedFluid == null || storedFluid.getStackSize() <= 0) return;
|
||||
int capacity;
|
||||
if (fluidContainer.getItem() instanceof IFluidContainerItem) {
|
||||
capacity = ((IFluidContainerItem) fluidContainer.getItem()).getCapacity(fluidContainer);
|
||||
} else if (FluidContainerRegistry.isContainer(fluidContainer)) {
|
||||
// Fill with fluid container registry, or abort if it failed
|
||||
ItemStack dummy = FluidContainerRegistry.fillFluidContainer(storedFluid.getFluidStack(), fluidContainer);
|
||||
capacity = FluidContainerRegistry.getContainerCapacity(dummy);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (capacity == 0) return;
|
||||
// The fluidstack that we will try to extract from the system.
|
||||
final IAEFluidStack canExtract = storedFluid.copy();
|
||||
// Maximum amount of fluid we can extract with the given container(s). Guarantees that we won't
|
||||
// run into issues w/ remainder fluid later.
|
||||
canExtract.setStackSize((long) capacity * fluidContainer.stackSize);
|
||||
IAEFluidStack actualExtract = this.host.getFluidInventory()
|
||||
.extractItems(canExtract, Actionable.SIMULATE, this.getActionSource());
|
||||
if (actualExtract == null) return;
|
||||
// Calculate the number of full fluid containers we extracted
|
||||
long toExtract = actualExtract.getStackSize();
|
||||
int filledTanks = (int) (toExtract / capacity);
|
||||
int remainder = (int) (toExtract % capacity);
|
||||
int emptyTanks = heldContainers - filledTanks;
|
||||
// Fill the filled tanks
|
||||
ItemStack filledStack = fluidContainer.copy();
|
||||
filledStack.stackSize = 1;
|
||||
if (filledTanks > 0) {
|
||||
if (filledStack.getItem() instanceof IFluidContainerItem) {
|
||||
int amt = ((IFluidContainerItem) filledStack.getItem())
|
||||
.fill(filledStack, actualExtract.getFluidStack(), true);
|
||||
assert amt == capacity;
|
||||
} else {
|
||||
// Should not be NPE since we affirmed that we have enough capacity.
|
||||
filledStack = FluidContainerRegistry.fillFluidContainer(actualExtract.getFluidStack(), filledStack);
|
||||
assert capacity == FluidContainerRegistry.getContainerCapacity(filledStack);
|
||||
}
|
||||
filledStack.stackSize = filledTanks;
|
||||
} else {
|
||||
filledStack.stackSize = 0;
|
||||
}
|
||||
// Calculate the remaining fluid to extract, if any
|
||||
ItemStack partialStack = fluidContainer.copy();
|
||||
if (remainder > 0) {
|
||||
actualExtract.setStackSize(remainder);
|
||||
partialStack.stackSize = 1;
|
||||
if (partialStack.getItem() instanceof IFluidContainerItem) {
|
||||
int amt = ((IFluidContainerItem) partialStack.getItem())
|
||||
.fill(partialStack, actualExtract.getFluidStack(), true);
|
||||
assert amt == remainder;
|
||||
emptyTanks--;
|
||||
} else {
|
||||
ItemStack dummy = FluidContainerRegistry
|
||||
.fillFluidContainer(actualExtract.getFluidStack(), partialStack);
|
||||
if (dummy == null) {
|
||||
// Failed to fill partial...
|
||||
partialStack.stackSize = 0;
|
||||
toExtract -= remainder;
|
||||
} else {
|
||||
partialStack = dummy;
|
||||
toExtract -= FluidContainerRegistry.getContainerCapacity(partialStack);
|
||||
emptyTanks--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
partialStack.stackSize = 0;
|
||||
}
|
||||
// Now perform the real extraction.
|
||||
actualExtract.setStackSize(toExtract);
|
||||
this.host.getFluidInventory().extractItems(canExtract, Actionable.MODULATE, this.getActionSource());
|
||||
|
||||
// Done. Put the output in the inventory or ground, and update stack size.
|
||||
// We can assume slotIndex == -1, since we don't actually allow extraction via shift click.
|
||||
boolean shouldSendStack = true;
|
||||
if (emptyTanks > 0) {
|
||||
ItemStack emptyStack = player.inventory.getItemStack();
|
||||
emptyStack.stackSize = emptyTanks;
|
||||
adjustStack(emptyStack);
|
||||
dropItem(filledStack);
|
||||
dropItem(partialStack);
|
||||
} else if (filledStack.stackSize != 0) {
|
||||
adjustStack(filledStack);
|
||||
player.inventory.setItemStack(filledStack);
|
||||
dropItem(partialStack);
|
||||
} else if (partialStack.stackSize != 0) {
|
||||
player.inventory.setItemStack(partialStack);
|
||||
} else {
|
||||
player.inventory.setItemStack(null);
|
||||
shouldSendStack = false;
|
||||
}
|
||||
if (shouldSendStack) {
|
||||
FluidCraft.proxy.netHandler.sendTo(
|
||||
new SPacketFluidUpdate(new HashMap<>(), player.inventory.getItemStack()),
|
||||
(EntityPlayerMP) player);
|
||||
} else {
|
||||
FluidCraft.proxy.netHandler.sendTo(new SPacketFluidUpdate(new HashMap<>()), (EntityPlayerMP) player);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void adjustStack(ItemStack stack) {
|
||||
if (stack.stackSize > stack.getMaxStackSize()) {
|
||||
dropItem(stack, stack.stackSize - stack.getMaxStackSize());
|
||||
stack.stackSize = stack.getMaxStackSize();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isEssentiaMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user