Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 96 additions & 37 deletions src/main/scala/li/cil/oc/integration/appeng/DriverExportBus.scala
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
package li.cil.oc.integration.appeng

import appeng.api.AEApi
import appeng.api.config.{Actionable, FuzzyMode, Settings, Upgrades}
import appeng.api.networking.security.MachineSource
import appeng.api.config._
import appeng.api.parts.IPartHost
import appeng.api.storage.StorageName
import appeng.api.storage.data.IAEItemStack
import appeng.parts.automation.PartExportBus
import appeng.core.settings.TickRates
import appeng.helpers.MultiCraftingTracker
import appeng.me.GridAccessException
import appeng.me.cache.NetworkMonitor
import appeng.parts.automation.{PartBaseExportBus, PartExportBus}
import appeng.util.{IterationCounter, Platform}
import li.cil.oc.api.driver
import li.cil.oc.api.driver.{EnvironmentProvider, NamedBlock}
import li.cil.oc.api.machine.{Arguments, Callback, Context}
import li.cil.oc.integration.ManagedTileEntityEnvironment
import li.cil.oc.integration.appeng.internal.PartItemBusBase
import li.cil.oc.util.ExtendedArguments._
import li.cil.oc.util.ResultWrapper._
import li.cil.oc.util.{BlockPosition, InventoryUtils}
import li.cil.oc.util.{BlockPosition, InventoryUtils, ReflectionUtils}
import net.minecraft.item.ItemStack
import net.minecraft.world.World
import net.minecraftforge.common.util.ForgeDirection

import scala.collection.convert.WrapAsScala._
import java.util
import scala.reflect.ClassTag

object DriverExportBus extends driver.SidedBlock {
Expand Down Expand Up @@ -52,54 +56,109 @@ object DriverExportBus extends driver.SidedBlock {
@Callback(doc = "function(side:number, filter: String):boolean -- Set the ore filter of the export bus pointing in the specified direction.")
def setExportOreFilter(context: Context, args: Arguments): Array[AnyRef] = this.setPartOreFilter(context, args)

@Callback(doc = "function(side:number, slot:number):boolean -- Make the export bus facing the specified direction perform a single export operation into the specified slot.")
private lazy val craftingTrackerGetterHandle = ReflectionUtils.getFieldGetterHandle(classOf[PartBaseExportBus[_]], "craftingTracker", allowSuper = false)

@Callback(doc = "function(side:number, slot:number):boolean, number -- Make the export bus facing the specified direction perform a single export operation into the specified slot.")
def exportIntoSlot(context: Context, args: Arguments): Array[AnyRef] = {
val side = args.checkSideAny(0)
val export = getPart(side)
InventoryUtils.inventoryAt(BlockPosition(host.getLocation).offset(side)) match {
case Some(inventory) =>
val targetSlot = args.checkSlot(inventory, 1)
val config = export.getInventoryByName("config")
val itemStorage = export.getProxy.getStorage.getItemInventory
var count = export.calculateAmountToSend()
// We need reflection here to avoid compiling against the return and
// argument type, which has changed in rv2-beta-20 or so.
val fuzzyMode = (try export.getConfigManager.getClass.getMethod("getSetting", classOf[Enum[_]]) catch {
case _: NoSuchMethodException => export.getConfigManager.getClass.getMethod("getSetting", classOf[Settings])
}).invoke(export.getConfigManager, Settings.FUZZY_MODE).asInstanceOf[FuzzyMode]
val source = new MachineSource(export)
var didSomething = false
for (slot <- 0 until config.getSizeInventory if count > 0) {
val filter = AEApi.instance.storage.createItemStack(config.getStackInSlot(slot))
val stacks =
if (export.getInstalledUpgrades(Upgrades.FUZZY) > 0)
itemStorage.getStorageList.findFuzzy(filter, fuzzyMode).toSeq
else
Seq(itemStorage.getStorageList.findPrecise(filter))
for (ais <- stacks.filter(_ != null).map(_.copy()) if count > 0) {
val is = ais.getItemStack
try {
val targetSlot = args.checkSlot(inventory, 1)
val config = export.getAEInventoryByName(StorageName.CONFIG)
val gridInv = getMonitor[IAEItemStack](export)
var count = export.calculateAmountToSend()
val origin = count
val mySrc = getMySrc(export)
var didSomething = false
val energy = export.getProxy.getEnergy
val oppositeSide = Option(side.getOpposite)

def pushItemToTargetSlot(stack: IAEItemStack, simulate: Boolean = false): Boolean = {
val is = stack.getItemStack
is.stackSize = count
if (InventoryUtils.insertIntoInventorySlot(is, inventory, Option(side.getOpposite), targetSlot, count, simulate = true)) {
if (!InventoryUtils.insertIntoInventorySlot(is, inventory, oppositeSide, targetSlot, simulate = true))
false
else if (simulate)
true
else {
val ais = stack.copy()
ais.setStackSize(count - is.stackSize)
val eais = AEApi.instance.storage.poweredExtraction(export.getProxy.getEnergy, itemStorage, ais, source)
val eais = Platform.poweredExtraction(energy, gridInv, ais, mySrc)
if (eais != null) {
val eis = eais.getItemStack
count -= eis.stackSize
didSomething = true
InventoryUtils.insertIntoInventorySlot(eis, inventory, Option(side.getOpposite), targetSlot)
if (eis.stackSize > 0) {
eais.setStackSize(eis.stackSize)
itemStorage.injectItems(ais, Actionable.MODULATE, source)
InventoryUtils.insertIntoInventorySlot(eis, inventory, oppositeSide, targetSlot)
}
true
}
}

if (export.getInstalledUpgrades(Upgrades.ORE_FILTER) == 0) {
val supportFz = supportFuzzy(export) && export.getInstalledUpgrades(Upgrades.FUZZY) > 0
val fuzzyMode = export.getConfigManager.getSetting(Settings.FUZZY_MODE).asInstanceOf[FuzzyMode]
val cg = export.getProxy.getCrafting
val craftOnly = export.getConfigManager.getSetting(Settings.CRAFT_ONLY) == YesNo.YES;
val isCraftingEnabled = export.getInstalledUpgrades(Upgrades.CRAFTING) > 0;
val craftingTracker = craftingTrackerGetterHandle.invoke(export).asInstanceOf[MultiCraftingTracker]
var slot = 0

def tryCrafting(slot: Int, filter: IAEItemStack): Boolean = {
craftingTracker.handleCrafting(slot, count, filter, export.getTile.getWorldObj, export.getProxy.getGrid, cg, mySrc)
}

while (count > 0 && slot < getSlotSize(export)) {
val filter = config.getAEStackInSlot(slot).asInstanceOf[IAEItemStack]
if (filter != null) {
if (craftOnly) {
if (isCraftingEnabled && pushItemToTargetSlot(filter, simulate = true)) {
didSomething = tryCrafting(slot, filter) || didSomething
}
}
else {
val before = count
if (supportFz) {
gridInv match {
case monitor: NetworkMonitor[IAEItemStack] =>
val it = monitor.getHandler.getSortedFuzzyItems(new util.ArrayList, filter, fuzzyMode, IterationCounter.fetchNewId).iterator()
while (count > 0 && it.hasNext) {
val ais = it.next()
if (ais != null) pushItemToTargetSlot(ais)
}
case _ =>
}
}
else pushItemToTargetSlot(filter)

if (count == before && isCraftingEnabled) {
didSomething = tryCrafting(slot, filter) || didSomething
}
}
}
slot += 1
}
}
else if (supportOreDict(export)) {
val filterPredicate = getOreFilterPredicate(export)
if (filterPredicate != null) {
val it = gridInv.getStorageList.iterator()
while (count > 0 && it.hasNext) {
val ais = it.next()
if (ais != null && filterPredicate.test(ais)) pushItemToTargetSlot(ais)
}
}
}
if (didSomething) {
context.pause((TickRates.ExportBus.getMin - 1) * 0.05)
}
result(didSomething, origin - count)
}
if (didSomething) {
context.pause(0.25)
catch {
case _: GridAccessException => result(null, "grid access exception")
}
result(didSomething)
case _ => result(Unit, "no inventory")
case _ => result(null, "no inventory")
}
}
}
Expand Down
79 changes: 79 additions & 0 deletions src/main/scala/li/cil/oc/integration/appeng/DriverImportBus.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
package li.cil.oc.integration.appeng

import appeng.api.config._
import appeng.api.parts.IPartHost
import appeng.api.storage.StorageName
import appeng.api.storage.data.IAEItemStack
import appeng.core.settings.TickRates
import appeng.me.GridAccessException
import appeng.parts.automation.PartImportBus
import appeng.util.Platform
import appeng.util.item.AEItemStack
import li.cil.oc.api.driver
import li.cil.oc.api.driver.{EnvironmentProvider, NamedBlock}
import li.cil.oc.api.machine.{Arguments, Callback, Context}
import li.cil.oc.integration.ManagedTileEntityEnvironment
import li.cil.oc.integration.appeng.internal.PartItemBusBase
import li.cil.oc.util.ExtendedArguments.extendedArguments
import li.cil.oc.util.ResultWrapper._
import li.cil.oc.util.{BlockPosition, InventoryUtils}
import net.minecraft.item.ItemStack
import net.minecraft.world.World
import net.minecraftforge.common.util.ForgeDirection
Expand Down Expand Up @@ -44,6 +53,76 @@ object DriverImportBus extends driver.SidedBlock {

@Callback(doc = "function(side:number, filter: String):boolean -- Set the ore filter of the import bus pointing in the specified direction.")
def setImportOreFilter(context: Context, args: Arguments): Array[AnyRef] = this.setPartOreFilter(context, args)

@Callback(doc = "function(side:number, slot:number):boolean, number -- Make the import bus facing the specified direction perform a single import operation from the specified slot.")
def importFromSlot(context: Context, args: Arguments): Array[AnyRef] = {
val side = args.checkSideAny(0)
val part = getPart(side)
InventoryUtils.inventoryAt(BlockPosition(host.getLocation).offset(side)) match {
case Some(inventory) =>
try {
val targetSlot = args.checkSlot(inventory, 1)
val stack = inventory.getStackInSlot(targetSlot)
if (stack == null || stack.stackSize == 0) {
result(false)
}
else {
var isMatch = false
var configured = false
val gridInv = getMonitor[IAEItemStack](part)
if (part.getInstalledUpgrades(Upgrades.ORE_FILTER) == 0) {
val supportFz = supportFuzzy(part) && part.getInstalledUpgrades(Upgrades.FUZZY) > 0
val fuzzyMode = part.getConfigManager.getSetting(Settings.FUZZY_MODE).asInstanceOf[FuzzyMode]
val config = part.getAEInventoryByName(StorageName.CONFIG)
var slot = 0
while (!isMatch && slot < getSlotSize(part)) {
val filter = config.getAEStackInSlot(slot).asInstanceOf[IAEItemStack]
if (filter != null) {
configured = true
if (supportFz && Platform.isSameItemFuzzy(stack, filter.getItemStack, fuzzyMode))
isMatch = true
else if (!supportFz && Platform.isSameItemPrecise(stack, filter.getItemStack))
isMatch = true
}
slot += 1
}
if (!configured) isMatch = true
} else if (supportOreDict(part)) {
val filterPredicate = getOreFilterPredicate(part)
if (filterPredicate != null) {
isMatch = filterPredicate.test(AEItemStack.create(stack))
}
}
if (!isMatch) result(false)
else {
var didSomething = false
var insert = 0
val energy = part.getProxy.getEnergy
InventoryUtils.extractFromInventorySlot(extracted => {
if (extracted != null) {
val before = extracted.stackSize
val source = getMySrc(part)
val failed = Platform.poweredInsert(energy, gridInv, AEItemStack.create(extracted), source)
extracted.stackSize = if (failed == null) 0 else failed.getStackSize.toInt
if (before != extracted.stackSize) {
insert = before - extracted.stackSize
didSomething = true
}
}
}, inventory, side.getOpposite, targetSlot, part.calculateAmountToSend())
if (didSomething) {
context.pause((TickRates.ImportBus.getMin - 1) * 0.05)
}
result(didSomething, insert)
}
}
}
catch {
case _: GridAccessException => result(null, "grid access exception")
}
case _ => result(null, "no inventory")
}
}
}

object Provider extends EnvironmentProvider {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
package li.cil.oc.integration.appeng.internal

import appeng.api.config.Upgrades
import appeng.api.networking.security.MachineSource
import appeng.api.parts.{IPart, IPartHost}
import appeng.api.storage.StorageName
import appeng.api.storage.data.{IAEItemStack, IAEStack}
import appeng.api.storage.{IMEMonitor, StorageName}
import appeng.helpers.IOreFilterable
import appeng.parts.automation.PartSharedItemBus
import appeng.parts.misc.PartStorageBus
import appeng.tile.inventory.IIAEStackInventory
import appeng.util.item.AEItemStack
import appeng.util.prioitylist.OreFilteredList
import li.cil.oc.api.machine.{Arguments, Context}
import li.cil.oc.api.network.ManagedEnvironment
import li.cil.oc.integration.appeng.AEStackFactory
import li.cil.oc.util.DatabaseAccess
import li.cil.oc.util.ExtendedArguments._
import li.cil.oc.util.ResultWrapper.result
import li.cil.oc.util.{DatabaseAccess, ReflectionUtils}
import net.minecraftforge.common.util.ForgeDirection

import java.lang.invoke.MethodHandle
import java.util.function.Predicate
import scala.language.implicitConversions
import scala.reflect.ClassTag

Expand Down Expand Up @@ -91,6 +95,9 @@ object PartEnvironmentBase {
}

trait PartSharedItemBusBase[PartType <: PartSharedItemBus[_]] extends PartEnvironmentBase[PartType] {

import PartSharedItemBusBase._

implicit def tag: ClassTag[PartType]

def getSlotSize(part: PartType): Int =
Expand All @@ -101,6 +108,45 @@ trait PartSharedItemBusBase[PartType <: PartSharedItemBus[_]] extends PartEnviro
val part = getPart(side)
result(getSlotSize(part))
}

def getMonitor[T <: IAEStack[T]](part: PartType): IMEMonitor[T] = {
getMonitorHandle.invoke(part).asInstanceOf[IMEMonitor[T]]
}

def setFilterPredicate(part: PartType, filterPredicate: Predicate[IAEItemStack]): Unit = {
filterPredicateSetterHandle.invoke(part, filterPredicate)
}

def supportFuzzy(part: PartType): Boolean = {
supportFuzzyHandle.invoke(part).asInstanceOf[Boolean]
}

def supportOreDict(part: PartType): Boolean = {
supportOreDictHandle.invoke(part).asInstanceOf[Boolean]
}

def getMySrc(part: PartType): MachineSource = {
mySrcGetterHandle.invoke(part).asInstanceOf[MachineSource]
}

def getOreFilterPredicate(part: PartType): Predicate[IAEItemStack] = {
val oreFilterString = part.getFilter
var filterPredicate = filterPredicateGetterHandle.invoke(part).asInstanceOf[Predicate[IAEItemStack]]
if (filterPredicate == null) {
filterPredicate = OreFilteredList.makeFilter(oreFilterString)
setFilterPredicate(part, filterPredicate)
}
filterPredicate
}
}

object PartSharedItemBusBase {
private lazy val getMonitorHandle: MethodHandle = ReflectionUtils.getMethodHandle(classOf[PartSharedItemBus[_]], "getMonitor", allowSuper = false)
private lazy val supportFuzzyHandle: MethodHandle = ReflectionUtils.getMethodHandle(classOf[PartSharedItemBus[_]], "supportFuzzy", allowSuper = false)
private lazy val supportOreDictHandle: MethodHandle = ReflectionUtils.getMethodHandle(classOf[PartSharedItemBus[_]], "supportOreDict", allowSuper = false)
private lazy val filterPredicateGetterHandle: MethodHandle = ReflectionUtils.getFieldGetterHandle(classOf[PartSharedItemBus[_]], "filterPredicate", allowSuper = false)
private lazy val filterPredicateSetterHandle: MethodHandle = ReflectionUtils.getFieldSetterHandle(classOf[PartSharedItemBus[_]], "filterPredicate", allowSuper = false)
private lazy val mySrcGetterHandle: MethodHandle = ReflectionUtils.getFieldGetterHandle(classOf[PartSharedItemBus[_]], "mySrc", allowSuper = false)
}

object PartItemConfigurablePart {
Expand Down Expand Up @@ -145,4 +191,4 @@ trait PartItemStorageBusBusBase[PartType <: PartStorageBus] extends PartStorageB

object PartItemStorageBusBusBase {
implicit def ConfigOps[PartType <: PartStorageBus](env: PartItemStorageBusBusBase[PartType]): PartItemConfigurablePart.ConfigOps[PartType] = new PartItemConfigurablePart.ConfigOps[PartType](env)
}
}
Loading