diff --git a/src/main/java/gripe/_90/appliede/me/strategy/EMCExportStrategy.java b/src/main/java/gripe/_90/appliede/me/strategy/EMCExportStrategy.java index e402899..105c441 100644 --- a/src/main/java/gripe/_90/appliede/me/strategy/EMCExportStrategy.java +++ b/src/main/java/gripe/_90/appliede/me/strategy/EMCExportStrategy.java @@ -1,5 +1,7 @@ package gripe._90.appliede.me.strategy; +import java.util.concurrent.atomic.AtomicLong; + import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; @@ -9,7 +11,6 @@ import appeng.api.config.Actionable; import appeng.api.stacks.AEKey; import appeng.api.storage.StorageHelper; -import appeng.util.BlockApiCache; import gripe._90.appliede.me.key.EMCKey; @@ -17,24 +18,22 @@ import moze_intel.projecte.api.capabilities.block_entity.IEmcStorage; @SuppressWarnings("UnstableApiUsage") -public class EMCExportStrategy implements StackExportStrategy { - private final BlockApiCache<IEmcStorage> apiCache; - private final Direction fromSide; - - public EMCExportStrategy(ServerLevel level, BlockPos fromPos, Direction fromSide) { - apiCache = BlockApiCache.create(PECapabilities.EMC_STORAGE_CAPABILITY, level, fromPos); - this.fromSide = fromSide; - } - +public record EMCExportStrategy(ServerLevel level, BlockPos pos, Direction side) implements StackExportStrategy { @Override public long transfer(StackTransferContext context, AEKey what, long maxAmount) { if (!(what instanceof EMCKey)) { return 0; } - var emcStorage = apiCache.find(fromSide); + var be = level.getBlockEntity(pos); + + if (be == null) { + return 0; + } + + var transferred = new AtomicLong(0); - if (emcStorage != null) { + be.getCapability(PECapabilities.EMC_STORAGE_CAPABILITY).ifPresent(emcStorage -> { var insertable = emcStorage.insertEmc(maxAmount, IEmcStorage.EmcAction.SIMULATE); var extracted = StorageHelper.poweredExtraction( context.getEnergySource(), @@ -48,10 +47,10 @@ public long transfer(StackTransferContext context, AEKey what, long maxAmount) { emcStorage.insertEmc(extracted, IEmcStorage.EmcAction.EXECUTE); } - return extracted; - } + transferred.addAndGet(extracted); + }); - return 0; + return transferred.get(); } @Override @@ -60,18 +59,24 @@ public long push(AEKey what, long maxAmount, Actionable mode) { return 0; } - var emcStorage = apiCache.find(fromSide); + var be = level.getBlockEntity(pos); - if (emcStorage != null) { + if (be == null) { + return 0; + } + + var transferred = new AtomicLong(0); + + be.getCapability(PECapabilities.EMC_STORAGE_CAPABILITY).ifPresent(emcStorage -> { var inserted = Math.min(maxAmount, emcStorage.insertEmc(maxAmount, IEmcStorage.EmcAction.SIMULATE)); if (inserted > 0) { emcStorage.insertEmc(inserted, IEmcStorage.EmcAction.EXECUTE); } - return inserted; - } + transferred.addAndGet(inserted); + }); - return 0; + return transferred.get(); } } diff --git a/src/main/java/gripe/_90/appliede/me/strategy/EMCImportStrategy.java b/src/main/java/gripe/_90/appliede/me/strategy/EMCImportStrategy.java index 86d4e81..6a66f71 100644 --- a/src/main/java/gripe/_90/appliede/me/strategy/EMCImportStrategy.java +++ b/src/main/java/gripe/_90/appliede/me/strategy/EMCImportStrategy.java @@ -1,5 +1,7 @@ package gripe._90.appliede.me.strategy; +import java.util.concurrent.atomic.AtomicLong; + import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; @@ -8,7 +10,6 @@ import appeng.api.behaviors.StackTransferContext; import appeng.api.config.Actionable; import appeng.api.storage.StorageHelper; -import appeng.util.BlockApiCache; import gripe._90.appliede.me.key.EMCKey; import gripe._90.appliede.me.key.EMCKeyType; @@ -17,42 +18,37 @@ import moze_intel.projecte.api.capabilities.block_entity.IEmcStorage; @SuppressWarnings("UnstableApiUsage") -public class EMCImportStrategy implements StackImportStrategy { - private final BlockApiCache<IEmcStorage> apiCache; - private final Direction fromSide; - - public EMCImportStrategy(ServerLevel level, BlockPos fromPos, Direction fromSide) { - apiCache = BlockApiCache.create(PECapabilities.EMC_STORAGE_CAPABILITY, level, fromPos); - this.fromSide = fromSide; - } - +public record EMCImportStrategy(ServerLevel level, BlockPos pos, Direction side) implements StackImportStrategy { @Override public boolean transfer(StackTransferContext context) { if (!context.isKeyTypeEnabled(EMCKeyType.TYPE)) { return false; } - var emcStorage = apiCache.find(fromSide); + var be = level.getBlockEntity(pos); - if (emcStorage == null) { + if (be == null) { return false; } var remainingTransfer = context.getOperationsRemaining() * EMCKeyType.TYPE.getAmountPerOperation(); - var inserted = Math.min(remainingTransfer, emcStorage.getStoredEmc()); - - StorageHelper.poweredInsert( - context.getEnergySource(), - context.getInternalStorage().getInventory(), - EMCKey.BASE, - inserted, - context.getActionSource(), - Actionable.MODULATE); - emcStorage.extractEmc(inserted, IEmcStorage.EmcAction.EXECUTE); - - var opsUsed = Math.max(1, inserted / EMCKeyType.TYPE.getAmountPerOperation()); - context.reduceOperationsRemaining(opsUsed); - - return inserted > 0; + var inserted = new AtomicLong(0); + + be.getCapability(PECapabilities.EMC_STORAGE_CAPABILITY).ifPresent(emcStorage -> { + inserted.set(Math.min(remainingTransfer, emcStorage.getStoredEmc())); + StorageHelper.poweredInsert( + context.getEnergySource(), + context.getInternalStorage().getInventory(), + EMCKey.BASE, + inserted.get(), + context.getActionSource(), + Actionable.MODULATE); + emcStorage.extractEmc(inserted.get(), IEmcStorage.EmcAction.EXECUTE); + + var opsUsed = Math.max(1, inserted.get() / EMCKeyType.TYPE.getAmountPerOperation()); + context.reduceOperationsRemaining(opsUsed); + }); + + return inserted.get() > 0; } } diff --git a/src/main/java/gripe/_90/appliede/me/strategy/EMCItemExportStrategy.java b/src/main/java/gripe/_90/appliede/me/strategy/EMCItemExportStrategy.java deleted file mode 100644 index 7cccd58..0000000 --- a/src/main/java/gripe/_90/appliede/me/strategy/EMCItemExportStrategy.java +++ /dev/null @@ -1,94 +0,0 @@ -package gripe._90.appliede.me.strategy; - -import com.google.common.primitives.Ints; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.server.level.ServerLevel; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemHandlerHelper; - -import appeng.api.behaviors.StackExportStrategy; -import appeng.api.behaviors.StackTransferContext; -import appeng.api.config.Actionable; -import appeng.api.stacks.AEItemKey; -import appeng.api.stacks.AEKey; -import appeng.util.BlockApiCache; - -@SuppressWarnings("UnstableApiUsage") -public class EMCItemExportStrategy implements StackExportStrategy { - private static final Logger LOGGER = LoggerFactory.getLogger(EMCItemExportStrategy.class); - - private final BlockApiCache<IItemHandler> apiCache; - private final Direction fromSide; - - public EMCItemExportStrategy(ServerLevel level, BlockPos fromPos, Direction fromSide) { - apiCache = BlockApiCache.create(ForgeCapabilities.ITEM_HANDLER, level, fromPos); - this.fromSide = fromSide; - } - - @Override - public long transfer(StackTransferContext context, AEKey what, long amount) { - if (!(context instanceof EMCTransferContext emcContext)) { - return 0; - } - - if (!(what instanceof AEItemKey item)) { - return 0; - } - - var adjacentStorage = apiCache.find(fromSide); - - if (adjacentStorage != null) { - var emcStorage = emcContext.getEmcStorage(); - var stack = item.toStack(Ints.saturatedCast(amount)); - - var extracted = emcStorage.extractItem(item, amount, Actionable.SIMULATE, context.getActionSource(), true); - var remainder = ItemHandlerHelper.insertItem(adjacentStorage, stack, true); - var wasInserted = extracted - remainder.getCount(); - - if (wasInserted > 0) { - extracted = emcStorage.extractItem(item, amount, Actionable.MODULATE, context.getActionSource(), true); - remainder = ItemHandlerHelper.insertItem(adjacentStorage, stack, false); - wasInserted = extracted - remainder.getCount(); - - if (wasInserted < extracted) { - var leftover = extracted - wasInserted; - emcStorage.insertItem(item, leftover, Actionable.MODULATE, context.getActionSource(), false); - - if (leftover > 0) { - LOGGER.error( - "Storage export: adjacent block unexpectedly refused insert, voided {}x{}", - leftover, - item); - } - } - } - - return wasInserted; - } - - return 0; - } - - @Override - public long push(AEKey what, long maxAmount, Actionable mode) { - if (!(what instanceof AEItemKey item)) { - return 0; - } - - var adjacentStorage = apiCache.find(fromSide); - - if (adjacentStorage != null) { - var stack = item.toStack(Ints.saturatedCast(maxAmount)); - var remainder = ItemHandlerHelper.insertItem(adjacentStorage, stack, mode.isSimulate()); - return maxAmount - remainder.getCount(); - } - - return 0; - } -} diff --git a/src/main/java/gripe/_90/appliede/me/strategy/EMCItemImportStrategy.java b/src/main/java/gripe/_90/appliede/me/strategy/EMCItemImportStrategy.java deleted file mode 100644 index 6826806..0000000 --- a/src/main/java/gripe/_90/appliede/me/strategy/EMCItemImportStrategy.java +++ /dev/null @@ -1,65 +0,0 @@ -package gripe._90.appliede.me.strategy; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.server.level.ServerLevel; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.items.IItemHandler; - -import appeng.api.behaviors.StackImportStrategy; -import appeng.api.behaviors.StackTransferContext; -import appeng.api.config.Actionable; -import appeng.api.stacks.AEItemKey; -import appeng.me.storage.ExternalStorageFacade; -import appeng.util.BlockApiCache; - -@SuppressWarnings("UnstableApiUsage") -public class EMCItemImportStrategy implements StackImportStrategy { - private final BlockApiCache<IItemHandler> apiCache; - private final Direction fromSide; - - public EMCItemImportStrategy(ServerLevel level, BlockPos fromPos, Direction fromSide) { - apiCache = BlockApiCache.create(ForgeCapabilities.ITEM_HANDLER, level, fromPos); - this.fromSide = fromSide; - } - - @Override - public boolean transfer(StackTransferContext context) { - if (!(context instanceof EMCTransferContext ctx)) { - return false; - } - - var itemHandler = apiCache.find(fromSide); - - if (itemHandler == null) { - return false; - } - - var adjacentStorage = ExternalStorageFacade.of(itemHandler); - var remaining = ctx.getOperationsRemaining(); - - for (var i = 0; i < adjacentStorage.getSlots() && remaining > 0; i++) { - var resource = adjacentStorage.getStackInSlot(i); - - if (resource == null || !(resource.what() instanceof AEItemKey item)) { - continue; - } - - if (context.isInFilter(resource.what()) == context.isInverted()) { - continue; - } - - var amount = adjacentStorage.extract(item, remaining, Actionable.SIMULATE, context.getActionSource()); - - if (amount > 0) { - var inserted = ctx.getEmcStorage() - .insertItem(item, amount, Actionable.MODULATE, context.getActionSource(), ctx.canLearn()); - adjacentStorage.extract(item, inserted, Actionable.MODULATE, context.getActionSource()); - context.reduceOperationsRemaining(inserted); - remaining -= (int) inserted; - } - } - - return true; - } -} diff --git a/src/main/java/gripe/_90/appliede/me/strategy/EMCTransferContext.java b/src/main/java/gripe/_90/appliede/me/strategy/EMCTransferContext.java deleted file mode 100644 index 2163926..0000000 --- a/src/main/java/gripe/_90/appliede/me/strategy/EMCTransferContext.java +++ /dev/null @@ -1,118 +0,0 @@ -package gripe._90.appliede.me.strategy; - -import com.google.common.primitives.Ints; - -import appeng.api.behaviors.StackTransferContext; -import appeng.api.networking.energy.IEnergySource; -import appeng.api.networking.security.IActionSource; -import appeng.api.networking.storage.IStorageService; -import appeng.api.stacks.AEItemKey; -import appeng.api.stacks.AEKey; -import appeng.api.stacks.AEKeyType; -import appeng.util.prioritylist.IPartitionList; - -import gripe._90.appliede.me.service.EMCStorage; - -@SuppressWarnings({"UnstableApiUsage", "NonExtendableApiUsage"}) -public class EMCTransferContext implements StackTransferContext { - private final EMCStorage emcStorage; - private final IActionSource actionSource; - private final IPartitionList filter; - private final int initialOperations; - - private int operationsRemaining; - private boolean isInverted; - private boolean canLearn; - - public EMCTransferContext( - EMCStorage emcStorage, IActionSource actionSource, IPartitionList filter, int operationsRemaining) { - this.emcStorage = emcStorage; - this.actionSource = actionSource; - this.filter = filter; - - initialOperations = operationsRemaining; - this.operationsRemaining = operationsRemaining; - } - - public EMCStorage getEmcStorage() { - return emcStorage; - } - - @Override - public IStorageService getInternalStorage() { - return null; - } - - @Override - public IEnergySource getEnergySource() { - return null; - } - - @Override - public IActionSource getActionSource() { - return actionSource; - } - - @Override - public int getOperationsRemaining() { - return operationsRemaining; - } - - @Override - public void setOperationsRemaining(int operationsRemaining) { - this.operationsRemaining = operationsRemaining; - } - - @Override - public boolean hasOperationsLeft() { - return operationsRemaining > 0; - } - - @Override - public boolean hasDoneWork() { - return initialOperations > operationsRemaining; - } - - @Override - public boolean isKeyTypeEnabled(AEKeyType space) { - return space.equals(AEKeyType.items()); - } - - @Override - public boolean isInFilter(AEKey key) { - return filter.isEmpty() || filter.isListed(key); - } - - @Override - public IPartitionList getFilter() { - return filter; - } - - @Override - public void setInverted(boolean inverted) { - isInverted = inverted; - } - - @Override - public boolean isInverted() { - return isInverted; - } - - public void setCanLearn(boolean learn) { - canLearn = learn; - } - - public boolean canLearn() { - return canLearn; - } - - @Override - public boolean canInsert(AEItemKey what, long amount) { - return true; - } - - @Override - public void reduceOperationsRemaining(long inserted) { - operationsRemaining -= Ints.saturatedCast(inserted); - } -} diff --git a/src/main/java/gripe/_90/appliede/part/EMCExportBusPart.java b/src/main/java/gripe/_90/appliede/part/EMCExportBusPart.java index 911b373..b75cb50 100644 --- a/src/main/java/gripe/_90/appliede/part/EMCExportBusPart.java +++ b/src/main/java/gripe/_90/appliede/part/EMCExportBusPart.java @@ -1,11 +1,19 @@ package gripe._90.appliede.part; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.google.common.primitives.Ints; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.inventory.MenuType; +import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.minecraftforge.items.ItemHandlerHelper; -import appeng.api.behaviors.StackExportStrategy; +import appeng.api.config.Actionable; import appeng.api.config.SchedulingMode; import appeng.api.config.Settings; import appeng.api.networking.IGrid; @@ -20,14 +28,10 @@ import appeng.menu.implementations.MenuTypeBuilder; import appeng.parts.PartModel; import appeng.parts.automation.IOBusPart; -import appeng.util.prioritylist.DefaultPriorityList; import gripe._90.appliede.AppliedE; import gripe._90.appliede.me.service.KnowledgeService; -import gripe._90.appliede.me.strategy.EMCItemExportStrategy; -import gripe._90.appliede.me.strategy.EMCTransferContext; -@SuppressWarnings("UnstableApiUsage") public class EMCExportBusPart extends IOBusPart { public static final MenuType<IOBusMenu> MENU = MenuTypeBuilder.create(IOBusMenu::new, EMCExportBusPart.class).build("emc_export_bus"); @@ -44,7 +48,8 @@ public class EMCExportBusPart extends IOBusPart { private static final PartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, AppEng.makeId("part/export_bus_has_channel")); - private StackExportStrategy strategy; + private static final Logger LOGGER = LoggerFactory.getLogger(EMCExportBusPart.class); + private int nextSlot = 0; public EMCExportBusPart(IPartItem<?> partItem) { @@ -66,59 +71,73 @@ public void writeToNBT(CompoundTag extra) { @Override protected boolean doBusWork(IGrid grid) { - var emcStorage = grid.getService(KnowledgeService.class).getStorage(); - var schedulingMode = getConfigManager().getSetting(Settings.SCHEDULING_MODE); - var context = new EMCTransferContext(emcStorage, source, DefaultPriorityList.INSTANCE, getOperationsPerTick()); - var slot = 0; + var adjacentPos = getHost().getBlockEntity().getBlockPos().relative(getSide()); + var blockEntity = getLevel().getBlockEntity(adjacentPos); - for (slot = 0; slot < availableSlots() && context.hasOperationsLeft(); slot++) { - var what = getConfig().getKey(getStartingSlot(schedulingMode, slot)); + if (blockEntity == null) { + return false; + } - if (!(what instanceof AEItemKey item)) { - continue; + var doneWork = new AtomicBoolean(false); + + blockEntity.getCapability(ForgeCapabilities.ITEM_HANDLER).ifPresent(itemHandler -> { + var emcStorage = grid.getService(KnowledgeService.class).getStorage(); + var schedulingMode = getConfigManager().getSetting(Settings.SCHEDULING_MODE); + var remaining = getOperationsPerTick(); + var slot = 0; + + for (slot = 0; slot < availableSlots() && remaining > 0; slot++) { + // spotless:off + var startingSlot = switch (schedulingMode) { + case RANDOM -> getLevel().getRandom().nextInt(availableSlots()); + case ROUNDROBIN -> (nextSlot + slot) % availableSlots(); + default -> slot; + }; + // spotless:on + var what = getConfig().getKey(startingSlot); + + if (!(what instanceof AEItemKey item)) { + continue; + } + + var stack = item.toStack(remaining); + var extracted = emcStorage.extractItem(item, remaining, Actionable.SIMULATE, source, true); + var remainder = ItemHandlerHelper.insertItem(itemHandler, stack, true); + var wasInserted = extracted - remainder.getCount(); + + if (wasInserted > 0) { + extracted = emcStorage.extractItem(item, remaining, Actionable.MODULATE, source, true); + remainder = ItemHandlerHelper.insertItem(itemHandler, stack, false); + wasInserted = extracted - remainder.getCount(); + + if (wasInserted < extracted) { + var leftover = extracted - wasInserted; + emcStorage.insertItem(item, leftover, Actionable.MODULATE, source, false); + + if (leftover > 0) { + LOGGER.error( + "Storage export: adjacent block unexpectedly refused insert, voided {}x{}", + leftover, + item); + } + } + } + + if (wasInserted > 0) { + remaining -= Ints.saturatedCast(wasInserted); + } } - var amount = getStrategy().transfer(context, item, context.getOperationsRemaining()); + if (remaining < getOperationsPerTick()) { + if (schedulingMode == SchedulingMode.ROUNDROBIN) { + nextSlot = (nextSlot + slot) % availableSlots(); + } - if (amount > 0) { - context.reduceOperationsRemaining(amount); + doneWork.set(true); } - } + }); - if (context.hasDoneWork()) { - updateSchedulingMode(schedulingMode, slot); - } - - return context.hasDoneWork(); - } - - private StackExportStrategy getStrategy() { - if (strategy == null) { - var self = getHost().getBlockEntity(); - var fromPos = self.getBlockPos().relative(getSide()); - var fromSide = getSide().getOpposite(); - strategy = new EMCItemExportStrategy((ServerLevel) getLevel(), fromPos, fromSide); - } - - return strategy; - } - - private int getStartingSlot(SchedulingMode schedulingMode, int x) { - if (schedulingMode == SchedulingMode.RANDOM) { - return getLevel().getRandom().nextInt(availableSlots()); - } - - if (schedulingMode == SchedulingMode.ROUNDROBIN) { - return (nextSlot + x) % availableSlots(); - } - - return x; - } - - private void updateSchedulingMode(SchedulingMode schedulingMode, int x) { - if (schedulingMode == SchedulingMode.ROUNDROBIN) { - nextSlot = (nextSlot + x) % availableSlots(); - } + return doneWork.get(); } @Override diff --git a/src/main/java/gripe/_90/appliede/part/EMCImportBusPart.java b/src/main/java/gripe/_90/appliede/part/EMCImportBusPart.java index 33e07eb..6b7e8c3 100644 --- a/src/main/java/gripe/_90/appliede/part/EMCImportBusPart.java +++ b/src/main/java/gripe/_90/appliede/part/EMCImportBusPart.java @@ -1,10 +1,14 @@ package gripe._90.appliede.part; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.google.common.primitives.Ints; + import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.inventory.MenuType; +import net.minecraftforge.common.capabilities.ForgeCapabilities; -import appeng.api.behaviors.StackImportStrategy; +import appeng.api.config.Actionable; import appeng.api.networking.IGrid; import appeng.api.parts.IPartCollisionHelper; import appeng.api.parts.IPartItem; @@ -14,6 +18,7 @@ import appeng.core.definitions.AEItems; import appeng.core.settings.TickRates; import appeng.items.parts.PartModels; +import appeng.me.storage.ExternalStorageFacade; import appeng.menu.implementations.IOBusMenu; import appeng.menu.implementations.MenuTypeBuilder; import appeng.parts.PartModel; @@ -21,10 +26,7 @@ import gripe._90.appliede.AppliedE; import gripe._90.appliede.me.service.KnowledgeService; -import gripe._90.appliede.me.strategy.EMCItemImportStrategy; -import gripe._90.appliede.me.strategy.EMCTransferContext; -@SuppressWarnings("UnstableApiUsage") public class EMCImportBusPart extends IOBusPart { public static final MenuType<IOBusMenu> MENU = MenuTypeBuilder.create(IOBusMenu::new, EMCImportBusPart.class).build("emc_import_bus"); @@ -41,8 +43,6 @@ public class EMCImportBusPart extends IOBusPart { private static final PartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, AppEng.makeId("part/import_bus_has_channel")); - private StackImportStrategy importStrategy; - public EMCImportBusPart(IPartItem<?> partItem) { super(TickRates.ImportBus, AEItemKey.filter(), partItem); } @@ -54,19 +54,47 @@ protected MenuType<?> getMenuType() { @Override protected boolean doBusWork(IGrid grid) { - if (importStrategy == null) { - var self = getHost().getBlockEntity(); - var fromPos = self.getBlockPos().relative(getSide()); - var fromSide = getSide().getOpposite(); - importStrategy = new EMCItemImportStrategy((ServerLevel) getLevel(), fromPos, fromSide); + var adjacentPos = getHost().getBlockEntity().getBlockPos().relative(getSide()); + var blockEntity = getLevel().getBlockEntity(adjacentPos); + + if (blockEntity == null) { + return false; } - var emc = grid.getService(KnowledgeService.class).getStorage(); - var context = new EMCTransferContext(emc, source, getFilter(), getOperationsPerTick()); - context.setInverted(isUpgradedWith(AEItems.INVERTER_CARD)); - context.setCanLearn(isUpgradedWith(AppliedE.LEARNING_CARD.get())); - importStrategy.transfer(context); - return context.hasDoneWork(); + var doneWork = new AtomicBoolean(false); + + blockEntity.getCapability(ForgeCapabilities.ITEM_HANDLER).ifPresent(itemHandler -> { + var emcStorage = grid.getService(KnowledgeService.class).getStorage(); + var adjacentStorage = ExternalStorageFacade.of(itemHandler); + var remaining = getOperationsPerTick(); + + for (var slot = 0; slot < itemHandler.getSlots() && remaining > 0; slot++) { + var item = AEItemKey.of(itemHandler.getStackInSlot(slot)); + + if (item == null) { + continue; + } + + if (!getFilter().isEmpty() && getFilter().isListed(item) == isUpgradedWith(AEItems.INVERTER_CARD)) { + continue; + } + + var amount = adjacentStorage.extract(item, remaining, Actionable.SIMULATE, source); + + if (amount > 0) { + var mayLearn = isUpgradedWith(AppliedE.LEARNING_CARD.get()); + amount = emcStorage.insertItem(item, amount, Actionable.MODULATE, source, mayLearn); + adjacentStorage.extract(item, amount, Actionable.MODULATE, source); + remaining -= Ints.saturatedCast(amount); + } + } + + if (remaining < getOperationsPerTick()) { + doneWork.set(true); + } + }); + + return doneWork.get(); } @Override