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 = {}
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(2, port, "number")
return send(card, "network.open", port)
@ -8,8 +14,12 @@ end
function driver.network.close(card, port)
checkArg(1, card, "string")
checkArg(2, port, "number")
return send(card, "network.close", port)
if port then
checkArg(2, port, "number")
return send(card, "network.close", port)
else
return send(card, "network.close")
end
end
function driver.network.send(card, target, port, ...)

View File

@ -114,6 +114,20 @@ trait Node extends Persistable {
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
import dan200.computer.api.{ILuaContext, IComputerAccess, IPeripheral}
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 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 visibility = Visibility.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() {
super.onConnect()
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) {
computer.update()
if (hasChanged.get)
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
if (isRunning != computer.isRunning)
ServerPacketSender.sendComputerState(this, computer.isRunning)
isRunning = computer.isRunning
for (component <- itemComponents) component match {
case Some(node) => node.update()
case _ => // Empty.
}
}
override def validate() = {

View File

@ -20,12 +20,18 @@ class NetworkCard extends Node {
openPorts.clear()
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))
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" =>
if (isPortValid(port.toInt)) result(openPorts.remove(port.toInt))
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" =>
if (isPortValid(port.toInt))
network.get.sendToAddress(this, new String(address, "UTF-8"), "network.message", Seq(port.toInt) ++ args: _*)