added bundled redstone support, only support for immibis' RedLogic mod for now

This commit is contained in:
Florian Nücke 2013-11-07 03:30:17 +01:00
parent bb7684acb7
commit eb3a8e1ff8
17 changed files with 380 additions and 44 deletions

View File

@ -4,12 +4,12 @@ if #args < 1 then
return
end
local side = rs.sides[args[1]]
local side = sides[args[1]]
if not side then
print("Invalid side.")
end
if type(side) == "string" then
side = rs.sides[side]
side = sides[side]
end
if #args > 1 then

View File

@ -0,0 +1,32 @@
local colors = {
[0] = "white",
[1] = "orange",
[2] = "magenta",
[3] = "lightBlue",
[4] = "yellow",
[5] = "lime",
[6] = "pink",
[7] = "gray",
[8] = "silver",
[9] = "cyan",
[10] = "purple",
[11] = "blue",
[12] = "brown",
[13] = "green",
[14] = "red",
[15] = "black"
}
do
local keys = {}
for k in pairs(colors) do
table.insert(keys, k)
end
for _, k in pairs(keys) do
colors[colors[k]] = k
end
end
-------------------------------------------------------------------------------
_G.colors = colors

View File

@ -131,8 +131,14 @@ keyboard.keys = {
}
-- Create inverse mapping for name lookup.
for k, v in pairs(keyboard.keys) do
keyboard.keys[v] = k
do
local keys = {}
for k in pairs(keyboard.keys) do
table.insert(keys, k)
end
for _, k in pairs(keys) do
keyboard.keys[keyboard.keys[k]] = k
end
end
-------------------------------------------------------------------------------

View File

@ -4,11 +4,16 @@ local sides = {
[2] = "back",
[3] = "front",
[4] = "right",
[5] = "left"
[5] = "left",
bottom = 0,
top = 1,
back = 2,
front = 3,
right = 4,
left = 5
}
for k, v in pairs(sides) do
sides[v] = k
end
sides.up = sides.top
sides.down = sides.bottom

View File

@ -45,6 +45,8 @@ trait Delegate {
def icon(side: ForgeDirection): Option[Icon] = None
def isBlockNormalCube(world: World, x: Int, y: Int, z: Int) = true
def isProvidingStrongPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = 0
def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = 0
@ -85,8 +87,6 @@ trait SpecialDelegate extends Delegate {
// ----------------------------------------------------------------------- //
def isBlockNormalCube(world: World, x: Int, y: Int, z: Int) = true
def isBlockSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = true
def shouldSideBeRendered(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) =

View File

@ -213,6 +213,12 @@ class Delegator[Child <: Delegate](id: Int) extends Block(id, Material.iron) {
case _ => false
}
override def isBlockNormalCube(world: World, x: Int, y: Int, z: Int) =
subBlock(world.getBlockMetadata(x, y, z)) match {
case Some(subBlock) => subBlock.isBlockNormalCube(world, x, y, z)
case _ => false
}
override def isProvidingStrongPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: Int) =
subBlock(world, x, y, z) match {
case Some(subBlock) => subBlock.isProvidingStrongPower(
@ -333,12 +339,6 @@ class Delegator[Child <: Delegate](id: Int) extends Block(id, Material.iron) {
class SimpleDelegator(id: Int) extends Delegator[SimpleDelegate](id)
class SpecialDelegator(id: Int) extends Delegator[SpecialDelegate](id) {
override def isBlockNormalCube(world: World, x: Int, y: Int, z: Int) =
subBlock(world.getBlockMetadata(x, y, z)) match {
case Some(subBlock) => subBlock.isBlockNormalCube(world, x, y, z)
case _ => false
}
override def isBlockSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: Int) =
subBlock(world.getBlockMetadata(x, y, z)) match {
case Some(subBlock) => subBlock.isBlockSolid(world, x, y, z, ForgeDirection.getOrientation(side))

View File

@ -1,5 +1,7 @@
package li.cil.oc.common.tileentity
import cpw.mods.fml.common.Loader
import li.cil.oc.Config
import li.cil.oc.api.Network
import li.cil.oc.api.driver.Slot
import li.cil.oc.client.{PacketSender => ClientPacketSender}
@ -9,11 +11,11 @@ import li.cil.oc.server.component.Redstone
import li.cil.oc.server.driver
import li.cil.oc.server.driver.Registry
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import mods.immibis.redlogic.api.wiring.IBundledEmitter
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.ForgeDirection
import li.cil.oc.Config
class Computer(isClient: Boolean) extends Rotatable with ComputerEnvironment with ComponentInventory with Redstone {
def this() = this(false)
@ -91,8 +93,10 @@ class Computer(isClient: Boolean) extends Rotatable with ComputerEnvironment wit
}
if (needsSaving)
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
if (isRunning != instance.isRunning)
if (isRunning != instance.isRunning) {
isOutputEnabled = hasRedstoneCard && instance.isRunning
ServerPacketSender.sendComputerState(this, instance.isRunning)
}
isRunning = instance.isRunning
updateRedstoneInput()
}
@ -134,7 +138,7 @@ class Computer(isClient: Boolean) extends Rotatable with ComputerEnvironment wit
super.onInventoryChanged()
if (!worldObj.isRemote) {
instance.recomputeMemory()
isOutputEnabled = hasRedstoneCard
isOutputEnabled = hasRedstoneCard && instance.isRunning
}
}
@ -151,6 +155,24 @@ class Computer(isClient: Boolean) extends Rotatable with ComputerEnvironment wit
global.ordinal())
}
protected def computeBundledInput(side: ForgeDirection) = {
val global = toGlobal(side)
if (Loader.isModLoaded("RedLogic")) {
worldObj.getBlockTileEntity(
xCoord + global.offsetX,
yCoord + global.offsetY,
zCoord + global.offsetZ) match {
case emitter: IBundledEmitter =>
var strength: Array[Byte] = null
for (i <- -1 to 5 if strength == null) {
strength = emitter.getBundledCableStrength(i, global.getOpposite.ordinal())
}
strength
case _ => null
}
} else null
}
override protected def onRedstoneInputChanged(side: ForgeDirection) {
super.onRedstoneInputChanged(side)
instance.signal("redstone_changed", side.ordinal())

View File

@ -25,6 +25,7 @@ import scala.Some
import scala.collection.convert.WrapAsScala._
import scala.collection.mutable
import scala.math.ScalaNumber
import scala.runtime.BoxedUnit
/**
* Wrapper class for Lua states set up to behave like a pseudo-OS.
@ -565,7 +566,7 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
}
def pushResult(lua: LuaState, value: AnyRef): Unit = value match {
case null | Unit => lua.pushNil()
case null | Unit | _: BoxedUnit => lua.pushNil()
case value: java.lang.Boolean => lua.pushBoolean(value.booleanValue)
case value: java.lang.Byte => lua.pushNumber(value.byteValue)
case value: java.lang.Character => lua.pushString(String.valueOf(value))

View File

@ -1,15 +1,30 @@
package li.cil.oc.server.component
import cpw.mods.fml.common.Optional
import cpw.mods.fml.common.Optional.Interface
import li.cil.oc.common.tileentity
import li.cil.oc.util.Persistable
import mods.immibis.redlogic.api.wiring._
import net.minecraft.nbt.{NBTTagByte, NBTTagList, NBTTagCompound}
import net.minecraftforge.common.ForgeDirection
import li.cil.oc.util.Persistable
trait Redstone extends tileentity.Environment with Persistable {
@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.Environment 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
@ -23,18 +38,33 @@ trait Redstone extends tileentity.Environment with Persistable {
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): Int = _input(side.ordinal())
def input(side: ForgeDirection) = (_input(side.ordinal()) & 0xFF).toShort
def output(side: ForgeDirection): Int = _output(side.ordinal())
def output(side: ForgeDirection) = (_output(side.ordinal()) & 0xFF).toShort
def output(side: ForgeDirection, value: Int): Unit = if (value != output(side)) {
_output(side.ordinal()) = (value max 0 min 15).toByte
def output(side: ForgeDirection, value: Short): Unit = if (value != output(side)) {
_output(side.ordinal()) = (value max 0 min 255).toByte
onRedstoneOutputChanged(side)
}
def bundledInput(side: ForgeDirection, color: Int) = (_bundledInput(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(side)
}
@ -48,10 +78,19 @@ trait Redstone extends tileentity.Environment with Persistable {
if (_shouldUpdateInput) {
_shouldUpdateInput = false
for (side <- ForgeDirection.VALID_DIRECTIONS) {
val oldInput = _input(side.ordinal())
val newInput = computeInput(side)
_input(side.ordinal()) = newInput.toByte
if (oldInput >= 0 && _input(side.ordinal()) != oldInput) {
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)
}
}
@ -63,17 +102,29 @@ trait Redstone extends tileentity.Environment with Persistable {
override def load(nbt: NBTTagCompound) = {
super.load(nbt)
if (nbt.hasKey("oc.rs.input")) {
val inputNbt = nbt.getTagList("oc.rs.input")
for (i <- 0 until (_input.length min inputNbt.tagCount)) {
_input(i) = inputNbt.tagAt(i).asInstanceOf[NBTTagByte].data
val inputNbt = nbt.getTagList("oc.rs.input")
for (i <- 0 until (_input.length min inputNbt.tagCount)) {
_input(i) = inputNbt.tagAt(i).asInstanceOf[NBTTagByte].data
}
val outputNbt = nbt.getTagList("oc.rs.output")
for (i <- 0 until (_output.length min outputNbt.tagCount)) {
_output(i) = outputNbt.tagAt(i).asInstanceOf[NBTTagByte].data
}
val bundledInputNbt = nbt.getTagList("oc.rs.bundledInput")
for (i <- 0 until (_bundledInput.length min bundledInputNbt.tagCount)) {
val bundleNbt = bundledInputNbt.tagAt(i).asInstanceOf[NBTTagList]
for (j <- 0 until (_bundledInput(i).length min bundleNbt.tagCount())) {
_bundledInput(i)(j) = bundleNbt.tagAt(j).asInstanceOf[NBTTagByte].data
}
}
if (nbt.hasKey("oc.rs.output")) {
val outputNbt = nbt.getTagList("oc.rs.output")
for (i <- 0 until (_output.length min outputNbt.tagCount)) {
_output(i) = outputNbt.tagAt(i).asInstanceOf[NBTTagByte].data
val bundledOutputNbt = nbt.getTagList("oc.rs.bundledOutput")
for (i <- 0 until (_bundledOutput.length min bundledOutputNbt.tagCount)) {
val bundleNbt = bundledOutputNbt.tagAt(i).asInstanceOf[NBTTagList]
for (j <- 0 until (_bundledOutput(i).length min bundleNbt.tagCount())) {
_bundledOutput(i)(j) = bundleNbt.tagAt(j).asInstanceOf[NBTTagByte].data
}
}
}
@ -92,13 +143,55 @@ trait Redstone extends tileentity.Environment with Persistable {
outputNbt.appendTag(new NBTTagByte(null, _output(i)))
}
nbt.setTag("oc.rs.output", outputNbt)
val bundledInputNbt = new NBTTagList()
for (i <- 0 until _bundledInput.length) {
val bundleNbt = new NBTTagList()
for (j <- 0 until _bundledInput(i).length) {
bundleNbt.appendTag(new NBTTagByte(null, _bundledInput(i)(j)))
}
bundledInputNbt.appendTag(bundleNbt)
}
nbt.setTag("oc.rs.bundledInput", bundledInputNbt)
val bundledOutputNbt = new NBTTagList()
for (i <- 0 until _bundledOutput.length) {
val bundleNbt = new NBTTagList()
for (j <- 0 until _bundledOutput(i).length) {
bundleNbt.appendTag(new NBTTagByte(null, _bundledOutput(i)(j)))
}
bundledOutputNbt.appendTag(bundleNbt)
}
nbt.setTag("oc.rs.bundledOutput", bundledOutputNbt)
}
// ----------------------------------------------------------------------- //
protected def computeInput(side: ForgeDirection): Int
protected def computeBundledInput(side: ForgeDirection): Array[Byte]
protected def onRedstoneInputChanged(side: ForgeDirection) {}
protected def onRedstoneOutputChanged(side: ForgeDirection) {}
// ----------------------------------------------------------------------- //
@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(toDirection)
@Optional.Method(modid = "RedLogic")
def onBundledInputChanged() = checkRedstoneInputChanged()
@Optional.Method(modid = "RedLogic")
def getEmittedSignalStrength(blockFace: Int, toDirection: Int): Short = _output(toDirection)
@Optional.Method(modid = "RedLogic")
def onRedstoneInputChanged() = checkRedstoneInputChanged()
}

View File

@ -1,7 +1,8 @@
package li.cil.oc.server.component
import cpw.mods.fml.common.Optional
import li.cil.oc.api
import li.cil.oc.api.network.{LuaCallback, Context, Arguments, Visibility}
import li.cil.oc.api.network._
import net.minecraftforge.common.ForgeDirection
class RedstoneCard extends ManagedComponent {
@ -11,7 +12,7 @@ class RedstoneCard extends ManagedComponent {
@LuaCallback(value = "getInput", direct = true)
def getInput(context: Context, args: Arguments): Array[AnyRef] = {
val side = args.checkInteger(0)
val side = checkSide(args, 0)
node.network.node(context.address).host match {
case redstone: Redstone =>
result(redstone.input(ForgeDirection.getOrientation(side)))
@ -21,7 +22,7 @@ class RedstoneCard extends ManagedComponent {
@LuaCallback(value = "getOutput", direct = true)
def getOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = args.checkInteger(0)
val side = checkSide(args, 0)
node.network.node(context.address).host match {
case redstone: Redstone =>
result(redstone.output(ForgeDirection.getOrientation(side)))
@ -31,13 +32,67 @@ class RedstoneCard extends ManagedComponent {
@LuaCallback("setOutput")
def setOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = args.checkInteger(0)
val value = args.checkInteger(1)
val side = checkSide(args, 0)
val value = args.checkInteger(1) max 0 min 15
node.network.node(context.address).host match {
case redstone: Redstone =>
redstone.output(ForgeDirection.getOrientation(side), value)
redstone.output(ForgeDirection.getOrientation(side), value.toShort)
result(redstone.output(ForgeDirection.getOrientation(side)))
case _ => result(false)
}
}
@LuaCallback(value = "getBundledInput", direct = true)
@Optional.Method(modid = "RedLogic")
def getBundledInput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0)
val color = checkColor(args, 1)
node.network.node(context.address).host match {
case redstone: Redstone =>
result(redstone.bundledInput(ForgeDirection.getOrientation(side), color))
case _ => result(0)
}
}
@LuaCallback(value = "getBundledOutput", direct = true)
@Optional.Method(modid = "RedLogic")
def getBundledOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0)
val color = checkColor(args, 1)
node.network.node(context.address).host match {
case redstone: Redstone =>
result(redstone.bundledOutput(ForgeDirection.getOrientation(side), color))
case _ => result(false)
}
}
@LuaCallback("setBundledOutput")
@Optional.Method(modid = "RedLogic")
def setBundledOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0)
val color = checkColor(args, 1)
val value = args.checkInteger(2) max 0 min 255
node.network.node(context.address).host match {
case redstone: Redstone =>
redstone.output(ForgeDirection.getOrientation(side), value.toShort)
result(redstone.bundledOutput(ForgeDirection.getOrientation(side), color, value.toShort))
case _ => result(false)
}
}
// ----------------------------------------------------------------------- //
private def checkSide(args: Arguments, index: Int): Int = {
val side = args.checkInteger(index)
if (side < 0 || side > 5)
throw new IllegalArgumentException("invalid side")
side
}
private def checkColor(args: Arguments, index: Int): Int = {
val color = args.checkInteger(index)
if (color < 0 || color > 15)
throw new IllegalArgumentException("invalid color")
color
}
}

View File

@ -202,6 +202,7 @@ object Component {
def isInteger(index: Int) =
index >= 0 && index < count && (args(index) match {
case value: java.lang.Integer => true
case value: java.lang.Double => true
case _ => false
})

View File

@ -0,0 +1,23 @@
package mods.immibis.redlogic.api.wiring;
/**
* Implemented by entities that can emit bundled cable signals.
*/
public interface IBundledEmitter {
/**
* Returns the current emitted bundled cable strength for each colour.
* The bytes are treated as having unsigned values from 0 to 255 - when extracting
* a value from the array, you need to convert it (value & 255).
*
* May return null, which is equivalent to returning an array with all values 0.
*
* Array indices are the same as the corresponding wool damage values.
*
* blockFace and toDirection are the same as the values passed to IRedstoneEmitter and IConnectable.
* blockFace can be -1 for freestanding wire connections.
*
* The return value will be used immediately, so the returned array may be overwritten
* by the next call to getBundledCableStrength.
*/
public byte[] getBundledCableStrength(int blockFace, int toDirection);
}

View File

@ -0,0 +1,8 @@
package mods.immibis.redlogic.api.wiring;
/**
* Implemented by tile entities that need to be notified when a connected bundled cable changes state.
*/
public interface IBundledUpdatable {
public void onBundledInputChanged();
}

View File

@ -0,0 +1,47 @@
package mods.immibis.redlogic.api.wiring;
/**
* Interface implemented by tile entities which can connect to wires in specific ways.
*
* Note: Although wires implement IConnectable, do not use IConnectable to determine if a wire
* is connected to you, as IConnectable only exposes possible connections, and there are reasons
* for wires to not connect (e.g. if there is a microblock in the way).
* Use {@link IWire#wireConnectsInDirection(int, int)} to determine the actual connections of a wire.
*/
public interface IConnectable {
/**
* Called to check whether a wire connects to this block.
* @param wire The wire being checked.
* @param blockFace The face the wire is on in the block containing it.
* -1 when checking for jacketed wire connections.
* @param fromDirection The direction the wire block is in, relative to this block.
* @return True to allow the wire connection.
*/
public boolean connects(IWire wire, int blockFace, int fromDirection);
/**
* Called to check whether a wire connects to this block from around a corner (actually an edge)
*
* Example:
*
* <pre>
* A#
* B
* </pre>
* In this situation, where A is the wire, # is a solid block and B is this block, X is right and Y is down,
* blockFace is -Y (up) and fromDirection is -X (left).
*
* Note this is different from:
* <pre>
* A
* #B
* </pre>
* where blockFace is -X and fromDirection is -Y.
*
* @param wire The wire being checked.
* @param blockFace The face of *this block* the edge is adjacent to.
* @param fromDirection The side the edge is on within that face.
* @return True to allow the wire connection.
*/
public boolean connectsAroundCorner(IWire wire, int blockFace, int fromDirection);
}

View File

@ -0,0 +1,14 @@
package mods.immibis.redlogic.api.wiring;
/**
* Implemented by tile entities that emit a full-strength red alloy signal.
*/
public interface IRedstoneEmitter {
/**
* toDirection and blockFace are the same as the ones passed to IConnectable.
* blockFace is -1 for freestanding wire connections.
*
* @return Signal strength from 0 to 255.
*/
public short getEmittedSignalStrength(int blockFace, int toDirection);
}

View File

@ -0,0 +1,11 @@
package mods.immibis.redlogic.api.wiring;
/**
* Interface implemented by tile entities that receive redstone updates.
* Insulated wire does not cause block updates when it changes state.
* Tile entities that connect to insulated wire must implement this if they need notification of state changes.
* Bare red alloy wire causes block updates and does not call onRedstoneInputChanged.
*/
public interface IRedstoneUpdatable {
public void onRedstoneInputChanged();
}

View File

@ -0,0 +1,18 @@
package mods.immibis.redlogic.api.wiring;
/**
* Marker interface for wire tile entities.
* Other mods should not implement this, nor any sub-interface.
*/
public interface IWire {
/**
* blockFace can be -1 to check freestanding wire connections.
* @see mods.immibis.redlogic.api.wiring.IConnectable
*/
public boolean wireConnectsInDirection(int blockFace, int direction);
/**
* Same as wireConnectsInDirection, but only checks for connections around an external corner.
*/
public boolean wireConnectsInDirectionAroundCorner(int blockFace, int direction);
}