Skip to content

Commit

Permalink
Formatting, test
Browse files Browse the repository at this point in the history
  • Loading branch information
shartte committed Mar 12, 2024
1 parent 2e70d08 commit 8bd3127
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 177 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ default boolean isAllowed(AEKey what) {
}

/**
* Return true if the key is {@link #isSupportedType(AEKey) of a supported type} and would pass a
* potential filter configured for the given slot.
* Return true if the key is {@link #isSupportedType(AEKey) of a supported type} and would pass a potential filter
* configured for the given slot.
*/
boolean isAllowedIn(int slot, AEKey what);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package appeng.helpers.externalstorage;

import appeng.api.stacks.AEKeyTypes;
import com.google.common.primitives.Ints;

import org.jetbrains.annotations.NotNull;
Expand Down
28 changes: 16 additions & 12 deletions src/main/java/appeng/helpers/externalstorage/GenericStackInv.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,22 @@

package appeng.helpers.externalstorage;

import java.util.Objects;
import java.util.Set;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;

import org.jetbrains.annotations.Nullable;

import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;

import it.unimi.dsi.fastutil.objects.Reference2LongArrayMap;
import it.unimi.dsi.fastutil.objects.Reference2LongMap;

import appeng.api.behaviors.GenericInternalInventory;
import appeng.api.behaviors.GenericSlotCapacities;
import appeng.api.config.Actionable;
Expand All @@ -32,18 +48,6 @@
import appeng.api.storage.MEStorage;
import appeng.core.AELog;
import appeng.util.ConfigMenuInventory;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import it.unimi.dsi.fastutil.objects.Reference2LongArrayMap;
import it.unimi.dsi.fastutil.objects.Reference2LongMap;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.Nullable;

import java.util.Objects;
import java.util.Set;

public class GenericStackInv implements MEStorage, GenericInternalInventory {
protected final GenericStack[] stacks;
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/appeng/items/contents/CellConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@

package appeng.items.contents;

import appeng.api.stacks.AEKeyType;
import java.util.Set;

import com.google.common.base.Preconditions;

import net.minecraft.world.item.ItemStack;

import appeng.api.stacks.AEKeyType;
import appeng.util.ConfigInventory;

import java.util.Set;

public final class CellConfig {
private CellConfig() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import java.util.Optional;
import java.util.Set;

import appeng.api.stacks.AEKeyTypes;
import org.jetbrains.annotations.Nullable;

import net.minecraft.core.BlockPos;
Expand Down
7 changes: 3 additions & 4 deletions src/main/java/appeng/parts/automation/IOBusPart.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@

package appeng.parts.automation;

import appeng.api.stacks.AEKeyType;
import java.util.Set;

import org.jetbrains.annotations.Nullable;

import net.minecraft.core.BlockPos;
Expand All @@ -43,7 +44,7 @@
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPartItem;
import appeng.api.parts.IPartModel;
import appeng.api.storage.AEKeyFilter;
import appeng.api.stacks.AEKeyType;
import appeng.api.storage.ISubMenuHost;
import appeng.api.util.AECableType;
import appeng.api.util.IConfigManager;
Expand All @@ -61,8 +62,6 @@
import appeng.util.Platform;
import appeng.util.prioritylist.IPartitionList;

import java.util.Set;

public abstract class IOBusPart extends UpgradeablePart implements IGridTickable, IConfigInvHost, ISubMenuHost {

public static final ResourceLocation MODEL_BASE = new ResourceLocation(AppEng.MOD_ID, "part/import_bus_base");
Expand Down
220 changes: 220 additions & 0 deletions src/main/java/appeng/server/testplots/InterfaceTestPlots.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
package appeng.server.testplots;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.entity.HopperBlockEntity;
import net.minecraft.world.level.block.state.properties.ChestType;
import net.minecraft.world.level.material.Fluids;
import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.fluids.FluidStack;

import appeng.api.config.Actionable;
import appeng.api.stacks.AEItemKey;
import appeng.api.stacks.GenericStack;
import appeng.api.stacks.KeyCounter;
import appeng.blockentity.misc.InterfaceBlockEntity;
import appeng.core.definitions.AEBlocks;
import appeng.core.definitions.AEItems;
import appeng.core.definitions.AEParts;
import appeng.me.helpers.BaseActionSource;
import appeng.parts.misc.InterfacePart;
import appeng.server.testworld.PlotBuilder;

public class InterfaceTestPlots {

/**
* Test that configured slots of interfaces are filtered and prevent insertion.
*/
@TestPlot("interface_slot_filtering")
public static void interfaceSlotFiltering(PlotBuilder builder) {
var o = BlockPos.ZERO;
builder.blockEntity(o, AEBlocks.INTERFACE, iface -> {
// Set slot 0 to sticks
iface.getInterfaceLogic().getConfig().setStack(0, new GenericStack(AEItemKey.of(Items.STICK), 1));
});
builder.hopper(o.above(), Direction.DOWN, Items.BRICK);
builder.test(helper -> {
helper.startSequence()
.thenExecute(() -> {
var itemCap = helper.getCapability(o, Capabilities.ItemHandler.BLOCK, Direction.UP);
helper.check(itemCap.isItemValid(0, ItemStack.EMPTY), "empty stack should be valid in slot 0");
helper.check(itemCap.isItemValid(0, Items.STICK.getDefaultInstance()),
"stick should be valid in slot 0");
helper.check(itemCap.isItemValid(1, Items.STICK.getDefaultInstance()),
"stick should be valid in slot 1");
helper.check(!itemCap.isItemValid(0, Blocks.BRICKS.asItem().getDefaultInstance()),
"bricks should not be valid in slot 0");
helper.check(itemCap.isItemValid(1, Blocks.BRICKS.asItem().getDefaultInstance()),
"bricks should be valid in slot 1");

var fluidCap = helper.getCapability(o, Capabilities.FluidHandler.BLOCK, Direction.UP);
helper.check(fluidCap.isFluidValid(0, FluidStack.EMPTY),
"empty fluid stack should be valid in slot 0");
helper.check(!fluidCap.isFluidValid(0, new FluidStack(Fluids.WATER, 1)),
"fluid should not be valid in slot 0");
helper.check(fluidCap.isFluidValid(1, new FluidStack(Fluids.WATER, 1)),
"fluid should be valid in slot 1");
})
.thenWaitUntil(() -> {
var iface = (InterfaceBlockEntity) helper.getBlockEntity(o);
helper.assertEquals(o, null, iface.getStorage().getKey(0));
helper.assertEquals(o, AEItemKey.of(Items.BRICK), iface.getStorage().getKey(1));
})
.thenExecute(() -> {
var hopper = (HopperBlockEntity) helper.getBlockEntity(o.above());
hopper.setItem(0, Items.STICK.getDefaultInstance());
})
.thenWaitUntil(() -> {
var iface = (InterfaceBlockEntity) helper.getBlockEntity(o);
helper.assertEquals(o, AEItemKey.of(Items.STICK), iface.getStorage().getKey(0));
helper.assertEquals(o, AEItemKey.of(Items.BRICK), iface.getStorage().getKey(1));
})
.thenSucceed();
});
}

/**
* Similar to {@link TestPlots#exportBusDupeRegression(PlotBuilder)}, but tests that interface restocking will not
* make the same mistake.
*/
@TestPlot("interface_restock_dupe_test")
public static void interfaceRestockDupeTest(PlotBuilder plot) {
var o = BlockPos.ZERO;
// Set up a double chest with 64 sticks which will report as 128 sticks
// and allow simulated extractions of 128 sticks to succeed.
plot.chest(o.north(), new ItemStack(Items.STICK, 64));
plot.blockState(o.north(), Blocks.CHEST.defaultBlockState().setValue(ChestBlock.TYPE, ChestType.RIGHT));
plot.cable(o).part(Direction.NORTH, AEParts.STORAGE_BUS);
plot.blockState(o.north().west(), Blocks.CHEST.defaultBlockState().setValue(ChestBlock.TYPE, ChestType.LEFT));
plot.cable(o.west()).part(Direction.NORTH, AEParts.STORAGE_BUS);

// Set up an interface that tries to stock 128 sticks
plot.blockEntity(o.above(), AEBlocks.INTERFACE, iface -> {
iface.getConfig().setStack(0, GenericStack.fromItemStack(new ItemStack(Items.STICK, 64)));
iface.getConfig().setStack(1, GenericStack.fromItemStack(new ItemStack(Items.STICK, 64)));
});
plot.creativeEnergyCell(o.below());

plot.test(helper -> {
helper.succeedWhen(() -> {
// Both double chests should be empty
helper.assertContainerEmpty(o.north());
helper.assertContainerEmpty(o.north().west());

// The output interface should have 64 sticks
var iface = (InterfaceBlockEntity) helper.getBlockEntity(o.above());
var counter = new KeyCounter();
iface.getInterfaceLogic().getStorage().getAvailableStacks(counter);
var stickCount = counter.get(AEItemKey.of(Items.STICK));
helper.check(stickCount == 64,
"Expected 64 sticks total, but found: " + stickCount);
});
});
}

/**
* Tests that the priority checks for interface -> interface restocking don't apply when the source interface is on
* another network. Regression test for https://github.com/AppliedEnergistics/Applied-Energistics-2/issues/6847.
*/
@TestPlot("interface_to_interface_different_networks")
public static void interfaceToInterfaceDifferentNetworks(PlotBuilder plot) {
var o = BlockPos.ZERO;
plot.cable(o)
.part(Direction.NORTH, AEParts.STORAGE_BUS);
plot.blockEntity(o.north(), AEBlocks.INTERFACE, iface -> {
// Need something in the config to not expose the full network...
iface.getConfig().setStack(0, GenericStack.fromItemStack(new ItemStack(Items.APPLE)));
iface.getStorage().setStack(0, GenericStack.fromItemStack(new ItemStack(Items.APPLE, 64)));
});
plot.block(o.north().north(), AEBlocks.CREATIVE_ENERGY_CELL);
plot.block(o.east(), AEBlocks.CREATIVE_ENERGY_CELL);
plot.blockEntity(o.south(), AEBlocks.INTERFACE, iface -> {
iface.getConfig().setStack(0, GenericStack.fromItemStack(new ItemStack(Items.APPLE)));
});

plot.test(helper -> helper.startSequence()
// Test interface restock
.thenWaitUntil(() -> {
var iface = (InterfaceBlockEntity) helper.getBlockEntity(o.south());
var apples = iface.getStorage().getStack(0);
helper.check(apples != null && apples.amount() == 1, "Expected 1 apple", o.south());
})
// Test interface pushing items away to subnet
.thenExecute(() -> {
var iface = (InterfaceBlockEntity) helper.getBlockEntity(o.south());
iface.getStorage().setStack(1, GenericStack.fromItemStack(new ItemStack(Items.DIAMOND)));
})
.thenWaitUntil(() -> {
var iface = (InterfaceBlockEntity) helper.getBlockEntity(o.north());
var diamonds = iface.getStorage().getStack(1);
helper.check(diamonds != null && diamonds.amount() == 1, "Expected 1 diamond", o.north());
})
.thenSucceed());
}

@TestPlot("interface_part_caps")
public static void interfacePartCaps(PlotBuilder plot) {
plot.cable(BlockPos.ZERO).part(Direction.UP, AEParts.INTERFACE);
plot.hopper(BlockPos.ZERO.above(), Direction.DOWN, Items.DIRT);

plot.test(helper -> {
helper.startSequence()
.thenWaitUntil(() -> {
var interfacePart = helper.getPart(BlockPos.ZERO, Direction.UP, InterfacePart.class);
var storage = interfacePart.getInterfaceLogic().getStorage();
helper.assertEquals(BlockPos.ZERO, AEItemKey.of(Items.DIRT), storage.getKey(0));
})
.thenSucceed();
});
}

/**
* Regression test for https://github.com/AppliedEnergistics/Applied-Energistics-2/issues/5919
*/
@TestPlot("canceling_jobs_from_interfacecrash")
public static void cancelingJobsFromInterfaceCrash(PlotBuilder plot) {
var origin = BlockPos.ZERO;

plot.creativeEnergyCell(origin);
// Stock 1 oak_plank via crafting
plot.blockEntity(origin.above(), AEBlocks.INTERFACE, iface -> {
iface.getUpgrades().addItems(AEItems.CRAFTING_CARD.stack());
iface.getConfig().setStack(0, new GenericStack(AEItemKey.of(Items.OAK_PLANKS), 1));
});
plot.block(origin.east(), AEBlocks.CRAFTING_STORAGE_1K);
// Set up a level emitter for oak_planks
plot.cable(origin.west()).craftingEmitter(Direction.WEST, Items.OAK_PLANKS);

plot.test(helper -> {
helper.startSequence()
.thenWaitUntil(() -> {
var grid = helper.getGrid(origin);
helper.check(
grid.getCraftingService().isRequesting(AEItemKey.of(Items.OAK_PLANKS)),
"Interface is not crafting oak planks");
})
.thenExecute(() -> {
// Cancel the job by removing the upgrade card
var iface = (InterfaceBlockEntity) helper.getBlockEntity(origin.above());
iface.getUpgrades().removeItems(1, ItemStack.EMPTY, null);

// and immediately insert a craft result into the network storage
// this would crash because the crafting job was not cleaned up properly before
// the crafting service ticks
var grid = helper.getGrid(origin);
var inserted = grid.getStorageService().getInventory().insert(
AEItemKey.of(Items.OAK_PLANKS), 1, Actionable.MODULATE, new BaseActionSource());
helper.check(inserted == 0,
"Nothing should have been inserted into the network");
helper.check(iface.getInterfaceLogic().getStorage().isEmpty(),
"Nothing should have been inserted into the interface");
})
.thenSucceed();
}).maxTicks(300 /* interface takes a while to request */);
}

}
Loading

0 comments on commit 8bd3127

Please sign in to comment.