redstone api overrides, backwards compatible

Providing the following overrides:

getInput(side: number): number
getInput(): table

setOutput(side, number): number
setOutput(values: table): table

getBundledInput(side: number, color: number): number
getBundledInput(side: number): table
getBundledInput(): table

getBundledOutput(side: number, color: number): number
getBundledOutput(side: number): table
getBundledOutput(): table

setBundledOutput(side: number, color: number, value: number): number
setBundledOutput(side: number, values: table): table
setBundledOutput(values: table): table

closes #2539
This commit is contained in:
payonel 2018-11-03 11:01:06 -07:00
parent a8336f2d69
commit e67d00221b
16 changed files with 329 additions and 123 deletions

View File

@ -483,9 +483,9 @@ object PacketHandler extends CommonPacketHandler {
def onRedstoneState(p: PacketParser) = def onRedstoneState(p: PacketParser) =
p.readTileEntity[RedstoneAware]() match { p.readTileEntity[RedstoneAware]() match {
case Some(t) => case Some(t) =>
t.isOutputEnabled = p.readBoolean() t.setOutputEnabled(p.readBoolean())
for (d <- ForgeDirection.VALID_DIRECTIONS) { for (d <- ForgeDirection.VALID_DIRECTIONS) {
t.output(d, p.readByte()) t.setOutput(d, p.readByte())
} }
case _ => // Invalid packet. case _ => // Invalid packet.
} }

View File

@ -29,7 +29,7 @@ abstract class RedstoneAware extends SimpleBlock with IRedNetOmniNode {
override def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = override def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) =
world.getTileEntity(x, y, z) match { 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) 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) { case t: tileentity.traits.BundledRedstoneAware => for (side <- ForgeDirection.VALID_DIRECTIONS) {
world.getBlock(position.offset(side)) match { world.getBlock(position.offset(side)) match {
case block: IRedNetNetworkContainer => case block: IRedNetNetworkContainer =>
case _ => for (color <- 0 until 16) { case _ => for (color <- 0 until 16) {
t.rednetInput(side, color, 0) t.setRednetInput(side, color, 0)
} }
} }
} }
case _ => 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) = override def getOutputValue(world: World, x: Int, y: Int, z: Int, side: ForgeDirection, color: Int) =
world.getTileEntity(x, y, z) match { 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 case _ => 0
} }
override def getOutputValues(world: World, x: Int, y: Int, z: Int, side: ForgeDirection) = override def getOutputValues(world: World, x: Int, y: Int, z: Int, side: ForgeDirection) =
world.getTileEntity(x, y, z) match { 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) 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]) = override def onInputsChanged(world: World, x: Int, y: Int, z: Int, side: ForgeDirection, inputValues: Array[Int]) =
world.getTileEntity(x, y, z) match { world.getTileEntity(x, y, z) match {
case t: tileentity.traits.BundledRedstoneAware => for (color <- 0 until 16) { case t: tileentity.traits.BundledRedstoneAware => for (color <- 0 until 16) {
t.rednetInput(side, color, inputValues(color)) t.setRednetInput(side, color, inputValues(color))
} }
case _ => case _ =>
} }

View File

@ -190,7 +190,7 @@ class Charger extends traits.Environment with traits.PowerAcceptor with traits.R
override def updateRedstoneInput(side: ForgeDirection) { override def updateRedstoneInput(side: ForgeDirection) {
super.updateRedstoneInput(side) 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 if (invertSignal) chargeSpeed = (15 - signal) / 15.0
else chargeSpeed = signal / 15.0 else chargeSpeed = signal / 15.0

View File

@ -1,5 +1,7 @@
package li.cil.oc.common.tileentity package li.cil.oc.common.tileentity
import java.util
import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly import cpw.mods.fml.relauncher.SideOnly
import li.cil.oc.common.item.data.PrintData 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.ExtendedAABB._
import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ExtendedNBT._
import net.minecraft.nbt.NBTTagCompound 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 { class Print extends traits.TileEntity with traits.RedstoneAware with traits.Rotatable {
val data = new PrintData() val data = new PrintData()
@ -29,12 +32,20 @@ class Print extends traits.TileEntity with traits.RedstoneAware with traits.Rota
false 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 = { def toggleState(): Unit = {
state = !state 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.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) world.markBlockForUpdate(x, y, z)
if (data.emitRedstoneWhenOn) { 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) { if (state && data.isButtonMode) {
world.scheduleBlockUpdate(x, y, z, block, block.tickRate(world)) 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) else boundsOn = boundsOn.rotateTowards(facing)
if (data.emitRedstoneWhenOff) { if (data.emitRedstoneWhenOff) {
ForgeDirection.VALID_DIRECTIONS.foreach(output(_, data.redstoneLevel)) setOutput(buildValueSet(data.redstoneLevel))
} }
} }

View File

@ -290,7 +290,7 @@ class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalance
override def markChanged(slot: Int): Unit = { override def markChanged(slot: Int): Unit = {
hasChanged.synchronized(hasChanged(slot) = true) hasChanged.synchronized(hasChanged(slot) = true)
isOutputEnabled = hasRedstoneCard setOutputEnabled(hasRedstoneCard)
isAbstractBusAvailable = hasAbstractBusCard isAbstractBusAvailable = hasAbstractBusCard
} }
@ -339,7 +339,7 @@ class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalance
override def markDirty() { override def markDirty() {
super.markDirty() super.markDirty()
if (isServer) { if (isServer) {
isOutputEnabled = hasRedstoneCard setOutputEnabled(hasRedstoneCard)
isAbstractBusAvailable = hasAbstractBusCard isAbstractBusAvailable = hasAbstractBusCard
ServerPacketSender.sendRackInventory(this) ServerPacketSender.sendRackInventory(this)
} }
@ -395,7 +395,7 @@ class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalance
ServerPacketSender.sendRackMountableData(this, slot) ServerPacketSender.sendRackMountableData(this, slot)
world.notifyBlocksOfNeighborChange(x, y, z, block) world.notifyBlocksOfNeighborChange(x, y, z, block)
// These are working state dependent, so recompute them. // These are working state dependent, so recompute them.
isOutputEnabled = hasRedstoneCard setOutputEnabled(hasRedstoneCard)
isAbstractBusAvailable = hasAbstractBusCard isAbstractBusAvailable = hasAbstractBusCard
} }

View File

@ -190,9 +190,9 @@ class RobotProxy(val robot: Robot) extends traits.Computer with traits.PowerInfo
override protected[tileentity] val _bundledOutput = robot._bundledOutput 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() override def checkRedstoneInputChanged() = robot.checkRedstoneInputChanged()

View File

@ -1,7 +1,10 @@
package li.cil.oc.common.tileentity.traits package li.cil.oc.common.tileentity.traits
import java.util
import cpw.mods.fml.common.Optional import cpw.mods.fml.common.Optional
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.api.machine.Arguments
import li.cil.oc.integration.Mods import li.cil.oc.integration.Mods
import li.cil.oc.integration.util.BundledRedstone import li.cil.oc.integration.util.BundledRedstone
import li.cil.oc.util.BlockPosition import li.cil.oc.util.BlockPosition
@ -31,8 +34,8 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def isOutputEnabled_=(value: Boolean) = { override def setOutputEnabled(value: Boolean): Unit = {
if (value != isOutputEnabled) { if (value != _isOutputEnabled) {
if (!value) { if (!value) {
for (i <- _bundledOutput.indices) { for (i <- _bundledOutput.indices) {
for (j <- _bundledOutput(i).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) = def getBundledInput: Array[Array[Int]] = {
(_bundledInput(side.ordinal()), _rednetInput(side.ordinal())).zipped.map(math.max) (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) { 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 = { 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) { if (oldValue != newValue) {
inputs(sideIndex)(colorIndex) = newValue
if (oldValue != -1) { 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) = def getBundledOutput: Array[Array[Int]] = _bundledInput
math.max(_bundledInput(side.ordinal())(color), _rednetInput(side.ordinal())(color))
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 getBundledOutput(side: ForgeDirection, color: Int): Int = getBundledOutput(side)(checkColor(color))
def bundledOutput(side: ForgeDirection, color: Int, value: Int): Unit = if (value != bundledOutput(side, color)) {
_bundledOutput(toLocal(side).ordinal())(color) = value
def notifyChangedSide(side: ForgeDirection): Unit = {
if (Mods.MineFactoryReloaded.isAvailable) { if (Mods.MineFactoryReloaded.isAvailable) {
val blockPos = BlockPosition(x, y, z).offset(side) val blockPos = BlockPosition(x, y, z).offset(side)
world.getBlock(blockPos) match { world.getBlock(blockPos) match {
@ -86,11 +120,50 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund
onRedstoneOutputChanged(side) 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) { override def updateRedstoneInput(side: ForgeDirection) {
super.updateRedstoneInput(side) super.updateRedstoneInput(side)
bundledInput(side, BundledRedstone.computeBundledInput(position, side)) setBundledInput(side, BundledRedstone.computeBundledInput(position, side))
} }
override def readFromNBTForServer(nbt: NBTTagCompound) { override def readFromNBTForServer(nbt: NBTTagCompound) {
@ -147,16 +220,16 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Optional.Method(modid = Mods.IDs.RedLogic) @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) @Optional.Method(modid = Mods.IDs.RedLogic)
def onBundledInputChanged() = checkRedstoneInputChanged() def onBundledInputChanged(): Unit = checkRedstoneInputChanged()
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Optional.Method(modid = Mods.IDs.ProjectRedTransmission) @Optional.Method(modid = Mods.IDs.ProjectRedTransmission)
def canConnectBundled(side: Int) = isOutputEnabled def canConnectBundled(side: Int): Boolean = _isOutputEnabled
@Optional.Method(modid = Mods.IDs.ProjectRedTransmission) @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)
} }

View File

@ -198,7 +198,7 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B
super.markDirty() super.markDirty()
if (isServer) { if (isServer) {
machine.onHostChanged() machine.onHostChanged()
isOutputEnabled = hasRedstoneCard setOutputEnabled(hasRedstoneCard)
isAbstractBusAvailable = hasAbstractBusCard isAbstractBusAvailable = hasAbstractBusCard
} }
} }

View File

@ -1,5 +1,7 @@
package li.cil.oc.common.tileentity.traits package li.cil.oc.common.tileentity.traits
import java.util
import cpw.mods.fml.common.Optional import cpw.mods.fml.common.Optional
import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly 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) new Optional.Interface(iface = "mods.immibis.redlogic.api.wiring.IRedstoneUpdatable", modid = Mods.IDs.RedLogic)
)) ))
trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitter with IRedstoneUpdatable { 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) = { def setOutputEnabled(value: Boolean): Unit = {
if (value != isOutputEnabled) { if (value != _isOutputEnabled) {
_isOutputEnabled = value _isOutputEnabled = value
if (!value) { if (!value) {
for (i <- _output.indices) { for (i <- _output.indices) {
@ -44,12 +46,34 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte
} }
onRedstoneOutputEnabledChanged() 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()) val oldInput = _input(side.ordinal())
_input(side.ordinal()) = newInput _input(side.ordinal()) = newInput
if (oldInput >= 0 && newInput != oldInput) { 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 _output(toLocal(side).ordinal()) = value
onRedstoneOutputChanged(side) 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() { def checkRedstoneInputChanged() {
@ -90,9 +137,7 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte
} }
} }
def updateRedstoneInput(side: ForgeDirection) { def updateRedstoneInput(side: ForgeDirection): Unit = setInput(side, BundledRedstone.computeInput(position, side))
input(side, BundledRedstone.computeInput(position, side))
}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@ -115,13 +160,13 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
override def readFromNBTForClient(nbt: NBTTagCompound) { override def readFromNBTForClient(nbt: NBTTagCompound) {
super.readFromNBTForClient(nbt) super.readFromNBTForClient(nbt)
isOutputEnabled = nbt.getBoolean("isOutputEnabled") _isOutputEnabled = nbt.getBoolean("isOutputEnabled")
nbt.getIntArray("output").copyToArray(_output) nbt.getIntArray("output").copyToArray(_output)
} }
override def writeToNBTForClient(nbt: NBTTagCompound) { override def writeToNBTForClient(nbt: NBTTagCompound) {
super.writeToNBTForClient(nbt) super.writeToNBTForClient(nbt)
nbt.setBoolean("isOutputEnabled", isOutputEnabled) nbt.setBoolean("isOutputEnabled", _isOutputEnabled)
nbt.setIntArray("output", _output) nbt.setIntArray("output", _output)
} }
@ -147,7 +192,7 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Optional.Method(modid = Mods.IDs.RedLogic) @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) @Optional.Method(modid = Mods.IDs.RedLogic)
override def connectsAroundCorner(wire: IWire, blockFace: Int, fromDirection: Int) = false 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 override def getEmittedSignalStrength(blockFace: Int, toDirection: Int): Short = _output(toLocal(ForgeDirection.getOrientation(toDirection)).ordinal()).toShort
@Optional.Method(modid = Mods.IDs.RedLogic) @Optional.Method(modid = Mods.IDs.RedLogic)
override def onRedstoneInputChanged() = checkRedstoneInputChanged() override def onRedstoneInputChanged(): Unit = checkRedstoneInputChanged()
} }

View File

@ -28,11 +28,11 @@ class BundledRedstoneDevice(val tileEntity: BundledRedstoneAware) extends IBundl
override def getBundledColor(side: ForgeDirection): MinecraftColor = MinecraftColor.ANY 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() override def onBundledUpdate(): Unit = tileEntity.checkRedstoneInputChanged()
} }

View File

@ -25,9 +25,9 @@ class RedstoneDevice(val tileEntity: RedstoneAware) extends IRedstoneDevice {
override def getRedstoneConnectionCache: IConnectionCache[_ <: IRedstoneDevice] = cache 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() override def onRedstoneUpdate(): Unit = tileEntity.checkRedstoneInputChanged()
} }

View File

@ -19,9 +19,9 @@ object BundledRedstoneProvider extends IBundledRedstoneProvider with RedstonePro
world.getTileEntity(x, y, z) match { world.getTileEntity(x, y, z) match {
case tile: BundledRedstoneAware => case tile: BundledRedstoneAware =>
var result = 0 var result = 0
val colours = tile.bundledOutput(ForgeDirection.VALID_DIRECTIONS(side)) val colors = tile.getBundledOutput(ForgeDirection.VALID_DIRECTIONS(side))
for (colour <- 0 to 15) { for (color <- 0 to 15) {
if (colours(colour) > 0) result |= 1 << colour if (colors(color) > 0) result |= 1 << color
} }
result result
case _ => -1 case _ => -1

View File

@ -483,7 +483,7 @@ object PacketSender {
pb.writeTileEntity(t) pb.writeTileEntity(t)
pb.writeBoolean(t.isOutputEnabled) pb.writeBoolean(t.isOutputEnabled)
for (d <- ForgeDirection.VALID_DIRECTIONS) { for (d <- ForgeDirection.VALID_DIRECTIONS) {
pb.writeByte(t.output(d)) pb.writeByte(t.getOutput(d))
} }
pb.sendToPlayersNearTileEntity(t) pb.sendToPlayersNearTileEntity(t)

View File

@ -11,6 +11,7 @@ import li.cil.oc.api.machine.Arguments
import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Callback
import li.cil.oc.api.machine.Context import li.cil.oc.api.machine.Context
import li.cil.oc.common.tileentity.traits.BundledRedstoneAware import li.cil.oc.common.tileentity.traits.BundledRedstoneAware
import net.minecraftforge.common.util.ForgeDirection
import scala.collection.convert.WrapAsJava._ import scala.collection.convert.WrapAsJava._
@ -26,56 +27,103 @@ trait RedstoneBundled extends RedstoneVanilla {
override def getDeviceInfo: util.Map[String, String] = deviceInfo override def getDeviceInfo: util.Map[String, String] = deviceInfo
private val COLOR_RANGE = 0 until 16
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def redstone: EnvironmentHost with BundledRedstoneAware 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.""") private def getBundleKey(args: Arguments): (Option[ForgeDirection], Option[Int]) = {
def getBundledInput(context: Context, args: Arguments): Array[AnyRef] = { args.count match {
val side = checkSide(args, 0) case 2 => (Option(checkSide(args, 0)), Option(checkColor(args, 1)))
if (args.optAny(1, null) == null) case 1 => (Option(checkSide(args, 0)), None)
result(redstone.bundledInput(side).zipWithIndex.map(_.swap).toMap) case 0 => (None, None)
else case _ => throw new Exception("too many arguments, expected 0, 1, or 2")
result(redstone.bundledInput(side, checkColor(args, 1))) }
} }
@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.""") private def tableToColorValues(table: util.Map[_, _]): Array[Int] = {
def getBundledOutput(context: Context, args: Arguments): Array[AnyRef] = { COLOR_RANGE.collect {
val side = checkSide(args, 0) case color: Int if table.containsKey(color) => {
if (args.optAny(1, null) == null) table.get(color) match {
result(redstone.bundledOutput(side).zipWithIndex.map(_.swap).toMap) case value: Integer => value.toInt
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 _ =>
} }
}.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) if (Settings.get.redstoneDelay > 0)
context.pause(Settings.get.redstoneDelay) 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 = { private def checkColor(args: Arguments, index: Int): Int = {
val color = args.checkInteger(index) val color = args.checkInteger(index)
if (color < 0 || color > 15) if (!COLOR_RANGE.contains(color))
throw new IllegalArgumentException("invalid color") throw new IllegalArgumentException("invalid color")
color color
} }

View File

@ -36,31 +36,43 @@ trait RedstoneVanilla extends RedstoneSignaller with DeviceInfo {
override def getDeviceInfo: util.Map[String, String] = 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 or table -- Get the redstone input (all sides, or optionally on the specified side)")
@Callback(direct = true, doc = """function(side:number):number -- Get the redstone input on the specified side.""")
def getInput(context: Context, args: Arguments): Array[AnyRef] = { def getInput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) getOptionalSide(args) match {
result(redstone.input(side)) 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] = { def getOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) getOptionalSide(args) match {
result(redstone.output(side)) 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] = { def setOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) var ret: AnyRef = null
val value = args.checkInteger(1) if (getAssignment(args) match {
redstone.output(side, value) case (side: ForgeDirection, value: Int) =>
if (Settings.get.redstoneDelay > 0) ret = new java.lang.Integer(redstone.getOutput(side))
context.pause(Settings.get.redstoneDelay) redstone.setOutput(side, value)
result(redstone.output(side)) 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] = { def getComparatorInput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) val side = checkSide(args, 0)
val blockPos = BlockPosition(redstone).offset(side) 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) val side = args.checkInteger(index)
if (side < 0 || side > 5) if (side < 0 || side > 5)
throw new IllegalArgumentException("invalid side") throw new IllegalArgumentException("invalid side")
redstone.toGlobal(ForgeDirection.getOrientation(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
} }

View File

@ -91,7 +91,7 @@ object ExtendedLuaState {
val tableIndex = lua.getTop val tableIndex = lua.getTop
memo += obj -> tableIndex memo += obj -> tableIndex
for ((key: AnyRef, value: AnyRef) <- map) { for ((key: AnyRef, value: AnyRef) <- map) {
if (key != null && key != Unit && !key.isInstanceOf[BoxedUnit]) { if (key != null && !key.isInstanceOf[BoxedUnit]) {
pushValue(key, memo) pushValue(key, memo)
val keyIndex = lua.getTop val keyIndex = lua.getTop
pushValue(value, memo) pushValue(value, memo)