mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-01-10 01:10:30 +00:00
Fix turtle.suck reporting incorrect error
Our GatedPredicate hack was clever, but also fundamentally didn't work. The predicate is called before extraction, so if extraction fails (for instance, canTakeItemThroughFace returns false), then we still think an item has been removed. To fix that, we inline StorageUtil.move, specialising it for what we need.
This commit is contained in:
parent
f8ef40d378
commit
e92c2d02f8
@ -54,7 +54,7 @@ public class TurtleSuckCommand implements TurtleCommand {
|
|||||||
case ContainerTransfer.NO_SPACE:
|
case ContainerTransfer.NO_SPACE:
|
||||||
return TurtleCommandResult.failure("No space for items");
|
return TurtleCommandResult.failure("No space for items");
|
||||||
case ContainerTransfer.NO_ITEMS:
|
case ContainerTransfer.NO_ITEMS:
|
||||||
return TurtleCommandResult.failure("No items to drop");
|
return TurtleCommandResult.failure("No items to take");
|
||||||
default:
|
default:
|
||||||
turtle.playAnimation(TurtleAnimation.WAIT);
|
turtle.playAnimation(TurtleAnimation.WAIT);
|
||||||
return TurtleCommandResult.success();
|
return TurtleCommandResult.success();
|
||||||
|
@ -329,8 +329,6 @@ class Turtle_Test {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks turtles can be cleaned in cauldrons.
|
* Checks turtles can be cleaned in cauldrons.
|
||||||
*
|
|
||||||
* Currently not required as turtles can no longer right-click cauldrons.
|
|
||||||
*/
|
*/
|
||||||
@GameTest
|
@GameTest
|
||||||
fun Cleaned_with_cauldrons(helper: GameTestHelper) = helper.sequence {
|
fun Cleaned_with_cauldrons(helper: GameTestHelper) = helper.sequence {
|
||||||
@ -643,7 +641,17 @@ class Turtle_Test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Turtle sucking from items
|
@GameTest
|
||||||
|
fun Sided_suck(helper: GameTestHelper) = helper.sequence {
|
||||||
|
thenOnComputer {
|
||||||
|
turtle.suckUp(Optional.empty()).await().assertArrayEquals(true)
|
||||||
|
turtle.getItemDetail(context, Optional.empty(), Optional.empty()).await().assertArrayEquals(
|
||||||
|
mapOf("name" to "minecraft:iron_ingot", "count" to 8),
|
||||||
|
)
|
||||||
|
|
||||||
|
turtle.suckUp(Optional.empty()).await().assertArrayEquals(false, "No items to take")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render turtles as an item.
|
* Render turtles as an item.
|
||||||
|
138
projects/common/src/testMod/resources/data/cctest/structures/turtle_test.sided_suck.snbt
generated
Normal file
138
projects/common/src/testMod/resources/data/cctest/structures/turtle_test.sided_suck.snbt
generated
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
{
|
||||||
|
DataVersion: 3465,
|
||||||
|
size: [5, 5, 5],
|
||||||
|
data: [
|
||||||
|
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:north,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [], Label: "turtle_test.sided_suck", On: 1b, Slot: 0, id: "computercraft:turtle_normal"}},
|
||||||
|
{pos: [2, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 2], state: "minecraft:furnace{facing:north,lit:false}", nbt: {BurnTime: 0s, CookTime: 0s, CookTimeTotal: 200s, Items: [{Count: 64b, Slot: 1b, id: "minecraft:coal"}, {Count: 8b, Slot: 2b, id: "minecraft:iron_ingot"}], RecipesUsed: {"minecraft:iron_ingot_from_smelting_raw_iron": 8}, id: "minecraft:furnace"}},
|
||||||
|
{pos: [2, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 4], state: "minecraft:air"}
|
||||||
|
],
|
||||||
|
entities: [],
|
||||||
|
palette: [
|
||||||
|
"minecraft:polished_andesite",
|
||||||
|
"minecraft:air",
|
||||||
|
"computercraft:turtle_normal{facing:north,waterlogged:false}",
|
||||||
|
"minecraft:furnace{facing:north,lit:false}"
|
||||||
|
]
|
||||||
|
}
|
@ -9,12 +9,11 @@ import net.fabricmc.fabric.api.transfer.v1.storage.SlottedStorage;
|
|||||||
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
|
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
|
||||||
import net.fabricmc.fabric.api.transfer.v1.storage.StorageUtil;
|
import net.fabricmc.fabric.api.transfer.v1.storage.StorageUtil;
|
||||||
import net.fabricmc.fabric.api.transfer.v1.storage.StorageView;
|
import net.fabricmc.fabric.api.transfer.v1.storage.StorageView;
|
||||||
|
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
|
||||||
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
|
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
@SuppressWarnings("UnstableApiUsage")
|
@SuppressWarnings("UnstableApiUsage")
|
||||||
public class FabricContainerTransfer implements ContainerTransfer {
|
public class FabricContainerTransfer implements ContainerTransfer {
|
||||||
@ -34,37 +33,31 @@ public class FabricContainerTransfer implements ContainerTransfer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int moveTo(ContainerTransfer destination, int maxAmount) {
|
public int moveTo(ContainerTransfer destination, int maxAmount) {
|
||||||
var predicate = new GatePredicate<ItemVariant>();
|
var hasItem = false;
|
||||||
|
|
||||||
var moved = StorageUtil.move(storage, ((FabricContainerTransfer) destination).storage, predicate, maxAmount, null);
|
var destStorage = ((FabricContainerTransfer) destination).storage;
|
||||||
if (moved > 0) return moved > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) moved;
|
for (var slot : storage.nonEmptyViews()) {
|
||||||
|
var resource = slot.getResource();
|
||||||
|
|
||||||
// Nasty hack here to check if move() actually found an item in the original inventory. Saves having to
|
try (var transaction = Transaction.openOuter()) {
|
||||||
// iterate over the source twice.
|
// Check how much can be extracted and inserted.
|
||||||
return predicate.hasItem() ? NO_SPACE : NO_ITEMS;
|
var maxExtracted = StorageUtil.simulateExtract(slot, resource, maxAmount, transaction);
|
||||||
}
|
if (maxExtracted == 0) continue;
|
||||||
|
|
||||||
/**
|
hasItem = true;
|
||||||
* A predicate which accepts the first value it sees, and then only those matching that value.
|
|
||||||
*
|
|
||||||
* @param <T> The type of the object to accept.
|
|
||||||
*/
|
|
||||||
private static final class GatePredicate<T> implements Predicate<T> {
|
|
||||||
private @Nullable T instance = null;
|
|
||||||
|
|
||||||
@Override
|
var accepted = destStorage.insert(resource, maxExtracted, transaction);
|
||||||
public boolean test(T o) {
|
if (accepted == 0) continue;
|
||||||
if (instance == null) {
|
|
||||||
instance = o;
|
// Extract or rollback.
|
||||||
return true;
|
if (slot.extract(resource, accepted, transaction) == accepted) {
|
||||||
|
transaction.commit();
|
||||||
|
return (int) accepted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return instance.equals(o);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasItem() {
|
return hasItem ? NO_SPACE : NO_ITEMS;
|
||||||
return instance != null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class SlottedImpl extends FabricContainerTransfer implements ContainerTransfer.Slotted {
|
private static final class SlottedImpl extends FabricContainerTransfer implements ContainerTransfer.Slotted {
|
||||||
|
Loading…
Reference in New Issue
Block a user