blob: 162851a050e4b6126e73e86c21e3737b01675556 [file] [log] [blame] [raw]
package li.cil.oc.server.component
import li.cil.oc.api.network._
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.{Settings, api}
import net.minecraft.nbt.{NBTTagInt, NBTTagCompound}
import scala.collection.convert.WrapAsScala._
import scala.collection.mutable
class NetworkCard extends ManagedComponent {
val node = api.Network.newNode(this, Visibility.Network).
withComponent("modem", Visibility.Neighbors).
create()
protected val openPorts = mutable.Set.empty[Int]
// ----------------------------------------------------------------------- //
@LuaCallback("open")
def open(context: Context, args: Arguments): Array[AnyRef] = {
val port = checkPort(args.checkInteger(0))
result(openPorts.add(port))
}
@LuaCallback("close")
def close(context: Context, args: Arguments): Array[AnyRef] = {
if (args.count == 0) {
openPorts.clear()
result(true)
}
else {
val port = checkPort(args.checkInteger(0))
result(openPorts.remove(port))
}
}
@LuaCallback(value = "isOpen", direct = true)
def isOpen(context: Context, args: Arguments): Array[AnyRef] = {
val port = checkPort(args.checkInteger(0))
result(openPorts.contains(port))
}
@LuaCallback(value = "isWireless", direct = true)
def isWireless(context: Context, args: Arguments): Array[AnyRef] = result(false)
@LuaCallback("send")
def send(context: Context, args: Arguments): Array[AnyRef] = {
val address = args.checkString(0)
val port = checkPort(args.checkInteger(1))
checkPacketSize(args.drop(2))
node.sendToAddress(address, "network.message", Seq(Int.box(port)) ++ args.drop(2): _*)
result(true)
}
@LuaCallback("broadcast")
def broadcast(context: Context, args: Arguments): Array[AnyRef] = {
val port = checkPort(args.checkInteger(0))
checkPacketSize(args.drop(1))
node.sendToReachable("network.message", Seq(Int.box(port)) ++ args.drop(1): _*)
result(true)
}
// ----------------------------------------------------------------------- //
override def onDisconnect(node: Node) {
super.onDisconnect(node)
if (node == this.node) {
openPorts.clear()
}
}
override def onMessage(message: Message) = {
super.onMessage(message)
if ((message.name == "computer.stopped" || message.name == "computer.started") && node.isNeighborOf(message.source))
openPorts.clear()
if (message.name == "network.message") message.data match {
case Array(port: Integer, args@_*) if openPorts.contains(port) =>
node.sendToReachable("computer.signal", Seq("modem_message", message.source.address, Int.box(port)) ++ args: _*)
case _ =>
}
}
// ----------------------------------------------------------------------- //
override def load(nbt: NBTTagCompound) {
super.load(nbt)
assert(openPorts.isEmpty)
openPorts ++= nbt.getTagList("openPorts").iterator[NBTTagInt].map(_.data)
}
override def save(nbt: NBTTagCompound) {
super.save(nbt)
nbt.setNewTagList("openPorts", openPorts)
}
// ----------------------------------------------------------------------- //
protected def checkPort(port: Int) =
if (port < 1 || port > 0xFFFF) throw new IllegalArgumentException("invalid port number")
else port
protected def checkPacketSize(data: Iterable[AnyRef]) {
val size = data.foldLeft(0)((acc, arg) => {
acc + (arg match {
case null | Unit | None => 4
case _: java.lang.Boolean => 4
case _: java.lang.Double => 8
case value: java.lang.String => value.length
case value: Array[Byte] => value.length
})
})
if (size > Settings.get.maxNetworkPacketSize) {
throw new IllegalArgumentException("packet too big (max " + Settings.get.maxNetworkPacketSize + ")")
}
}
}