mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-14 17:56:34 -04:00
More extraction of logic into traits.
*BREAKING CHANGE*: Reworked inventory and tank controllers a bit. Specifically, the methods taking `sides.back` to indicate the robots own inventory now only operate on the world, internal inventory is accessed via separate methods now (e.g. getStackInSlot(sides.back, ...) -> getStackInInternalSlot(...)).
This commit is contained in:
parent
fe9d7edc16
commit
a322981dea
@ -0,0 +1,7 @@
|
||||
package li.cil.oc.common.inventory
|
||||
|
||||
trait InventorySelection {
|
||||
def selectedSlot: Int
|
||||
|
||||
def selectedSlot_=(value: Int): Unit
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package li.cil.oc.common.inventory
|
||||
|
||||
trait TankSelection {
|
||||
def selectedTank: Int
|
||||
|
||||
def selectedTank_=(value: Int): Unit
|
||||
}
|
@ -17,7 +17,7 @@ object DroneTemplate extends Template {
|
||||
override protected val suggestedComponents = Array(
|
||||
"BIOS" -> hasComponent("eeprom") _)
|
||||
|
||||
override protected def hostClass = classOf[internal.Microcontroller]
|
||||
override protected def hostClass = classOf[internal.Drone]
|
||||
|
||||
def select(stack: ItemStack) = api.Items.get(stack) == api.Items.get("droneCase")
|
||||
|
||||
@ -45,6 +45,7 @@ object DroneTemplate extends Template {
|
||||
val upgradeSlots = new NBTTagList()
|
||||
upgradeSlots.appendTag(Map("tier" -> Tier.Three))
|
||||
upgradeSlots.appendTag(Map("tier" -> Tier.Two))
|
||||
upgradeSlots.appendTag(Map("tier" -> Tier.One))
|
||||
nbt.setTag("upgradeSlots", upgradeSlots)
|
||||
|
||||
val componentSlots = new NBTTagList()
|
||||
@ -60,7 +61,7 @@ object DroneTemplate extends Template {
|
||||
FMLInterModComms.sendMessage("OpenComputers", "registerAssemblerTemplate", nbt)
|
||||
}
|
||||
|
||||
override protected def maxComplexity(inventory: IInventory) = 6
|
||||
override protected def maxComplexity(inventory: IInventory) = 8
|
||||
|
||||
override protected def caseTier(inventory: IInventory) = if (select(inventory.getStackInSlot(0))) Tier.One else Tier.None
|
||||
}
|
||||
|
@ -17,7 +17,9 @@ import li.cil.oc.api.network._
|
||||
import li.cil.oc.client.gui
|
||||
import li.cil.oc.common.Slot
|
||||
import li.cil.oc.common.Tier
|
||||
import li.cil.oc.common.inventory.InventorySelection
|
||||
import li.cil.oc.common.inventory.MultiTank
|
||||
import li.cil.oc.common.inventory.TankSelection
|
||||
import li.cil.oc.integration.opencomputers.DriverKeyboard
|
||||
import li.cil.oc.integration.opencomputers.DriverRedstoneCard
|
||||
import li.cil.oc.integration.opencomputers.DriverScreen
|
||||
@ -47,7 +49,7 @@ import scala.collection.mutable
|
||||
// robot moves we only create a new proxy tile entity, hook the instance of this
|
||||
// class that was held by the old proxy to it and can then safely forget the
|
||||
// old proxy, which will be cleaned up by Minecraft like any other tile entity.
|
||||
class Robot extends traits.Computer with traits.PowerInformation with IFluidHandler with internal.Robot with MultiTank {
|
||||
class Robot extends traits.Computer with traits.PowerInformation with IFluidHandler with internal.Robot with MultiTank with InventorySelection with TankSelection {
|
||||
var proxy: RobotProxy = _
|
||||
|
||||
val info = new ItemUtils.RobotData()
|
||||
@ -99,6 +101,12 @@ class Robot extends traits.Computer with traits.PowerInformation with IFluidHand
|
||||
|
||||
var selectedSlot = actualSlot(0)
|
||||
|
||||
val tank = new MultiTank {
|
||||
override def tankCount = Robot.this.tankCount
|
||||
|
||||
override def getFluidTank(index: Int) = Robot.this.getFluidTank(index)
|
||||
}
|
||||
|
||||
var selectedTank = 0
|
||||
|
||||
// For client.
|
||||
@ -760,42 +768,42 @@ class Robot extends traits.Computer with traits.PowerInformation with IFluidHand
|
||||
|
||||
override def fill(from: ForgeDirection, resource: FluidStack, doFill: Boolean) =
|
||||
tryGetTank(selectedTank) match {
|
||||
case Some(tank) =>
|
||||
tank.fill(resource, doFill)
|
||||
case Some(t) =>
|
||||
t.fill(resource, doFill)
|
||||
case _ => 0
|
||||
}
|
||||
|
||||
override def drain(from: ForgeDirection, resource: FluidStack, doDrain: Boolean) =
|
||||
tryGetTank(selectedTank) match {
|
||||
case Some(tank) if tank.getFluid != null && tank.getFluid.isFluidEqual(resource) =>
|
||||
tank.drain(resource.amount, doDrain)
|
||||
case Some(t) if t.getFluid != null && t.getFluid.isFluidEqual(resource) =>
|
||||
t.drain(resource.amount, doDrain)
|
||||
case _ => null
|
||||
}
|
||||
|
||||
override def drain(from: ForgeDirection, maxDrain: Int, doDrain: Boolean) = {
|
||||
tryGetTank(selectedTank) match {
|
||||
case Some(tank) =>
|
||||
tank.drain(maxDrain, doDrain)
|
||||
case Some(t) =>
|
||||
t.drain(maxDrain, doDrain)
|
||||
case _ => null
|
||||
}
|
||||
}
|
||||
|
||||
override def canFill(from: ForgeDirection, fluid: Fluid) = {
|
||||
tryGetTank(selectedTank) match {
|
||||
case Some(tank) => tank.getFluid == null || tank.getFluid.getFluid == fluid
|
||||
case Some(t) => t.getFluid == null || t.getFluid.getFluid == fluid
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
override def canDrain(from: ForgeDirection, fluid: Fluid): Boolean = {
|
||||
tryGetTank(selectedTank) match {
|
||||
case Some(tank) => tank.getFluid != null && tank.getFluid.getFluid == fluid
|
||||
case Some(t) => t.getFluid != null && t.getFluid.getFluid == fluid
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
override def getTankInfo(from: ForgeDirection) =
|
||||
components.collect {
|
||||
case Some(tank: IFluidTank) => tank.getInfo
|
||||
case Some(t: IFluidTank) => t.getInfo
|
||||
}.toArray
|
||||
}
|
||||
|
@ -5,9 +5,10 @@ import li.cil.oc.api.driver.EnvironmentAware
|
||||
import li.cil.oc.api.driver.EnvironmentHost
|
||||
import li.cil.oc.api.driver.item.HostAware
|
||||
import li.cil.oc.api.internal.Adapter
|
||||
import li.cil.oc.api.internal.Robot
|
||||
import li.cil.oc.common.Slot
|
||||
import li.cil.oc.common.Tier
|
||||
import li.cil.oc.common.entity.Drone
|
||||
import li.cil.oc.common.tileentity.Robot
|
||||
import li.cil.oc.server.component
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
@ -16,8 +17,9 @@ object DriverUpgradeInventoryController extends Item with HostAware with Environ
|
||||
isOneOf(stack, api.Items.get("inventoryControllerUpgrade"))
|
||||
|
||||
override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = host match {
|
||||
case robot: EnvironmentHost with Robot => new component.UpgradeInventoryControllerInRobot(robot)
|
||||
case adapter: EnvironmentHost with Adapter => new component.UpgradeInventoryControllerInAdapter(adapter)
|
||||
case host: EnvironmentHost with Adapter => new component.UpgradeInventoryController.Adapter(host)
|
||||
case host: EnvironmentHost with Drone => new component.UpgradeInventoryController.Drone(host)
|
||||
case host: EnvironmentHost with Robot => new component.UpgradeInventoryController.Robot(host)
|
||||
case _ => null
|
||||
}
|
||||
|
||||
@ -25,5 +27,5 @@ object DriverUpgradeInventoryController extends Item with HostAware with Environ
|
||||
|
||||
override def tier(stack: ItemStack) = Tier.Two
|
||||
|
||||
override def providedEnvironment(stack: ItemStack) = classOf[component.UpgradeInventoryControllerInRobot]
|
||||
override def providedEnvironment(stack: ItemStack) = classOf[component.UpgradeInventoryController.Robot]
|
||||
}
|
||||
|
@ -5,9 +5,10 @@ import li.cil.oc.api.driver.EnvironmentAware
|
||||
import li.cil.oc.api.driver.EnvironmentHost
|
||||
import li.cil.oc.api.driver.item.HostAware
|
||||
import li.cil.oc.api.internal.Adapter
|
||||
import li.cil.oc.api.internal.Robot
|
||||
import li.cil.oc.common.Slot
|
||||
import li.cil.oc.common.Tier
|
||||
import li.cil.oc.common.entity.Drone
|
||||
import li.cil.oc.common.tileentity.Robot
|
||||
import li.cil.oc.server.component
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
@ -16,8 +17,9 @@ object DriverUpgradeTankController extends Item with HostAware with EnvironmentA
|
||||
isOneOf(stack, api.Items.get("tankControllerUpgrade"))
|
||||
|
||||
override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = host match {
|
||||
case robot: EnvironmentHost with Robot => new component.UpgradeTankControllerInRobot(robot)
|
||||
case adapter: EnvironmentHost with Adapter => new component.UpgradeTankControllerInAdapter(adapter)
|
||||
case host: EnvironmentHost with Adapter => new component.UpgradeTankController.Adapter(host)
|
||||
case host: EnvironmentHost with Drone => new component.UpgradeTankController.Drone(host)
|
||||
case host: EnvironmentHost with Robot => new component.UpgradeTankController.Robot(host)
|
||||
case _ => null
|
||||
}
|
||||
|
||||
@ -25,5 +27,5 @@ object DriverUpgradeTankController extends Item with HostAware with EnvironmentA
|
||||
|
||||
override def tier(stack: ItemStack) = Tier.Two
|
||||
|
||||
override def providedEnvironment(stack: ItemStack) = classOf[component.UpgradeTankControllerInRobot]
|
||||
override def providedEnvironment(stack: ItemStack) = classOf[component.UpgradeTankController.Robot]
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package li.cil.oc.server.component
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.Network
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
@ -12,8 +11,6 @@ import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.InventoryUtils
|
||||
import net.minecraft.entity.item.EntityItem
|
||||
import net.minecraft.world.WorldServer
|
||||
import net.minecraftforge.common.util.FakePlayerFactory
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
class Drone(val host: entity.Drone) extends prefab.ManagedEnvironment with traits.WorldControl with traits.InventoryControl with traits.InventoryWorldControl with traits.TankAware with traits.TankControl with traits.TankWorldControl {
|
||||
@ -21,13 +18,7 @@ class Drone(val host: entity.Drone) extends prefab.ManagedEnvironment with trait
|
||||
withComponent("drone").
|
||||
create()
|
||||
|
||||
def world = host.world
|
||||
|
||||
def x = math.floor(host.posX).toInt
|
||||
|
||||
def y = math.floor(host.posY).toInt
|
||||
|
||||
def z = math.floor(host.posZ).toInt
|
||||
override protected def position = BlockPosition(host)
|
||||
|
||||
override def inventory = host.inventory
|
||||
|
||||
@ -41,14 +32,6 @@ class Drone(val host: entity.Drone) extends prefab.ManagedEnvironment with trait
|
||||
|
||||
override def selectedTank_=(value: Int) = host.selectedTank = value
|
||||
|
||||
override protected def fakePlayer = {
|
||||
val player = FakePlayerFactory.get(world.asInstanceOf[WorldServer], Settings.get.fakePlayerProfile)
|
||||
player.posX = host.posX
|
||||
player.posY = host.posY
|
||||
player.posZ = host.posZ
|
||||
player
|
||||
}
|
||||
|
||||
override protected def checkSideForAction(args: Arguments, n: Int) =
|
||||
args.checkSide(n, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
|
||||
|
@ -0,0 +1,79 @@
|
||||
package li.cil.oc.server.component
|
||||
|
||||
import li.cil.oc.api.Network
|
||||
import li.cil.oc.api.driver.EnvironmentHost
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.api.network._
|
||||
import li.cil.oc.api.prefab
|
||||
import li.cil.oc.common.entity
|
||||
import li.cil.oc.common.tileentity
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
object UpgradeInventoryController {
|
||||
|
||||
class Adapter(val host: EnvironmentHost) extends prefab.ManagedEnvironment with traits.WorldInventoryAnalytics {
|
||||
override val node = Network.newNode(this, Visibility.Network).
|
||||
withComponent("inventory_controller", Visibility.Network).
|
||||
create()
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override protected def position = BlockPosition(host)
|
||||
|
||||
override protected def checkSideForAction(args: Arguments, n: Int) = args.checkSide(n, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
}
|
||||
|
||||
class Drone(val host: EnvironmentHost with entity.Drone) extends prefab.ManagedEnvironment with traits.InventoryAnalytics with traits.InventoryWorldControlMk2 with traits.WorldInventoryAnalytics {
|
||||
override val node = Network.newNode(this, Visibility.Network).
|
||||
withComponent("inventory_controller", Visibility.Neighbors).
|
||||
create()
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override protected def position = BlockPosition(host)
|
||||
|
||||
override def inventory = host.inventory
|
||||
|
||||
override def selectedSlot = host.selectedSlot
|
||||
|
||||
override def selectedSlot_=(value: Int) = host.selectedSlot = value
|
||||
|
||||
override protected def checkSideForAction(args: Arguments, n: Int) = args.checkSide(n, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
}
|
||||
|
||||
class Robot(val host: EnvironmentHost with tileentity.Robot) extends prefab.ManagedEnvironment with traits.InventoryAnalytics with traits.InventoryWorldControlMk2 with traits.WorldInventoryAnalytics {
|
||||
override val node = Network.newNode(this, Visibility.Network).
|
||||
withComponent("inventory_controller", Visibility.Neighbors).
|
||||
create()
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override protected def position = BlockPosition(host)
|
||||
|
||||
override def inventory = host.dynamicInventory
|
||||
|
||||
override def selectedSlot = host.selectedSlot
|
||||
|
||||
override def selectedSlot_=(value: Int) = host.selectedSlot = value
|
||||
|
||||
override protected def checkSideForAction(args: Arguments, n: Int) = host.toGlobal(args.checkSideForAction(n))
|
||||
|
||||
@Callback(doc = """function():boolean -- Swaps the equipped tool with the content of the currently selected inventory slot.""")
|
||||
def equip(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
if (host.inventorySize > 0) {
|
||||
val selectedSlot = host.selectedSlot
|
||||
val equipped = host.getStackInSlot(0)
|
||||
val selected = host.getStackInSlot(selectedSlot)
|
||||
host.setInventorySlotContents(0, selected)
|
||||
host.setInventorySlotContents(selectedSlot, equipped)
|
||||
result(true)
|
||||
}
|
||||
else result(false)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
package li.cil.oc.server.component
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.Network
|
||||
import li.cil.oc.api.driver.EnvironmentHost
|
||||
import li.cil.oc.api.internal.Adapter
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.api.network._
|
||||
import li.cil.oc.api.prefab
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.DatabaseAccess
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.InventoryUtils
|
||||
import net.minecraft.inventory.IInventory
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.world.WorldServer
|
||||
import net.minecraftforge.common.util.FakePlayerFactory
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
class UpgradeInventoryControllerInAdapter(val host: EnvironmentHost with Adapter) extends prefab.ManagedEnvironment {
|
||||
override val node = Network.newNode(this, Visibility.Network).
|
||||
withComponent("inventory_controller", Visibility.Network).
|
||||
create()
|
||||
|
||||
private val fakePlayer = FakePlayerFactory.get(host.world.asInstanceOf[WorldServer], Settings.get.fakePlayerProfile)
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@Callback(doc = """function(side:number):number -- Get the number of slots in the inventory on the specified side of the adapter.""")
|
||||
def getInventorySize(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if checkPermission(inventory) => result(inventory.getSizeInventory)
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number, slot:number):number -- Get number of items in the specified slot of the inventory on the specified side of the adapter.""")
|
||||
def getSlotStackSize(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if checkPermission(inventory) =>
|
||||
result(Option(inventory.getStackInSlot(args.checkSlot(inventory, 1))).fold(0)(_.stackSize))
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number, slot:number):number -- Get the maximum number of items in the specified slot of the inventory on the specified side of the adapter.""")
|
||||
def getSlotMaxStackSize(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if checkPermission(inventory) =>
|
||||
result(Option(inventory.getStackInSlot(args.checkSlot(inventory, 1))).fold(0)(_.getMaxStackSize))
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(slotA:number, slotB:number):boolean -- Get whether the items in the two specified slots of the inventory on the specified side of the adapter are of the same type.""")
|
||||
def compareStacks(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if checkPermission(inventory) =>
|
||||
val stackA = inventory.getStackInSlot(args.checkSlot(inventory, 1))
|
||||
val stackB = inventory.getStackInSlot(args.checkSlot(inventory, 2))
|
||||
result(haveSameItemType(stackA, stackB))
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number, slot:number):table -- Get a description of the stack in the specified slot of the inventory on the specified side of the adapter.""")
|
||||
def getStackInSlot(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
|
||||
val facing = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if checkPermission(inventory) =>
|
||||
result(inventory.getStackInSlot(args.checkSlot(inventory, 1)))
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
else result(Unit, "not enabled in config")
|
||||
|
||||
@Callback(doc = """function(side:number, slot:number, dbAddress:string, dbSlot:number):boolean -- Store an item stack description in the specified slot of the database with the specified address. Returns true if something was overwritten.""")
|
||||
def store(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if checkPermission(inventory) =>
|
||||
val stack = inventory.getStackInSlot(args.checkSlot(inventory, 1))
|
||||
DatabaseAccess.withDatabase(node, args.checkString(2), database => {
|
||||
val dbSlot = args.checkSlot(database.data, 3)
|
||||
val nonEmpty = database.data.getStackInSlot(dbSlot) != null
|
||||
database.data.setInventorySlotContents(dbSlot, stack.copy())
|
||||
result(nonEmpty)
|
||||
})
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
private def checkPermission(inventory: IInventory) = {
|
||||
fakePlayer synchronized {
|
||||
fakePlayer.setPosition(host.xPosition, host.yPosition, host.zPosition)
|
||||
inventory.isUseableByPlayer(fakePlayer)
|
||||
}
|
||||
}
|
||||
|
||||
private def haveSameItemType(stackA: ItemStack, stackB: ItemStack) =
|
||||
(Option(stackA), Option(stackB)) match {
|
||||
case (Some(a), Some(b)) =>
|
||||
a.getItem == b.getItem &&
|
||||
(!a.getHasSubtypes || a.getItemDamage == b.getItemDamage)
|
||||
case (None, None) => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
@ -1,188 +0,0 @@
|
||||
package li.cil.oc.server.component
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.Network
|
||||
import li.cil.oc.api.driver.EnvironmentHost
|
||||
import li.cil.oc.api.internal.Robot
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.api.network._
|
||||
import li.cil.oc.api.prefab
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.DatabaseAccess
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.InventoryUtils
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
class UpgradeInventoryControllerInRobot(val host: EnvironmentHost with Robot) extends prefab.ManagedEnvironment {
|
||||
override val node = Network.newNode(this, Visibility.Network).
|
||||
withComponent("inventory_controller", Visibility.Neighbors).
|
||||
create()
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@Callback(doc = """function(side:number):number -- Get the number of slots in the inventory on the specified side of the robot. Back refers to the robot's own inventory.""")
|
||||
def getInventorySize(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForInventory(args, 0)
|
||||
if (facing == host.facing.getOpposite) result(host.inventorySize)
|
||||
else InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if inventory.isUseableByPlayer(host.player) => result(inventory.getSizeInventory)
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number, slot:number):number -- Get number of items in the specified slot of the inventory on the specified side of the robot. Back refers to the robot's own inventory.""")
|
||||
def getSlotStackSize(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForInventory(args, 0)
|
||||
if (facing == host.facing.getOpposite)
|
||||
result(Option(host.getStackInSlot(args.checkSlot(host, 1))).fold(0)(_.stackSize))
|
||||
else InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if inventory.isUseableByPlayer(host.player) =>
|
||||
result(Option(inventory.getStackInSlot(args.checkSlot(inventory, 1))).fold(0)(_.stackSize))
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number, slot:number):number -- Get the maximum number of items in the specified slot of the inventory on the specified side of the robot. Back refers to the robot's own inventory.""")
|
||||
def getSlotMaxStackSize(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForInventory(args, 0)
|
||||
if (facing == host.facing.getOpposite)
|
||||
result(Option(host.getStackInSlot(args.checkSlot(host, 1))).fold(0)(_.getMaxStackSize))
|
||||
InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if inventory.isUseableByPlayer(host.player) =>
|
||||
result(Option(inventory.getStackInSlot(args.checkSlot(inventory, 1))).fold(0)(_.getMaxStackSize))
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(slotA:number, slotB:number):boolean -- Get whether the items in the two specified slots of the inventory on the specified side of the robot are of the same type. Back refers to the robot's own inventory.""")
|
||||
def compareStacks(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForInventory(args, 0)
|
||||
if (facing == host.facing.getOpposite) {
|
||||
val stackA = host.getStackInSlot(args.checkSlot(host, 1))
|
||||
val stackB = host.getStackInSlot(args.checkSlot(host, 2))
|
||||
result(haveSameItemType(stackA, stackB))
|
||||
}
|
||||
InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if inventory.isUseableByPlayer(host.player) =>
|
||||
val stackA = inventory.getStackInSlot(args.checkSlot(inventory, 1))
|
||||
val stackB = inventory.getStackInSlot(args.checkSlot(inventory, 2))
|
||||
result(haveSameItemType(stackA, stackB))
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number, slot:number):table -- Get a description of the stack in the the inventory on the specified side of the robot. Back refers to the robot's own inventory.""")
|
||||
def getStackInSlot(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
|
||||
val facing = checkSideForInventory(args, 0)
|
||||
if (facing == host.facing.getOpposite) {
|
||||
val slot = args.checkSlot(host, 1)
|
||||
result(host.getStackInSlot(slot))
|
||||
}
|
||||
else InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if inventory.isUseableByPlayer(host.player) =>
|
||||
val slot = args.checkSlot(inventory, 1)
|
||||
result(inventory.getStackInSlot(slot))
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
else result(Unit, "not enabled in config")
|
||||
|
||||
@Callback(doc = """function(side:number, slot:number, dbAddress:string, dbSlot:number):boolean -- Store an item stack description in the specified slot of the database with the specified address. Returns true if something was overwritten.""")
|
||||
def store(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForInventory(args, 0)
|
||||
def store(stack: ItemStack) = DatabaseAccess.withDatabase(node, args.checkString(2), database => {
|
||||
val dbSlot = args.checkSlot(database.data, 3)
|
||||
val nonEmpty = database.data.getStackInSlot(dbSlot) != null
|
||||
database.data.setInventorySlotContents(dbSlot, stack.copy())
|
||||
result(nonEmpty)
|
||||
})
|
||||
if (facing == host.facing.getOpposite) {
|
||||
val slot = args.checkSlot(host, 1)
|
||||
store(host.getStackInSlot(slot))
|
||||
}
|
||||
else InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if inventory.isUseableByPlayer(host.player) =>
|
||||
val slot = args.checkSlot(inventory, 1)
|
||||
store(inventory.getStackInSlot(slot))
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(facing:number, slot:number[, count:number]):boolean -- Drops the selected item stack into the specified slot of an inventory.""")
|
||||
def dropIntoSlot(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val count = args.optionalItemCount(2)
|
||||
val selectedSlot = host.selectedSlot
|
||||
val stack = host.getStackInSlot(selectedSlot)
|
||||
if (stack != null && stack.stackSize > 0) {
|
||||
InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if inventory.isUseableByPlayer(host.player) =>
|
||||
val slot = args.checkSlot(inventory, 1)
|
||||
if (!InventoryUtils.insertIntoInventorySlot(stack, inventory, Option(facing.getOpposite), slot, count)) {
|
||||
// Cannot drop into that inventory.
|
||||
return result(false, "inventory full/invalid slot")
|
||||
}
|
||||
else if (stack.stackSize == 0) {
|
||||
// Dropped whole stack.
|
||||
host.setInventorySlotContents(selectedSlot, null)
|
||||
}
|
||||
else {
|
||||
// Dropped partial stack.
|
||||
host.markDirty()
|
||||
}
|
||||
case _ => return result(false, "no inventory")
|
||||
}
|
||||
|
||||
context.pause(Settings.get.dropDelay)
|
||||
|
||||
result(true)
|
||||
}
|
||||
else result(false)
|
||||
}
|
||||
|
||||
@Callback(doc = """function(facing:number, slot:number[, count:number]):boolean -- Sucks items from the specified slot of an inventory.""")
|
||||
def suckFromSlot(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val count = args.optionalItemCount(2)
|
||||
|
||||
InventoryUtils.inventoryAt(BlockPosition(host).offset(facing)) match {
|
||||
case Some(inventory) if inventory.isUseableByPlayer(host.player) =>
|
||||
val slot = args.checkSlot(inventory, 1)
|
||||
if (InventoryUtils.extractFromInventorySlot(host.player.inventory.addItemStackToInventory, inventory, facing.getOpposite, slot, count)) {
|
||||
context.pause(Settings.get.suckDelay)
|
||||
result(true)
|
||||
}
|
||||
else result(false)
|
||||
case _ => result(false, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function():boolean -- Swaps the equipped tool with the content of the currently selected inventory slot.""")
|
||||
def equip(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
if (host.inventorySize > 0) {
|
||||
val selectedSlot = host.selectedSlot
|
||||
val equipped = host.getStackInSlot(0)
|
||||
val selected = host.getStackInSlot(selectedSlot)
|
||||
host.setInventorySlotContents(0, selected)
|
||||
host.setInventorySlotContents(selectedSlot, equipped)
|
||||
result(true)
|
||||
}
|
||||
else result(false)
|
||||
}
|
||||
|
||||
private def haveSameItemType(stackA: ItemStack, stackB: ItemStack) =
|
||||
(Option(stackA), Option(stackB)) match {
|
||||
case (Some(a), Some(b)) =>
|
||||
a.getItem == b.getItem &&
|
||||
(!a.getHasSubtypes || a.getItemDamage == b.getItemDamage)
|
||||
case (None, None) => true
|
||||
case _ => false
|
||||
}
|
||||
|
||||
private def checkSideForInventory(args: Arguments, n: Int) = host.toGlobal(args.checkSide(n, ForgeDirection.SOUTH, ForgeDirection.NORTH, ForgeDirection.UP, ForgeDirection.DOWN))
|
||||
|
||||
private def checkSideForAction(args: Arguments, n: Int) = host.toGlobal(args.checkSideForAction(n))
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package li.cil.oc.server.component
|
||||
|
||||
import li.cil.oc.api.Network
|
||||
import li.cil.oc.api.driver.EnvironmentHost
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.network._
|
||||
import li.cil.oc.api.prefab
|
||||
import li.cil.oc.common.entity
|
||||
import li.cil.oc.common.tileentity
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
object UpgradeTankController {
|
||||
|
||||
class Adapter(val host: EnvironmentHost) extends prefab.ManagedEnvironment with traits.WorldTankAnalytics {
|
||||
override val node = Network.newNode(this, Visibility.Network).
|
||||
withComponent("tank_controller", Visibility.Network).
|
||||
create()
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override protected def position = BlockPosition(host)
|
||||
|
||||
override protected def checkSideForAction(args: Arguments, n: Int) = args.checkSide(n, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
}
|
||||
|
||||
class Drone(val host: EnvironmentHost with entity.Drone) extends prefab.ManagedEnvironment with traits.TankInventoryControl with traits.WorldTankAnalytics {
|
||||
override val node = Network.newNode(this, Visibility.Network).
|
||||
withComponent("tank_controller", Visibility.Neighbors).
|
||||
create()
|
||||
|
||||
override protected def position = BlockPosition(host)
|
||||
|
||||
override def inventory = host.inventory
|
||||
|
||||
override def selectedSlot = host.selectedSlot
|
||||
|
||||
override def selectedSlot_=(value: Int) = host.selectedSlot = value
|
||||
|
||||
override def tank = host.tank
|
||||
|
||||
override def selectedTank = host.selectedTank
|
||||
|
||||
override def selectedTank_=(value: Int) = host.selectedTank = value
|
||||
|
||||
override protected def checkSideForAction(args: Arguments, n: Int) = args.checkSide(n, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
}
|
||||
|
||||
class Robot(val host: EnvironmentHost with tileentity.Robot) extends prefab.ManagedEnvironment with traits.TankInventoryControl with traits.WorldTankAnalytics {
|
||||
override val node = Network.newNode(this, Visibility.Network).
|
||||
withComponent("tank_controller", Visibility.Neighbors).
|
||||
create()
|
||||
|
||||
override protected def position = BlockPosition(host)
|
||||
|
||||
override def inventory = host.dynamicInventory
|
||||
|
||||
override def selectedSlot = host.selectedSlot
|
||||
|
||||
override def selectedSlot_=(value: Int) = host.selectedSlot = value
|
||||
|
||||
override def tank = host.tank
|
||||
|
||||
override def selectedTank = host.selectedTank
|
||||
|
||||
override def selectedTank_=(value: Int) = host.selectedTank = value
|
||||
|
||||
override protected def checkSideForAction(args: Arguments, n: Int) = host.toGlobal(args.checkSideForAction(n))
|
||||
}
|
||||
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package li.cil.oc.server.component
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.Network
|
||||
import li.cil.oc.api.driver.EnvironmentHost
|
||||
import li.cil.oc.api.internal.Adapter
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.api.network._
|
||||
import li.cil.oc.api.prefab
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
import net.minecraftforge.fluids.IFluidHandler
|
||||
|
||||
class UpgradeTankControllerInAdapter(val host: EnvironmentHost with Adapter) extends prefab.ManagedEnvironment {
|
||||
override val node = Network.newNode(this, Visibility.Network).
|
||||
withComponent("tank_controller", Visibility.Network).
|
||||
create()
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@Callback(doc = """function(side:number):number -- Get the amount of fluid in the tank on the specified side of the adapter.""")
|
||||
def getTankLevel(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
host.world.getTileEntity(BlockPosition(host).offset(facing)) match {
|
||||
case handler: IFluidHandler =>
|
||||
result(handler.getTankInfo(facing.getOpposite).map(info => Option(info.fluid).fold(0)(_.amount)).sum)
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number):number -- Get the capacity of the tank on the specified side of the adapter.""")
|
||||
def getTankCapacity(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
host.world.getTileEntity(BlockPosition(host).offset(facing)) match {
|
||||
case handler: IFluidHandler =>
|
||||
result(handler.getTankInfo(facing.getOpposite).map(_.capacity).foldLeft(0)((max, capacity) => math.max(max, capacity)))
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number):table -- Get a description of the fluid in the the tank on the specified side of the adapter.""")
|
||||
def getFluidInTank(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
|
||||
val facing = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
host.world.getTileEntity(BlockPosition(host).offset(facing)) match {
|
||||
case handler: IFluidHandler => result(handler.getTankInfo(facing.getOpposite))
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
else result(Unit, "not enabled in config")
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
package li.cil.oc.server.component
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.Network
|
||||
import li.cil.oc.api.driver.EnvironmentHost
|
||||
import li.cil.oc.api.internal.Robot
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.api.network._
|
||||
import li.cil.oc.api.prefab
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
import net.minecraftforge.fluids.FluidContainerRegistry
|
||||
import net.minecraftforge.fluids.IFluidContainerItem
|
||||
import net.minecraftforge.fluids.IFluidHandler
|
||||
|
||||
class UpgradeTankControllerInRobot(val host: EnvironmentHost with Robot) extends prefab.ManagedEnvironment {
|
||||
override val node = Network.newNode(this, Visibility.Network).
|
||||
withComponent("tank_controller", Visibility.Neighbors).
|
||||
create()
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@Callback(doc = """function(side:number):number -- Get the amount of fluid in the tank on the specified side of the robot. Back refers to the robot's own selected tank.""")
|
||||
def getTankLevel(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForTank(args, 0)
|
||||
if (facing == host.facing.getOpposite) result(Option(host.getFluidTank(host.selectedTank)).fold(0)(_.getFluidAmount))
|
||||
else host.world.getTileEntity(BlockPosition(host).offset(facing)) match {
|
||||
case handler: IFluidHandler =>
|
||||
result((Option(host.getFluidTank(host.selectedTank)) match {
|
||||
case Some(tank) => handler.getTankInfo(facing.getOpposite).filter(info => info.fluid == null || info.fluid.isFluidEqual(tank.getFluid))
|
||||
case _ => handler.getTankInfo(facing.getOpposite)
|
||||
}).map(info => Option(info.fluid).fold(0)(_.amount)).sum)
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number):number -- Get the capacity of the tank on the specified side of the robot. Back refers to the robot's own selected tank.""")
|
||||
def getTankCapacity(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForTank(args, 0)
|
||||
if (facing == host.facing.getOpposite) result(Option(host.getFluidTank(host.selectedTank)).fold(0)(_.getCapacity))
|
||||
else host.world.getTileEntity(BlockPosition(host).offset(facing)) match {
|
||||
case handler: IFluidHandler =>
|
||||
result((Option(host.getFluidTank(host.selectedTank)) match {
|
||||
case Some(tank) => handler.getTankInfo(facing.getOpposite).filter(info => info.fluid == null || info.fluid.isFluidEqual(tank.getFluid))
|
||||
case _ => handler.getTankInfo(facing.getOpposite)
|
||||
}).map(_.capacity).foldLeft(0)((max, capacity) => math.max(max, capacity)))
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number):table -- Get a description of the fluid in the the tank on the specified side of the robot. Back refers to the robot's own selected tank.""")
|
||||
def getFluidInTank(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
|
||||
val facing = checkSideForTank(args, 0)
|
||||
if (facing == host.facing.getOpposite) result(Option(host.getFluidTank(host.selectedTank)).map(_.getFluid).orNull)
|
||||
else host.world.getTileEntity(BlockPosition(host).offset(facing)) match {
|
||||
case handler: IFluidHandler => result(handler.getTankInfo(facing.getOpposite))
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
else result(Unit, "not enabled in config")
|
||||
|
||||
@Callback(doc = """function([amount:number]):boolean -- Transfers fluid from a tank in the selected inventory slot to the selected tank.""")
|
||||
def drain(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val amount = args.optionalFluidCount(0)
|
||||
Option(host.getFluidTank(host.selectedTank)) match {
|
||||
case Some(tank) =>
|
||||
host.getStackInSlot(host.selectedSlot) match {
|
||||
case stack: ItemStack =>
|
||||
if (FluidContainerRegistry.isFilledContainer(stack)) {
|
||||
val contents = FluidContainerRegistry.getFluidForFilledItem(stack)
|
||||
val container = stack.getItem.getContainerItem(stack)
|
||||
if (tank.getCapacity - tank.getFluidAmount < contents.amount) {
|
||||
result(Unit, "tank is full")
|
||||
}
|
||||
else if (tank.fill(contents, false) < contents.amount) {
|
||||
result(Unit, "incompatible fluid")
|
||||
}
|
||||
else {
|
||||
tank.fill(contents, true)
|
||||
host.decrStackSize(host.selectedSlot, 1)
|
||||
host.player().inventory.addItemStackToInventory(container)
|
||||
result(true)
|
||||
}
|
||||
}
|
||||
else stack.getItem match {
|
||||
case container: IFluidContainerItem =>
|
||||
val drained = container.drain(stack, amount, false)
|
||||
val transferred = tank.fill(drained, true)
|
||||
if (transferred > 0) {
|
||||
container.drain(stack, transferred, true)
|
||||
result(true)
|
||||
}
|
||||
else result(Unit, "incompatible or no fluid")
|
||||
case _ => result(Unit, "item is empty or not a fluid container")
|
||||
}
|
||||
case _ => result(Unit, "nothing selected")
|
||||
}
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function([amount:number]):boolean -- Transfers fluid from the selected tank to a tank in the selected inventory slot.""")
|
||||
def fill(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val amount = args.optionalFluidCount(0)
|
||||
Option(host.getFluidTank(host.selectedTank)) match {
|
||||
case Some(tank) =>
|
||||
host.getStackInSlot(host.selectedSlot) match {
|
||||
case stack: ItemStack =>
|
||||
if (FluidContainerRegistry.isEmptyContainer(stack)) {
|
||||
val drained = tank.drain(amount, false)
|
||||
val filled = FluidContainerRegistry.fillFluidContainer(drained, stack)
|
||||
if (filled == null) {
|
||||
result(Unit, "tank is empty")
|
||||
}
|
||||
else {
|
||||
tank.drain(FluidContainerRegistry.getFluidForFilledItem(filled).amount, true)
|
||||
host.decrStackSize(host.selectedSlot, 1)
|
||||
host.player().inventory.addItemStackToInventory(filled)
|
||||
result(true)
|
||||
}
|
||||
}
|
||||
else stack.getItem match {
|
||||
case container: IFluidContainerItem =>
|
||||
val drained = tank.drain(amount, false)
|
||||
val transferred = container.fill(stack, drained, true)
|
||||
if (transferred > 0) {
|
||||
tank.drain(transferred, true)
|
||||
result(true)
|
||||
}
|
||||
else result(Unit, "incompatible or no fluid")
|
||||
case _ => result(Unit, "item is full or not a fluid container")
|
||||
}
|
||||
case _ => result(Unit, "nothing selected")
|
||||
}
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
|
||||
private def checkSideForTank(args: Arguments, n: Int) = host.toGlobal(args.checkSide(n, ForgeDirection.SOUTH, ForgeDirection.NORTH, ForgeDirection.UP, ForgeDirection.DOWN))
|
||||
}
|
@ -10,19 +10,17 @@ import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.api.network._
|
||||
import li.cil.oc.api.prefab
|
||||
import li.cil.oc.common.ToolDurabilityProviders
|
||||
import li.cil.oc.common.inventory.MultiTank
|
||||
import li.cil.oc.common.tileentity
|
||||
import li.cil.oc.server.component.traits
|
||||
import li.cil.oc.server.{PacketSender => ServerPacketSender}
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.ExtendedNBT._
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
import li.cil.oc.util.ResultWrapper.result
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.EntityLivingBase
|
||||
import net.minecraft.entity.item.EntityMinecart
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.inventory.IInventory
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraft.util.MovingObjectPosition
|
||||
import net.minecraft.util.MovingObjectPosition.MovingObjectType
|
||||
@ -41,13 +39,7 @@ class Robot(val robot: tileentity.Robot) extends prefab.ManagedEnvironment with
|
||||
val romRobot = Option(api.FileSystem.asManagedEnvironment(api.FileSystem.
|
||||
fromClass(OpenComputers.getClass, Settings.resourceDomain, "lua/component/robot"), "robot"))
|
||||
|
||||
def world = robot.world
|
||||
|
||||
def x = robot.x
|
||||
|
||||
def y = robot.y
|
||||
|
||||
def z = robot.z
|
||||
override protected def position = BlockPosition(robot)
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@ -64,11 +56,7 @@ class Robot(val robot: tileentity.Robot) extends prefab.ManagedEnvironment with
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
val tank = new MultiTank {
|
||||
override def tankCount = robot.tankCount
|
||||
|
||||
override def getFluidTank(index: Int) = robot.getFluidTank(index)
|
||||
}
|
||||
override def tank = robot.tank
|
||||
|
||||
def selectedTank = robot.selectedTank
|
||||
|
||||
@ -205,7 +193,7 @@ class Robot(val robot: tileentity.Robot) extends prefab.ManagedEnvironment with
|
||||
case Some(entity) =>
|
||||
attack(player, entity)
|
||||
case _ =>
|
||||
if (world.extinguishFire(player, x, y, z, facing.ordinal)) {
|
||||
if (world.extinguishFire(player, position, facing)) {
|
||||
triggerDelay()
|
||||
(true, "fire")
|
||||
}
|
||||
@ -435,16 +423,15 @@ class Robot(val robot: tileentity.Robot) extends prefab.ManagedEnvironment with
|
||||
}
|
||||
|
||||
private def clickParamsForPlace(facing: ForgeDirection) = {
|
||||
(x, y, z,
|
||||
(position.x, position.y, position.z,
|
||||
0.5f + facing.offsetX * 0.5f,
|
||||
0.5f + facing.offsetY * 0.5f,
|
||||
0.5f + facing.offsetZ * 0.5f)
|
||||
}
|
||||
|
||||
private def clickParamsForItemUse(facing: ForgeDirection, side: ForgeDirection) = {
|
||||
(x + facing.offsetX + side.offsetX,
|
||||
y + facing.offsetY + side.offsetY,
|
||||
z + facing.offsetZ + side.offsetZ,
|
||||
val blockPos = position.offset(facing).offset(side)
|
||||
(blockPos.x, blockPos.y, blockPos.z,
|
||||
0.5f - side.offsetX * 0.5f,
|
||||
0.5f - side.offsetY * 0.5f,
|
||||
0.5f - side.offsetZ * 0.5f)
|
||||
|
@ -0,0 +1,32 @@
|
||||
package li.cil.oc.server.component.traits
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.server.component.result
|
||||
import li.cil.oc.util.DatabaseAccess
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
trait InventoryAnalytics extends InventoryAware with NetworkAware {
|
||||
@Callback(doc = """function([slot:number]):table -- Get a description of the stack in the specified slot or the selected slot.""")
|
||||
def getStackInInternalSlot(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
|
||||
val slot = optSlot(args, 0)
|
||||
result(inventory.getStackInSlot(slot))
|
||||
}
|
||||
else result(Unit, "not enabled in config")
|
||||
|
||||
@Callback(doc = """function(slot:number, dbAddress:string, dbSlot:number):boolean -- Store an item stack description in the specified slot of the database with the specified address.""")
|
||||
def storeInternal(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val localSlot = args.checkSlot(inventory, 0)
|
||||
val dbAddress = args.checkString(1)
|
||||
def store(stack: ItemStack) = DatabaseAccess.withDatabase(node, dbAddress, database => {
|
||||
val dbSlot = args.checkSlot(database.data, 2)
|
||||
val nonEmpty = database.data.getStackInSlot(dbSlot) != null
|
||||
database.data.setInventorySlotContents(dbSlot, stack.copy())
|
||||
result(nonEmpty)
|
||||
})
|
||||
store(inventory.getStackInSlot(localSlot))
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package li.cil.oc.server.component.traits
|
||||
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import net.minecraft.inventory.IInventory
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
@ -17,6 +19,10 @@ trait InventoryAware {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
protected def optSlot(args: Arguments, n: Int) =
|
||||
if (args.count > 0 && args.checkAny(0) != null) args.checkSlot(inventory, 0)
|
||||
else selectedSlot
|
||||
|
||||
protected def stackInSlot(slot: Int) = Option(inventory.getStackInSlot(slot))
|
||||
|
||||
protected def haveSameItemType(stackA: ItemStack, stackB: ItemStack) =
|
||||
|
@ -12,20 +12,16 @@ trait InventoryControl extends InventoryAware {
|
||||
|
||||
@Callback(doc = "function([slot:number]):number -- Get the currently selected slot; set the selected slot if specified.")
|
||||
def select(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
if (args.count > 0 && args.checkAny(0) != null) {
|
||||
val slot = args.checkSlot(inventory, 0)
|
||||
if (slot != selectedSlot) {
|
||||
selectedSlot = slot
|
||||
}
|
||||
val slot = optSlot(args, 0)
|
||||
if (slot != selectedSlot) {
|
||||
selectedSlot = slot
|
||||
}
|
||||
result(selectedSlot + 1)
|
||||
}
|
||||
|
||||
@Callback(direct = true, doc = "function([slot:number]):number -- Get the number of items in the specified slot, otherwise in the selected slot.")
|
||||
def count(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val slot =
|
||||
if (args.count > 0 && args.checkAny(0) != null) args.checkSlot(inventory, 0)
|
||||
else selectedSlot
|
||||
val slot = optSlot(args, 0)
|
||||
result(stackInSlot(slot) match {
|
||||
case Some(stack) => stack.stackSize
|
||||
case _ => 0
|
||||
@ -34,9 +30,7 @@ trait InventoryControl extends InventoryAware {
|
||||
|
||||
@Callback(direct = true, doc = "function([slot:number]):number -- Get the remaining space in the specified slot, otherwise in the selected slot.")
|
||||
def space(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val slot =
|
||||
if (args.count > 0 && args.checkAny(0) != null) args.checkSlot(inventory, 0)
|
||||
else selectedSlot
|
||||
val slot = optSlot(args, 0)
|
||||
result(stackInSlot(slot) match {
|
||||
case Some(stack) => math.min(inventory.getInventoryStackLimit, stack.getMaxStackSize) - stack.stackSize
|
||||
case _ => inventory.getInventoryStackLimit
|
||||
|
@ -4,7 +4,6 @@ import li.cil.oc.Settings
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
import li.cil.oc.util.InventoryUtils
|
||||
@ -20,7 +19,7 @@ trait InventoryWorldControl extends InventoryAware with WorldAware with SideRest
|
||||
stackInSlot(selectedSlot) match {
|
||||
case Some(stack) => Option(stack.getItem) match {
|
||||
case Some(item: ItemBlock) =>
|
||||
val blockPos = BlockPosition(x, y, z, Option(world)).offset(side)
|
||||
val blockPos = position.offset(side)
|
||||
val idMatches = item.field_150939_a == world.getBlock(blockPos)
|
||||
val subTypeMatches = !item.getHasSubtypes || item.getMetadata(stack.getItemDamage) == world.getBlockMetadata(blockPos)
|
||||
return result(idMatches && subTypeMatches)
|
||||
@ -37,7 +36,7 @@ trait InventoryWorldControl extends InventoryAware with WorldAware with SideRest
|
||||
val count = args.optionalItemCount(1)
|
||||
val stack = inventory.getStackInSlot(selectedSlot)
|
||||
if (stack != null && stack.stackSize > 0) {
|
||||
InventoryUtils.inventoryAt(BlockPosition(x, y, z, Option(world)).offset(facing)) match {
|
||||
InventoryUtils.inventoryAt(position.offset(facing)) match {
|
||||
case Some(inv) if inv.isUseableByPlayer(fakePlayer) =>
|
||||
if (!InventoryUtils.insertIntoInventory(stack, inv, Option(facing.getOpposite), count)) {
|
||||
// Cannot drop into that inventory.
|
||||
@ -68,7 +67,7 @@ trait InventoryWorldControl extends InventoryAware with WorldAware with SideRest
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val count = args.optionalItemCount(1)
|
||||
|
||||
if (InventoryUtils.inventoryAt(BlockPosition(x, y, z, Option(world)).offset(facing)).exists(inventory => {
|
||||
if (InventoryUtils.inventoryAt(position.offset(facing)).exists(inventory => {
|
||||
inventory.isUseableByPlayer(fakePlayer) && InventoryUtils.extractFromInventory(InventoryUtils.insertIntoInventory(_, this.inventory, slots = Option(insertionSlots)), inventory, facing.getOpposite, count)
|
||||
})) {
|
||||
context.pause(Settings.get.suckDelay)
|
||||
|
@ -0,0 +1,62 @@
|
||||
package li.cil.oc.server.component.traits
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.server.component.result
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.InventoryUtils
|
||||
import net.minecraft.inventory.IInventory
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
trait InventoryWorldControlMk2 extends InventoryAware with WorldAware with SideRestricted {
|
||||
@Callback(doc = """function(facing:number, slot:number[, count:number]):boolean -- Drops the selected item stack into the specified slot of an inventory.""")
|
||||
def dropIntoSlot(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val count = args.optionalItemCount(2)
|
||||
val stack = inventory.getStackInSlot(selectedSlot)
|
||||
if (stack != null && stack.stackSize > 0) {
|
||||
withInventory(facing, inventory => {
|
||||
val slot = args.checkSlot(inventory, 1)
|
||||
if (!InventoryUtils.insertIntoInventorySlot(stack, inventory, Option(facing.getOpposite), slot, count)) {
|
||||
// Cannot drop into that inventory.
|
||||
return result(false, "inventory full/invalid slot")
|
||||
}
|
||||
else if (stack.stackSize == 0) {
|
||||
// Dropped whole stack.
|
||||
inventory.setInventorySlotContents(selectedSlot, null)
|
||||
}
|
||||
else {
|
||||
// Dropped partial stack.
|
||||
inventory.markDirty()
|
||||
}
|
||||
|
||||
context.pause(Settings.get.dropDelay)
|
||||
|
||||
result(true)
|
||||
})
|
||||
}
|
||||
else result(false)
|
||||
}
|
||||
|
||||
@Callback(doc = """function(facing:number, slot:number[, count:number]):boolean -- Sucks items from the specified slot of an inventory.""")
|
||||
def suckFromSlot(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val count = args.optionalItemCount(2)
|
||||
withInventory(facing, inventory => {
|
||||
val slot = args.checkSlot(inventory, 1)
|
||||
if (InventoryUtils.extractFromInventorySlot(InventoryUtils.insertIntoInventory(_, this.inventory, slots = Option(insertionSlots)), inventory, facing.getOpposite, slot, count)) {
|
||||
context.pause(Settings.get.suckDelay)
|
||||
result(true)
|
||||
}
|
||||
else result(false)
|
||||
})
|
||||
}
|
||||
|
||||
private def withInventory(side: ForgeDirection, f: IInventory => Array[AnyRef]) =
|
||||
InventoryUtils.inventoryAt(position.offset(side)) match {
|
||||
case Some(inventory) if inventory.isUseableByPlayer(fakePlayer) => f(inventory)
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package li.cil.oc.server.component.traits
|
||||
|
||||
import li.cil.oc.api.network.Node
|
||||
|
||||
trait NetworkAware {
|
||||
def node: Node
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package li.cil.oc.server.component.traits
|
||||
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.common.inventory.MultiTank
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
|
||||
trait TankAware {
|
||||
@ -12,6 +14,10 @@ trait TankAware {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
protected def optTank(args: Arguments, n: Int) =
|
||||
if (args.count > 0 && args.checkAny(0) != null) args.checkTank(tank, 0)
|
||||
else selectedTank
|
||||
|
||||
protected def getTank(index: Int) = Option(tank.getFluidTank(index))
|
||||
|
||||
protected def fluidInTank(index: Int) = getTank(index) match {
|
||||
|
@ -0,0 +1,137 @@
|
||||
package li.cil.oc.server.component.traits
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.server.component.result
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.InventoryUtils
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraftforge.fluids.FluidContainerRegistry
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
import net.minecraftforge.fluids.IFluidContainerItem
|
||||
|
||||
trait TankInventoryControl extends WorldAware with InventoryAware with TankAware {
|
||||
@Callback(doc = """function([slot:number]):number -- Get the amount of fluid in the tank item in the specified slot or the selected slot.""")
|
||||
def getTankLevelInSlot(context: Context, args: Arguments): Array[AnyRef] =
|
||||
withFluidInfo(optSlot(args, 0), (fluid, _) => result(fluid.amount))
|
||||
|
||||
@Callback(doc = """function([slot:number]):number -- Get the capacity of the tank item in the specified slot of the robot or the selected slot.""")
|
||||
def getTankCapacityInSlot(context: Context, args: Arguments): Array[AnyRef] =
|
||||
withFluidInfo(optSlot(args, 0), (_, capacity) => result(capacity))
|
||||
|
||||
@Callback(doc = """function([slot:number]):table -- Get a description of the fluid in the tank item in the specified slot or the selected slot.""")
|
||||
def getFluidInTankInSlot(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
|
||||
withFluidInfo(optSlot(args, 0), (fluid, _) => result(fluid))
|
||||
}
|
||||
else result(Unit, "not enabled in config")
|
||||
|
||||
@Callback(doc = """function([tank:number]):table -- Get a description of the fluid in the tank in the specified slot or the selected slot.""")
|
||||
def getFluidInInternalTank(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
|
||||
result(Option(tank.getFluidTank(optTank(args, 0))).map(_.getFluid).orNull)
|
||||
}
|
||||
else result(Unit, "not enabled in config")
|
||||
|
||||
@Callback(doc = """function([amount:number]):boolean -- Transfers fluid from a tank in the selected inventory slot to the selected tank.""")
|
||||
def drain(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val amount = args.optionalFluidCount(0)
|
||||
Option(tank.getFluidTank(selectedTank)) match {
|
||||
case Some(into) => inventory.getStackInSlot(selectedSlot) match {
|
||||
case stack: ItemStack =>
|
||||
if (FluidContainerRegistry.isFilledContainer(stack)) {
|
||||
val contents = FluidContainerRegistry.getFluidForFilledItem(stack)
|
||||
val container = stack.getItem.getContainerItem(stack)
|
||||
if (into.getCapacity - into.getFluidAmount < contents.amount) {
|
||||
result(Unit, "tank is full")
|
||||
}
|
||||
else if (into.fill(contents, false) < contents.amount) {
|
||||
result(Unit, "incompatible fluid")
|
||||
}
|
||||
else {
|
||||
into.fill(contents, true)
|
||||
inventory.decrStackSize(selectedSlot, 1)
|
||||
InventoryUtils.insertIntoInventory(container, inventory, slots = Option(insertionSlots))
|
||||
if (container.stackSize > 0) {
|
||||
InventoryUtils.spawnStackInWorld(position, container)
|
||||
}
|
||||
result(true)
|
||||
}
|
||||
}
|
||||
else stack.getItem match {
|
||||
case from: IFluidContainerItem =>
|
||||
val drained = from.drain(stack, amount, false)
|
||||
val transferred = into.fill(drained, true)
|
||||
if (transferred > 0) {
|
||||
from.drain(stack, transferred, true)
|
||||
result(true)
|
||||
}
|
||||
else result(Unit, "incompatible or no fluid")
|
||||
case _ => result(Unit, "item is empty or not a fluid container")
|
||||
}
|
||||
case _ => result(Unit, "nothing selected")
|
||||
}
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function([amount:number]):boolean -- Transfers fluid from the selected tank to a tank in the selected inventory slot.""")
|
||||
def fill(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val amount = args.optionalFluidCount(0)
|
||||
Option(tank.getFluidTank(selectedTank)) match {
|
||||
case Some(from) => inventory.getStackInSlot(selectedSlot) match {
|
||||
case stack: ItemStack =>
|
||||
if (FluidContainerRegistry.isEmptyContainer(stack)) {
|
||||
val drained = from.drain(amount, false)
|
||||
val filled = FluidContainerRegistry.fillFluidContainer(drained, stack)
|
||||
if (filled == null) {
|
||||
result(Unit, "tank is empty")
|
||||
}
|
||||
else {
|
||||
from.drain(FluidContainerRegistry.getFluidForFilledItem(filled).amount, true)
|
||||
inventory.decrStackSize(selectedSlot, 1)
|
||||
InventoryUtils.insertIntoInventory(filled, inventory, slots = Option(insertionSlots))
|
||||
if (filled.stackSize > 0) {
|
||||
InventoryUtils.spawnStackInWorld(position, filled)
|
||||
}
|
||||
result(true)
|
||||
}
|
||||
}
|
||||
else stack.getItem match {
|
||||
case into: IFluidContainerItem =>
|
||||
val drained = from.drain(amount, false)
|
||||
val transferred = into.fill(stack, drained, true)
|
||||
if (transferred > 0) {
|
||||
from.drain(transferred, true)
|
||||
result(true)
|
||||
}
|
||||
else result(Unit, "incompatible or no fluid")
|
||||
case _ => result(Unit, "item is full or not a fluid container")
|
||||
}
|
||||
case _ => result(Unit, "nothing selected")
|
||||
}
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
|
||||
private def withFluidInfo(slot: Int, f: (FluidStack, Int) => Array[AnyRef]) = {
|
||||
def fluidInfo(stack: ItemStack) = {
|
||||
if (FluidContainerRegistry.isFilledContainer(stack)) {
|
||||
Option((FluidContainerRegistry.getFluidForFilledItem(stack), FluidContainerRegistry.getContainerCapacity(stack)))
|
||||
}
|
||||
else if (FluidContainerRegistry.isEmptyContainer(stack)) {
|
||||
Option((new FluidStack(0, 0), FluidContainerRegistry.getContainerCapacity(stack)))
|
||||
}
|
||||
else stack.getItem match {
|
||||
case from: IFluidContainerItem => Option((from.getFluid(stack), from.getCapacity(stack)))
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
inventory.getStackInSlot(slot) match {
|
||||
case stack: ItemStack => fluidInfo(stack) match {
|
||||
case Some((fluid, capacity)) => f(fluid, capacity)
|
||||
case _ => result(Unit, "item is not a fluid container")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,10 +3,9 @@ package li.cil.oc.server.component.traits
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.ExtendedBlock._
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.ResultWrapper.result
|
||||
import net.minecraftforge.fluids.FluidRegistry
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
@ -18,7 +17,7 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted {
|
||||
val side = checkSideForAction(args, 0)
|
||||
fluidInTank(selectedTank) match {
|
||||
case Some(stack) =>
|
||||
val blockPos = BlockPosition(x, y, z).offset(side)
|
||||
val blockPos = position.offset(side)
|
||||
if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match {
|
||||
case handler: IFluidHandler =>
|
||||
result(Option(handler.getTankInfo(side.getOpposite)).exists(_.exists(other => stack.isFluidEqual(other.fluid))))
|
||||
@ -44,7 +43,7 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted {
|
||||
result(Unit, "tank is full")
|
||||
}
|
||||
else {
|
||||
val blockPos = BlockPosition(x, y, z).offset(facing)
|
||||
val blockPos = position.offset(facing)
|
||||
if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match {
|
||||
case handler: IFluidHandler =>
|
||||
tank.getFluid match {
|
||||
@ -88,7 +87,7 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted {
|
||||
if (count > 0 && amount == 0) {
|
||||
result(Unit, "tank is empty")
|
||||
}
|
||||
val blockPos = BlockPosition(x, y, z, Option(world)).offset(facing)
|
||||
val blockPos = position.offset(facing)
|
||||
if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match {
|
||||
case handler: IFluidHandler =>
|
||||
tank.getFluid match {
|
||||
@ -119,7 +118,7 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted {
|
||||
world.breakBlock(blockPos)
|
||||
world.setBlock(blockPos, fluidBlock)
|
||||
// This fake neighbor update is required to get stills to start flowing.
|
||||
world.notifyBlockOfNeighborChange(blockPos, world.getBlock(x, y, z))
|
||||
world.notifyBlockOfNeighborChange(blockPos, world.getBlock(position))
|
||||
result(true)
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,16 @@
|
||||
package li.cil.oc.server.component.traits
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedBlock._
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.EntityLivingBase
|
||||
import net.minecraft.entity.item.EntityMinecart
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.WorldServer
|
||||
import net.minecraftforge.common.MinecraftForge
|
||||
import net.minecraftforge.common.util.FakePlayer
|
||||
import net.minecraftforge.common.util.FakePlayerFactory
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
import net.minecraftforge.event.world.BlockEvent
|
||||
import net.minecraftforge.fluids.FluidRegistry
|
||||
@ -18,26 +20,28 @@ import scala.reflect.ClassTag
|
||||
import scala.reflect.classTag
|
||||
|
||||
trait WorldAware {
|
||||
protected def world: World
|
||||
protected def position: BlockPosition
|
||||
|
||||
protected def x: Int
|
||||
protected def world = position.world.get
|
||||
|
||||
protected def y: Int
|
||||
|
||||
protected def z: Int
|
||||
|
||||
protected def fakePlayer: FakePlayer
|
||||
protected def fakePlayer: FakePlayer = {
|
||||
val player = FakePlayerFactory.get(world.asInstanceOf[WorldServer], Settings.get.fakePlayerProfile)
|
||||
player.posX = position.x + 0.5
|
||||
player.posY = position.y + 0.5
|
||||
player.posZ = position.z + 0.5
|
||||
player
|
||||
}
|
||||
|
||||
protected def entitiesInBlock[Type <: Entity : ClassTag](blockPos: BlockPosition) = {
|
||||
world.getEntitiesWithinAABB(classTag[Type].runtimeClass, blockPos.bounds).map(_.asInstanceOf[Type])
|
||||
}
|
||||
|
||||
protected def entitiesOnSide[Type <: Entity : ClassTag](side: ForgeDirection) = {
|
||||
entitiesInBlock[Type](BlockPosition(x, y, z, Option(world)).offset(side))
|
||||
entitiesInBlock[Type](position.offset(side))
|
||||
}
|
||||
|
||||
protected def closestEntity[Type <: Entity : ClassTag](side: ForgeDirection) = {
|
||||
val blockPos = BlockPosition(x, y, z, Option(world)).offset(side)
|
||||
val blockPos = position.offset(side)
|
||||
Option(world.findNearestEntityWithinAABB(classTag[Type].runtimeClass, blockPos.bounds, fakePlayer)).map(_.asInstanceOf[Type])
|
||||
}
|
||||
|
||||
@ -46,7 +50,7 @@ trait WorldAware {
|
||||
case Some(_@(_: EntityLivingBase | _: EntityMinecart)) =>
|
||||
(true, "entity")
|
||||
case _ =>
|
||||
val blockPos = BlockPosition(x, y, z, Option(world)).offset(side)
|
||||
val blockPos = position.offset(side)
|
||||
val block = world.getBlock(blockPos)
|
||||
val metadata = world.getBlockMetadata(blockPos)
|
||||
if (block.isAir(blockPos)) {
|
||||
|
@ -0,0 +1,72 @@
|
||||
package li.cil.oc.server.component.traits
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.server.component.result
|
||||
import li.cil.oc.util.DatabaseAccess
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.InventoryUtils
|
||||
import net.minecraft.inventory.IInventory
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
trait WorldInventoryAnalytics extends WorldAware with SideRestricted with NetworkAware {
|
||||
@Callback(doc = """function(side:number):number -- Get the number of slots in the inventory on the specified side of the robot.""")
|
||||
def getInventorySize(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
withInventory(facing, inventory => result(inventory.getSizeInventory))
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number, slot:number):number -- Get number of items in the specified slot of the inventory on the specified side of the robot.""")
|
||||
def getSlotStackSize(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
withInventory(facing, inventory => result(Option(inventory.getStackInSlot(args.checkSlot(inventory, 1))).fold(0)(_.stackSize)))
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number, slot:number):number -- Get the maximum number of items in the specified slot of the inventory on the specified side of the robot.""")
|
||||
def getSlotMaxStackSize(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
withInventory(facing, inventory => result(Option(inventory.getStackInSlot(args.checkSlot(inventory, 1))).fold(0)(_.getMaxStackSize)))
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number, slotA:number, slotB:number):boolean -- Get whether the items in the two specified slots of the inventory on the specified side of the robot are of the same type.""")
|
||||
def compareStacks(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
withInventory(facing, inventory => {
|
||||
val stackA = inventory.getStackInSlot(args.checkSlot(inventory, 1))
|
||||
val stackB = inventory.getStackInSlot(args.checkSlot(inventory, 2))
|
||||
result(stackA == stackB ||
|
||||
(stackA != null && stackB != null &&
|
||||
stackA.getItem == stackB.getItem &&
|
||||
(!stackA.getHasSubtypes || stackA.getItemDamage == stackB.getItemDamage)))
|
||||
})
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number, slot:number):table -- Get a description of the stack in the the inventory on the specified side of the robot.""")
|
||||
def getStackInSlot(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
withInventory(facing, inventory => result(inventory.getStackInSlot(args.checkSlot(inventory, 1))))
|
||||
}
|
||||
else result(Unit, "not enabled in config")
|
||||
|
||||
@Callback(doc = """function(side:number, slot:number, dbAddress:string, dbSlot:number):boolean -- Store an item stack description in the specified slot of the database with the specified address.""")
|
||||
def store(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val dbAddress = args.checkString(2)
|
||||
def store(stack: ItemStack) = DatabaseAccess.withDatabase(node, dbAddress, database => {
|
||||
val dbSlot = args.checkSlot(database.data, 3)
|
||||
val nonEmpty = database.data.getStackInSlot(dbSlot) != null
|
||||
database.data.setInventorySlotContents(dbSlot, stack.copy())
|
||||
result(nonEmpty)
|
||||
})
|
||||
withInventory(facing, inventory => store(inventory.getStackInSlot(args.checkSlot(inventory, 1))))
|
||||
}
|
||||
|
||||
private def withInventory(side: ForgeDirection, f: IInventory => Array[AnyRef]) =
|
||||
InventoryUtils.inventoryAt(position.offset(side)) match {
|
||||
case Some(inventory) if inventory.isUseableByPlayer(fakePlayer) => f(inventory)
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package li.cil.oc.server.component.traits
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.server.component.result
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
import net.minecraftforge.fluids.IFluidHandler
|
||||
|
||||
trait WorldTankAnalytics extends WorldAware with SideRestricted {
|
||||
@Callback(doc = """function(side:number):number -- Get the amount of fluid in the tank on the specified side.""")
|
||||
def getTankLevel(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
world.getTileEntity(position.offset(facing)) match {
|
||||
case handler: IFluidHandler =>
|
||||
result(handler.getTankInfo(facing.getOpposite).map(info => Option(info.fluid).fold(0)(_.amount)).sum)
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number):number -- Get the capacity of the tank on the specified side.""")
|
||||
def getTankCapacity(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
world.getTileEntity(position.offset(facing)) match {
|
||||
case handler: IFluidHandler =>
|
||||
result(handler.getTankInfo(facing.getOpposite).map(_.capacity).foldLeft(0)((max, capacity) => math.max(max, capacity)))
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(side:number):table -- Get a description of the fluid in the the tank on the specified side.""")
|
||||
def getFluidInTank(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
world.getTileEntity(position.offset(facing)) match {
|
||||
case handler: IFluidHandler =>
|
||||
result(handler.getTankInfo(facing.getOpposite))
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
}
|
||||
else result(Unit, "not enabled in config")
|
||||
}
|
@ -2,9 +2,11 @@ package li.cil.oc.util
|
||||
|
||||
import li.cil.oc.api.driver.EnvironmentHost
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.tileentity.TileEntity
|
||||
import net.minecraft.world.IBlockAccess
|
||||
import net.minecraft.world.World
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
import scala.language.implicitConversions
|
||||
|
||||
@ -17,10 +19,10 @@ object ExtendedWorld {
|
||||
class ExtendedBlockAccess(val world: IBlockAccess) {
|
||||
def getBlock(position: BlockPosition) = world.getBlock(position.x, position.y, position.z)
|
||||
|
||||
def getBlockMetadata(position: BlockPosition) = world.getBlockMetadata(position.x, position.y, position.z)
|
||||
|
||||
def getBlockMapColor(position: BlockPosition) = getBlock(position).getMapColor(getBlockMetadata(position))
|
||||
|
||||
def getBlockMetadata(position: BlockPosition) = world.getBlockMetadata(position.x, position.y, position.z)
|
||||
|
||||
def getTileEntity(position: BlockPosition): TileEntity = world.getTileEntity(position.x, position.y, position.z)
|
||||
|
||||
def getTileEntity(host: EnvironmentHost): TileEntity = getTileEntity(BlockPosition(host))
|
||||
@ -31,19 +33,21 @@ object ExtendedWorld {
|
||||
class ExtendedWorld(override val world: World) extends ExtendedBlockAccess(world) {
|
||||
def blockExists(position: BlockPosition) = world.blockExists(position.x, position.y, position.z)
|
||||
|
||||
def breakBlock(position: BlockPosition, drops: Boolean = true) = world.func_147480_a(position.x, position.y, position.z, drops)
|
||||
|
||||
def extinguishFire(player: EntityPlayer, position: BlockPosition, side: ForgeDirection) = world.extinguishFire(player, position.x, position.y, position.z, side.ordinal)
|
||||
|
||||
def getBlockHardness(position: BlockPosition) = getBlock(position).getBlockHardness(world, position.x, position.y, position.z)
|
||||
|
||||
def getBlockHarvestLevel(position: BlockPosition) = getBlock(position).getHarvestLevel(getBlockMetadata(position))
|
||||
|
||||
def getBlockHarvestTool(position: BlockPosition) = getBlock(position).getHarvestTool(getBlockMetadata(position))
|
||||
|
||||
def setBlockToAir(position: BlockPosition) = world.setBlockToAir(position.x, position.y, position.z)
|
||||
|
||||
def notifyBlockOfNeighborChange(position: BlockPosition, block: Block) = world.notifyBlockOfNeighborChange(position.x, position.y, position.z, block)
|
||||
|
||||
def breakBlock(position: BlockPosition, drops: Boolean = true) = world.func_147480_a(position.x, position.y, position.z, drops)
|
||||
|
||||
def setBlock(position: BlockPosition, block: Block) = world.setBlock(position.x, position.y, position.z, block)
|
||||
|
||||
def setBlockToAir(position: BlockPosition) = world.setBlockToAir(position.x, position.y, position.z)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ object InventoryUtils {
|
||||
/**
|
||||
* Utility method for spawning an item stack in the world.
|
||||
*/
|
||||
def spawnStackInWorld(position: BlockPosition, stack: ItemStack, direction: ForgeDirection): EntityItem = position.world match {
|
||||
def spawnStackInWorld(position: BlockPosition, stack: ItemStack, direction: ForgeDirection = ForgeDirection.UP): EntityItem = position.world match {
|
||||
case Some(world) =>
|
||||
val rng = world.rand
|
||||
val (tx, ty, tz) = (
|
||||
|
Loading…
x
Reference in New Issue
Block a user