Extracted tank logic from robot component and some minor bugfixing.

This commit is contained in:
Florian Nücke 2014-12-15 21:38:54 +01:00
parent 006935ba06
commit c5e79df8b5
18 changed files with 290 additions and 230 deletions

View File

@ -79,6 +79,7 @@ public interface MachineHost extends EnvironmentHost {
* <p/>
* This method is called from executor threads, so it must be thread-safe.
*/
// TODO Merge with {@link EnvironmentHost#markChanged} in 1.5
void markForSaving();
/**

View File

@ -0,0 +1,10 @@
package li.cil.oc.common.inventory
import net.minecraftforge.fluids.IFluidTank
// TODO Move to api.internal in 1.5, make internal.Robot extend this.
trait MultiTank {
def tankCount: Int
def getFluidTank(index: Int): IFluidTank
}

View File

@ -17,6 +17,7 @@ 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.MultiTank
import li.cil.oc.integration.opencomputers.DriverKeyboard
import li.cil.oc.integration.opencomputers.DriverRedstoneCard
import li.cil.oc.integration.opencomputers.DriverScreen
@ -43,7 +44,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 {
class Robot extends traits.Computer with traits.PowerInformation with IFluidHandler with internal.Robot with MultiTank {
var proxy: RobotProxy = _
val info = new ItemUtils.RobotData()
@ -651,7 +652,7 @@ class Robot extends traits.Computer with traits.PowerInformation with IFluidHand
}
override def setInventorySlotContents(slot: Int, stack: ItemStack) {
if (slot < getSizeInventory - componentCount && isItemValidForSlot(slot, stack)) {
if (slot < getSizeInventory - componentCount && (isItemValidForSlot(slot, stack) || stack == null)) {
if (stack != null && stack.stackSize > 1 && isComponentSlot(slot)) {
super.setInventorySlotContents(slot, stack.splitStack(1))
if (stack.stackSize > 0 && isServer) {

View File

@ -9,6 +9,7 @@ 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.common.inventory.MultiTank
import li.cil.oc.integration.Mods
import mods.immibis.redlogic.api.wiring.IWire
import net.minecraft.entity.Entity
@ -21,7 +22,7 @@ import net.minecraftforge.fluids.Fluid
import net.minecraftforge.fluids.FluidStack
import net.minecraftforge.fluids.IFluidHandler
class RobotProxy(val robot: Robot) extends traits.Computer with traits.PowerInformation with ISidedInventory with IFluidHandler with internal.Robot {
class RobotProxy(val robot: Robot) extends traits.Computer with traits.PowerInformation with ISidedInventory with IFluidHandler with internal.Robot with MultiTank {
def this() = this(new Robot())
// ----------------------------------------------------------------------- //

View File

@ -118,8 +118,7 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B
if (_isRunning != machine.isRunning) {
_isRunning = machine.isRunning
isOutputEnabled = hasRedstoneCard
isAbstractBusAvailable = hasAbstractBusCard
markDirty()
ServerPacketSender.sendComputerState(this)
}

View File

@ -19,7 +19,7 @@ trait Environment extends TileEntity with network.Environment with driver.Enviro
override def zPosition = z + 0.5
override def markChanged() = if (canUpdate) isChangeScheduled = true else markDirty()
override def markChanged() = if (canUpdate) isChangeScheduled = true else world.markTileEntityChunkModified(x, y, z, this)
protected def isConnected = node.address != null && node.network != null

View File

@ -105,7 +105,7 @@ object ModOpenComputers extends ModProxy {
blacklistHost(classOf[internal.Adapter], "geolyzer", "keyboard", "screen1", "angelUpgrade", "batteryUpgrade1", "batteryUpgrade2", "batteryUpgrade3", "chunkloaderUpgrade", "craftingUpgrade", "experienceUpgrade", "generatorUpgrade", "inventoryUpgrade", "navigationUpgrade", "pistonUpgrade", "solarGeneratorUpgrade", "tankUpgrade", "tractorBeamUpgrade")
blacklistHost(classOf[internal.Microcontroller], "graphicsCard1", "graphicsCard2", "graphicsCard3", "keyboard", "screen1", "angelUpgrade", "chunkloaderUpgrade", "craftingUpgrade", "databaseUpgrade1", "databaseUpgrade2", "databaseUpgrade3", "experienceUpgrade", "generatorUpgrade", "inventoryUpgrade", "inventoryControllerUpgrade", "navigationUpgrade", "tankUpgrade", "tankControllerUpgrade", "tractorBeamUpgrade")
blacklistHost(classOf[internal.Drone], "graphicsCard1", "graphicsCard2", "graphicsCard3", "keyboard", "lanCard", "redstoneCard1", "screen1", "angelUpgrade", "craftingUpgrade", "experienceUpgrade", "generatorUpgrade", "tankUpgrade", "tankControllerUpgrade")
blacklistHost(classOf[internal.Drone], "graphicsCard1", "graphicsCard2", "graphicsCard3", "keyboard", "lanCard", "redstoneCard1", "screen1", "angelUpgrade", "craftingUpgrade", "experienceUpgrade")
blacklistHost(classOf[internal.Tablet], "lanCard", "redstoneCard1", "screen1", "angelUpgrade", "chunkloaderUpgrade", "craftingUpgrade", "databaseUpgrade1", "databaseUpgrade2", "databaseUpgrade3", "experienceUpgrade", "generatorUpgrade", "inventoryUpgrade", "inventoryControllerUpgrade", "tankUpgrade", "tankControllerUpgrade")
if (!WirelessRedstone.isAvailable) {

View File

@ -16,7 +16,7 @@ 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.WorldInspectable with traits.InventoryInspectable with traits.InventoryWorldInterop {
class Drone(val host: entity.Drone) extends prefab.ManagedEnvironment with traits.WorldControl with traits.InventoryControl with traits.InventoryWorldControl {
override val node = Network.newNode(this, Visibility.Network).
withComponent("drone").
create()

View File

@ -10,6 +10,7 @@ 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}
@ -28,11 +29,10 @@ import net.minecraft.util.MovingObjectPosition.MovingObjectType
import net.minecraft.util.Vec3
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.common.util.ForgeDirection
import net.minecraftforge.fluids._
import scala.collection.convert.WrapAsScala._
class Robot(val robot: tileentity.Robot) extends prefab.ManagedEnvironment with traits.WorldInspectable with traits.InventoryInspectable with traits.InventoryWorldInterop {
class Robot(val robot: tileentity.Robot) extends prefab.ManagedEnvironment with traits.WorldControl with traits.InventoryControl with traits.InventoryWorldControl with traits.TankControl with traits.TankWorldControl {
override val node = api.Network.newNode(this, Visibility.Network).
withComponent("robot").
withConnector(Settings.get.bufferRobot).
@ -90,13 +90,25 @@ 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)
}
def selectedTank = robot.selectedTank
override def selectedTank_=(value: Int) = robot.selectedTank = value
// ----------------------------------------------------------------------- //
override protected def fakePlayer = robot.player()
override protected def checkSideForAction(args: Arguments, n: Int) = robot.toGlobal(args.checkSideForAction(n))
// ----------------------------------------------------------------------- //
private def checkSideForFace(args: Arguments, n: Int, facing: ForgeDirection) = robot.toGlobal(args.checkSideForFace(n, robot.toLocal(facing)))
def selectedTank = robot.selectedTank
// ----------------------------------------------------------------------- //
def canPlaceInAir = {
val event = new RobotPlaceInAirEvent(robot)
@ -378,195 +390,6 @@ class Robot(val robot: tileentity.Robot) extends prefab.ManagedEnvironment with
// ----------------------------------------------------------------------- //
@Callback
def tankCount(context: Context, args: Arguments): Array[AnyRef] = result(robot.tankCount)
@Callback
def selectTank(context: Context, args: Arguments): Array[AnyRef] = {
if (args.count > 0 && args.checkAny(0) != null) {
robot.selectedTank = checkTank(args, 0)
}
result(selectedTank + 1)
}
@Callback(direct = true)
def tankLevel(context: Context, args: Arguments): Array[AnyRef] = {
val index =
if (args.count > 0 && args.checkAny(0) != null) checkTank(args, 0)
else selectedTank
result(fluidInTank(index) match {
case Some(fluid) => fluid.amount
case _ => 0
})
}
@Callback(direct = true)
def tankSpace(context: Context, args: Arguments): Array[AnyRef] = {
val index =
if (args.count > 0 && args.checkAny(0) != null) checkTank(args, 0)
else selectedTank
result(getTank(index) match {
case Some(tank) => tank.getCapacity - tank.getFluidAmount
case _ => 0
})
}
@Callback
def compareFluidTo(context: Context, args: Arguments): Array[AnyRef] = {
val index = checkTank(args, 0)
result((fluidInTank(selectedTank), fluidInTank(index)) match {
case (Some(stackA), Some(stackB)) => haveSameFluidType(stackA, stackB)
case (None, None) => true
case _ => false
})
}
@Callback
def transferFluidTo(context: Context, args: Arguments): Array[AnyRef] = {
val index = checkTank(args, 0)
val count = args.optionalFluidCount(1)
if (index == selectedTank || count == 0) {
result(true)
}
else (getTank(selectedTank), getTank(index)) match {
case (Some(from), Some(to)) =>
val drained = from.drain(count, false)
val transferred = to.fill(drained, true)
if (transferred > 0) {
from.drain(transferred, true)
robot.markDirty()
result(true)
}
else if (count >= from.getFluidAmount && to.getCapacity >= from.getFluidAmount && from.getCapacity >= to.getFluidAmount) {
// Swap.
val tmp = to.drain(to.getFluidAmount, true)
to.fill(from.drain(from.getFluidAmount, true), true)
from.fill(tmp, true)
robot.markDirty()
result(true)
}
else result(Unit, "incompatible or no fluid")
case _ => result(Unit, "invalid index")
}
}
@Callback
def compareFluid(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSideForAction(args, 0)
fluidInTank(selectedTank) match {
case Some(stack) =>
val (nx, ny, nz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ)
if (world.blockExists(nx, ny, nz)) world.getTileEntity(nx, ny, nz) match {
case handler: IFluidHandler =>
result(Option(handler.getTankInfo(side.getOpposite)).exists(_.exists(other => stack.isFluidEqual(other.fluid))))
case _ =>
val block = world.getBlock(x + side.offsetX, y + side.offsetY, z + side.offsetZ)
val fluid = FluidRegistry.lookupFluidForBlock(block)
result(stack.getFluid == fluid)
}
else result(false)
case _ => result(false)
}
}
@Callback
def drain(context: Context, args: Arguments): Array[AnyRef] = {
val facing = checkSideForAction(args, 0)
val count = args.optionalFluidCount(1)
getTank(selectedTank) match {
case Some(tank) =>
val space = tank.getCapacity - tank.getFluidAmount
val amount = math.min(count, space)
if (count > 0 && amount == 0) {
result(Unit, "tank is full")
}
else {
val (nx, ny, nz) = (x + facing.offsetX, y + facing.offsetY, z + facing.offsetZ)
if (world.blockExists(nx, ny, nz)) world.getTileEntity(nx, ny, nz) match {
case handler: IFluidHandler =>
tank.getFluid match {
case stack: FluidStack =>
val drained = handler.drain(facing.getOpposite, new FluidStack(stack, amount), true)
if ((drained != null && drained.amount > 0) || amount == 0) {
tank.fill(drained, true)
result(true)
}
else result(Unit, "incompatible or no fluid")
case _ =>
tank.fill(handler.drain(facing.getOpposite, amount, true), true)
result(true)
}
case _ =>
val block = world.getBlock(x + facing.offsetX, y + facing.offsetY, z + facing.offsetZ)
val fluid = FluidRegistry.lookupFluidForBlock(block)
if (fluid == null) {
result(Unit, "incompatible or no fluid")
}
else if (tank.fill(new FluidStack(fluid, 1000), false) == 1000) {
tank.fill(new FluidStack(fluid, 1000), true)
world.setBlockToAir(x + facing.offsetX, y + facing.offsetY, z + facing.offsetZ)
result(true)
}
else result(Unit, "tank is full")
}
else result(Unit, "incompatible or no fluid")
}
case _ => result(Unit, "no tank selected")
}
}
@Callback
def fill(context: Context, args: Arguments): Array[AnyRef] = {
val facing = checkSideForAction(args, 0)
val count = args.optionalFluidCount(1)
getTank(selectedTank) match {
case Some(tank) =>
val amount = math.min(count, tank.getFluidAmount)
if (count > 0 && amount == 0) {
result(Unit, "tank is empty")
}
val (bx, by, bz) = (x + facing.offsetX, y + facing.offsetY, z + facing.offsetZ)
if (world.blockExists(bx, by, bz)) world.getTileEntity(bx, by, bz) match {
case handler: IFluidHandler =>
tank.getFluid match {
case stack: FluidStack =>
val filled = handler.fill(facing.getOpposite, new FluidStack(stack, amount), true)
if (filled > 0 || amount == 0) {
tank.drain(filled, true)
result(true)
}
else result(Unit, "incompatible or no fluid")
case _ =>
result(Unit, "tank is empty")
}
case _ =>
val block = world.getBlock(bx, by, bz)
if (block != null && !block.isAir(world, x, y, z) && !block.isReplaceable(world, x, y, z)) {
result(Unit, "no space")
}
else if (tank.getFluidAmount < 1000) {
result(Unit, "tank is empty")
}
else if (!tank.getFluid.getFluid.canBePlacedInWorld) {
result(Unit, "incompatible fluid")
}
else {
val fluidBlock = tank.getFluid.getFluid.getBlock
tank.drain(1000, true)
world.func_147480_a(bx, by, bz, true)
world.setBlock(bx, by, bz, fluidBlock)
// This fake neighbor update is required to get stills to start flowing.
world.notifyBlockOfNeighborChange(bx, by, bz, robot.block)
result(true)
}
}
else result(Unit, "no space")
case _ => result(Unit, "no tank selected")
}
}
// ----------------------------------------------------------------------- //
override def onConnect(node: Node) {
super.onConnect(node)
if (node == this.node) {
@ -659,21 +482,4 @@ class Robot(val robot: tileentity.Robot) extends prefab.ManagedEnvironment with
(hit.hitVec.yCoord - hit.blockY).toFloat,
(hit.hitVec.zCoord - hit.blockZ).toFloat)
}
// ----------------------------------------------------------------------- //
private def haveSameFluidType(stackA: FluidStack, stackB: FluidStack) = stackA.isFluidEqual(stackB)
private def getTank(index: Int) = robot.tryGetTank(index)
private def fluidInTank(index: Int) = getTank(index) match {
case Some(tank) => Option(tank.getFluid)
case _ => None
}
// ----------------------------------------------------------------------- //
private def checkTank(args: Arguments, n: Int) = args.checkTank(robot, n)
private def checkSideForFace(args: Arguments, n: Int, facing: ForgeDirection) = robot.toGlobal(args.checkSideForFace(n, robot.toLocal(facing)))
}

View File

@ -10,7 +10,7 @@ trait InventoryAware {
def selectedSlot_=(value: Int): Unit
def insertionSlots = {
protected def insertionSlots = {
val slots = (0 until inventory.getSizeInventory).toIterable
slots.drop(selectedSlot) ++ slots.take(selectedSlot)
}

View File

@ -6,11 +6,11 @@ import li.cil.oc.api.machine.Context
import li.cil.oc.util.ExtendedArguments._
import li.cil.oc.util.ResultWrapper.result
trait InventoryInspectable extends InventoryAware {
@Callback
trait InventoryControl extends InventoryAware {
@Callback(doc = "function():number -- The size of this device's internal inventory.")
def inventorySize(context: Context, args: Arguments): Array[AnyRef] = result(inventory.getSizeInventory)
@Callback
@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)
@ -21,7 +21,7 @@ trait InventoryInspectable extends InventoryAware {
result(selectedSlot + 1)
}
@Callback(direct = true)
@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)
@ -32,7 +32,7 @@ trait InventoryInspectable extends InventoryAware {
})
}
@Callback(direct = true)
@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)
@ -43,7 +43,7 @@ trait InventoryInspectable extends InventoryAware {
})
}
@Callback
@Callback(doc = "function(otherSlot:number):boolean -- Compare the contents of the selected slot to the contents of the specified slot.")
def compareTo(context: Context, args: Arguments): Array[AnyRef] = {
val slot = args.checkSlot(inventory, 0)
result((stackInSlot(selectedSlot), stackInSlot(slot)) match {
@ -53,7 +53,7 @@ trait InventoryInspectable extends InventoryAware {
})
}
@Callback
@Callback(doc = "function(toSlot:number[, amount:number]):boolean -- Move up to the specified amount of items from the selected slot into the specified slot.")
def transferTo(context: Context, args: Arguments): Array[AnyRef] = {
val slot = args.checkSlot(inventory, 0)
val count = args.optionalItemCount(1)

View File

@ -13,7 +13,7 @@ import net.minecraft.entity.item.EntityItem
import net.minecraft.item.ItemBlock
import net.minecraftforge.common.util.ForgeDirection
trait InventoryWorldInterop extends InventoryAware with WorldAware with SideRestricted {
trait InventoryWorldControl extends InventoryAware with WorldAware with SideRestricted {
@Callback
def compare(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSideForAction(args, 0)

View File

@ -0,0 +1,23 @@
package li.cil.oc.server.component.traits
import li.cil.oc.common.inventory.MultiTank
import net.minecraftforge.fluids.FluidStack
trait TankAware {
def tank: MultiTank
def selectedTank: Int
def selectedTank_=(value: Int): Unit
// ----------------------------------------------------------------------- //
protected def getTank(index: Int) = Option(tank.getFluidTank(index))
protected def fluidInTank(index: Int) = getTank(index) match {
case Some(tank) => Option(tank.getFluid)
case _ => None
}
protected def haveSameFluidType(stackA: FluidStack, stackB: FluidStack) = stackA.isFluidEqual(stackB)
}

View File

@ -0,0 +1,79 @@
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.ExtendedArguments._
import li.cil.oc.util.ResultWrapper.result
trait TankControl extends TankAware {
@Callback
def tankCount(context: Context, args: Arguments): Array[AnyRef] = result(tank.tankCount)
@Callback
def selectTank(context: Context, args: Arguments): Array[AnyRef] = {
if (args.count > 0 && args.checkAny(0) != null) {
selectedTank = args.checkTank(tank, 0)
}
result(selectedTank + 1)
}
@Callback(direct = true)
def tankLevel(context: Context, args: Arguments): Array[AnyRef] = {
val index =
if (args.count > 0 && args.checkAny(0) != null) args.checkTank(tank, 0)
else selectedTank
result(fluidInTank(index) match {
case Some(fluid) => fluid.amount
case _ => 0
})
}
@Callback(direct = true)
def tankSpace(context: Context, args: Arguments): Array[AnyRef] = {
val index =
if (args.count > 0 && args.checkAny(0) != null) args.checkTank(tank, 0)
else selectedTank
result(getTank(index) match {
case Some(tank) => tank.getCapacity - tank.getFluidAmount
case _ => 0
})
}
@Callback
def compareFluidTo(context: Context, args: Arguments): Array[AnyRef] = {
val index = args.checkTank(tank, 0)
result((fluidInTank(selectedTank), fluidInTank(index)) match {
case (Some(stackA), Some(stackB)) => haveSameFluidType(stackA, stackB)
case (None, None) => true
case _ => false
})
}
@Callback
def transferFluidTo(context: Context, args: Arguments): Array[AnyRef] = {
val index = args.checkTank(tank, 0)
val count = args.optionalFluidCount(1)
if (index == selectedTank || count == 0) {
result(true)
}
else (getTank(selectedTank), getTank(index)) match {
case (Some(from), Some(to)) =>
val drained = from.drain(count, false)
val transferred = to.fill(drained, true)
if (transferred > 0) {
from.drain(transferred, true)
result(true)
}
else if (count >= from.getFluidAmount && to.getCapacity >= from.getFluidAmount && from.getCapacity >= to.getFluidAmount) {
// Swap.
val tmp = to.drain(to.getFluidAmount, true)
to.fill(from.drain(from.getFluidAmount, true), true)
from.fill(tmp, true)
result(true)
}
else result(Unit, "incompatible or no fluid")
case _ => result(Unit, "invalid index")
}
}
}

View File

@ -0,0 +1,130 @@
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.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
import net.minecraftforge.fluids.IFluidHandler
trait TankWorldControl extends TankAware with WorldAware with SideRestricted {
@Callback
def compareFluid(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSideForAction(args, 0)
fluidInTank(selectedTank) match {
case Some(stack) =>
val blockPos = BlockPosition(x, y, z).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))))
case _ =>
val block = world.getBlock(blockPos)
val fluid = FluidRegistry.lookupFluidForBlock(block)
result(stack.getFluid == fluid)
}
else result(false)
case _ => result(false)
}
}
@Callback
def drain(context: Context, args: Arguments): Array[AnyRef] = {
val facing = checkSideForAction(args, 0)
val count = args.optionalFluidCount(1)
getTank(selectedTank) match {
case Some(tank) =>
val space = tank.getCapacity - tank.getFluidAmount
val amount = math.min(count, space)
if (count > 0 && amount == 0) {
result(Unit, "tank is full")
}
else {
val blockPos = BlockPosition(x, y, z).offset(facing)
if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match {
case handler: IFluidHandler =>
tank.getFluid match {
case stack: FluidStack =>
val drained = handler.drain(facing.getOpposite, new FluidStack(stack, amount), true)
if ((drained != null && drained.amount > 0) || amount == 0) {
tank.fill(drained, true)
result(true)
}
else result(Unit, "incompatible or no fluid")
case _ =>
val transferred = tank.fill(handler.drain(facing.getOpposite, amount, true), true)
result(transferred > 0, transferred)
}
case _ =>
val block = world.getBlock(blockPos)
val fluid = FluidRegistry.lookupFluidForBlock(block)
if (fluid == null) {
result(Unit, "incompatible or no fluid")
}
else if (tank.fill(new FluidStack(fluid, 1000), false) == 1000) {
tank.fill(new FluidStack(fluid, 1000), true)
world.setBlockToAir(blockPos)
result(true)
}
else result(Unit, "tank is full")
}
else result(Unit, "incompatible or no fluid")
}
case _ => result(Unit, "no tank selected")
}
}
@Callback
def fill(context: Context, args: Arguments): Array[AnyRef] = {
val facing = checkSideForAction(args, 0)
val count = args.optionalFluidCount(1)
getTank(selectedTank) match {
case Some(tank) =>
val amount = math.min(count, tank.getFluidAmount)
if (count > 0 && amount == 0) {
result(Unit, "tank is empty")
}
val blockPos = BlockPosition(x, y, z).offset(facing)
if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match {
case handler: IFluidHandler =>
tank.getFluid match {
case stack: FluidStack =>
val filled = handler.fill(facing.getOpposite, new FluidStack(stack, amount), true)
if (filled > 0 || amount == 0) {
tank.drain(filled, true)
result(true)
}
else result(Unit, "incompatible or no fluid")
case _ =>
result(Unit, "tank is empty")
}
case _ =>
val block = world.getBlock(blockPos)
if (!block.isAir(blockPos) && !block.isReplaceable(blockPos)) {
result(Unit, "no space")
}
else if (tank.getFluidAmount < 1000) {
result(Unit, "tank is empty")
}
else if (!tank.getFluid.getFluid.canBePlacedInWorld) {
result(Unit, "incompatible fluid")
}
else {
val fluidBlock = tank.getFluid.getFluid.getBlock
tank.drain(1000, true)
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))
result(true)
}
}
else result(Unit, "no space")
case _ => result(Unit, "no tank selected")
}
}
}

View File

@ -5,7 +5,7 @@ import li.cil.oc.api.machine.Callback
import li.cil.oc.api.machine.Context
import li.cil.oc.util.ResultWrapper.result
trait WorldInspectable extends WorldAware with SideRestricted {
trait WorldControl extends WorldAware with SideRestricted {
@Callback
def detect(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSideForAction(args, 0)

View File

@ -2,6 +2,7 @@ package li.cil.oc.util
import li.cil.oc.api.internal.Robot
import li.cil.oc.api.machine.Arguments
import li.cil.oc.common.inventory.MultiTank
import net.minecraft.inventory.IInventory
import net.minecraftforge.common.util.ForgeDirection
@ -45,9 +46,9 @@ object ExtendedArguments {
slot + 1 + robot.containerCount
}
def checkTank(robot: Robot, n: Int) = {
def checkTank(multi: MultiTank, n: Int) = {
val tank = args.checkInteger(n) - 1
if (tank < 0 || tank >= robot.tankCount) {
if (tank < 0 || tank >= multi.tankCount) {
throw new IllegalArgumentException("invalid tank index")
}
tank

View File

@ -1,6 +1,7 @@
package li.cil.oc.util
import li.cil.oc.api.driver.EnvironmentHost
import net.minecraft.block.Block
import net.minecraft.tileentity.TileEntity
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
@ -28,6 +29,8 @@ object ExtendedWorld {
}
class ExtendedWorld(override val world: World) extends ExtendedBlockAccess(world) {
def blockExists(position: BlockPosition) = world.blockExists(position.x, position.y, position.z)
def getBlockHardness(position: BlockPosition) = getBlock(position).getBlockHardness(world, position.x, position.y, position.z)
def getBlockHarvestLevel(position: BlockPosition) = getBlock(position).getHarvestLevel(getBlockMetadata(position))
@ -35,6 +38,12 @@ object ExtendedWorld {
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)
}
}