update method in node; adapter is a computercraft peripheral now (untested obviously since cc isn't 1.64 yet); some more access options for network cards

This commit is contained in:
Florian Nücke 2013-10-13 12:59:43 +02:00
parent 2dadc4b3b6
commit c3ae449242
5 changed files with 116 additions and 5 deletions

View File

@ -1,6 +1,12 @@
driver.network = {} driver.network = {}
function driver.network.open(card, port) function driver.network.open(card, port)
checkArg(1, card, "string")
checkArg(2, port, "number")
return send(card, "network.open=", port)
end
function driver.network.isOpen(card, port)
checkArg(1, card, "string") checkArg(1, card, "string")
checkArg(2, port, "number") checkArg(2, port, "number")
return send(card, "network.open", port) return send(card, "network.open", port)
@ -8,8 +14,12 @@ end
function driver.network.close(card, port) function driver.network.close(card, port)
checkArg(1, card, "string") checkArg(1, card, "string")
if port then
checkArg(2, port, "number") checkArg(2, port, "number")
return send(card, "network.close", port) return send(card, "network.close", port)
else
return send(card, "network.close")
end
end end
function driver.network.send(card, target, port, ...) function driver.network.send(card, target, port, ...)

View File

@ -114,6 +114,20 @@ trait Node extends Persistable {
None None
} }
/**
* This is called once per tick, if the node is owned either by a computer
* (meaning it's an item component installed in a computer) or is managed by
* an adapter (meaning it was acquired via a block driver for a block whose
* tile entity is not a node).
* <p/>
* For nodes implemented directly in tile entities you should just call this
* from the tile entity's `updateEntity` function yourself, as necessary.
* <p/>
* When implementing an "inventory", i.e. something that holds item
* components, be sure to call `update` for the installed components' nodes.
*/
def update() {}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
/** /**

View File

@ -1,17 +1,41 @@
package li.cil.oc.common.tileentity package li.cil.oc.common.tileentity
import dan200.computer.api.{ILuaContext, IComputerAccess, IPeripheral}
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.network.{Visibility, Node} import li.cil.oc.api.network.{Message, Visibility, Node}
import li.cil.oc.server.driver import li.cil.oc.server.driver
import net.minecraftforge.common.ForgeDirection import net.minecraftforge.common.ForgeDirection
import scala.collection.mutable
class Adapter extends Rotatable with Node { class Adapter extends Rotatable with Node with IPeripheral {
val name = "adapter" val name = "adapter"
val visibility = Visibility.None val visibility = Visibility.None
private val blocks = Array.fill[Option[(Node, api.driver.Block)]](6)(None) private val blocks = Array.fill[Option[(Node, api.driver.Block)]](6)(None)
private val computers = mutable.ArrayBuffer.empty[IComputerAccess]
private val openPorts = mutable.Map.empty[IComputerAccess, mutable.Set[Int]]
override def updateEntity() {
for (block <- blocks) block match {
case Some((node, driver)) => node.update()
case _ => // Empty.
}
}
override def receive(message: Message) = super.receive(message) orElse {
message.data match {
case Array(port: Int, answerPort: Double, data: AnyRef) if message.name == "network.message" =>
for ((computer, ports) <- openPorts) if (ports.contains(port)) {
computer.queueEvent("modem_message", Array(computer.getAttachmentName, Int.box(port), Int.box(answerPort.toInt), data))
}
case _ => // Ignore.
}
None
}
override protected def onConnect() { override protected def onConnect() {
super.onConnect() super.onConnect()
neighborChanged() neighborChanged()
@ -46,4 +70,55 @@ class Adapter extends Rotatable with Node {
} }
} }
} }
// ----------------------------------------------------------------------- //
override def getType = "oc_adapter"
override def attach(computer: IComputerAccess) {
computers += computer
openPorts += computer -> mutable.Set.empty
}
override def detach(computer: IComputerAccess) {
computers -= computer
openPorts -= computer
}
override def getMethodNames = Array("open", "isOpen", "close", "closeAll", "transmit", "isWireless")
override def callMethod(computer: IComputerAccess, context: ILuaContext, method: Int, arguments: Array[AnyRef]) = getMethodNames()(method) match {
case "open" =>
val port = parsePort(arguments, 0)
if (openPorts(computer).size >= 128)
throw new IllegalArgumentException("too many open channels")
Array(Boolean.box(openPorts(computer).add(port)))
case "isOpen" =>
val port = parsePort(arguments, 0)
Array(Boolean.box(openPorts(computer).contains(port)))
case "close" =>
val port = parsePort(arguments, 0)
Array(Boolean.box(openPorts(computer).remove(port)))
case "closeAll" =>
openPorts(computer).clear()
null
case "transmit" =>
val sendPort = parsePort(arguments, 0)
val answerPort = parsePort(arguments, 1)
network.foreach(_.sendToVisible(this, "network.message", sendPort, answerPort, arguments(2)))
null
case "isWireless" => Array(Boolean.box(false))
case _ => null
}
override def canAttachToSide(side: Int) = true
private def parsePort(args: Array[AnyRef], index: Int) = {
if (args.length < index - 1 || !args(index).isInstanceOf[Int])
throw new IllegalArgumentException("bad argument #%d (number expected)".format(index))
val port = args(index).asInstanceOf[Int]
if (port < 1 || port > 0xFFFF)
throw new IllegalArgumentException("bad argument #%d (number in [1, 65535] expected)".format(index))
port
}
} }

View File

@ -60,11 +60,17 @@ class Computer(isClient: Boolean) extends Rotatable with component.Computer.Envi
override def updateEntity() = if (!worldObj.isRemote) { override def updateEntity() = if (!worldObj.isRemote) {
computer.update() computer.update()
if (hasChanged.get) if (hasChanged.get)
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this) worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
if (isRunning != computer.isRunning) if (isRunning != computer.isRunning)
ServerPacketSender.sendComputerState(this, computer.isRunning) ServerPacketSender.sendComputerState(this, computer.isRunning)
isRunning = computer.isRunning isRunning = computer.isRunning
for (component <- itemComponents) component match {
case Some(node) => node.update()
case _ => // Empty.
}
} }
override def validate() = { override def validate() = {

View File

@ -20,12 +20,18 @@ class NetworkCard extends Node {
openPorts.clear() openPorts.clear()
None None
case Array(port: Double) if message.name == "network.open" => case Array(port: Double) if message.name == "network.open=" =>
if (isPortValid(port.toInt)) result(openPorts.add(port.toInt)) if (isPortValid(port.toInt)) result(openPorts.add(port.toInt))
else result(Unit, "invalid port number") else result(Unit, "invalid port number")
case Array(port: Double) if message.name == "network.open" =>
if (isPortValid(port.toInt)) result(openPorts.contains(port.toInt))
else result(Unit, "invalid port number")
case Array(port: Double) if message.name == "network.close" => case Array(port: Double) if message.name == "network.close" =>
if (isPortValid(port.toInt)) result(openPorts.remove(port.toInt)) if (isPortValid(port.toInt)) result(openPorts.remove(port.toInt))
else result(Unit, "invalid port number") else result(Unit, "invalid port number")
case Array() if message.name == "network.close" =>
openPorts.clear()
result(true)
case Array(address: Array[Byte], port: Double, args@_*) if message.name == "network.send" => case Array(address: Array[Byte], port: Double, args@_*) if message.name == "network.send" =>
if (isPortValid(port.toInt)) if (isPortValid(port.toInt))
network.get.sendToAddress(this, new String(address, "UTF-8"), "network.message", Seq(port.toInt) ++ args: _*) network.get.sendToAddress(this, new String(address, "UTF-8"), "network.message", Seq(port.toInt) ++ args: _*)