Avoid network scans in getAvailableItems (#1473)

This commit is contained in:
RecursivePineapple authored and GitHub committed 2026-09-20 08:07:06 +00:00
1 parent d0cc848236
commit 12d9b0d205
14 files changed
+177 -12

No files matched your search

@@ -99,7 +99,7 @@ public interface IMEInventory<StackType extends IAEStack> {
* @param out the IItemList the results will be written to
* @param iteration numeric id for this iteration, use {@link appeng.util.IterationCounter#fetchNewId()} to avoid
* conflicts
* @param filter optional filter
* @param filter optional filter, must be kept the same throughout an iteration if NetworkItemList might be made
* @return returns same list that was passed in, is passed out. Network-aware implementations may instead return a
* filtered {@link NetworkItemList} to preserve per-network accounting during nested scans.
*/
@@ -16,6 +16,8 @@ package appeng.api.storage;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
@@ -161,6 +163,12 @@ public class MEMonitorHandler<StackType extends IAEStack<?>> implements IMEMonit
return this.getHandler().getAvailableItems(out, iteration);
}
@Override
public IItemList<StackType> getAvailableItems(IItemList<StackType> out, int iteration,
Optional<Predicate<StackType>> filter) {
return this.getHandler().getAvailableItems(out, iteration, filter);
}
@Override
public StackType getAvailableItem(@Nonnull StackType request, int iteration) {
return this.getHandler().getAvailableItem(request, iteration);
@@ -16,6 +16,8 @@ package appeng.api.storage.data;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Optional;
import java.util.function.Predicate;
import org.jetbrains.annotations.Nullable;
@@ -64,6 +66,25 @@ public interface IItemList<StackType extends IAEStack> extends IItemContainer<St
*/
StackType getFirstItem();
/**
* Mirror of {@link appeng.api.storage.IMEInventory#getAvailableItems(IItemList, int, Optional)}.
*/
default void getAvailableItems(IItemList<StackType> out, int iteration, Optional<Predicate<StackType>> filter) {
if (!filter.isPresent()) {
for (final StackType i : this) {
out.add(i);
}
} else {
Predicate<StackType> pred = filter.get();
for (final StackType i : this) {
if (pred.test(i)) {
out.add(i);
}
}
}
}
/**
* @return the number of items in the list
*/
@@ -332,6 +332,16 @@ public class StorageBusTests {
helper.succeed();
}
@GameTest(template = "multi_storage_bus")
public static void multipleStorageBusReadCorrectly(GameTestHelper helper) {
TileController controller = getController(helper);
helper.startSequence().thenWaitUntil("wait network to wake up and expose correct items", 60, () -> {
assertActive(helper, controller.getProxy(), "Controller grid proxy should become active");
assertNetworkMonitorStoredAmount(helper, controller, Blocks.cobblestone, 128);
assertNetworkMonitorStoredAmount(helper, controller, Blocks.dirt, 128);
}).thenSucceed();
}
private static TileController getController(GameTestHelper helper) {
return helper.assertTileEntityPresent(TileController.class, CONTROLLER_LABEL);
}
+7
View File
@@ -17,8 +17,10 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.function.Predicate;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
@@ -136,6 +138,11 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T> {
return this.getHandler().getAvailableItems(out, iteration);
}
@Override
public IItemList<T> getAvailableItems(IItemList<T> out, int iteration, Optional<Predicate<T>> filter) {
return this.getHandler().getAvailableItems(out, iteration, filter);
}
@Override
public PrioritizedNetworkItemList<T> getAvailableItemsWithPriority(int iteration) {
return this.getHandler().getAvailableItemsWithPriority(iteration);
@@ -13,6 +13,9 @@ package appeng.me.storage;
import static appeng.util.item.AEFluidStackType.FLUID_STACK_TYPE;
import static appeng.util.item.AEItemStackType.ITEM_STACK_TYPE;
import java.util.Optional;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
import net.minecraft.inventory.IInventory;
@@ -430,6 +433,14 @@ public abstract class CellInventory<StackType extends IAEStack<StackType>> imple
return count == 0 ? null : request.copy().setStackSize(count);
}
@Override
public IItemList<StackType> getAvailableItems(IItemList<StackType> out, int iteration,
Optional<Predicate<StackType>> filter) {
this.getCellStacks().getAvailableItems(out, iteration, filter);
return out;
}
@Override
public ItemStack getItemStack() {
return this.cellItem;
@@ -1,5 +1,10 @@
package appeng.me.storage;
import java.util.Optional;
import java.util.function.Predicate;
import org.jetbrains.annotations.NotNull;
import appeng.api.config.Actionable;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.storage.IMEInventory;
@@ -32,6 +37,16 @@ public class MEInventoryWrapper<T extends IAEStack<T>> implements IMEInventory<T
return this.delegate.getAvailableItems(out, iteration);
}
@Override
public IItemList<T> getAvailableItems(IItemList<T> out, int iteration, Optional<Predicate<T>> filter) {
return this.delegate.getAvailableItems(out, iteration, filter);
}
@Override
public T getAvailableItem(@NotNull T request, int iteration) {
return this.delegate.getAvailableItem(request, iteration);
}
@Override
public IAEStackType<?> getStackType() {
return this.type;
@@ -13,6 +13,8 @@ package appeng.me.storage;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.function.Predicate;
import appeng.api.config.StorageFilter;
import appeng.api.networking.security.BaseActionSource;
@@ -85,6 +87,19 @@ public class MEMonitorPassThrough<T extends IAEStack<T>> extends MEPassThrough<T
}
}
@Override
public IItemList<T> getAvailableItems(final IItemList<T> out, int iterator, Optional<Predicate<T>> filter) {
if (out instanceof ItemFilterList) {
return super.getAvailableItems(out, iterator, filter);
}
IItemList<T> ret = super.getAvailableItems(new ItemListIgnoreCrafting(out), iterator, filter);
if (ret instanceof ItemListIgnoreCrafting) {
return out;
} else {
return ret;
}
}
@Override
public void addListener(final IMEMonitorHandlerReceiver l, final Object verificationToken) {
this.listeners.put(l, verificationToken);
@@ -10,6 +10,9 @@
package appeng.me.storage;
import java.util.Optional;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
import org.jetbrains.annotations.NotNull;
@@ -78,6 +81,11 @@ public class MEPassThrough<T extends IAEStack<T>> implements IMEInventoryHandler
return this.internal.getAvailableItem(request, iteration);
}
@Override
public IItemList<T> getAvailableItems(IItemList<T> out, int iteration, Optional<Predicate<T>> filter) {
return this.internal.getAvailableItems(out, iteration, filter);
}
@Override
public StorageChannel getChannel() {
return this.internal.getChannel();
@@ -24,35 +24,36 @@ public class StorageBusInventoryHandler<T extends IAEStack<T>> extends MEInvento
}
@Override
public IItemList<T> getAvailableItems(final IItemList<T> out, int iteration, Optional<Predicate<T>> preFilter) {
public IItemList<T> getAvailableItems(final IItemList<T> out, int iteration, Optional<Predicate<T>> filter) {
if (!this.hasReadAccess && !isVisible()) {
return out;
}
if (out instanceof ItemFilterList) return this.getAvailableItemsFilter(out, iteration);
Predicate<T> filterCondition = preFilter.orElse(null);
Predicate<T> storageBusFilter = $ -> true;
if (this.isExtractFilterActive() && !this.getExtractPartitionList().isEmpty()) {
Predicate<T> extractFilter = this.getExtractFilterCondition();
filterCondition = filterCondition == null ? extractFilter : extractFilter.and(filterCondition);
storageBusFilter = this.getExtractFilterCondition();
}
final IItemList<T> availableItems = this.getInternal().getAvailableItems(
(IItemList<T>) this.getStackType().createList(),
iteration,
Optional.ofNullable(filterCondition));
final IItemList<T> availableItems = this.getInternal()
.getAvailableItems((IItemList<T>) this.getStackType().createList(), iteration, filter);
if (availableItems instanceof NetworkItemList) {
if (availableItems instanceof NetworkItemList networkItemList) {
// when we cross between networks on a NetworkInventoryHandler dive, we need to break the "out" contract to
// avoid modifying the passed in list which belongs to a different network (and would cause double-counting
// for triangle-shaped networks)
return availableItems;
NetworkItemList<T> itemList = new NetworkItemList<>(networkItemList);
itemList.addFilter(storageBusFilter);
return itemList;
} else {
// for non-cross-network dives, we need to honor the "out" contract
// and put the results in the passed in list
for (T items : availableItems) {
out.add(items);
if (storageBusFilter == null || storageBusFilter.test(items)) {
out.add(items);
}
}
return out;
}
@@ -1,6 +1,8 @@
package appeng.tile.misc;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -349,6 +351,13 @@ public class TileSuperMEReplenisher extends AENetworkTile
}
}
@Override
public IAEStack<?> getAvailableItem(final IAEStack<?> aes, int iteration) {
IAEStack<?> result = this.storage.findPrecise(aes);
if (result == null) return null;
return result.copy();
}
@Override
public IItemList<IAEStack<?>> getAvailableItems(IItemList<IAEStack<?>> out, int iteration) {
final IAEStackType<?> outStackType = out.getStackType();
@@ -356,6 +365,20 @@ public class TileSuperMEReplenisher extends AENetworkTile
return out;
}
@Override
public IItemList<IAEStack<?>> getAvailableItems(IItemList<IAEStack<?>> out, int iteration,
Optional<Predicate<IAEStack<?>>> filter) {
final IAEStackType<?> outStackType = out.getStackType();
this.storage.forEach(aes -> {
if (aes.getStackType().equals(outStackType)) {
if (!filter.isPresent() || filter.get().test(aes)) {
out.add(aes);
}
}
});
return out;
}
@Override
public IAEStack<?> injectItems(IAEStack<?> input, Actionable type, BaseActionSource src) {
return this.injectItems(input, type, this.out);
@@ -14,6 +14,8 @@ import static appeng.util.item.AEItemStackType.ITEM_STACK_TYPE;
import java.util.Collection;
import java.util.Iterator;
import java.util.Optional;
import java.util.function.Predicate;
import appeng.api.config.FuzzyMode;
import appeng.api.storage.data.IAEItemStack;
@@ -135,6 +137,26 @@ public final class HashBasedItemList implements IItemList<IAEItemStack> {
return null;
}
@Override
public void getAvailableItems(IItemList<IAEItemStack> out, int iteration,
Optional<Predicate<IAEItemStack>> filter) {
if (!filter.isPresent()) {
this.records.forEach(stack -> {
if (stack.isMeaningful()) {
out.add(stack);
}
});
} else {
Predicate<IAEItemStack> pred = filter.get();
this.records.forEach(stack -> {
if (stack.isMeaningful() && pred.test(stack)) {
out.add(stack);
}
});
}
}
@Override
public int size() {
return this.records.size();
@@ -0,0 +1,24 @@
{
"format_version": 2,
"size": [2, 1, 5],
"palette": {
"A": {"name": "appliedenergistics2:tile.BlockCableBus", "meta": 0, "label": "AE2 Cable and/or Bus"},
"B": {"name": "appliedenergistics2:tile.BlockChest", "meta": 0, "label": "ME Chest"},
"C": {"name": "appliedenergistics2:tile.BlockCreativeEnergyController", "meta": 1, "label": "ME Self-Powered Controller"},
"D": {"name": "appliedenergistics2:tile.BlockInterface", "meta": 0, "label": "ME Interface"}
},
"layers": [
[
"CB",
"DA",
"DA",
"DA",
".C"
]
],
"annotations": {
"labels": {
"controller": [1, 0, 4]
}
}
}