216 lines
8.2 KiB
Java
216 lines
8.2 KiB
Java
package appeng.parts.misc;
|
|
|
|
import appeng.api.AEApi;
|
|
import appeng.api.config.AccessRestriction;
|
|
import appeng.api.config.Actionable;
|
|
import appeng.api.config.Settings;
|
|
import appeng.api.networking.security.IActionSource;
|
|
import appeng.api.networking.storage.IBaseMonitor;
|
|
import appeng.api.networking.ticking.TickRateModulation;
|
|
import appeng.api.storage.IMEInventory;
|
|
import appeng.api.storage.IMEMonitorHandlerReceiver;
|
|
import appeng.api.storage.IStorageChannel;
|
|
import appeng.api.storage.channels.IItemStorageChannel;
|
|
import appeng.api.storage.data.IAEItemStack;
|
|
import appeng.api.storage.data.IItemList;
|
|
import appeng.core.AELog;
|
|
import appeng.me.GridAccessException;
|
|
import appeng.me.helpers.IGridProxyable;
|
|
import appeng.me.storage.ITickingMonitor;
|
|
import appeng.util.item.AEItemStack;
|
|
import com.google.common.primitives.Ints;
|
|
import com.jaquadro.minecraft.storagedrawers.api.capabilities.IItemRepository;
|
|
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
|
import net.minecraft.item.ItemStack;
|
|
|
|
import java.util.*;
|
|
|
|
|
|
/**
|
|
* Wraps an Item Repository in such a way that it can be used as an IMEInventory for items.
|
|
* Used by the Storage Bus
|
|
*/
|
|
|
|
class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAEItemStack>, ITickingMonitor {
|
|
private final Object2ObjectMap<IMEMonitorHandlerReceiver<IAEItemStack>, Object> listeners = new Object2ObjectOpenHashMap<>();
|
|
private IActionSource mySource;
|
|
private final IItemRepository itemRepository;
|
|
private final IGridProxyable proxyable;
|
|
private final InventoryCache cache;
|
|
private AccessRestriction access;
|
|
|
|
ItemRepositoryAdapter(IItemRepository itemRepository, IGridProxyable proxy) {
|
|
this.itemRepository = itemRepository;
|
|
this.proxyable = proxy;
|
|
this.cache = new InventoryCache(this.itemRepository);
|
|
if (this.proxyable instanceof PartStorageBus) {
|
|
PartStorageBus partStorageBus = (PartStorageBus) this.proxyable;
|
|
this.access = ((AccessRestriction) partStorageBus.getConfigManager().getSetting(Settings.ACCESS));
|
|
}
|
|
this.cache.update();
|
|
}
|
|
|
|
@Override
|
|
public IAEItemStack injectItems(IAEItemStack iox, Actionable type, IActionSource src) {
|
|
// Try to reuse the cached stack
|
|
ItemStack inputStack = iox.getCachedItemStack(iox.getStackSize());
|
|
|
|
ItemStack remaining;
|
|
|
|
remaining = this.itemRepository.insertItem(inputStack, type == Actionable.SIMULATE);
|
|
|
|
// Store the stack in the cache for next time.
|
|
if (type == Actionable.SIMULATE) {
|
|
iox.setCachedItemStack(inputStack);
|
|
} else {
|
|
if (!remaining.isEmpty()) {
|
|
iox.setCachedItemStack(remaining);
|
|
}
|
|
}
|
|
|
|
// At this point, we still have some items left...
|
|
if (remaining == inputStack) {
|
|
// The stack remained unmodified, target inventory is full
|
|
return iox;
|
|
}
|
|
|
|
if (type == Actionable.MODULATE) {
|
|
IAEItemStack added = iox.copy().setStackSize(iox.getStackSize() - remaining.getCount());
|
|
this.cache.currentlyCached.add(added);
|
|
this.postDifference(Collections.singletonList(added));
|
|
try {
|
|
this.proxyable.getProxy().getTick().alertDevice(this.proxyable.getProxy().getNode());
|
|
} catch (GridAccessException ex) {
|
|
// meh
|
|
}
|
|
}
|
|
|
|
return AEItemStack.fromItemStack(remaining);
|
|
|
|
}
|
|
|
|
@Override
|
|
public IAEItemStack extractItems(IAEItemStack request, Actionable mode, IActionSource src) {
|
|
int remainingSize = Ints.saturatedCast(request.getStackSize());
|
|
|
|
final boolean simulate = (mode == Actionable.SIMULATE);
|
|
|
|
ItemStack extracted = this.itemRepository.extractItem(request.getDefinition(), remainingSize, simulate);
|
|
|
|
if (extracted.getCount() > remainingSize) {
|
|
// Something broke. It should never return more than we requested...
|
|
// We're going to silently eat the remainder
|
|
AELog.warn("Mod that provided item handler %s is broken. Returned %s items while only requesting %d.", this.itemRepository.getClass().getName(), extracted.toString(), remainingSize);
|
|
extracted.setCount(remainingSize);
|
|
}
|
|
|
|
if (!extracted.isEmpty()) {
|
|
IAEItemStack extractedAEItemStack = AEItemStack.fromItemStack(extracted);
|
|
if (mode == Actionable.MODULATE) {
|
|
IAEItemStack cachedStack = this.cache.currentlyCached.findPrecise(request);
|
|
if (cachedStack != null) {
|
|
cachedStack.decStackSize(extractedAEItemStack.getStackSize());
|
|
this.postDifference(Collections.singletonList(extractedAEItemStack.copy().setStackSize(-extractedAEItemStack.getStackSize())));
|
|
}
|
|
try {
|
|
this.proxyable.getProxy().getTick().alertDevice(this.proxyable.getProxy().getNode());
|
|
} catch (GridAccessException ex) {
|
|
// meh
|
|
}
|
|
}
|
|
return extractedAEItemStack;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public IItemList<IAEItemStack> getAvailableItems(IItemList<IAEItemStack> out) {
|
|
return this.cache.getAvailableItems(out);
|
|
}
|
|
|
|
@Override
|
|
public IStorageChannel<IAEItemStack> getChannel() {
|
|
return AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class);
|
|
}
|
|
|
|
@Override
|
|
public void addListener(IMEMonitorHandlerReceiver<IAEItemStack> l, Object verificationToken) {
|
|
this.listeners.put(l, verificationToken);
|
|
}
|
|
|
|
@Override
|
|
public void removeListener(IMEMonitorHandlerReceiver<IAEItemStack> l) {
|
|
this.listeners.remove(l);
|
|
}
|
|
|
|
private void postDifference(Iterable<IAEItemStack> a) {
|
|
final Iterator<Map.Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object>> i = this.listeners.entrySet().iterator();
|
|
while (i.hasNext()) {
|
|
final Map.Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object> l = i.next();
|
|
final IMEMonitorHandlerReceiver<IAEItemStack> key = l.getKey();
|
|
if (key.isValid(l.getValue())) {
|
|
key.postChange(this, a, this.mySource);
|
|
} else {
|
|
i.remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public TickRateModulation onTick() {
|
|
List<IAEItemStack> changes = this.cache.update();
|
|
if (!changes.isEmpty() && access.hasPermission(AccessRestriction.READ)) {
|
|
this.postDifference(changes);
|
|
return TickRateModulation.URGENT;
|
|
} else {
|
|
return TickRateModulation.SLOWER;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setActionSource(final IActionSource mySource) {
|
|
this.mySource = mySource;
|
|
}
|
|
|
|
private static class InventoryCache {
|
|
private IItemList<IAEItemStack> currentlyCached = AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createList();
|
|
private final IItemRepository iItemRepository;
|
|
|
|
public InventoryCache(IItemRepository iItemRepository) {
|
|
this.iItemRepository = iItemRepository;
|
|
}
|
|
|
|
public IItemList<IAEItemStack> getAvailableItems(IItemList<IAEItemStack> out) {
|
|
currentlyCached.iterator().forEachRemaining(out::add);
|
|
return out;
|
|
}
|
|
|
|
public List<IAEItemStack> update() {
|
|
final List<IAEItemStack> changes = new ArrayList<>();
|
|
|
|
IItemList<IAEItemStack> currentlyOnStorage = AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createList();
|
|
this.iItemRepository.getAllItems().stream().map(s -> AEItemStack.fromItemStack(s.itemPrototype).setStackSize(s.count)).forEach(currentlyOnStorage::add);
|
|
|
|
for (final IAEItemStack is : currentlyCached) {
|
|
is.setStackSize(-is.getStackSize());
|
|
}
|
|
|
|
for (final IAEItemStack is : currentlyOnStorage) {
|
|
currentlyCached.add(is);
|
|
}
|
|
|
|
for (final IAEItemStack is : currentlyCached) {
|
|
if (is.getStackSize() != 0) {
|
|
changes.add(is);
|
|
}
|
|
}
|
|
|
|
currentlyCached = currentlyOnStorage;
|
|
|
|
return changes;
|
|
}
|
|
|
|
}
|
|
}
|