diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index 0651c8390..4f6d19d97 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -483,9 +483,9 @@ object PacketHandler extends CommonPacketHandler { def onRedstoneState(p: PacketParser) = p.readTileEntity[RedstoneAware]() match { case Some(t) => - t.isOutputEnabled = p.readBoolean() + t.setOutputEnabled(p.readBoolean()) for (d <- ForgeDirection.VALID_DIRECTIONS) { - t.output(d, p.readByte()) + t.setOutput(d, p.readByte()) } case _ => // Invalid packet. } diff --git a/src/main/scala/li/cil/oc/common/block/RedstoneAware.scala b/src/main/scala/li/cil/oc/common/block/RedstoneAware.scala index 2b7cd2357..d43e8041d 100644 --- a/src/main/scala/li/cil/oc/common/block/RedstoneAware.scala +++ b/src/main/scala/li/cil/oc/common/block/RedstoneAware.scala @@ -29,7 +29,7 @@ abstract class RedstoneAware extends SimpleBlock with IRedNetOmniNode { override def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = world.getTileEntity(x, y, z) match { - case redstone: tileentity.traits.RedstoneAware => redstone.output(side) max 0 + case redstone: tileentity.traits.RedstoneAware => redstone.getOutput(side) max 0 case _ => super.isProvidingWeakPower(world, x, y, z, side) } @@ -42,9 +42,9 @@ abstract class RedstoneAware extends SimpleBlock with IRedNetOmniNode { case t: tileentity.traits.BundledRedstoneAware => for (side <- ForgeDirection.VALID_DIRECTIONS) { world.getBlock(position.offset(side)) match { case block: IRedNetNetworkContainer => - case _ => for (color <- 0 until 16) { - t.rednetInput(side, color, 0) - } + case _ => for (color <- 0 until 16) { + t.setRednetInput(side, color, 0) + } } } case _ => @@ -66,13 +66,13 @@ abstract class RedstoneAware extends SimpleBlock with IRedNetOmniNode { override def getOutputValue(world: World, x: Int, y: Int, z: Int, side: ForgeDirection, color: Int) = world.getTileEntity(x, y, z) match { - case t: tileentity.traits.BundledRedstoneAware => t.bundledOutput(side, color) + case t: tileentity.traits.BundledRedstoneAware => t.getBundledOutput(side, color) case _ => 0 } override def getOutputValues(world: World, x: Int, y: Int, z: Int, side: ForgeDirection) = world.getTileEntity(x, y, z) match { - case t: tileentity.traits.BundledRedstoneAware => t.bundledOutput(side) + case t: tileentity.traits.BundledRedstoneAware => t.getBundledOutput(side) case _ => Array.fill(16)(0) } @@ -81,7 +81,7 @@ abstract class RedstoneAware extends SimpleBlock with IRedNetOmniNode { override def onInputsChanged(world: World, x: Int, y: Int, z: Int, side: ForgeDirection, inputValues: Array[Int]) = world.getTileEntity(x, y, z) match { case t: tileentity.traits.BundledRedstoneAware => for (color <- 0 until 16) { - t.rednetInput(side, color, inputValues(color)) + t.setRednetInput(side, color, inputValues(color)) } case _ => } diff --git a/src/main/scala/li/cil/oc/common/tileentity/Charger.scala b/src/main/scala/li/cil/oc/common/tileentity/Charger.scala index faae2be53..48d6c4651 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Charger.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Charger.scala @@ -190,7 +190,7 @@ class Charger extends traits.Environment with traits.PowerAcceptor with traits.R override def updateRedstoneInput(side: ForgeDirection) { super.updateRedstoneInput(side) - val signal = math.max(0, math.min(15, ForgeDirection.VALID_DIRECTIONS.map(input).max)) + val signal = getInput.max min 15 if (invertSignal) chargeSpeed = (15 - signal) / 15.0 else chargeSpeed = signal / 15.0 diff --git a/src/main/scala/li/cil/oc/common/tileentity/Print.scala b/src/main/scala/li/cil/oc/common/tileentity/Print.scala index 79f1efb81..105b03548 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Print.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Print.scala @@ -1,5 +1,7 @@ package li.cil.oc.common.tileentity +import java.util + import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly import li.cil.oc.common.item.data.PrintData @@ -8,7 +10,8 @@ import li.cil.oc.util.ExtendedAABB import li.cil.oc.util.ExtendedAABB._ import li.cil.oc.util.ExtendedNBT._ import net.minecraft.nbt.NBTTagCompound -import net.minecraftforge.common.util.ForgeDirection + +import scala.collection.convert.WrapAsJava._ class Print extends traits.TileEntity with traits.RedstoneAware with traits.Rotatable { val data = new PrintData() @@ -29,12 +32,20 @@ class Print extends traits.TileEntity with traits.RedstoneAware with traits.Rota false } + private def buildValueSet(value: Int): util.Map[AnyRef, AnyRef] = { + val map: util.Map[AnyRef, AnyRef] = new util.HashMap[AnyRef, AnyRef]() + (0 until 6).foreach { + side => map.put(new java.lang.Integer(side), new java.lang.Integer(value)) + } + map + } + def toggleState(): Unit = { state = !state world.playSoundEffect(x + 0.5, y + 0.5, z + 0.5, "random.click", 0.3F, if (state) 0.6F else 0.5F) world.markBlockForUpdate(x, y, z) if (data.emitRedstoneWhenOn) { - ForgeDirection.VALID_DIRECTIONS.foreach(output(_, if (state) data.redstoneLevel else 0)) + setOutput(buildValueSet(if (state) data.redstoneLevel else 0)) } if (state && data.isButtonMode) { world.scheduleBlockUpdate(x, y, z, block, block.tickRate(world)) @@ -92,7 +103,7 @@ class Print extends traits.TileEntity with traits.RedstoneAware with traits.Rota else boundsOn = boundsOn.rotateTowards(facing) if (data.emitRedstoneWhenOff) { - ForgeDirection.VALID_DIRECTIONS.foreach(output(_, data.redstoneLevel)) + setOutput(buildValueSet(data.redstoneLevel)) } } diff --git a/src/main/scala/li/cil/oc/common/tileentity/Rack.scala b/src/main/scala/li/cil/oc/common/tileentity/Rack.scala index 6dfee65f9..f12cc0f05 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Rack.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Rack.scala @@ -290,7 +290,7 @@ class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalance override def markChanged(slot: Int): Unit = { hasChanged.synchronized(hasChanged(slot) = true) - isOutputEnabled = hasRedstoneCard + setOutputEnabled(hasRedstoneCard) isAbstractBusAvailable = hasAbstractBusCard } @@ -339,7 +339,7 @@ class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalance override def markDirty() { super.markDirty() if (isServer) { - isOutputEnabled = hasRedstoneCard + setOutputEnabled(hasRedstoneCard) isAbstractBusAvailable = hasAbstractBusCard ServerPacketSender.sendRackInventory(this) } @@ -395,7 +395,7 @@ class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalance ServerPacketSender.sendRackMountableData(this, slot) world.notifyBlocksOfNeighborChange(x, y, z, block) // These are working state dependent, so recompute them. - isOutputEnabled = hasRedstoneCard + setOutputEnabled(hasRedstoneCard) isAbstractBusAvailable = hasAbstractBusCard } diff --git a/src/main/scala/li/cil/oc/common/tileentity/RobotProxy.scala b/src/main/scala/li/cil/oc/common/tileentity/RobotProxy.scala index 34c039b5a..bc44ce085 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/RobotProxy.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/RobotProxy.scala @@ -190,9 +190,9 @@ class RobotProxy(val robot: Robot) extends traits.Computer with traits.PowerInfo override protected[tileentity] val _bundledOutput = robot._bundledOutput - override def isOutputEnabled = robot.isOutputEnabled + override def isOutputEnabled: Boolean = robot.isOutputEnabled - override def isOutputEnabled_=(value: Boolean) = robot.isOutputEnabled_=(value) + override def setOutputEnabled(value: Boolean): Unit = robot.setOutputEnabled(value) override def checkRedstoneInputChanged() = robot.checkRedstoneInputChanged() diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala index d3ac67d7d..031824acf 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala @@ -1,7 +1,10 @@ package li.cil.oc.common.tileentity.traits +import java.util + import cpw.mods.fml.common.Optional import li.cil.oc.Settings +import li.cil.oc.api.machine.Arguments import li.cil.oc.integration.Mods import li.cil.oc.integration.util.BundledRedstone import li.cil.oc.util.BlockPosition @@ -31,8 +34,8 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund // ----------------------------------------------------------------------- // - override def isOutputEnabled_=(value: Boolean) = { - if (value != isOutputEnabled) { + override def setOutputEnabled(value: Boolean): Unit = { + if (value != _isOutputEnabled) { if (!value) { for (i <- _bundledOutput.indices) { for (j <- _bundledOutput(i).indices) { @@ -41,40 +44,71 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund } } } - super.isOutputEnabled_=(value) + super.setOutputEnabled(value) } - def bundledInput(side: ForgeDirection) = - (_bundledInput(side.ordinal()), _rednetInput(side.ordinal())).zipped.map(math.max) + def getBundledInput: Array[Array[Int]] = { + (0 until 6).map(side => (0 until 16).map(color => _bundledInput(side)(color) max _rednetInput(side)(color) max 0).toArray).toArray + } - def bundledInput(side: ForgeDirection, newBundledInput: Array[Int]): Unit = { + private def checkSide(side: ForgeDirection): Int = { + val index = side.ordinal + if (index >= 6) throw new IndexOutOfBoundsException(s"Bad side $side") + index + } + + private def checkColor(color: Int): Int = { + if (color < 0 || color >= 16) throw new IndexOutOfBoundsException(s"Bad color $color") + color + } + + def getBundledInput(side: ForgeDirection): Array[Int] = { + val sideIndex = checkSide(side) + val bundled = _bundledInput(sideIndex) + val rednet = _rednetInput(sideIndex) + (bundled, rednet).zipped.map((a, b) => a max b max 0) + } + + def getBundledInput(side: ForgeDirection, color: Int): Int = { + val sideIndex = checkSide(side) + val colorIndex = checkColor(color) + val bundled = _bundledInput(sideIndex)(colorIndex) + val rednet = _rednetInput(sideIndex)(colorIndex) + bundled max rednet max 0 + } + + def setBundledInput(side: ForgeDirection, color: Int, newValue: Int): Unit = { + updateInput(_bundledInput, side, color, newValue) + } + + def setBundledInput(side: ForgeDirection, newBundledInput: Array[Int]): Unit = { for (color <- 0 until 16) { - updateInput(_bundledInput, side, color, if (newBundledInput == null) 0 else newBundledInput(color)) + val value = if (newBundledInput == null || color >= newBundledInput.length) 0 else newBundledInput(color) + setBundledInput(side, color, value) } } - def rednetInput(side: ForgeDirection, color: Int, value: Int): Unit = updateInput(_rednetInput, side, color, value) + def setRednetInput(side: ForgeDirection, color: Int, value: Int): Unit = updateInput(_rednetInput, side, color, value) def updateInput(inputs: Array[Array[Int]], side: ForgeDirection, color: Int, newValue: Int): Unit = { - val oldValue = inputs(side.ordinal())(color) + val sideIndex = checkSide(side) + val colorIndex = checkColor(color) + val oldValue = inputs(sideIndex)(colorIndex) if (oldValue != newValue) { + inputs(sideIndex)(colorIndex) = newValue if (oldValue != -1) { - onRedstoneInputChanged(RedstoneChangedEventArgs(side, oldValue, newValue, color)) + onRedstoneInputChanged(RedstoneChangedEventArgs(side, oldValue, newValue, colorIndex)) } - inputs(side.ordinal())(color) = newValue } } - def bundledInput(side: ForgeDirection, color: Int) = - math.max(_bundledInput(side.ordinal())(color), _rednetInput(side.ordinal())(color)) + def getBundledOutput: Array[Array[Int]] = _bundledInput - def bundledOutput(side: ForgeDirection) = _bundledOutput(toLocal(side).ordinal()) + def getBundledOutput(side: ForgeDirection): Array[Int] = _bundledOutput(checkSide(toLocal(side))) - def bundledOutput(side: ForgeDirection, color: Int): Int = bundledOutput(side)(color) - - def bundledOutput(side: ForgeDirection, color: Int, value: Int): Unit = if (value != bundledOutput(side, color)) { - _bundledOutput(toLocal(side).ordinal())(color) = value + def getBundledOutput(side: ForgeDirection, color: Int): Int = getBundledOutput(side)(checkColor(color)) + def notifyChangedSide(side: ForgeDirection): Unit = { if (Mods.MineFactoryReloaded.isAvailable) { val blockPos = BlockPosition(x, y, z).offset(side) world.getBlock(blockPos) match { @@ -86,11 +120,50 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund onRedstoneOutputChanged(side) } + def setBundledOutput(side: ForgeDirection, color: Int, value: Int): Boolean = if (value != getBundledOutput(side, color)) { + _bundledOutput(checkSide(toLocal(side)))(checkColor(color)) = value + notifyChangedSide(side) + true + } else false + + def setBundledOutput(side: ForgeDirection, values: util.Map[_, _]): Boolean = { + val sideIndex = toLocal(side).ordinal + var changed: Boolean = false + (0 until 16).foreach(color => { + // due to a bug in our jnlua layer, I cannot loop the map + valueToInt(getObjectFuzzy(values, color)) match { + case Some(newValue: Int) => + if (newValue != getBundledOutput(side, color)) { + _bundledOutput(sideIndex)(color) = newValue + changed = true + } + case _ => + } + }) + if (changed) { + notifyChangedSide(side) + } + changed + } + + def setBundledOutput(values: util.Map[_, _]): Boolean = { + var changed: Boolean = false + ForgeDirection.VALID_DIRECTIONS.foreach(side => { + val sideIndex = toLocal(side).ordinal + // due to a bug in our jnlua layer, I cannot loop the map + getObjectFuzzy(values, sideIndex) match { + case Some(child: util.Map[_, _]) if setBundledOutput(side, child) => changed = true + case _ => + } + }) + changed + } + // ----------------------------------------------------------------------- // override def updateRedstoneInput(side: ForgeDirection) { super.updateRedstoneInput(side) - bundledInput(side, BundledRedstone.computeBundledInput(position, side)) + setBundledInput(side, BundledRedstone.computeBundledInput(position, side)) } override def readFromNBTForServer(nbt: NBTTagCompound) { @@ -147,16 +220,16 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund // ----------------------------------------------------------------------- // @Optional.Method(modid = Mods.IDs.RedLogic) - def getBundledCableStrength(blockFace: Int, toDirection: Int): Array[Byte] = bundledOutput(ForgeDirection.getOrientation(toDirection)).map(value => math.min(math.max(value, 0), 255).toByte) + def getBundledCableStrength(blockFace: Int, toDirection: Int): Array[Byte] = getBundledOutput(ForgeDirection.getOrientation(toDirection)).map(value => math.min(math.max(value, 0), 255).toByte) @Optional.Method(modid = Mods.IDs.RedLogic) - def onBundledInputChanged() = checkRedstoneInputChanged() + def onBundledInputChanged(): Unit = checkRedstoneInputChanged() // ----------------------------------------------------------------------- // @Optional.Method(modid = Mods.IDs.ProjectRedTransmission) - def canConnectBundled(side: Int) = isOutputEnabled + def canConnectBundled(side: Int): Boolean = _isOutputEnabled @Optional.Method(modid = Mods.IDs.ProjectRedTransmission) - def getBundledSignal(side: Int) = bundledOutput(ForgeDirection.getOrientation(side)).map(value => math.min(math.max(value, 0), 255).toByte) + def getBundledSignal(side: Int): Array[Byte] = getBundledOutput(ForgeDirection.getOrientation(side)).map(value => math.min(math.max(value, 0), 255).toByte) } diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala index fa2cc2b06..e98ee49dc 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala @@ -198,7 +198,7 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B super.markDirty() if (isServer) { machine.onHostChanged() - isOutputEnabled = hasRedstoneCard + setOutputEnabled(hasRedstoneCard) isAbstractBusAvailable = hasAbstractBusCard } } diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala index 0ea9baf28..5d58afe55 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala @@ -1,5 +1,7 @@ package li.cil.oc.common.tileentity.traits +import java.util + import cpw.mods.fml.common.Optional import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly @@ -24,18 +26,18 @@ case class RedstoneChangedEventArgs (side: ForgeDirection, oldValue: Int, newVal new Optional.Interface(iface = "mods.immibis.redlogic.api.wiring.IRedstoneUpdatable", modid = Mods.IDs.RedLogic) )) trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitter with IRedstoneUpdatable { - protected[tileentity] val _input = Array.fill(6)(-1) + protected[tileentity] val _input: Array[Int] = Array.fill(6)(-1) - protected[tileentity] val _output = Array.fill(6)(0) + protected[tileentity] val _output: Array[Int] = Array.fill(6)(0) - protected var _isOutputEnabled = false + protected var _isOutputEnabled: Boolean = false - protected var shouldUpdateInput = true + def isOutputEnabled: Boolean = _isOutputEnabled - def isOutputEnabled = _isOutputEnabled + protected var shouldUpdateInput: Boolean = true - def isOutputEnabled_=(value: Boolean) = { - if (value != isOutputEnabled) { + def setOutputEnabled(value: Boolean): Unit = { + if (value != _isOutputEnabled) { _isOutputEnabled = value if (!value) { for (i <- _output.indices) { @@ -44,12 +46,34 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte } onRedstoneOutputEnabledChanged() } - this } - def input(side: ForgeDirection) = _input(side.ordinal()) max 0 + protected def getObjectFuzzy(map: util.Map[_, _], key: Int): Option[AnyRef] = { + val refMap: util.Map[AnyRef, AnyRef] = map.asInstanceOf[util.Map[AnyRef, AnyRef]] + if (refMap.containsKey(key)) + Option(refMap.get(key)) + else if (refMap.containsKey(new Integer(key))) + Option(refMap.get(new Integer(key))) + else if (refMap.containsKey(new Integer(key) * 1.0)) + Option(refMap.get(new Integer(key) * 1.0)) + else if (refMap.containsKey(key * 1.0)) + Option(refMap.get(key * 1.0)) + else + None + } - def input(side: ForgeDirection, newInput: Int): Unit = { + protected def valueToInt(value: AnyRef): Option[Int] = { + value match { + case Some(num: Number) => Option(num.intValue) + case _ => None + } + } + + def getInput: Array[Int] = _input.map(math.max(_, 0)) + + def getInput(side: ForgeDirection): Int = _input(side.ordinal) max 0 + + def setInput(side: ForgeDirection, newInput: Int): Unit = { val oldInput = _input(side.ordinal()) _input(side.ordinal()) = newInput if (oldInput >= 0 && newInput != oldInput) { @@ -57,14 +81,37 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte } } - def maxInput = ForgeDirection.VALID_DIRECTIONS.map(input).max + def setInput(values: Array[Int]): Unit = { + for (side <- ForgeDirection.VALID_DIRECTIONS) { + val value = if (side.ordinal <= values.length) values(side.ordinal) else 0 + setInput(side, value) + } + } - def output(side: ForgeDirection) = _output(toLocal(side).ordinal()) + def maxInput: Int = _input.map(math.max(_, 0)).max - def output(side: ForgeDirection, value: Int): Unit = if (value != output(side)) { + def getOutput: Array[Int] = ForgeDirection.VALID_DIRECTIONS.map{ side: ForgeDirection => _output(toLocal(side).ordinal) } + + def getOutput(side: ForgeDirection) = _output(toLocal(side).ordinal()) + + def setOutput(side: ForgeDirection, value: Int): Boolean = { + if (value == getOutput(side)) return false _output(toLocal(side).ordinal()) = value - onRedstoneOutputChanged(side) + true + } + + def setOutput(values: util.Map[_, _]): Boolean = { + var changed: Boolean = false + ForgeDirection.VALID_DIRECTIONS.foreach(side => { + val sideIndex = toLocal(side).ordinal + // due to a bug in our jnlua layer, I cannot loop the map + valueToInt(getObjectFuzzy(values, sideIndex)) match { + case Some(num: Int) if setOutput(side, num) => changed = true + case _ => + } + }) + changed } def checkRedstoneInputChanged() { @@ -90,9 +137,7 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte } } - def updateRedstoneInput(side: ForgeDirection) { - input(side, BundledRedstone.computeInput(position, side)) - } + def updateRedstoneInput(side: ForgeDirection): Unit = setInput(side, BundledRedstone.computeInput(position, side)) // ----------------------------------------------------------------------- // @@ -115,13 +160,13 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte @SideOnly(Side.CLIENT) override def readFromNBTForClient(nbt: NBTTagCompound) { super.readFromNBTForClient(nbt) - isOutputEnabled = nbt.getBoolean("isOutputEnabled") + _isOutputEnabled = nbt.getBoolean("isOutputEnabled") nbt.getIntArray("output").copyToArray(_output) } override def writeToNBTForClient(nbt: NBTTagCompound) { super.writeToNBTForClient(nbt) - nbt.setBoolean("isOutputEnabled", isOutputEnabled) + nbt.setBoolean("isOutputEnabled", _isOutputEnabled) nbt.setIntArray("output", _output) } @@ -147,7 +192,7 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte // ----------------------------------------------------------------------- // @Optional.Method(modid = Mods.IDs.RedLogic) - override def connects(wire: IWire, blockFace: Int, fromDirection: Int) = isOutputEnabled + override def connects(wire: IWire, blockFace: Int, fromDirection: Int): Boolean = _isOutputEnabled @Optional.Method(modid = Mods.IDs.RedLogic) override def connectsAroundCorner(wire: IWire, blockFace: Int, fromDirection: Int) = false @@ -156,5 +201,5 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte override def getEmittedSignalStrength(blockFace: Int, toDirection: Int): Short = _output(toLocal(ForgeDirection.getOrientation(toDirection)).ordinal()).toShort @Optional.Method(modid = Mods.IDs.RedLogic) - override def onRedstoneInputChanged() = checkRedstoneInputChanged() + override def onRedstoneInputChanged(): Unit = checkRedstoneInputChanged() } diff --git a/src/main/scala/li/cil/oc/integration/bluepower/BundledRedstoneDevice.scala b/src/main/scala/li/cil/oc/integration/bluepower/BundledRedstoneDevice.scala index 2e20a0610..cda9070e9 100644 --- a/src/main/scala/li/cil/oc/integration/bluepower/BundledRedstoneDevice.scala +++ b/src/main/scala/li/cil/oc/integration/bluepower/BundledRedstoneDevice.scala @@ -28,11 +28,11 @@ class BundledRedstoneDevice(val tileEntity: BundledRedstoneAware) extends IBundl override def getBundledColor(side: ForgeDirection): MinecraftColor = MinecraftColor.ANY - override def getBundledOutput(side: ForgeDirection): Array[Byte] = tileEntity.bundledOutput(side).map(_.toByte) + override def getBundledOutput(side: ForgeDirection): Array[Byte] = tileEntity.getBundledOutput(side).map(_.toByte) - override def getBundledPower(side: ForgeDirection): Array[Byte] = tileEntity.bundledInput(side).map(_.toByte) + override def getBundledPower(side: ForgeDirection): Array[Byte] = tileEntity.getBundledInput(side).map(_.toByte) - override def setBundledPower(side: ForgeDirection, power: Array[Byte]): Unit = tileEntity.bundledInput(side, power.map(_ & 0xFF)) + override def setBundledPower(side: ForgeDirection, power: Array[Byte]): Unit = tileEntity.setBundledInput(side, power.map(_ & 0xFF)) override def onBundledUpdate(): Unit = tileEntity.checkRedstoneInputChanged() } diff --git a/src/main/scala/li/cil/oc/integration/bluepower/RedstoneDevice.scala b/src/main/scala/li/cil/oc/integration/bluepower/RedstoneDevice.scala index f97193757..ee7e91edd 100644 --- a/src/main/scala/li/cil/oc/integration/bluepower/RedstoneDevice.scala +++ b/src/main/scala/li/cil/oc/integration/bluepower/RedstoneDevice.scala @@ -25,9 +25,9 @@ class RedstoneDevice(val tileEntity: RedstoneAware) extends IRedstoneDevice { override def getRedstoneConnectionCache: IConnectionCache[_ <: IRedstoneDevice] = cache - override def getRedstonePower(side: ForgeDirection): Byte = tileEntity.output(side).toByte + override def getRedstonePower(side: ForgeDirection): Byte = tileEntity.getOutput(side).toByte - override def setRedstonePower(side: ForgeDirection, power: Byte): Unit = tileEntity.input(side, power & 0xFF) + override def setRedstonePower(side: ForgeDirection, power: Byte): Unit = tileEntity.setInput(side, power & 0xFF) override def onRedstoneUpdate(): Unit = tileEntity.checkRedstoneInputChanged() } diff --git a/src/main/scala/li/cil/oc/integration/computercraft/BundledRedstoneProvider.scala b/src/main/scala/li/cil/oc/integration/computercraft/BundledRedstoneProvider.scala index feddf6b0c..9dd85000c 100644 --- a/src/main/scala/li/cil/oc/integration/computercraft/BundledRedstoneProvider.scala +++ b/src/main/scala/li/cil/oc/integration/computercraft/BundledRedstoneProvider.scala @@ -19,9 +19,9 @@ object BundledRedstoneProvider extends IBundledRedstoneProvider with RedstonePro world.getTileEntity(x, y, z) match { case tile: BundledRedstoneAware => var result = 0 - val colours = tile.bundledOutput(ForgeDirection.VALID_DIRECTIONS(side)) - for (colour <- 0 to 15) { - if (colours(colour) > 0) result |= 1 << colour + val colors = tile.getBundledOutput(ForgeDirection.VALID_DIRECTIONS(side)) + for (color <- 0 to 15) { + if (colors(color) > 0) result |= 1 << color } result case _ => -1 diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index 9ef817c9c..e86ca626a 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -483,7 +483,7 @@ object PacketSender { pb.writeTileEntity(t) pb.writeBoolean(t.isOutputEnabled) for (d <- ForgeDirection.VALID_DIRECTIONS) { - pb.writeByte(t.output(d)) + pb.writeByte(t.getOutput(d)) } pb.sendToPlayersNearTileEntity(t) diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneBundled.scala b/src/main/scala/li/cil/oc/server/component/RedstoneBundled.scala index 616da070e..c80ed60af 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneBundled.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneBundled.scala @@ -11,6 +11,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.common.tileentity.traits.BundledRedstoneAware +import net.minecraftforge.common.util.ForgeDirection import scala.collection.convert.WrapAsJava._ @@ -26,56 +27,103 @@ trait RedstoneBundled extends RedstoneVanilla { override def getDeviceInfo: util.Map[String, String] = deviceInfo + private val COLOR_RANGE = 0 until 16 + // ----------------------------------------------------------------------- // override def redstone: EnvironmentHost with BundledRedstoneAware - @Callback(direct = true, doc = """function(side:number[, color:number]):number or table -- Get the bundled redstone input on the specified side and with the specified color.""") - def getBundledInput(context: Context, args: Arguments): Array[AnyRef] = { - val side = checkSide(args, 0) - if (args.optAny(1, null) == null) - result(redstone.bundledInput(side).zipWithIndex.map(_.swap).toMap) - else - result(redstone.bundledInput(side, checkColor(args, 1))) + private def getBundleKey(args: Arguments): (Option[ForgeDirection], Option[Int]) = { + args.count match { + case 2 => (Option(checkSide(args, 0)), Option(checkColor(args, 1))) + case 1 => (Option(checkSide(args, 0)), None) + case 0 => (None, None) + case _ => throw new Exception("too many arguments, expected 0, 1, or 2") + } } - @Callback(direct = true, doc = """function(side:number[, color:number]):number or table -- Get the bundled redstone output on the specified side and with the specified color.""") - def getBundledOutput(context: Context, args: Arguments): Array[AnyRef] = { - val side = checkSide(args, 0) - if (args.optAny(1, null) == null) - result(redstone.bundledOutput(side).zipWithIndex.map(_.swap).toMap) - else - result(redstone.bundledOutput(side, checkColor(args, 1))) - } - - @Callback(doc = """function(side:number, color:number, value:number):number -- Set the bundled redstone output on the specified side and with the specified color.""") - def setBundledOutput(context: Context, args: Arguments): Array[AnyRef] = { - val side = checkSide(args, 0) - if (args.isTable(1)) { - val table = args.checkTable(1) - (0 to 15).map(color => (color, table.get(color))).foreach { - case (color, number: Number) => redstone.bundledOutput(side, color, number.intValue()) - case _ => + private def tableToColorValues(table: util.Map[_, _]): Array[Int] = { + COLOR_RANGE.collect { + case color: Int if table.containsKey(color) => { + table.get(color) match { + case value: Integer => value.toInt + } } + }.toArray + } + + private def colorsToMap(ar: Array[Int]): Map[Int, Int] = { + COLOR_RANGE.map{ + case color if color < ar.length => color -> ar(color) + }.toMap + } + + private def sidesToMap(ar: Array[Array[Int]]): Map[Int, Map[Int, Int]] = { + SIDE_RANGE.map { + case side if side.ordinal < ar.length && ar(side.ordinal).length > 0 => side.ordinal -> colorsToMap(ar(side.ordinal)) + }.toMap + } + + private def getBundleAssignment(args: Arguments): (Any, Any, Any) = { + args.count match { + case 3 => (checkSide(args, 0), checkColor(args, 1), args.checkInteger(2)) + case 2 => (checkSide(args, 0), args.checkTable(1), null) + case 1 => (args.checkTable(0), null, null) + case _ => throw new Exception("invalid number of arguments, expected 1, 2, or 3") + } + } + + @Callback(direct = true, doc = "function([side:number[, color:number]]):number or table -- Fewer params returns set of inputs") + def getBundledInput(context: Context, args: Arguments): Array[AnyRef] = { + val (side, color) = getBundleKey(args) + + if (color.isDefined) { + result(redstone.getBundledInput(side.get, color.get)) + } else if (side.isDefined) { + result(colorsToMap(redstone.getBundledInput(side.get))) + } else { + result(sidesToMap(redstone.getBundledInput)) + } + } + + @Callback(direct = true, doc = "function([side:number[, color:number]]):number or table -- Fewer params returns set of outputs") + def getBundledOutput(context: Context, args: Arguments): Array[AnyRef] = { + val (side, color) = getBundleKey(args) + + if (color.isDefined) { + result(redstone.getBundledOutput(side.get, color.get)) + } else if (side.isDefined) { + result(colorsToMap(redstone.getBundledOutput(side.get))) + } else { + result(sidesToMap(redstone.getBundledOutput)) + } + } + + @Callback(doc = "function([side:number[, color:number,]] value:number or table):number or table -- Fewer params to assign set of outputs. Returns previous values") + def setBundledOutput(context: Context, args: Arguments): Array[AnyRef] = { + var ret: AnyRef = null + if (getBundleAssignment(args) match { + case (side: ForgeDirection, color: Int, value: Int) => + ret = redstone.getBundledOutput(side, color) + redstone.setBundledOutput(side, color, value) + case (side: ForgeDirection, value: util.Map[_, _], _) => + ret = redstone.getBundledOutput(side) + redstone.setBundledOutput(side, value) + case (value: util.Map[_, _], _, _) => + ret = redstone.getBundledOutput + redstone.setBundledOutput(value) + }) { if (Settings.get.redstoneDelay > 0) context.pause(Settings.get.redstoneDelay) - result(true) - } - else { - val color = checkColor(args, 1) - val value = args.checkInteger(2) - redstone.bundledOutput(side, color, value) - if (Settings.get.redstoneDelay > 0) - context.pause(Settings.get.redstoneDelay) - result(redstone.bundledOutput(side, color)) } + result(ret) } // ----------------------------------------------------------------------- // private def checkColor(args: Arguments, index: Int): Int = { val color = args.checkInteger(index) - if (color < 0 || color > 15) + if (!COLOR_RANGE.contains(color)) throw new IllegalArgumentException("invalid color") color } diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala b/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala index ac2e6dc1c..a2cf26393 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala @@ -36,31 +36,43 @@ trait RedstoneVanilla extends RedstoneSignaller with DeviceInfo { override def getDeviceInfo: util.Map[String, String] = deviceInfo + protected val SIDE_RANGE: Array[ForgeDirection] = ForgeDirection.VALID_DIRECTIONS + // ----------------------------------------------------------------------- // - - @Callback(direct = true, doc = """function(side:number):number -- Get the redstone input on the specified side.""") + @Callback(direct = true, doc = "function([side:number]):number or table -- Get the redstone input (all sides, or optionally on the specified side)") def getInput(context: Context, args: Arguments): Array[AnyRef] = { - val side = checkSide(args, 0) - result(redstone.input(side)) + getOptionalSide(args) match { + case Some(side: Int) => result(redstone.getInput(side)) + case _ => result(valuesToMap(redstone.getInput)) + } } - @Callback(direct = true, doc = """function(side:number):number -- Get the redstone output on the specified side.""") + @Callback(direct = true, doc = "function([side:number]):number or table -- Get the redstone output (all sides, or optionally on the specified side)") def getOutput(context: Context, args: Arguments): Array[AnyRef] = { - val side = checkSide(args, 0) - result(redstone.output(side)) + getOptionalSide(args) match { + case Some(side: Int) => result(redstone.getOutput(side)) + case _ => result(valuesToMap(redstone.getOutput)) + } } - @Callback(doc = """function(side:number, value:number):number -- Set the redstone output on the specified side.""") + @Callback(doc = "function([side:number, ]value:number or table):number or table -- Set the redstone output (all sides, or optionally on the specified side). Returns previous values") def setOutput(context: Context, args: Arguments): Array[AnyRef] = { - val side = checkSide(args, 0) - val value = args.checkInteger(1) - redstone.output(side, value) - if (Settings.get.redstoneDelay > 0) - context.pause(Settings.get.redstoneDelay) - result(redstone.output(side)) + var ret: AnyRef = null + if (getAssignment(args) match { + case (side: ForgeDirection, value: Int) => + ret = new java.lang.Integer(redstone.getOutput(side)) + redstone.setOutput(side, value) + case (value: util.Map[_, _], _) => + ret = valuesToMap(redstone.getOutput) + redstone.setOutput(value) + }) { + if (Settings.get.redstoneDelay > 0) + context.pause(Settings.get.redstoneDelay) + } + result(ret) } - @Callback(direct = true, doc = """function(side:number):number -- Get the comparator input on the specified side.""") + @Callback(direct = true, doc = "function(side:number):number -- Get the comparator input on the specified side.") def getComparatorInput(context: Context, args: Arguments): Array[AnyRef] = { val side = checkSide(args, 0) val blockPos = BlockPosition(redstone).offset(side) @@ -87,10 +99,27 @@ trait RedstoneVanilla extends RedstoneSignaller with DeviceInfo { // ----------------------------------------------------------------------- // - protected def checkSide(args: Arguments, index: Int) = { + private def getOptionalSide(args: Arguments): Option[Int] = { + if (args.count == 1) + Option(checkSide(args, 0).ordinal) + else + None + } + + private def getAssignment(args: Arguments): (Any, Any) = { + args.count match { + case 2 => (checkSide(args, 0), args.checkInteger(1)) + case 1 => (args.checkTable(0), null) + case _ => throw new Exception("invalid number of arguments, expected 1 or 2") + } + } + + protected def checkSide(args: Arguments, index: Int): ForgeDirection = { val side = args.checkInteger(index) if (side < 0 || side > 5) throw new IllegalArgumentException("invalid side") redstone.toGlobal(ForgeDirection.getOrientation(side)) } + + private def valuesToMap(ar: Array[Int]): Map[Int, Int] = SIDE_RANGE.map(_.ordinal).map{ case side if side < ar.length => side -> ar(side) }.toMap } diff --git a/src/main/scala/li/cil/oc/util/ExtendedLuaState.scala b/src/main/scala/li/cil/oc/util/ExtendedLuaState.scala index 9e99f1849..a7fa03ee9 100644 --- a/src/main/scala/li/cil/oc/util/ExtendedLuaState.scala +++ b/src/main/scala/li/cil/oc/util/ExtendedLuaState.scala @@ -91,7 +91,7 @@ object ExtendedLuaState { val tableIndex = lua.getTop memo += obj -> tableIndex for ((key: AnyRef, value: AnyRef) <- map) { - if (key != null && key != Unit && !key.isInstanceOf[BoxedUnit]) { + if (key != null && !key.isInstanceOf[BoxedUnit]) { pushValue(key, memo) val keyIndex = lua.getTop pushValue(value, memo)