blob: e906aa5ae5afbb19b507795047adb947b7e740b4 [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 cpw.mods.fml.relauncher.{SideOnly, Side}
import li.cil.oc.Settings
import li.cil.oc.api.network
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import li.cil.oc.util.Persistable
import mods.immibis.redlogic.api.wiring._
import net.minecraft.block.Block
import net.minecraft.nbt.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.IRedstoneEmitter", modid = "RedLogic"),
new Interface(iface = "mods.immibis.redlogic.api.wiring.IRedstoneUpdatable", modid = "RedLogic")
))
trait RedstoneAware extends RotationAware with network.Environment with Persistable with IConnectable with IRedstoneEmitter with IRedstoneUpdatable {
protected val _input = Array.fill(6)(-1)
protected val _output = Array.fill(6)(0)
protected var _isOutputEnabled = false
protected 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
}
}
onRedstoneOutputChanged(ForgeDirection.UNKNOWN)
}
this
}
def input(side: ForgeDirection) = _input(side.ordinal())
def maxInput = ForgeDirection.VALID_DIRECTIONS.map(input).max
def output(side: ForgeDirection) = _output(toLocal(side).ordinal())
def output(side: ForgeDirection, value: Int): Unit = if (value != output(side)) {
_output(toLocal(side).ordinal()) = value
onRedstoneOutputChanged(side)
}
def checkRedstoneInputChanged() {
shouldUpdateInput = isServer
}
// ----------------------------------------------------------------------- //
def updateRedstoneInput() {
if (shouldUpdateInput) {
shouldUpdateInput = false
for (side <- ForgeDirection.VALID_DIRECTIONS) {
val oldInput = _input(side.ordinal())
val newInput = computeInput(side)
_input(side.ordinal()) = newInput
if (oldInput >= 0 && input(side) != oldInput) {
onRedstoneInputChanged(side)
}
}
}
}
// ----------------------------------------------------------------------- //
override def load(nbt: NBTTagCompound) = {
super.load(nbt)
val input = nbt.getIntArray(Settings.namespace + "rs.input")
input.copyToArray(_input, 0, input.length min _input.length)
val output = nbt.getIntArray(Settings.namespace + "rs.output")
output.copyToArray(_output, 0, output.length min _output.length)
}
override def save(nbt: NBTTagCompound) = {
super.save(nbt)
nbt.setIntArray(Settings.namespace + "rs.input", _input)
nbt.setIntArray(Settings.namespace + "rs.output", _output)
}
@SideOnly(Side.CLIENT)
override def readFromNBTForClient(nbt: NBTTagCompound) {
super.readFromNBTForClient(nbt)
isOutputEnabled = nbt.getBoolean("isOutputEnabled")
nbt.getIntArray("output").copyToArray(_output)
}
override def writeToNBTForClient(nbt: NBTTagCompound) {
super.writeToNBTForClient(nbt)
nbt.setBoolean("isOutputEnabled", isOutputEnabled)
nbt.setIntArray("output", _output)
}
// ----------------------------------------------------------------------- //
protected def computeInput(side: ForgeDirection) = {
val (sx, sy, sz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ)
// See BlockRedstoneLogic.getInputStrength() for reference.
val vanilla = math.max(world.getIndirectPowerLevelTo(sx, sy, sz, side.ordinal()),
if (world.getBlockId(sx, sy, sz) == Block.redstoneWire.blockID) world.getBlockMetadata(sx, sy, sz) else 0)
val redLogic = if (Loader.isModLoaded("RedLogic")) {
world.getBlockTileEntity(sx, sy, sz) match {
case emitter: IRedstoneEmitter =>
var strength = 0
for (i <- -1 to 5) {
strength = math.max(strength, emitter.getEmittedSignalStrength(i, side.getOpposite.ordinal()))
}
strength
case _ => 0
}
}
else 0
math.max(vanilla, redLogic)
}
protected def onRedstoneInputChanged(side: ForgeDirection) {}
protected def onRedstoneOutputChanged(side: ForgeDirection) {
if (side == ForgeDirection.UNKNOWN) {
world.notifyBlocksOfNeighborChange(x, y, z, block.blockID)
}
else {
val nx = x + side.offsetX
val ny = y + side.offsetY
val nz = 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) = isOutputEnabled
@Optional.Method(modid = "RedLogic")
def connectsAroundCorner(wire: IWire, blockFace: Int, fromDirection: Int) = false
@Optional.Method(modid = "RedLogic")
def getEmittedSignalStrength(blockFace: Int, toDirection: Int): Short = _output(toLocal(ForgeDirection.getOrientation(toDirection)).ordinal()).toShort
@Optional.Method(modid = "RedLogic")
def onRedstoneInputChanged() = checkRedstoneInputChanged()
}