From 9b3797271f8de2f6155e468c4f0dc9803a2df856 Mon Sep 17 00:00:00 2001 From: hinyb <40139991+hinyb@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:05:44 +0800 Subject: [PATCH 1/2] refactor(appeng): move getMonitor out of AEUtil --- .../li/cil/oc/integration/appeng/AEUtil.scala | 18 ------------------ .../oc/integration/appeng/NetworkControl.scala | 16 ++++++++++++++-- .../appeng/internal/SubscriptionBase.scala | 7 +++---- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/appeng/AEUtil.scala b/src/main/scala/li/cil/oc/integration/appeng/AEUtil.scala index bc87b94333..f331e53296 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/AEUtil.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/AEUtil.scala @@ -1,10 +1,6 @@ package li.cil.oc.integration.appeng import appeng.api.AEApi -import appeng.api.storage.IMEMonitor -import appeng.api.storage.data.IAEStack -import appeng.me.GridAccessException -import appeng.me.helpers.IGridProxyable import cpw.mods.fml.common.Loader import cpw.mods.fml.common.versioning.VersionRange import li.cil.oc.api @@ -13,8 +9,6 @@ import li.cil.oc.common.item.data.{DroneData, RobotData} import li.cil.oc.integration.Mods import net.minecraft.item.ItemStack -import scala.reflect.ClassTag - object AEUtil { val versionsWithNewItemDefinitionAPI = VersionRange.createFromVersionSpec("[rv2-beta-20,)") @@ -165,16 +159,4 @@ object AEUtil { } null } - - def getMonitor[T <: IAEStack[T] : ClassTag](controller: IGridProxyable): Option[IMEMonitor[T]] = { - for { - c <- Option(controller) - entry <- AEStackFactory.getEntry[T]() - inv <- try { - Option(c.getProxy.getStorage.getMEMonitor(entry.stackType).asInstanceOf[IMEMonitor[T]]) - } catch { - case _: GridAccessException => None - } - } yield inv - } } diff --git a/src/main/scala/li/cil/oc/integration/appeng/NetworkControl.scala b/src/main/scala/li/cil/oc/integration/appeng/NetworkControl.scala index 814a51a45b..dafcca187d 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/NetworkControl.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/NetworkControl.scala @@ -7,8 +7,9 @@ import appeng.api.networking.crafting.{CraftingItemList, ICraftingLink, ICraftin import appeng.api.networking.security.{BaseActionSource, IActionHost, MachineSource} import appeng.api.networking.storage.IBaseMonitor import appeng.api.storage.data.{IAEFluidStack, IAEItemStack, IAEStack, IItemList} -import appeng.api.storage.{IMEInventory, IMEMonitor, IMEMonitorHandlerReceiver} +import appeng.api.storage.{IMEMonitor, IMEMonitorHandlerReceiver} import appeng.api.util.AECableType +import appeng.me.GridAccessException import appeng.me.cluster.implementations.CraftingCPUCluster import appeng.me.helpers.IGridProxyable import appeng.tile.crafting.TileCraftingMonitorTile @@ -334,6 +335,17 @@ trait NetworkControl[AETile >: Null <: TileEntity with IGridProxyable with IActi } object NetworkControl extends AETypes { + def getMonitor[T <: IAEStack[T] : ClassTag](controller: IGridProxyable): Option[IMEMonitor[T]] = { + for { + c <- Option(controller) + entry <- AEStackFactory.getEntry[T]() + inv <- try { + Option(c.getProxy.getStorage.getMEMonitor(entry.stackType).asInstanceOf[IMEMonitor[T]]) + } catch { + case _: GridAccessException => None + } + } yield inv + } //noinspection ScalaUnusedSymbol private class Craftable(var controller: TileEntity with IGridProxyable with IActionHost, var stack: AEStack) extends AbstractValue with ICraftingRequester { @@ -592,7 +604,7 @@ object NetworkControl extends AETypes { private abstract class NetworkContents[T <: IAEStack[T] : ClassTag](var controller: TileEntity with IGridProxyable with IActionHost) extends AbstractValue with IMEMonitorHandlerReceiver[T] { def this() = this(null) - private def getMonitor: Option[IMEMonitor[T]] = AEUtil.getMonitor[T](controller) + private def getMonitor: Option[IMEMonitor[T]] = NetworkControl.getMonitor[T](controller) private var items: IItemList[T] = null private var itemIterator: java.util.Iterator[T] = null diff --git a/src/main/scala/li/cil/oc/integration/appeng/internal/SubscriptionBase.scala b/src/main/scala/li/cil/oc/integration/appeng/internal/SubscriptionBase.scala index 405b697110..3187b484b3 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/internal/SubscriptionBase.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/internal/SubscriptionBase.scala @@ -8,8 +8,7 @@ import appeng.me.helpers.IGridProxyable import li.cil.oc.api.Persistable import li.cil.oc.api.network.Node import li.cil.oc.common.EventHandler -import li.cil.oc.integration.appeng.AEUtil -import li.cil.oc.integration.appeng.NetworkControl.convert +import li.cil.oc.integration.appeng.NetworkControl.{convert, getMonitor} import net.minecraft.nbt.NBTTagCompound import net.minecraft.tileentity.TileEntity @@ -36,7 +35,7 @@ trait SubscriptionBase[T <: IAEStack[T]] extends IMEMonitorHandlerReceiver[T] wi private def updateSubscribe(): Unit = { if (tile.isInvalid) return - AEUtil.getMonitor[T](tile) match { + getMonitor[T](tile) match { case Some(inv) => if (subscribe) inv.addListener(this, null) @@ -71,4 +70,4 @@ trait SubscriptionBase[T <: IAEStack[T]] extends IMEMonitorHandlerReceiver[T] wi override def save(nbt: NBTTagCompound): Unit = { nbt.setBoolean(event_name, subscribe) } -} \ No newline at end of file +} From 239697645e069b1fc0a20d7a40e82bd67831ff15 Mon Sep 17 00:00:00 2001 From: hinyb <40139991+hinyb@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:49:55 +0800 Subject: [PATCH 2/2] feat(inventory): add support for infinite stack size inventory --- .../li/cil/oc/integration/appeng/AEUtil.scala | 4 +++ .../scala/li/cil/oc/util/InventoryUtils.scala | 33 ++++++++++++------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/appeng/AEUtil.scala b/src/main/scala/li/cil/oc/integration/appeng/AEUtil.scala index f331e53296..108967a437 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/AEUtil.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/AEUtil.scala @@ -1,12 +1,14 @@ package li.cil.oc.integration.appeng import appeng.api.AEApi +import appeng.parts.p2p.PartP2PItems import cpw.mods.fml.common.Loader import cpw.mods.fml.common.versioning.VersionRange import li.cil.oc.api import li.cil.oc.common.item.Delegator import li.cil.oc.common.item.data.{DroneData, RobotData} import li.cil.oc.integration.Mods +import net.minecraft.inventory.IInventory import net.minecraft.item.ItemStack object AEUtil { @@ -134,6 +136,8 @@ object AEUtil { AEApi.instance.definitions.parts.storageBus.isSameAs(stack) } + def isPartP2PItems(inventory: IInventory): Boolean = inventory.isInstanceOf[PartP2PItems] + def isRobot(stack: ItemStack): Boolean = api.Items.get(stack) == api.Items.get("robot") diff --git a/src/main/scala/li/cil/oc/util/InventoryUtils.scala b/src/main/scala/li/cil/oc/util/InventoryUtils.scala index 9be21bb001..b04e927d7c 100644 --- a/src/main/scala/li/cil/oc/util/InventoryUtils.scala +++ b/src/main/scala/li/cil/oc/util/InventoryUtils.scala @@ -1,5 +1,7 @@ package li.cil.oc.util +import li.cil.oc.integration.Mods +import li.cil.oc.integration.appeng.AEUtil import li.cil.oc.util.ExtendedWorld._ import net.minecraft.block.BlockChest import net.minecraft.entity.Entity @@ -55,6 +57,11 @@ object InventoryUtils { def inventoryAt(position: BlockPosition): Option[IInventory] = inventorySourceAt(position). map(a => a.inventory) + def shouldSkipStackSizeCheck(inventory: IInventory): Boolean = { + (inventory.getClass.toString == "class wanion.avaritiaddons.block.chest.infinity.TileEntityInfinityChest") || + (Mods.AppliedEnergistics2.isModAvailable && AEUtil.isPartP2PItems(inventory) && inventory.getInventoryStackLimit == Int.MaxValue) + } + /** * Inserts a stack into an inventory. *
@@ -76,14 +83,15 @@ object InventoryUtils { * The number of items inserted can be limited, to avoid unnecessary * changes to the inventory the stack may come from, for example. */ - def insertIntoInventorySlot(stack: ItemStack, inventory: IInventory, side: Option[ForgeDirection], slot: Int, limit: Int = 64, simulate: Boolean = false) = + def insertIntoInventorySlot(stack: ItemStack, inventory: IInventory, side: Option[ForgeDirection], slot: Int, limit: Int = Int.MaxValue, simulate: Boolean = false) = (stack != null && limit > 0) && { val isSideValidForSlot = (inventory, side) match { case (inventory: ISidedInventory, Some(s)) => inventory.canInsertItem(slot, stack, s.ordinal) case _ => true } (stack.stackSize > 0 && inventory.isItemValidForSlot(slot, stack) && isSideValidForSlot) && { - val maxStackSize = math.min(inventory.getInventoryStackLimit, stack.getMaxStackSize) + val invLimit = inventory.getInventoryStackLimit + val maxStackSize = if (shouldSkipStackSizeCheck(inventory)) invLimit else math.min(invLimit, stack.getMaxStackSize) val existing = inventory.getStackInSlot(slot) val shouldMerge = existing != null && existing.stackSize < maxStackSize && existing.isItemEqual(stack) && ItemStack.areItemStackTagsEqual(existing, stack) @@ -134,7 +142,7 @@ object InventoryUtils { * also be achieved by a check in the consumer, but it saves some unnecessary * code repetition this way. */ - def extractFromInventorySlot(consumer: ItemStack => Unit, inventory: IInventory, side: ForgeDirection, slot: Int, limit: Int = 64): Int = { + def extractFromInventorySlot(consumer: ItemStack => Unit, inventory: IInventory, side: ForgeDirection, slot: Int, limit: Int = Int.MaxValue): Int = { val stack = inventory.getStackInSlot(slot) if (stack == null || limit <= 0) @@ -147,7 +155,8 @@ object InventoryUtils { case _ => } - val maxStackSize = math.min(inventory.getInventoryStackLimit, stack.getMaxStackSize) + val invLimit = inventory.getInventoryStackLimit + val maxStackSize = if (shouldSkipStackSizeCheck(inventory)) invLimit else math.min(invLimit, stack.getMaxStackSize) val amount = stack.stackSize min limit min maxStackSize val extracted = stack.splitStack(amount) consumer(extracted) @@ -177,7 +186,7 @@ object InventoryUtils { * item stack will be adjusted to reflect the number items inserted, by * having its size decremented accordingly. */ - def insertIntoInventory(stack: ItemStack, inventory: IInventory, side: Option[ForgeDirection] = None, limit: Int = 64, simulate: Boolean = false, slots: Option[Iterable[Int]] = None) = + def insertIntoInventory(stack: ItemStack, inventory: IInventory, side: Option[ForgeDirection] = None, limit: Int = Int.MaxValue, simulate: Boolean = false, slots: Option[Iterable[Int]] = None) = (stack != null && limit > 0) && { var success = false var remaining = limit @@ -233,7 +242,7 @@ object InventoryUtils { *
* This returns true if at least one item was extracted. */ - def extractAnyFromInventory(consumer: ItemStack => Unit, inventory: IInventory, side: ForgeDirection, limit: Int = 64): Int = { + def extractAnyFromInventory(consumer: ItemStack => Unit, inventory: IInventory, side: ForgeDirection, limit: Int = Int.MaxValue): Int = { val range = inventory match { case sided: ISidedInventory => sided.getAccessibleSlotsFromSide(side.ordinal).toIterable case _ => 0 until inventory.getSizeInventory @@ -280,7 +289,7 @@ object InventoryUtils { * Utility method for calling insertIntoInventory on an inventory * in the world. */ - def insertIntoInventoryAt(stack: ItemStack, position: BlockPosition, side: Option[ForgeDirection] = None, limit: Int = 64, simulate: Boolean = false): Boolean = + def insertIntoInventoryAt(stack: ItemStack, position: BlockPosition, side: Option[ForgeDirection] = None, limit: Int = Int.MaxValue, simulate: Boolean = false): Boolean = inventoryAt(position).exists(insertIntoInventory(stack, _, side, limit, simulate)) type Extractor = () => Int @@ -289,7 +298,7 @@ object InventoryUtils { * Utility method for calling extractFromInventory on an inventory * in the world. */ - def getExtractorFromInventoryAt(consumer: ItemStack => Unit, position: BlockPosition, side: ForgeDirection, limit: Int = 64): Extractor = + def getExtractorFromInventoryAt(consumer: ItemStack => Unit, position: BlockPosition, side: ForgeDirection, limit: Int = Int.MaxValue): Extractor = inventoryAt(position) match { case Some(inventory) => () => extractAnyFromInventory(consumer, inventory, side, limit) case _ => null @@ -309,14 +318,14 @@ object InventoryUtils { *
* This returns true if at least one item was transferred. */ - def transferBetweenInventories(source: IInventory, sourceSide: ForgeDirection, sink: IInventory, sinkSide: Option[ForgeDirection], limit: Int = 64) = + def transferBetweenInventories(source: IInventory, sourceSide: ForgeDirection, sink: IInventory, sinkSide: Option[ForgeDirection], limit: Int = Int.MaxValue) = extractAnyFromInventory( insertIntoInventory(_, sink, sinkSide, limit), source, sourceSide, limit) /** * Like transferBetweenInventories but moving between specific slots. */ - def transferBetweenInventoriesSlots(source: IInventory, sourceSide: ForgeDirection, sourceSlot: Int, sink: IInventory, sinkSide: Option[ForgeDirection], sinkSlot: Option[Int], limit: Int = 64) = + def transferBetweenInventoriesSlots(source: IInventory, sourceSide: ForgeDirection, sourceSlot: Int, sink: IInventory, sinkSide: Option[ForgeDirection], sinkSlot: Option[Int], limit: Int = Int.MaxValue) = sinkSlot match { case Some(explicitSinkSlot) => extractFromInventorySlot( @@ -330,7 +339,7 @@ object InventoryUtils { * Utility method for calling transferBetweenInventories on inventories * in the world. */ - def getTransferBetweenInventoriesAt(source: BlockPosition, sourceSide: ForgeDirection, sink: BlockPosition, sinkSide: Option[ForgeDirection], limit: Int = 64): Extractor = + def getTransferBetweenInventoriesAt(source: BlockPosition, sourceSide: ForgeDirection, sink: BlockPosition, sinkSide: Option[ForgeDirection], limit: Int = Int.MaxValue): Extractor = inventoryAt(source) match { case Some(sourceInventory) => inventoryAt(sink) match { @@ -344,7 +353,7 @@ object InventoryUtils { * Utility method for calling transferBetweenInventoriesSlots on inventories * in the world. */ - def getTransferBetweenInventoriesSlotsAt(sourcePos: BlockPosition, sourceSide: ForgeDirection, sourceSlot: Int, sinkPos: BlockPosition, sinkSide: Option[ForgeDirection], sinkSlot: Option[Int], limit: Int = 64): Extractor = + def getTransferBetweenInventoriesSlotsAt(sourcePos: BlockPosition, sourceSide: ForgeDirection, sourceSlot: Int, sinkPos: BlockPosition, sinkSide: Option[ForgeDirection], sinkSlot: Option[Int], limit: Int = Int.MaxValue): Extractor = inventoryAt(sourcePos) match { case Some(sourceInventory) => inventoryAt(sinkPos) match {