blob: dff9508338d14fef4f822c941cf861894b54b8d9 [file] [log] [blame] [raw]
package li.cil.oc.common.tileentity
import cpw.mods.fml.common.Optional.Interface
import cpw.mods.fml.common.{Loader, Optional}
import li.cil.oc.Config
import li.cil.oc.api.network
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.Persistable
import mods.immibis.redlogic.api.wiring._
import net.minecraft.nbt.{NBTTagByteArray, NBTTagCompound}
import net.minecraftforge.common.ForgeDirection
@Optional.InterfaceList(Array(
new Interface(iface = "mods.immibis.redlogic.api.wiring.IConnectable", modid = "RedLogic"),
new Interface(iface = "mods.immibis.redlogic.api.wiring.IBundledEmitter", modid = "RedLogic"),
new Interface(iface = "mods.immibis.redlogic.api.wiring.IBundledUpdatable", modid = "RedLogic"),
new Interface(iface = "mods.immibis.redlogic.api.wiring.IRedstoneEmitter", modid = "RedLogic"),
new Interface(iface = "mods.immibis.redlogic.api.wiring.IRedstoneUpdatable", modid = "RedLogic")
))
trait Redstone extends TileEntity with network.Environment with Rotatable with Persistable
with IConnectable with IBundledEmitter with IBundledUpdatable with IRedstoneEmitter with IRedstoneUpdatable {
private val _input = Array.fill[Byte](6)(-1)
private val _output = Array.fill[Byte](6)(0)
private val _bundledInput = Array.fill[Array[Byte]](6)(Array.fill[Byte](16)(-1))
private val _bundledOutput = Array.fill[Array[Byte]](6)(Array.fill[Byte](16)(0))
private var _isOutputEnabled = true
private var _shouldUpdateInput = true
def isOutputEnabled = _isOutputEnabled
def isOutputEnabled_=(value: Boolean) = {
if (value != isOutputEnabled) {
_isOutputEnabled = value
if (!isOutputEnabled) {
for (i <- 0 until _output.length) {
_output(i) = 0.toByte
}
for (i <- 0 until _bundledOutput.length) {
for (j <- 0 until _bundledOutput(i).length) {
_bundledOutput(i)(j) = 0.toByte
}
}
}
onRedstoneOutputChanged(ForgeDirection.UNKNOWN)
}
this
}
def input(side: ForgeDirection) = (_input(toGlobal(side).ordinal()) & 0xFF).toShort
def output(side: ForgeDirection) = (_output(side.ordinal()) & 0xFF).toShort
def output(side: ForgeDirection, value: Short): Unit = if (value != output(side)) {
_output(side.ordinal()) = (value max 0 min 255).toByte
onRedstoneOutputChanged(toGlobal(side))
}
def bundledInput(side: ForgeDirection, color: Int) = (_bundledInput(toGlobal(side).ordinal())(color) & 0xFF).toShort
def bundledOutput(side: ForgeDirection, color: Int) =
(_bundledOutput(side.ordinal())(color) & 0xFF).toShort
def bundledOutput(side: ForgeDirection, color: Int, value: Short): Unit = if (value != bundledOutput(side, color)) {
_bundledOutput(side.ordinal())(color) = (value max 0 min 255).toByte
onRedstoneOutputChanged(toGlobal(side))
}
def checkRedstoneInputChanged() {
_shouldUpdateInput = true
}
// ----------------------------------------------------------------------- //
def updateRedstoneInput() {
if (_shouldUpdateInput) {
_shouldUpdateInput = false
for (side <- ForgeDirection.VALID_DIRECTIONS) {
val (oldInput, oldBundledInput) = (_input(side.ordinal()), _bundledInput(side.ordinal()))
val (newInput, newBundledInput) = (computeInput(side), computeBundledInput(side))
_input(side.ordinal()) = (newInput max 0 min 255).toByte
var changed = oldInput >= 0 && input(side) != oldInput
if (newBundledInput != null) for (i <- 0 until 16) {
changed = changed || oldBundledInput(i) != newBundledInput(i)
oldBundledInput(i) = newBundledInput(i)
}
else for (i <- 0 until 16) {
changed = changed || oldBundledInput(i) != 0.toByte
oldBundledInput(i) = 0.toByte
}
if (changed) {
onRedstoneInputChanged(side)
}
}
}
}
// ----------------------------------------------------------------------- //
override def load(nbt: NBTTagCompound) = {
super.load(nbt)
nbt.getByteArray(Config.namespace + "rs.input").copyToArray(_input)
nbt.getByteArray(Config.namespace + "rs.output").copyToArray(_output)
nbt.getTagList(Config.namespace + "rs.bundledInput").iterator[NBTTagByteArray].zipWithIndex.foreach {
case (input, side) => input.byteArray.copyToArray(_bundledInput(side))
}
nbt.getTagList(Config.namespace + "rs.bundledOutput").iterator[NBTTagByteArray].zipWithIndex.foreach {
case (input, side) => input.byteArray.copyToArray(_bundledOutput(side))
}
}
override def save(nbt: NBTTagCompound) = {
super.save(nbt)
nbt.setByteArray(Config.namespace + "rs.input", _input)
nbt.setByteArray(Config.namespace + "rs.output", _output)
nbt.setNewTagList(Config.namespace + "rs.bundledInput", _bundledInput.view)
nbt.setNewTagList(Config.namespace + "rs.bundledOutput", _bundledOutput.view)
}
// ----------------------------------------------------------------------- //
protected def computeInput(side: ForgeDirection) = {
world.getIndirectPowerLevelTo(
x + side.offsetX,
y + side.offsetY,
z + side.offsetZ,
side.ordinal())
}
protected def computeBundledInput(side: ForgeDirection) = {
if (Loader.isModLoaded("RedLogic")) {
world.getBlockTileEntity(
x + side.offsetX,
y + side.offsetY,
z + side.offsetZ) match {
case wire: IInsulatedRedstoneWire =>
var strength: Array[Byte] = null
for (face <- -1 to 5 if wire.wireConnectsInDirection(face, side.ordinal()) && strength == null) {
strength = Array.fill[Byte](16)(0)
strength(wire.getInsulatedWireColour) = wire.getEmittedSignalStrength(face, side.ordinal()).toByte
}
strength
case emitter: IBundledEmitter =>
var strength: Array[Byte] = null
for (i <- -1 to 5 if strength == null) {
strength = emitter.getBundledCableStrength(i, side.getOpposite.ordinal())
}
strength
case _ => null
}
} else null
}
protected def onRedstoneInputChanged(side: ForgeDirection) {}
protected def onRedstoneOutputChanged(side: ForgeDirection) {
if (side == ForgeDirection.UNKNOWN) {
world.notifyBlocksOfNeighborChange(x, y, z, block.blockID)
}
else {
val (nx, ny, nz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ)
world.notifyBlockOfNeighborChange(nx, ny, nz, block.blockID)
world.notifyBlocksOfNeighborChange(nx, ny, nz, world.getBlockId(nx, ny, nz))
}
if (isServer) ServerPacketSender.sendRedstoneState(this)
else world.markBlockForRenderUpdate(x, y, z)
}
// ----------------------------------------------------------------------- //
@Optional.Method(modid = "RedLogic")
def connects(wire: IWire, blockFace: Int, fromDirection: Int) = true
@Optional.Method(modid = "RedLogic")
def connectsAroundCorner(wire: IWire, blockFace: Int, fromDirection: Int) = false
@Optional.Method(modid = "RedLogic")
def getBundledCableStrength(blockFace: Int, toDirection: Int): Array[Byte] = _bundledOutput(toLocal(ForgeDirection.getOrientation(toDirection)).ordinal())
@Optional.Method(modid = "RedLogic")
def onBundledInputChanged() = checkRedstoneInputChanged()
@Optional.Method(modid = "RedLogic")
def getEmittedSignalStrength(blockFace: Int, toDirection: Int): Short = (_output(toLocal(ForgeDirection.getOrientation(toDirection)).ordinal()) & 0xFF).toShort
@Optional.Method(modid = "RedLogic")
def onRedstoneInputChanged() = checkRedstoneInputChanged()
}