diff --git a/build.gradle b/build.gradle index 13f98166918..57c7727d561 100644 --- a/build.gradle +++ b/build.gradle @@ -322,6 +322,7 @@ legacyForge { } client { client() + jvmArguments.add("-XX:+AllowEnhancedClassRedefinition") } gametestWorld { client() diff --git a/src/generated/resources/assets/ae2/lang/en_us.json b/src/generated/resources/assets/ae2/lang/en_us.json index 08d853ce93f..5827c79dd0b 100644 --- a/src/generated/resources/assets/ae2/lang/en_us.json +++ b/src/generated/resources/assets/ae2/lang/en_us.json @@ -963,6 +963,7 @@ "item.ae2.spatial_storage_cell_16": "16³ Spatial Storage Cell", "item.ae2.spatial_storage_cell_2": "2³ Spatial Storage Cell", "item.ae2.speed_card": "Acceleration Card", + "item.ae2.sticky_card": "Sticky Card", "item.ae2.stonecutting_pattern": "Stonecutting Pattern", "item.ae2.storage_bus": "ME Storage Bus", "item.ae2.storage_monitor": "ME Storage Monitor", diff --git a/src/generated/resources/assets/ae2/models/item/sticky_card.json b/src/generated/resources/assets/ae2/models/item/sticky_card.json new file mode 100644 index 00000000000..e353f6e2a28 --- /dev/null +++ b/src/generated/resources/assets/ae2/models/item/sticky_card.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "ae2:item/sticky_card" + } +} \ No newline at end of file diff --git a/src/main/java/appeng/api/ids/AEItemIds.java b/src/main/java/appeng/api/ids/AEItemIds.java index 0fd6d65f31a..973fa4a7014 100644 --- a/src/main/java/appeng/api/ids/AEItemIds.java +++ b/src/main/java/appeng/api/ids/AEItemIds.java @@ -228,6 +228,7 @@ public final class AEItemIds { public static final ResourceLocation ENERGY_CARD = id("energy_card"); public static final ResourceLocation EQUAL_DISTRIBUTION_CARD = id("equal_distribution_card"); public static final ResourceLocation AUTO_COMPLETE_CARD = id("auto_complete_card"); + public static final ResourceLocation STICKY_CARD = id("sticky_card"); public static final ResourceLocation SPATIAL_2_CELL_COMPONENT = id("spatial_cell_component_2"); public static final ResourceLocation SPATIAL_16_CELL_COMPONENT = id("spatial_cell_component_16"); public static final ResourceLocation SPATIAL_128_CELL_COMPONENT = id("spatial_cell_component_128"); diff --git a/src/main/java/appeng/api/storage/MEStorage.java b/src/main/java/appeng/api/storage/MEStorage.java index 65c6253ce81..51c59da8e01 100644 --- a/src/main/java/appeng/api/storage/MEStorage.java +++ b/src/main/java/appeng/api/storage/MEStorage.java @@ -34,6 +34,7 @@ import appeng.api.networking.security.IActionSource; import appeng.api.stacks.AEKey; import appeng.api.stacks.KeyCounter; +import org.jetbrains.annotations.Nullable; /** * AE's Equivalent to IInventory, used to reading contents, and manipulating contents of ME Inventories. @@ -95,6 +96,22 @@ default long extract(AEKey what, long amount, Actionable mode, IActionSource sou default void getAvailableStacks(KeyCounter out) { } + /** + * If that key has any inventory marked as sticky it should only be able to insert into that one or other + * inventories that have it marked as sticky + *

+ * If for example a storage bus has a sticky card with a filter for stone, then on that network it should be the + * only place where stone can be stored. + *

+ * @apiNote Pass a null value to check if the inventory is sticky at all. + * + * @return Whether the specified stack is sticky for this inventory. + * @param what what to check. + */ + default boolean isSticky(@Nullable AEKey what) { + return false; + } + /** * @return The type of storage represented by this object. */ diff --git a/src/main/java/appeng/core/definitions/AEItems.java b/src/main/java/appeng/core/definitions/AEItems.java index 9836ee62718..b46e9cce8f6 100644 --- a/src/main/java/appeng/core/definitions/AEItems.java +++ b/src/main/java/appeng/core/definitions/AEItems.java @@ -224,6 +224,7 @@ private static ItemDefinition makePortableFluidCell(ResourceLo public static final ItemDefinition EQUAL_DISTRIBUTION_CARD = item("Equal Distribution Card", AEItemIds.EQUAL_DISTRIBUTION_CARD, Upgrades::createUpgradeCardItem); public static final ItemDefinition ENERGY_CARD = item("Energy Card", AEItemIds.ENERGY_CARD, p -> new EnergyCardItem(p, 1)); public static final ItemDefinition AUTO_COMPLETE_CARD = item("Auto Complete Card", AEItemIds.AUTO_COMPLETE_CARD, Upgrades::createUpgradeCardItem); + public static final ItemDefinition STICKY_CARD = item("Sticky Card", AEItemIds.STICKY_CARD, Upgrades::createUpgradeCardItem); public static final ItemDefinition SPATIAL_2_CELL_COMPONENT = item("2³ Spatial Component", AEItemIds.SPATIAL_2_CELL_COMPONENT, MaterialItem::new); public static final ItemDefinition SPATIAL_16_CELL_COMPONENT = item("16³ Spatial Component", AEItemIds.SPATIAL_16_CELL_COMPONENT, MaterialItem::new); public static final ItemDefinition SPATIAL_128_CELL_COMPONENT = item("128³ Spatial Component", AEItemIds.SPATIAL_128_CELL_COMPONENT, MaterialItem::new); diff --git a/src/main/java/appeng/datagen/providers/models/ItemModelProvider.java b/src/main/java/appeng/datagen/providers/models/ItemModelProvider.java index 6f40e65a84b..59b6411cbf8 100644 --- a/src/main/java/appeng/datagen/providers/models/ItemModelProvider.java +++ b/src/main/java/appeng/datagen/providers/models/ItemModelProvider.java @@ -66,6 +66,7 @@ protected void registerModels() { flatSingleLayer(AEItems.ENGINEERING_PROCESSOR_PRINT, "item/printed_engineering_processor"); flatSingleLayer(AEItems.EQUAL_DISTRIBUTION_CARD, "item/card_equal_distribution"); flatSingleLayer(AEItems.AUTO_COMPLETE_CARD, "item/auto_complete_card"); + flatSingleLayer(AEItems.STICKY_CARD, "item/sticky_card"); storageCell(AEItems.FLUID_CELL_1K, "item/fluid_storage_cell_1k"); storageCell(AEItems.FLUID_CELL_4K, "item/fluid_storage_cell_4k"); storageCell(AEItems.FLUID_CELL_16K, "item/fluid_storage_cell_16k"); diff --git a/src/main/java/appeng/init/internal/InitUpgrades.java b/src/main/java/appeng/init/internal/InitUpgrades.java index 0b5940909a3..242068ece02 100644 --- a/src/main/java/appeng/init/internal/InitUpgrades.java +++ b/src/main/java/appeng/init/internal/InitUpgrades.java @@ -82,6 +82,7 @@ public static void init() { Upgrades.add(AEItems.INVERTER_CARD, itemCell, 1, storageCellGroup); Upgrades.add(AEItems.EQUAL_DISTRIBUTION_CARD, itemCell, 1, storageCellGroup); Upgrades.add(AEItems.VOID_CARD, itemCell, 1, storageCellGroup); + Upgrades.add(AEItems.STICKY_CARD, itemCell, 1, storageCellGroup); } var fluidCells = List.of( @@ -91,6 +92,7 @@ public static void init() { Upgrades.add(AEItems.INVERTER_CARD, fluidCell, 1, storageCellGroup); Upgrades.add(AEItems.EQUAL_DISTRIBUTION_CARD, fluidCell, 1, storageCellGroup); Upgrades.add(AEItems.VOID_CARD, fluidCell, 1, storageCellGroup); + Upgrades.add(AEItems.STICKY_CARD, fluidCell, 1, storageCellGroup); } var portableCells = List.of( @@ -127,6 +129,7 @@ public static void init() { Upgrades.add(AEItems.INVERTER_CARD, AEParts.STORAGE_BUS, 1); Upgrades.add(AEItems.CAPACITY_CARD, AEParts.STORAGE_BUS, 5); Upgrades.add(AEItems.VOID_CARD, AEParts.STORAGE_BUS, 1); + Upgrades.add(AEItems.STICKY_CARD, AEParts.STORAGE_BUS, 1); // Formation Plane Upgrades.add(AEItems.FUZZY_CARD, AEParts.FORMATION_PLANE, 1); diff --git a/src/main/java/appeng/me/cells/BasicCellInventory.java b/src/main/java/appeng/me/cells/BasicCellInventory.java index 8509ac34c35..502e4bd5c64 100644 --- a/src/main/java/appeng/me/cells/BasicCellInventory.java +++ b/src/main/java/appeng/me/cells/BasicCellInventory.java @@ -463,4 +463,10 @@ public long extract(AEKey what, long amount, Actionable mode, IActionSource sour public Component getDescription() { return i.getHoverName(); } + + @Override + public boolean isSticky(AEKey what) { + return getUpgradesInventory().isInstalled(AEItems.STICKY_CARD) + && (what == null || partitionList.matchesFilter(what, this.partitionListMode)); + } } diff --git a/src/main/java/appeng/me/storage/DriveWatcher.java b/src/main/java/appeng/me/storage/DriveWatcher.java index 148073e178e..89c83da5846 100644 --- a/src/main/java/appeng/me/storage/DriveWatcher.java +++ b/src/main/java/appeng/me/storage/DriveWatcher.java @@ -28,9 +28,11 @@ public class DriveWatcher extends MEInventoryHandler { private CellState oldStatus = CellState.EMPTY; private final Runnable activityCallback; + private final StorageCell cell; public DriveWatcher(StorageCell i, Runnable activityCallback) { super(i); + this.cell = i; this.activityCallback = activityCallback; this.oldStatus = getStatus(); } @@ -74,4 +76,9 @@ public long extract(AEKey what, long amount, Actionable mode, IActionSource sour return extracted; } + + @Override + public boolean isSticky(AEKey what) { + return cell.isSticky(what); + } } diff --git a/src/main/java/appeng/me/storage/NetworkStorage.java b/src/main/java/appeng/me/storage/NetworkStorage.java index 9e6d61d0595..8f88cb2cff5 100644 --- a/src/main/java/appeng/me/storage/NetworkStorage.java +++ b/src/main/java/appeng/me/storage/NetworkStorage.java @@ -48,6 +48,7 @@ public class NetworkStorage implements MEStorage { private boolean mountsInUse; private final NavigableMap> priorityInventory; + private final NavigableMap> priorityStickyInventory; private final List secondPassInventories = new ArrayList<>(); // Queued mount/unmount operations that occurred while an insert/extract was ongoing @@ -57,6 +58,7 @@ public class NetworkStorage implements MEStorage { public NetworkStorage() { this.priorityInventory = new TreeMap<>(PRIORITY_SORTER); + this.priorityStickyInventory = new TreeMap<>(PRIORITY_SORTER); } public void mount(int priority, MEStorage inventory) { @@ -66,8 +68,13 @@ public void mount(int priority, MEStorage inventory) { } queuedOperations.add(new MountOperation(priority, inventory)); } else { - this.priorityInventory.computeIfAbsent(priority, k -> new ArrayList<>()) - .add(inventory); + if (!inventory.isSticky(null)) { + this.priorityInventory.computeIfAbsent(priority, k -> new ArrayList<>()) + .add(inventory); + } else { + this.priorityStickyInventory.computeIfAbsent(priority, k -> new ArrayList<>()) + .add(inventory); + } } } @@ -96,14 +103,25 @@ public long insert(AEKey what, long amount, Actionable type, IActionSource src) } var remaining = amount; + boolean hasSticky = false; mountsInUse = true; try { + // first, we need to check if any inventory has this key marked as sticky + for (var invList : this.priorityStickyInventory.values()) { + for (var inv : invList) { + if (inv.isSticky(what)) { + hasSticky = true; + remaining -= inv.insert(what, remaining, type, src); + } + } + } + for (var invList : this.priorityInventory.values()) { secondPassInventories.clear(); - // First give every inventory a chance to accept the item if it's preferential storage for the given - // stack + // then we give every inventory a chance to accept the item if it's preferential storage for the given + // stack and taking into account its sticky status var ii = invList.iterator(); while (ii.hasNext() && remaining > 0) { var inv = ii.next(); @@ -112,6 +130,11 @@ public long insert(AEKey what, long amount, Actionable type, IActionSource src) continue; } + // skip this inventory if we're looking for a sticky one and it is not + if (hasSticky && !inv.isSticky(what)) { + continue; + } + if (inv.isPreferredStorageFor(what, src)) { remaining -= inv.insert(what, remaining, type, src); } else { diff --git a/src/main/java/appeng/parts/storagebus/StorageBusPart.java b/src/main/java/appeng/parts/storagebus/StorageBusPart.java index 4bef0305a3c..dfe1a67e532 100644 --- a/src/main/java/appeng/parts/storagebus/StorageBusPart.java +++ b/src/main/java/appeng/parts/storagebus/StorageBusPart.java @@ -55,6 +55,7 @@ import appeng.api.parts.IPartHost; import appeng.api.parts.IPartItem; import appeng.api.parts.IPartModel; +import appeng.api.stacks.AEKey; import appeng.api.stacks.AEKeyType; import appeng.api.storage.IStorageMounts; import appeng.api.storage.IStorageProvider; @@ -456,7 +457,7 @@ public final void setPriority(int newValue) { /** * This inventory forwards to the actual external inventory and allows the inventory to be swapped out underneath. */ - private static class StorageBusInventory extends MEInventoryHandler { + private class StorageBusInventory extends MEInventoryHandler { public StorageBusInventory(MEStorage inventory) { super(inventory); } @@ -475,6 +476,12 @@ public void setAccessRestriction(AccessRestriction setting) { setAllowExtraction(setting.isAllowExtraction()); setAllowInsertion(setting.isAllowInsertion()); } + + @Override + public boolean isSticky(AEKey what) { + return isUpgradedWith(AEItems.STICKY_CARD) + && (what == null || this.getPartitionList().matchesFilter(what, this.getWhitelist())); + } } @Override diff --git a/src/main/resources/assets/ae2/textures/item/sticky_card.png b/src/main/resources/assets/ae2/textures/item/sticky_card.png new file mode 100644 index 00000000000..e9797729cc6 Binary files /dev/null and b/src/main/resources/assets/ae2/textures/item/sticky_card.png differ