Fixes #582 "Exporter deletes items on 'Extract Only'"

The exporter would try to insert an item, and re-insert back the remainder if there is no space. However, for storages that use "extract only" the exporter would not be able to re-insert back the remainder, which leads to item loss.

To prevent this you can now run a simulate check on extractItem so the exporter can first check *if* the item can be inserted, and be sure there is no remainder.
This commit is contained in:
Raoul Van den Berge
2016-11-05 19:08:08 +01:00
parent fd953a52f0
commit 909d32cfb4
21 changed files with 110 additions and 99 deletions

View File

@@ -239,23 +239,25 @@ public interface INetworkMaster {
/**
* Extracts an item from this network.
*
* @param stack the prototype of the stack to extract, do NOT modify
* @param size the amount of that prototype that has to be extracted
* @param flags the flags to compare on, see {@link IComparer}
* @param stack the prototype of the stack to extract, do NOT modify
* @param size the amount of that prototype that has to be extracted
* @param flags the flags to compare on, see {@link IComparer}
* @param simulate true if we are simulating, false otherwise
* @return null if we didn't extract anything, or a stack with the result
*/
@Nullable
ItemStack extractItem(@Nonnull ItemStack stack, int size, int flags);
ItemStack extractItem(@Nonnull ItemStack stack, int size, int flags, boolean simulate);
/**
* Extracts an item from this network.
*
* @param stack the prototype of the stack to extract, do NOT modify
* @param size the amount of that prototype that has to be extracted
* @param stack the prototype of the stack to extract, do NOT modify
* @param size the amount of that prototype that has to be extracted
* @param simulate true if we are simulating, false otherwise
* @return null if we didn't extract anything, or a stack with the result
*/
default ItemStack extractItem(@Nonnull ItemStack stack, int size) {
return extractItem(stack, size, IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT);
default ItemStack extractItem(@Nonnull ItemStack stack, int size, boolean simulate) {
return extractItem(stack, size, IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT, simulate);
}
/**
@@ -275,20 +277,22 @@ public interface INetworkMaster {
* @param stack the prototype of the stack to extract, do NOT modify
* @param size the amount of that prototype that has to be extracted
* @param flags the flags to compare on, see {@link IComparer}
* @param simulate true if we are simulating, false otherwise
* @return null if we didn't extract anything, or a stack with the result
*/
@Nullable
FluidStack extractFluid(@Nonnull FluidStack stack, int size, int flags);
FluidStack extractFluid(@Nonnull FluidStack stack, int size, int flags, boolean simulate);
/**
* Extracts a fluid from this network.
*
* @param stack the prototype of the stack to extract, do NOT modify
* @param size the amount of that prototype that has to be extracted
* @param simulate true if we are simulating, false otherwise
* @return null if we didn't extract anything, or a stack with the result
*/
default FluidStack extractFluid(FluidStack stack, int size) {
return extractFluid(stack, size, IComparer.COMPARE_NBT);
default FluidStack extractFluid(FluidStack stack, int size, boolean simulate) {
return extractFluid(stack, size, IComparer.COMPARE_NBT, simulate);
}
/**

View File

@@ -28,13 +28,12 @@ public interface IFluidStorage extends IStorage<FluidStack> {
* <p>
* If the fluid we found in the system is smaller than the requested size, return that fluid anyway.
*
* @param stack a prototype of the fluid to extract, do NOT modify
* @param size the amount of that fluid that has to be extracted
* @param flags the flags to compare on, see {@link IComparer}
* @param stack a prototype of the fluid to extract, do NOT modify
* @param size the amount of that fluid that has to be extracted
* @param flags the flags to compare on, see {@link IComparer}
* @param simulate true if we are simulating, false otherwise
* @return null if we didn't extract anything, or a stack with the result
*/
@Nullable
FluidStack extractFluid(@Nonnull FluidStack stack, int size, int flags);
FluidStack extractFluid(@Nonnull FluidStack stack, int size, int flags, boolean simulate);
}

View File

@@ -28,11 +28,12 @@ public interface IItemStorage extends IStorage<ItemStack> {
* <p>
* If the stack we found in the system is smaller than the requested size, return that stack anyway.
*
* @param stack a prototype of the stack to extract, do NOT modify
* @param size the amount of that prototype that has to be extracted
* @param flags the flags to compare on, see {@link IComparer}
* @param stack a prototype of the stack to extract, do NOT modify
* @param size the amount of that prototype that has to be extracted
* @param flags the flags to compare on, see {@link IComparer}
* @param simulate true if we are simulating, false otherwise
* @return null if we didn't extract anything, or a stack with the result
*/
@Nullable
ItemStack extractItem(@Nonnull ItemStack stack, int size, int flags);
ItemStack extractItem(@Nonnull ItemStack stack, int size, int flags, boolean simulate);
}

View File

@@ -85,11 +85,11 @@ public class CraftingStepCraft extends CraftingStep {
FluidStack fluidInItem = RSUtils.getFluidFromStack(insertStack, true);
if (fluidInItem != null) {
network.extractFluid(fluidInItem, fluidInItem.amount, compare);
network.extractItem(RSUtils.EMPTY_BUCKET, 1, compare);
network.extractFluid(fluidInItem, fluidInItem.amount, compare, false);
network.extractItem(RSUtils.EMPTY_BUCKET, 1, compare, false);
actualInputs.add(insertStack.copy());
} else {
ItemStack input = network.extractItem(insertStack, insertStack.stackSize, compare);
ItemStack input = network.extractItem(insertStack, insertStack.stackSize, compare, false);
if (input != null) {
actualInputs.add(input);
} else {

View File

@@ -60,7 +60,7 @@ public class CraftingStepProcess extends CraftingStep {
IItemHandler inventory = getPattern().getContainer().getFacingInventory();
int compare = CraftingTask.DEFAULT_COMPARE | (getPattern().isOredict() ? IComparer.COMPARE_OREDICT : 0);
for (ItemStack insertStack : getToInsert()) {
ItemStack tookStack = network.extractItem(insertStack, insertStack.stackSize, compare);
ItemStack tookStack = network.extractItem(insertStack, insertStack.stackSize, compare, false);
ItemHandlerHelper.insertItem(inventory, tookStack, false);
}
}

View File

@@ -327,7 +327,7 @@ public class CraftingTask implements ICraftingTask {
for (FluidStack stack : toTakeFluids.getStacks()) {
FluidStack stackExtracted = network.extractFluid(stack, stack.amount);
FluidStack stackExtracted = network.extractFluid(stack, stack.amount, false);
if (stackExtracted != null) {
toTakeFluids.remove(stack, stack.amount, false);
tookFluids.add(stackExtracted);

View File

@@ -25,7 +25,7 @@ public class FluidGridHandler implements IFluidGridHandler {
FluidStack stack = network.getFluidStorageCache().getList().get(hash);
if (stack != null && RSUtils.hasFluidBucket(stack)) {
ItemStack bucket = network.extractItem(RSUtils.EMPTY_BUCKET, 1);
ItemStack bucket = network.extractItem(RSUtils.EMPTY_BUCKET, 1, false);
if (bucket == null) {
for (int i = 0; i < player.inventory.getSizeInventory(); ++i) {
@@ -42,7 +42,7 @@ public class FluidGridHandler implements IFluidGridHandler {
}
if (bucket != null) {
bucket.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, null).fill(network.extractFluid(stack, Fluid.BUCKET_VOLUME), true);
bucket.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, null).fill(network.extractFluid(stack, Fluid.BUCKET_VOLUME, false), true);
if (shift) {
if (!player.inventory.addItemStackToInventory(bucket.copy())) {

View File

@@ -14,6 +14,7 @@ import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
public class ItemGridHandler implements IItemGridHandler {
@@ -62,16 +63,20 @@ public class ItemGridHandler implements IItemGridHandler {
size = Math.min(size, maxItemSize);
ItemStack took = network.extractItem(item, size);
ItemStack took = network.extractItem(item, size, true);
if (took != null) {
if ((flags & EXTRACT_SHIFT) == EXTRACT_SHIFT) {
ItemStack remainder = ItemHandlerHelper.insertItem(player.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, EnumFacing.UP), took, false);
IItemHandler playerInventory = player.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, EnumFacing.UP);
if (remainder != null) {
network.insertItem(remainder, remainder.stackSize, false);
if (ItemHandlerHelper.insertItem(playerInventory, took, true) == null) {
took = network.extractItem(item, size, false);
ItemHandlerHelper.insertItem(playerInventory, took, false);
}
} else {
took = network.extractItem(item, size, false);
if (single && held != null) {
held.stackSize++;
} else {

View File

@@ -142,23 +142,25 @@ public abstract class FluidStorageNBT implements IFluidStorage {
}
@Override
public synchronized FluidStack extractFluid(FluidStack stack, int size, int flags) {
public synchronized FluidStack extractFluid(FluidStack stack, int size, int flags, boolean simulate) {
for (FluidStack otherStack : stacks) {
if (API.instance().getComparer().isEqual(otherStack, stack, flags)) {
if (size > otherStack.amount) {
size = otherStack.amount;
}
if (otherStack.amount - size == 0) {
stacks.remove(otherStack);
} else {
otherStack.amount -= size;
if (!simulate) {
if (otherStack.amount - size == 0) {
stacks.remove(otherStack);
} else {
otherStack.amount -= size;
}
tag.setInteger(NBT_STORED, getStored() - size);
onStorageChanged();
}
tag.setInteger(NBT_STORED, getStored() - size);
onStorageChanged();
return RSUtils.copyStackWithSize(otherStack, size);
}
}

View File

@@ -185,23 +185,25 @@ public abstract class ItemStorageNBT implements IItemStorage {
}
@Override
public synchronized ItemStack extractItem(ItemStack stack, int size, int flags) {
public synchronized ItemStack extractItem(ItemStack stack, int size, int flags, boolean simulate) {
for (ItemStack otherStack : stacks) {
if (API.instance().getComparer().isEqual(otherStack, stack, flags)) {
if (size > otherStack.stackSize) {
size = otherStack.stackSize;
}
if (otherStack.stackSize - size == 0) {
stacks.remove(otherStack);
} else {
otherStack.stackSize -= size;
if (!simulate) {
if (otherStack.stackSize - size == 0) {
stacks.remove(otherStack);
} else {
otherStack.stackSize -= size;
}
tag.setInteger(NBT_STORED, getStored() - size);
onStorageChanged();
}
tag.setInteger(NBT_STORED, getStored() - size);
onStorageChanged();
return ItemHandlerHelper.copyStackWithSize(otherStack, size);
}
}

View File

@@ -119,7 +119,7 @@ public class TileConstructor extends TileMultipartNode implements IComparable, I
Block block = stack.getFluid().getBlock();
if (worldObj.isAirBlock(front) && block.canPlaceBlockAt(worldObj, front)) {
FluidStack took = network.extractFluid(stack, Fluid.BUCKET_VOLUME, compare);
FluidStack took = network.extractFluid(stack, Fluid.BUCKET_VOLUME, compare, false);
if (took != null) {
IBlockState state = block.getDefaultState();
@@ -142,7 +142,7 @@ public class TileConstructor extends TileMultipartNode implements IComparable, I
BlockPos front = pos.offset(getDirection());
if (worldObj.isAirBlock(front) && block.getBlock().canPlaceBlockAt(worldObj, front)) {
ItemStack took = network.extractItem(itemFilters.getStackInSlot(0), 1, compare);
ItemStack took = network.extractItem(itemFilters.getStackInSlot(0), 1, compare, false);
if (took != null) {
@SuppressWarnings("deprecation")
@@ -186,7 +186,7 @@ public class TileConstructor extends TileMultipartNode implements IComparable, I
}
private void dropItem() {
ItemStack took = network.extractItem(item, 1);
ItemStack took = network.extractItem(item, 1, false);
if (took != null) {
// From BlockDispenser#getDispensePosition

View File

@@ -619,7 +619,7 @@ public class TileController extends TileBase implements INetworkMaster, IEnergyR
}
@Override
public ItemStack extractItem(@Nonnull ItemStack stack, int size, int flags) {
public ItemStack extractItem(@Nonnull ItemStack stack, int size, int flags, boolean simulate) {
int requested = size;
int received = 0;
ItemStack newStack = null;
@@ -628,11 +628,11 @@ public class TileController extends TileBase implements INetworkMaster, IEnergyR
ItemStack took = null;
if (storage.getAccessType() != AccessType.INSERT) {
took = storage.extractItem(stack, requested - received, flags);
took = storage.extractItem(stack, requested - received, flags, simulate);
}
if (took != null) {
if (storage instanceof ItemStorageExternal) {
if (storage instanceof ItemStorageExternal && !simulate) {
((ItemStorageExternal) storage).updateForced();
}
@@ -650,7 +650,7 @@ public class TileController extends TileBase implements INetworkMaster, IEnergyR
}
}
if (newStack != null) {
if (newStack != null && !simulate) {
itemStorage.remove(newStack);
}
@@ -707,7 +707,7 @@ public class TileController extends TileBase implements INetworkMaster, IEnergyR
@Nullable
@Override
public FluidStack extractFluid(@Nonnull FluidStack stack, int size, int flags) {
public FluidStack extractFluid(@Nonnull FluidStack stack, int size, int flags, boolean simulate) {
int requested = size;
int received = 0;
FluidStack newStack = null;
@@ -716,7 +716,7 @@ public class TileController extends TileBase implements INetworkMaster, IEnergyR
FluidStack took = null;
if (storage.getAccessType() != AccessType.INSERT) {
took = storage.extractFluid(stack, requested - received, flags);
took = storage.extractFluid(stack, requested - received, flags, simulate);
}
if (took != null) {

View File

@@ -134,12 +134,12 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte
}
@Override
public ItemStack extractItem(ItemStack stack, int size, int flags) {
public ItemStack extractItem(ItemStack stack, int size, int flags, boolean simulate) {
if (!IFilterable.canTake(itemFilters, mode, getCompare(), stack)) {
return null;
}
return super.extractItem(stack, size, flags);
return super.extractItem(stack, size, flags, simulate);
}
@Override
@@ -180,12 +180,12 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte
}
@Override
public FluidStack extractFluid(FluidStack stack, int size, int flags) {
public FluidStack extractFluid(FluidStack stack, int size, int flags, boolean simulate) {
if (!IFilterable.canTakeFluids(fluidFilters, mode, getCompare(), stack)) {
return null;
}
return super.extractFluid(stack, size, flags);
return super.extractFluid(stack, size, flags, simulate);
}
@Override
@@ -277,7 +277,7 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte
continue;
}
ItemStack extracted = storage.extractItem(stack, upgrades.getInteractStackSize(), compare);
ItemStack extracted = storage.extractItem(stack, upgrades.getInteractStackSize(), compare, false);
if (extracted == null) {
continue;
}
@@ -316,7 +316,7 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte
}
if (toExtract != null) {
extracted = network.extractItem(toExtract, upgrades.getInteractStackSize(), compare);
extracted = network.extractItem(toExtract, upgrades.getInteractStackSize(), compare, false);
}
} else {
while (itemFilters.getSlots() > i && extracted == null) {
@@ -327,7 +327,7 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte
}
if (stack != null) {
extracted = network.extractItem(stack, upgrades.getInteractStackSize(), compare);
extracted = network.extractItem(stack, upgrades.getInteractStackSize(), compare, false);
}
}
}
@@ -361,7 +361,7 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte
}
if (stack != null) {
extracted = storage.extractFluid(stack, upgrades.getInteractStackSize(), compare);
extracted = storage.extractFluid(stack, upgrades.getInteractStackSize(), compare, false);
}
} while (extracted == null && storage.getStacks().size() > i);
@@ -397,7 +397,7 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte
}
if (toExtract != null) {
extracted = network.extractFluid(toExtract, upgrades.getInteractStackSize(), compare);
extracted = network.extractFluid(toExtract, upgrades.getInteractStackSize(), compare, false);
}
} else {
while (fluidFilters.getSlots() > i && extracted == null) {
@@ -408,7 +408,7 @@ public class TileDiskManipulator extends TileNode implements IComparable, IFilte
}
if (stack != null) {
extracted = network.extractFluid(stack, upgrades.getInteractStackSize(), compare);
extracted = network.extractFluid(stack, upgrades.getInteractStackSize(), compare, false);
}
}
}

View File

@@ -63,14 +63,12 @@ public class TileExporter extends TileMultipartNode implements IComparable, ITyp
ItemStack slot = itemFilters.getStackInSlot(i);
if (slot != null) {
ItemStack took = network.extractItem(slot, upgrades.getInteractStackSize(), compare);
ItemStack took = network.extractItem(slot, upgrades.getInteractStackSize(), compare, true);
if (took != null) {
ItemStack remainder = ItemHandlerHelper.insertItem(handler, took, false);
if (ItemHandlerHelper.insertItem(handler, took, true) == null) {
took = network.extractItem(slot, upgrades.getInteractStackSize(), compare, false);
if (remainder != null) {
network.insertItem(remainder, remainder.stackSize, false);
}
ItemHandlerHelper.insertItem(handler, took, false);
} else if (upgrades.hasUpgrade(ItemUpgrade.TYPE_CRAFTING)) {
network.scheduleCraftingTask(slot, 1, compare);
}
@@ -88,14 +86,12 @@ public class TileExporter extends TileMultipartNode implements IComparable, ITyp
if (stackInStorage != null) {
int toExtract = Math.min(Fluid.BUCKET_VOLUME * upgrades.getInteractStackSize(), stackInStorage.amount);
FluidStack took = network.extractFluid(stack, toExtract, compare);
FluidStack took = network.extractFluid(stack, toExtract, compare, true);
if (took != null) {
int remainder = toExtract - handler.fill(took, true);
if (took != null && (toExtract - handler.fill(took, false)) == 0) {
took = network.extractFluid(stack, toExtract, compare, false);
if (remainder > 0) {
network.insertFluid(took, remainder, false);
}
handler.fill(took, true);
}
}
}

View File

@@ -130,14 +130,12 @@ public class TileFluidInterface extends TileNode implements IComparable {
if (stackInStorage != null) {
int toExtract = Math.min(Fluid.BUCKET_VOLUME * upgrades.getInteractStackSize(), stackInStorage.amount);
FluidStack took = network.extractFluid(stack, toExtract, compare);
FluidStack took = network.extractFluid(stack, toExtract, compare, true);
if (took != null) {
int remainder = toExtract - tankOut.fillInternal(took, true);
if (took != null && (toExtract - tankOut.fillInternal(took, false)) == 0) {
took = network.extractFluid(stack, toExtract, compare, false);
if (remainder > 0) {
network.insertFluid(took, remainder, false);
}
tankOut.fillInternal(took, true);
}
}
}

View File

@@ -81,7 +81,7 @@ public class TileInterface extends TileNode implements IComparable {
int delta = got == null ? wanted.stackSize : (wanted.stackSize - got.stackSize);
if (delta > 0) {
ItemStack result = network.extractItem(wanted, delta, compare);
ItemStack result = network.extractItem(wanted, delta, compare, false);
if (result != null) {
if (exportItems.getStackInSlot(i) == null) {

View File

@@ -57,11 +57,11 @@ public class FluidStorageExternal implements IFluidStorage {
@Nullable
@Override
public FluidStack extractFluid(@Nonnull FluidStack stack, int size, int flags) {
public FluidStack extractFluid(@Nonnull FluidStack stack, int size, int flags, boolean simulate) {
FluidStack toDrain = RSUtils.copyStackWithSize(stack, size);
if (API.instance().getComparer().isEqual(getContents(), toDrain, flags)) {
return handler.drain(toDrain, true);
return handler.drain(toDrain, !simulate);
}
return null;

View File

@@ -86,7 +86,7 @@ public class ItemStorageDSU extends ItemStorageExternal {
}
@Override
public ItemStack extractItem(@Nonnull ItemStack stack, int size, int flags) {
public ItemStack extractItem(@Nonnull ItemStack stack, int size, int flags, boolean simulate) {
if (API.instance().getComparer().isEqual(stack, unit.getStoredItemType(), flags)) {
if (size > unit.getStoredItemType().stackSize) {
size = unit.getStoredItemType().stackSize;
@@ -94,7 +94,9 @@ public class ItemStorageDSU extends ItemStorageExternal {
ItemStack stored = unit.getStoredItemType();
unit.setStoredItemCount(stored.stackSize - size);
if (!simulate) {
unit.setStoredItemCount(stored.stackSize - size);
}
return ItemHandlerHelper.copyStackWithSize(stored, size);
}

View File

@@ -71,7 +71,7 @@ public class ItemStorageDrawer extends ItemStorageExternal {
}
@Override
public ItemStack extractItem(ItemStack stack, int size, int flags) {
public ItemStack extractItem(ItemStack stack, int size, int flags, boolean simulate) {
if (API.instance().getComparer().isEqual(stack, drawer.getStoredItemPrototype(), flags) && drawer.canItemBeExtracted(stack)) {
if (size > drawer.getStoredItemCount()) {
size = drawer.getStoredItemCount();
@@ -79,8 +79,10 @@ public class ItemStorageDrawer extends ItemStorageExternal {
ItemStack stored = drawer.getStoredItemPrototype();
drawer.setStoredItemCount(drawer.getStoredItemCount() - size);
if (!simulate) {
drawer.setStoredItemCount(drawer.getStoredItemCount() - size);
}
return ItemHandlerHelper.copyStackWithSize(stored, size);
}

View File

@@ -50,7 +50,7 @@ public class ItemStorageItemHandler extends ItemStorageExternal {
}
@Override
public ItemStack extractItem(ItemStack stack, int size, int flags) {
public ItemStack extractItem(ItemStack stack, int size, int flags, boolean simulate) {
int remaining = size;
ItemStack received = null;
@@ -59,7 +59,7 @@ public class ItemStorageItemHandler extends ItemStorageExternal {
ItemStack slot = handler.getStackInSlot(i);
if (slot != null && API.instance().getComparer().isEqual(slot, stack, flags)) {
ItemStack got = handler.extractItem(i, remaining, false);
ItemStack got = handler.extractItem(i, remaining, simulate);
if (got != null) {
if (received == null) {

View File

@@ -290,7 +290,7 @@ public class TileGrid extends TileNode implements IGrid {
}
} else if (slot != null) {
if (slot.stackSize == 1 && isConnected()) {
matrix.setInventorySlotContents(i, network.extractItem(slot, 1));
matrix.setInventorySlotContents(i, network.extractItem(slot, 1, false));
} else {
matrix.decrStackSize(i, 1);
}
@@ -393,7 +393,7 @@ public class TileGrid extends TileNode implements IGrid {
// If we are connected, first try to get the possibilities from the network
if (isConnected()) {
for (ItemStack possibility : possibilities) {
ItemStack took = network.extractItem(possibility, 1);
ItemStack took = network.extractItem(possibility, 1, false);
if (took != null) {
matrix.setInventorySlotContents(i, took);