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 {