mirror of
https://github.com/GTNewHorizons/Applied-Energistics-2-Unofficial.git
synced 2026-10-26 14:25:20 +00:00
Fix/inconsistent network read order (#867)
Co-authored-by: Martin Robertz <dream-master@gmx.net>
This commit is contained in:
1 parent
1d0303d030
commit
6a4ee8c6b0
9 files changed
+425
-82
No files matched your search
@@ -99,4 +99,14 @@ public interface IMEInventoryHandler<StackType extends IAEStack> extends IMEInve
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the network inventory (if any) that is being accessed. This should only return a value for inventories that
|
||||
* connect two ME networks (= storage bus on interface).
|
||||
*
|
||||
* @return the accessed network inventory
|
||||
*/
|
||||
default IMENetworkInventory<StackType> getExternalNetworkInventory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* The MIT License (MIT) Copyright (c) 2013 AlgorithmX2 Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software
|
||||
* without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions: The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
|
||||
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package appeng.api.storage;
|
||||
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
|
||||
public interface IMENetworkInventory<StackType extends IAEStack> extends IMEInventoryHandler<StackType> {
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.IMEMonitorHandlerReceiver;
|
||||
import appeng.api.storage.IMENetworkInventory;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
@@ -165,6 +166,16 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T> {
|
||||
return this.getHandler().validForPass(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public IMENetworkInventory<T> getExternalNetworkInventory() {
|
||||
IMEInventoryHandler<T> handler = this.getHandler();
|
||||
if (handler instanceof IMENetworkInventory<?>networkInventory) {
|
||||
return (IMENetworkInventory<T>) networkInventory;
|
||||
}
|
||||
return handler.getExternalNetworkInventory();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public IMEInventoryHandler<T> getHandler() {
|
||||
|
||||
@@ -21,6 +21,7 @@ import appeng.api.config.StorageFilter;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IMENetworkInventory;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
@@ -249,6 +250,15 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
|
||||
return isSticky || this.internal.getSticky();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public IMENetworkInventory<T> getExternalNetworkInventory() {
|
||||
if (internal instanceof IMENetworkInventory<?>networkInventory) {
|
||||
return (IMENetworkInventory<T>) networkInventory;
|
||||
}
|
||||
return this.internal.getExternalNetworkInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMEInventory<T> getInternal() {
|
||||
return this.internal;
|
||||
|
||||
@@ -77,8 +77,12 @@ public class MEMonitorPassThrough<T extends IAEStack<T>> extends MEPassThrough<T
|
||||
if (out instanceof ItemFilterList) {
|
||||
return super.getAvailableItems(out, iterator);
|
||||
}
|
||||
super.getAvailableItems(new ItemListIgnoreCrafting(out), iterator);
|
||||
return out;
|
||||
IItemList<T> ret = super.getAvailableItems(new ItemListIgnoreCrafting(out), iterator);
|
||||
if (ret instanceof ItemListIgnoreCrafting) {
|
||||
return out;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,6 +18,7 @@ import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IMENetworkInventory;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
@@ -109,6 +110,18 @@ public class MEPassThrough<T extends IAEStack<T>> implements IMEInventoryHandler
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public IMENetworkInventory<T> getExternalNetworkInventory() {
|
||||
if (internal instanceof IMENetworkInventory<?>networkInventory) {
|
||||
return (IMENetworkInventory<T>) networkInventory;
|
||||
}
|
||||
if (internal instanceof IMEInventoryHandler<?>inventoryHandler) {
|
||||
return (IMENetworkInventory<T>) inventoryHandler.getExternalNetworkInventory();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
StorageChannel getWrappedChannel() {
|
||||
return this.wrappedChannel;
|
||||
}
|
||||
|
||||
@@ -28,13 +28,16 @@ import appeng.api.networking.security.ISecurityGrid;
|
||||
import appeng.api.networking.security.MachineSource;
|
||||
import appeng.api.networking.security.PlayerSource;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IMENetworkInventory;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.me.cache.SecurityCache;
|
||||
import appeng.util.SortedArrayList;
|
||||
import appeng.util.inv.ItemListIgnoreCrafting;
|
||||
import appeng.util.item.NetworkItemList;
|
||||
|
||||
public class NetworkInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHandler<T> {
|
||||
public class NetworkInventoryHandler<T extends IAEStack<T>> implements IMENetworkInventory<T> {
|
||||
|
||||
private static final ThreadLocal<LinkedList> DEPTH_MOD = new ThreadLocal<>();
|
||||
private static final ThreadLocal<LinkedList> DEPTH_SIM = new ThreadLocal<>();
|
||||
@@ -77,6 +80,7 @@ public class NetworkInventoryHandler<T extends IAEStack<T>> implements IMEInvent
|
||||
private final SecurityCache security;
|
||||
private final List<IMEInventoryHandler<T>> priorityInventory;
|
||||
private int myPass = 0;
|
||||
private NetworkItemList<T> iterationItems = null;
|
||||
|
||||
public NetworkInventoryHandler(final StorageChannel chan, final SecurityCache security) {
|
||||
this.myChannel = chan;
|
||||
@@ -289,51 +293,97 @@ public class NetworkInventoryHandler<T extends IAEStack<T>> implements IMEInvent
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public IItemList<T> getAvailableItems(IItemList out, int iteration) {
|
||||
if (this.diveIteration(this, Actionable.SIMULATE, iteration)) {
|
||||
return out;
|
||||
return this.iterationItems == null ? out : this.iterationItems;
|
||||
}
|
||||
|
||||
final boolean isIgnoreCrafting = out instanceof ItemListIgnoreCrafting;
|
||||
final boolean isSource = this.getDepth(Actionable.SIMULATE).size() == 1;
|
||||
|
||||
final NetworkItemList<T> networkItemList = new NetworkItemList<>(
|
||||
this,
|
||||
() -> (IItemList<T>) getChannel().createList());
|
||||
this.iterationItems = networkItemList;
|
||||
|
||||
final IItemList<T> currentNetworkItemList = isIgnoreCrafting
|
||||
? new ItemListIgnoreCrafting<>((IItemList<T>) getChannel().createList())
|
||||
: (IItemList<T>) getChannel().createList();
|
||||
final List<IMEInventoryHandler<T>> priorityInventory = this.priorityInventory;
|
||||
final int size = priorityInventory.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
out = priorityInventory.get(i).getAvailableItems(out, iteration);
|
||||
final IMEInventoryHandler<T> inv = priorityInventory.get(i);
|
||||
final IMENetworkInventory<T> externalNetworkInventory = inv.getExternalNetworkInventory();
|
||||
if (externalNetworkInventory == this) {
|
||||
continue; // ignore any attempts to read self
|
||||
}
|
||||
final IItemList<T> passedInList = getChannel().createList();
|
||||
final IItemList<T> passedOutList = inv.getAvailableItems(passedInList, iteration);
|
||||
|
||||
if (externalNetworkInventory != null && passedOutList instanceof NetworkItemList) {
|
||||
networkItemList.addNetworkItems(externalNetworkInventory, passedOutList);
|
||||
} else {
|
||||
for (T item : passedOutList) {
|
||||
currentNetworkItemList.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
networkItemList.addNetworkItems(this, currentNetworkItemList);
|
||||
|
||||
this.surface(this, Actionable.SIMULATE);
|
||||
|
||||
return out;
|
||||
|
||||
// we're partially violating the api by making the returned list a different one from the provided one, however
|
||||
// when we're done with the network inventory scan we fulfill our api contract again
|
||||
return isSource ? networkItemList.buildFinalItemList(out) : networkItemList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getAvailableItem(@Nonnull T request, int iteration) {
|
||||
long count = 0;
|
||||
|
||||
if (this.diveIteration(this, Actionable.SIMULATE, iteration)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final List<IMEInventoryHandler<T>> priorityInventory = this.priorityInventory;
|
||||
final int size = priorityInventory.size();
|
||||
boolean readsFromOtherNetwork = false;
|
||||
for (int i = 0; i < size; i++) {
|
||||
IMEInventoryHandler<T> j = priorityInventory.get(i);
|
||||
final T stack = j.getAvailableItem(request, iteration);
|
||||
if (stack != null && stack.getStackSize() > 0) {
|
||||
count += stack.getStackSize();
|
||||
if (count < 0) {
|
||||
// overflow
|
||||
count = Long.MAX_VALUE;
|
||||
if (priorityInventory.get(i).getExternalNetworkInventory() != null) {
|
||||
readsFromOtherNetwork = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (readsFromOtherNetwork) {
|
||||
final T stack = this.getAvailableItems(getChannel().createList(), iteration).findPrecise(request);
|
||||
count = addStackCount(stack, count);
|
||||
} else {
|
||||
if (this.diveIteration(this, Actionable.SIMULATE, iteration)) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
IMEInventoryHandler<T> j = priorityInventory.get(i);
|
||||
final T stack = j.getAvailableItem(request, iteration);
|
||||
count = addStackCount(stack, count);
|
||||
if (count == Long.MAX_VALUE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.surface(this, Actionable.SIMULATE);
|
||||
}
|
||||
|
||||
this.surface(this, Actionable.SIMULATE);
|
||||
|
||||
return count == 0 ? null : request.copy().setStackSize(count);
|
||||
}
|
||||
|
||||
private long addStackCount(T stack, long count) {
|
||||
if (stack != null && stack.getStackSize() > 0) {
|
||||
count += stack.getStackSize();
|
||||
if (count < 0) {
|
||||
// overflow
|
||||
count = Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private boolean diveIteration(final NetworkInventoryHandler<T> networkInventoryHandler, final Actionable type,
|
||||
int iteration) {
|
||||
if (iteration == this.myPass) {
|
||||
@@ -407,4 +457,5 @@ public class NetworkInventoryHandler<T extends IAEStack<T>> implements IMEInvent
|
||||
public boolean validForPass(final int i) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +1,16 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.me.cache.NetworkMonitor;
|
||||
import appeng.util.item.ItemFilterList;
|
||||
import appeng.util.item.NetworkItemList;
|
||||
|
||||
public class StorageBusInventoryHandler<T extends IAEStack<T>> extends MEInventoryHandler<T> {
|
||||
|
||||
private static final ThreadLocal<Map<Integer, Map<NetworkInventoryHandler<?>, IItemList<?>>>> networkItemsForIteration = new ThreadLocal<>();
|
||||
|
||||
public StorageBusInventoryHandler(IMEInventory<T> i, StorageChannel channel) {
|
||||
super(i, channel);
|
||||
}
|
||||
@@ -39,65 +33,24 @@ public class StorageBusInventoryHandler<T extends IAEStack<T>> extends MEInvento
|
||||
@Override
|
||||
protected IItemList<T> filterAvailableItems(IItemList<T> out, int iteration) {
|
||||
Predicate<T> filterCondition = this.getExtractFilterCondition();
|
||||
getAvailableItems(out, iteration, filterCondition);
|
||||
return out;
|
||||
return getAvailableItems(out, iteration, filterCondition);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private IItemList<T> getAvailableItems(IItemList<T> out, int iteration, Predicate<T> filterCondition) {
|
||||
final IItemList<T> allAvailableItems = this.getAllAvailableItems(iteration);
|
||||
Iterator<T> it = allAvailableItems.iterator();
|
||||
while (it.hasNext()) {
|
||||
T items = it.next();
|
||||
if (filterCondition.test(items)) {
|
||||
out.add(items);
|
||||
// have to remove the item otherwise it could be counted double
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private IItemList<T> getAllAvailableItems(int iteration) {
|
||||
NetworkInventoryHandler<T> networkInventoryHandler = getNetworkInventoryHandler();
|
||||
if (networkInventoryHandler == null) {
|
||||
return this.getInternal()
|
||||
.getAvailableItems((IItemList<T>) this.getInternal().getChannel().createList(), iteration);
|
||||
}
|
||||
|
||||
Map<Integer, Map<NetworkInventoryHandler<?>, IItemList<?>>> s = networkItemsForIteration.get();
|
||||
if (s != null && !s.containsKey(iteration)) {
|
||||
s = null;
|
||||
}
|
||||
if (s == null) {
|
||||
s = Collections.singletonMap(iteration, new IdentityHashMap<>());
|
||||
networkItemsForIteration.set(s);
|
||||
}
|
||||
Map<NetworkInventoryHandler<?>, IItemList<?>> networkInventoryItems = s.get(iteration);
|
||||
if (!networkInventoryItems.containsKey(networkInventoryHandler)) {
|
||||
IItemList<T> allAvailableItems = this.getInternal()
|
||||
.getAvailableItems((IItemList<T>) this.getInternal().getChannel().createList(), iteration);
|
||||
networkInventoryItems.put(networkInventoryHandler, allAvailableItems);
|
||||
}
|
||||
|
||||
return (IItemList<T>) networkInventoryItems.get(networkInventoryHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the NetworkInventoryHandler for this storage bus
|
||||
*/
|
||||
private NetworkInventoryHandler<T> getNetworkInventoryHandler() {
|
||||
return (NetworkInventoryHandler<T>) findNetworkInventoryHandler(this.getInternal());
|
||||
}
|
||||
|
||||
private NetworkInventoryHandler<?> findNetworkInventoryHandler(IMEInventory<?> inventory) {
|
||||
if (inventory instanceof MEPassThrough<?>passThrough) {
|
||||
return findNetworkInventoryHandler(passThrough.getInternal());
|
||||
} else if (inventory instanceof NetworkMonitor<?>networkMonitor) {
|
||||
return findNetworkInventoryHandler(networkMonitor.getHandler());
|
||||
} else if (inventory instanceof NetworkInventoryHandler<?>networkInventoryHandler) {
|
||||
return networkInventoryHandler;
|
||||
final IItemList<T> availableItems = this.getInternal()
|
||||
.getAvailableItems((IItemList<T>) getChannel().createList(), iteration);
|
||||
if (availableItems instanceof NetworkItemList) {
|
||||
NetworkItemList<T> networkItemList = new NetworkItemList<>((NetworkItemList<T>) availableItems);
|
||||
networkItemList.addFilter(filterCondition);
|
||||
return networkItemList;
|
||||
} else {
|
||||
return null;
|
||||
for (T items : availableItems) {
|
||||
if (filterCondition.test(items)) {
|
||||
out.add(items);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2. Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved. Applied
|
||||
* Energistics 2 is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
|
||||
* Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version. Applied Energistics 2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
||||
* Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
|
||||
* Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.util.item;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import appeng.api.config.FuzzyMode;
|
||||
import appeng.api.storage.IMENetworkInventory;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
|
||||
/**
|
||||
* A NetworkItemList contains one or more IItemLists from different networks. These IItemLists can themselves be
|
||||
* NetworkItemLists. This allows us to filter items from multiple, or same networks with different filters while also
|
||||
* including all their subnetworks and filters.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class NetworkItemList<T extends IAEStack> implements IItemList<T> {
|
||||
|
||||
/**
|
||||
* The network this list was created for.
|
||||
*/
|
||||
private final IMENetworkInventory<T> network;
|
||||
/**
|
||||
* The networks and their items that were read from this {@code network}. For non-network inventories the
|
||||
* network-key is equal to {@code network}.
|
||||
*/
|
||||
private final Map<IMENetworkInventory<T>, IItemList<T>> networkItemLists;
|
||||
private final Supplier<IItemList<T>> newItemListSupplier;
|
||||
private final List<Predicate<T>> predicates;
|
||||
|
||||
public NetworkItemList(IMENetworkInventory<T> network, Supplier<IItemList<T>> newItemListSupplier) {
|
||||
this.network = network;
|
||||
this.networkItemLists = new HashMap<>();
|
||||
this.predicates = new ArrayList<>();
|
||||
this.newItemListSupplier = newItemListSupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shallow copy of a network item list. Filters are not copied.
|
||||
*
|
||||
* @param networkItemList the list to copy from
|
||||
*/
|
||||
public NetworkItemList(NetworkItemList<T> networkItemList) {
|
||||
this.network = networkItemList.network;
|
||||
this.predicates = new ArrayList<>();
|
||||
this.networkItemLists = networkItemList.networkItemLists;
|
||||
this.newItemListSupplier = networkItemList.newItemListSupplier;
|
||||
}
|
||||
|
||||
public void addNetworkItems(IMENetworkInventory<T> network, IItemList<T> itemList) {
|
||||
IItemList<T> l = networkItemLists.get(network);
|
||||
|
||||
if (l instanceof NetworkItemList) {
|
||||
if (itemList instanceof NetworkItemList) {
|
||||
// since the network is the same we combine the predicates
|
||||
for (Predicate<T> filter : ((NetworkItemList<T>) itemList).predicates) {
|
||||
((NetworkItemList<T>) l).addFilter(filter);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"This NetworkItemList already contains a NetworkItemList for the provided network and cannot replace it with a non-NetworkItemList");
|
||||
}
|
||||
} else if (l != null) {
|
||||
throw new RuntimeException(
|
||||
"This NetworkItemList already contains a non-NetworkItemList for the provided network and cannot replace it");
|
||||
}
|
||||
networkItemLists.put(network, itemList);
|
||||
}
|
||||
|
||||
private Stream<NetworkItemStack<T>> getNetworkItemStackStream(final Set<IMENetworkInventory<T>> visitedNetworks) {
|
||||
return networkItemLists.entrySet().stream()
|
||||
// equivalent to a worse performing mapMulti
|
||||
.flatMap(entry -> {
|
||||
if (entry.getValue() instanceof NetworkItemList) {
|
||||
if (visitedNetworks.contains(entry.getKey())) {
|
||||
return Stream.empty();
|
||||
}
|
||||
final Set<IMENetworkInventory<T>> localVisitedNetworks = new HashSet<>(visitedNetworks);
|
||||
localVisitedNetworks.add(entry.getKey());
|
||||
return ((NetworkItemList<T>) entry.getValue())
|
||||
.getFilteredNetworkItemStackStream(Collections.unmodifiableSet(localVisitedNetworks));
|
||||
} else {
|
||||
List<NetworkItemStack<T>> buffer = new ArrayList<>();
|
||||
StreamSupport.stream(entry.getValue().spliterator(), false)
|
||||
.forEach(item -> buffer.add(new NetworkItemStack<>(entry.getKey(), item)));
|
||||
return buffer.stream();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Stream<NetworkItemStack<T>> filter(Stream<NetworkItemStack<T>> stream) {
|
||||
Predicate<T> predicate = buildFilter();
|
||||
if (predicate == null) return stream;
|
||||
else return stream.filter(e -> predicate.test(e.getItemStack()));
|
||||
}
|
||||
|
||||
public Stream<T> getItems() {
|
||||
return getFilteredNetworkItemStackStream().distinct().map(NetworkItemStack::getItemStack);
|
||||
}
|
||||
|
||||
private Stream<NetworkItemStack<T>> getFilteredNetworkItemStackStream() {
|
||||
Set<IMENetworkInventory<T>> visitedNetworks = new HashSet<>();
|
||||
visitedNetworks.add(this.network);
|
||||
return filter(getNetworkItemStackStream(Collections.unmodifiableSet(visitedNetworks)));
|
||||
}
|
||||
|
||||
private Stream<NetworkItemStack<T>> getFilteredNetworkItemStackStream(
|
||||
final Set<IMENetworkInventory<T>> visitedNetworks) {
|
||||
return filter(getNetworkItemStackStream(visitedNetworks));
|
||||
}
|
||||
|
||||
public void addFilter(Predicate<T> filter) {
|
||||
predicates.add(filter);
|
||||
}
|
||||
|
||||
private Predicate<T> buildFilter() {
|
||||
Predicate<T> predicate = null;
|
||||
for (Predicate<T> filter : predicates) {
|
||||
if (predicate == null) {
|
||||
predicate = filter;
|
||||
} else {
|
||||
predicate = predicate.or(filter);
|
||||
}
|
||||
}
|
||||
return predicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes all available items to a new combined list.
|
||||
*
|
||||
* @return the available items in the network as a combined IItemList
|
||||
*/
|
||||
public IItemList<T> buildFinalItemList() {
|
||||
IItemList<T> out = newItemListSupplier.get();
|
||||
return buildFinalItemList(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes all available items to the provided list.
|
||||
*
|
||||
* @param out the IItemList the results will be written to
|
||||
* @return returns same list that was passed in, is passed out
|
||||
*/
|
||||
public IItemList<T> buildFinalItemList(IItemList<T> out) {
|
||||
getItems().forEach(out::add);
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStorage(T option) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCrafting(T option) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRequestable(T option) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getFirstItem() {
|
||||
return getItems().findFirst().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return (int) getItems().count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return getItems().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetStatus() {
|
||||
for (IItemList<T> list : networkItemLists.values()) {
|
||||
list.resetStatus();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(T option) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T findPrecise(T i) {
|
||||
return buildFinalItemList().findPrecise(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> findFuzzy(final T input, final FuzzyMode fuzzy) {
|
||||
return buildFinalItemList().findFuzzy(input, fuzzy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return !getItems().findAny().isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getStackType() {
|
||||
IItemList<T> list = networkItemLists.values().stream().findAny().orElse(null);
|
||||
return list == null ? LIST_NUll : list.getStackType();
|
||||
}
|
||||
|
||||
private class NetworkItemStack<U extends IAEStack> {
|
||||
|
||||
private final IMENetworkInventory<U> networkInventory;
|
||||
private final U itemStack;
|
||||
|
||||
public NetworkItemStack(IMENetworkInventory<U> networkInventory, U itemStack) {
|
||||
this.networkInventory = networkInventory;
|
||||
this.itemStack = itemStack;
|
||||
}
|
||||
|
||||
public IMENetworkInventory<U> getNetworkInventory() {
|
||||
return networkInventory;
|
||||
}
|
||||
|
||||
public U getItemStack() {
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof NetworkItemStack)) return false;
|
||||
NetworkItemStack<?> that = (NetworkItemStack<?>) o;
|
||||
// only use reference equality
|
||||
return networkInventory == that.networkInventory && itemStack == that.itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int hash = 1;
|
||||
// only use identity for hash
|
||||
hash = hash * prime + System.identityHashCode(networkInventory);
|
||||
hash = hash * prime + System.identityHashCode(itemStack);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user