removed mention of udp from internet cards, those were a lie; text.serialize now line breaks and indents in pretty print mode; tostringing tables with metatable that has a __tostring method in text.serialize with pretty print; corrected comment in config; explicitly putting textures and localizations into the public domain in the license info; deleting empty file system folders from disk on save to reduce clutter in <saves>/opencomputers dir; doc field of callback annotations can now be read in computers, methods in proxies are tostring'ed to the docstring; returning false from component.modem.close() when no ports are open, now

This commit is contained in:
Florian Nücke 2014-02-11 23:35:46 +01:00
parent f48d3d304e
commit c4da02b65c
22 changed files with 146 additions and 69 deletions

View File

@ -46,15 +46,15 @@ class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with ISidedI
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback @Callback(doc = """function():boolean -- Starts the robot. Returns true if the state changed.""")
def start(context: Context, args: Arguments): Array[AnyRef] = def start(context: Context, args: Arguments): Array[AnyRef] =
result(!computer.isPaused && computer.start()) result(!computer.isPaused && computer.start())
@Callback @Callback(doc = """function():boolean -- Stops the robot. Returns true if the state changed.""")
def stop(context: Context, args: Arguments): Array[AnyRef] = def stop(context: Context, args: Arguments): Array[AnyRef] =
result(computer.stop()) result(computer.stop())
@Callback(direct = true) @Callback(direct = true, doc = """function():boolean -- Returns whether the robot is running.""")
def isRunning(context: Context, args: Arguments): Array[AnyRef] = def isRunning(context: Context, args: Arguments): Array[AnyRef] =
result(computer.isRunning) result(computer.isRunning)

View File

@ -25,10 +25,10 @@ class Screen(var tier: Int) extends Buffer with SidedEnvironment with Rotatable
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override protected val _buffer = new component.Buffer(this) { override protected val _buffer = new component.Buffer(this) {
@Callback @Callback(doc = """function():boolean -- Returns whether the screen is currently on.""")
def isOn(computer: Context, args: Arguments): Array[AnyRef] = result(origin.isOn) def isOn(computer: Context, args: Arguments): Array[AnyRef] = result(origin.isOn)
@Callback @Callback(doc = """function():boolean -- Turns off the screen. Returns true if it was on.""")
def turnOn(computer: Context, args: Arguments): Array[AnyRef] = { def turnOn(computer: Context, args: Arguments): Array[AnyRef] = {
if (!origin.isOn) { if (!origin.isOn) {
origin.turnOn() origin.turnOn()
@ -37,7 +37,7 @@ class Screen(var tier: Int) extends Buffer with SidedEnvironment with Rotatable
else result(false, origin.isOn) else result(false, origin.isOn)
} }
@Callback @Callback(doc = """function():boolean -- Turns the screen on. Returns true if it was off.""")
def turnOff(computer: Context, args: Arguments): Array[AnyRef] = { def turnOff(computer: Context, args: Arguments): Array[AnyRef] = {
if (origin.isOn) { if (origin.isOn) {
origin.turnOff() origin.turnOff()

View File

@ -54,25 +54,25 @@ class AbstractBus(val device: IBusDevice) extends ManagedComponent with IBusDriv
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback @Callback(doc = """function():boolean -- Whether the local bus interface is enabled.""")
def getEnabled(context: Context, args: Arguments): Array[AnyRef] = result(isEnabled) def getEnabled(context: Context, args: Arguments): Array[AnyRef] = result(isEnabled)
@Callback @Callback(doc = """function(enabled:boolean):boolean -- Sets whether the local bus interface should be enabled.""")
def setEnabled(context: Context, args: Arguments): Array[AnyRef] = { def setEnabled(context: Context, args: Arguments): Array[AnyRef] = {
isEnabled = args.checkBoolean(0) isEnabled = args.checkBoolean(0)
result(isEnabled) result(isEnabled)
} }
@Callback @Callback(doc = """function():number -- Get the local interface address.""")
def getAddress(context: Context, args: Arguments): Array[AnyRef] = result(address) def getAddress(context: Context, args: Arguments): Array[AnyRef] = result(address)
@Callback @Callback(doc = """function(address:number):number -- Sets the local interface address.""")
def setAddress(context: Context, args: Arguments): Array[AnyRef] = { def setAddress(context: Context, args: Arguments): Array[AnyRef] = {
address = args.checkInteger(0) & 0xFFFF address = args.checkInteger(0) & 0xFFFF
result(address) result(address)
} }
@Callback @Callback(doc = """function(address:number, data:table):boolean -- Sends data across the abstract bus.""")
def send(context: Context, args: Arguments): Array[AnyRef] = { def send(context: Context, args: Arguments): Array[AnyRef] = {
val target = args.checkInteger(0) & 0xFFFF val target = args.checkInteger(0) & 0xFFFF
val data = args.checkTable(1) val data = args.checkTable(1)
@ -84,7 +84,7 @@ class AbstractBus(val device: IBusDevice) extends ManagedComponent with IBusDriv
else result(false, "not enough energy") else result(false, "not enough energy")
} }
@Callback(direct = true) @Callback(direct = true, doc = """function():number -- The maximum packet size that can be sent over the bus.""")
def maxPacketSize(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.maxNetworkPacketSize) def maxPacketSize(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.maxNetworkPacketSize)
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //

View File

@ -5,21 +5,21 @@ import li.cil.oc.common.tileentity.BundledRedstoneAware
class BundledRedstone(override val owner: BundledRedstoneAware) extends Redstone(owner) { class BundledRedstone(override val owner: BundledRedstoneAware) extends Redstone(owner) {
@Callback(direct = true) @Callback(direct = true, doc = """function(side:number, color:number):number -- Get the bundled redstone input on the specified side and with the specified color.""")
def getBundledInput(context: Context, args: Arguments): Array[AnyRef] = { def getBundledInput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) val side = checkSide(args, 0)
val color = checkColor(args, 1) val color = checkColor(args, 1)
result(owner.bundledInput(side, color)) result(owner.bundledInput(side, color))
} }
@Callback(direct = true) @Callback(direct = true, doc = """function(side:number, color:number):number -- Get the bundled redstone output on the specified side and with the specified color.""")
def getBundledOutput(context: Context, args: Arguments): Array[AnyRef] = { def getBundledOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) val side = checkSide(args, 0)
val color = checkColor(args, 1) val color = checkColor(args, 1)
result(owner.bundledOutput(side, color)) result(owner.bundledOutput(side, color))
} }
@Callback @Callback(doc = """function(side:number, color:number, value:number):number -- Set the bundled redstone output on the specified side and with the specified color.""")
def setBundledOutput(context: Context, args: Arguments): Array[AnyRef] = { def setBundledOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) val side = checkSide(args, 0)
val color = checkColor(args, 1) val color = checkColor(args, 1)

View File

@ -44,10 +44,10 @@ class InternetCard extends ManagedComponent {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback(direct = true) @Callback(direct = true, doc = """function():boolean -- Returns whether HTTP requests can be made (config setting).""")
def isHttpEnabled(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.httpEnabled) def isHttpEnabled(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.httpEnabled)
@Callback @Callback(doc = """function():boolean -- Starts an HTTP request. If this returns true, further results will be pushed using `http_response` signals.""")
def request(context: Context, args: Arguments): Array[AnyRef] = { def request(context: Context, args: Arguments): Array[AnyRef] = {
if (owner.isEmpty || context.node.address != owner.get.node.address) { if (owner.isEmpty || context.node.address != owner.get.node.address) {
throw new IllegalArgumentException("can only be used by the owning computer") throw new IllegalArgumentException("can only be used by the owning computer")
@ -130,10 +130,10 @@ class InternetCard extends ManagedComponent {
}) })
} }
@Callback(direct = true) @Callback(direct = true, doc = """function():boolean -- Returns whether TCP connections can be made (config setting).""")
def isTcpEnabled(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.httpEnabled) def isTcpEnabled(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.httpEnabled)
@Callback @Callback(doc = """function(address:string[, port:number]):number -- Opens a new TCP connection. Returns the handle of the connection.""")
def connect(context: Context, args: Arguments): Array[AnyRef] = { def connect(context: Context, args: Arguments): Array[AnyRef] = {
val address = args.checkString(0) val address = args.checkString(0)
val port = if (args.count > 1) args.checkInteger(1) else -1 val port = if (args.count > 1) args.checkInteger(1) else -1
@ -151,7 +151,7 @@ class InternetCard extends ManagedComponent {
result(handle) result(handle)
} }
@Callback @Callback(doc = """function(handle:number) -- Closes an open socket stream.""")
def close(context: Context, args: Arguments): Array[AnyRef] = { def close(context: Context, args: Arguments): Array[AnyRef] = {
val handle = args.checkInteger(0) val handle = args.checkInteger(0)
connections.remove(handle) match { connections.remove(handle) match {
@ -161,7 +161,7 @@ class InternetCard extends ManagedComponent {
null null
} }
@Callback @Callback(doc = """function(handle:number, data:string):number -- Tries to write data to the socket stream. Returns the number of bytes written.""")
def write(context: Context, args: Arguments): Array[AnyRef] = { def write(context: Context, args: Arguments): Array[AnyRef] = {
val handle = args.checkInteger(0) val handle = args.checkInteger(0)
val value = args.checkByteArray(1) val value = args.checkByteArray(1)
@ -173,7 +173,7 @@ class InternetCard extends ManagedComponent {
} }
} }
@Callback @Callback(doc = """function(handle:number, n:number):string -- Tries to read data from the socket stream. Returns the read byte array.""")
def read(context: Context, args: Arguments): Array[AnyRef] = { def read(context: Context, args: Arguments): Array[AnyRef] = {
val handle = args.checkInteger(0) val handle = args.checkInteger(0)
val n = math.min(Settings.get.maxReadBuffer, math.max(0, args.checkInteger(1))) val n = math.min(Settings.get.maxReadBuffer, math.max(0, args.checkInteger(1)))

View File

@ -17,17 +17,18 @@ class NetworkCard extends ManagedComponent {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback @Callback(doc = """function(port:number):boolean -- Opens the specified port. Returns true if the port was opened.""")
def open(context: Context, args: Arguments): Array[AnyRef] = { def open(context: Context, args: Arguments): Array[AnyRef] = {
val port = checkPort(args.checkInteger(0)) val port = checkPort(args.checkInteger(0))
result(openPorts.add(port)) result(openPorts.add(port))
} }
@Callback @Callback(doc = """function([port:number]):boolean -- Closes the specified port (default: all ports). Returns true if ports were closed.""")
def close(context: Context, args: Arguments): Array[AnyRef] = { def close(context: Context, args: Arguments): Array[AnyRef] = {
if (args.count == 0) { if (args.count == 0) {
val closed = openPorts.size > 0
openPorts.clear() openPorts.clear()
result(true) result(closed)
} }
else { else {
val port = checkPort(args.checkInteger(0)) val port = checkPort(args.checkInteger(0))
@ -35,16 +36,16 @@ class NetworkCard extends ManagedComponent {
} }
} }
@Callback(direct = true) @Callback(direct = true, doc = """function(port:number):boolean -- Whether the specified port is open.""")
def isOpen(context: Context, args: Arguments): Array[AnyRef] = { def isOpen(context: Context, args: Arguments): Array[AnyRef] = {
val port = checkPort(args.checkInteger(0)) val port = checkPort(args.checkInteger(0))
result(openPorts.contains(port)) result(openPorts.contains(port))
} }
@Callback(direct = true) @Callback(direct = true, doc = """function():boolean -- Whether this is a wireless network card.""")
def isWireless(context: Context, args: Arguments): Array[AnyRef] = result(false) def isWireless(context: Context, args: Arguments): Array[AnyRef] = result(false)
@Callback @Callback(doc = """function(address:string, port:number, data...) -- Sends the specified data to the specified target.""")
def send(context: Context, args: Arguments): Array[AnyRef] = { def send(context: Context, args: Arguments): Array[AnyRef] = {
val address = args.checkString(0) val address = args.checkString(0)
val port = checkPort(args.checkInteger(1)) val port = checkPort(args.checkInteger(1))
@ -53,7 +54,7 @@ class NetworkCard extends ManagedComponent {
result(true) result(true)
} }
@Callback @Callback(doc = """function(port:number, data...) -- Broadcasts the specified data on the specified port.""")
def broadcast(context: Context, args: Arguments): Array[AnyRef] = { def broadcast(context: Context, args: Arguments): Array[AnyRef] = {
val port = checkPort(args.checkInteger(0)) val port = checkPort(args.checkInteger(0))
checkPacketSize(args.drop(1)) checkPacketSize(args.drop(1))
@ -61,7 +62,7 @@ class NetworkCard extends ManagedComponent {
result(true) result(true)
} }
@Callback(direct = true) @Callback(direct = true, doc = """function():number -- Gets the maximum packet size (config setting).""")
def maxPacketSize(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.maxNetworkPacketSize) def maxPacketSize(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.maxNetworkPacketSize)
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //

View File

@ -12,19 +12,19 @@ class Redstone(val owner: RedstoneAware) extends ManagedComponent {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback(direct = true) @Callback(direct = true, doc = """function(side:number):number -- Get the redstone input on the specified side.""")
def getInput(context: Context, args: Arguments): Array[AnyRef] = { def getInput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) val side = checkSide(args, 0)
result(owner.input(side)) result(owner.input(side))
} }
@Callback(direct = true) @Callback(direct = true, doc = """function(side:number):number -- Get the redstone output on the specified side.""")
def getOutput(context: Context, args: Arguments): Array[AnyRef] = { def getOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) val side = checkSide(args, 0)
result(owner.output(side)) result(owner.output(side))
} }
@Callback() @Callback(doc = """function(side:number, value:number):number -- Set the redstone output on the specified side.""")
def setOutput(context: Context, args: Arguments): Array[AnyRef] = { def setOutput(context: Context, args: Arguments): Array[AnyRef] = {
val side = checkSide(args, 0) val side = checkSide(args, 0)
val value = args.checkInteger(1) val value = args.checkInteger(1)

View File

@ -17,7 +17,7 @@ class UpgradeCrafting(val owner: MCTileEntity) extends ManagedComponent {
withComponent("crafting"). withComponent("crafting").
create() create()
@Callback @Callback(doc = """function([count:number]):number -- Tries to craft the specified number of items in the top left area of the inventory.""")
def craft(context: RobotContext, args: Arguments): Array[AnyRef] = { def craft(context: RobotContext, args: Arguments): Array[AnyRef] = {
val count = if (args.count > 0) args.checkInteger(0) else Int.MaxValue val count = if (args.count > 0) args.checkInteger(0) else Int.MaxValue
result(CraftingInventory.craft(context, count)) result(CraftingInventory.craft(context, count))

View File

@ -21,7 +21,7 @@ class UpgradeGenerator(val owner: TileEntity) extends ManagedComponent {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback @Callback(doc = """function([count:number]):boolean -- Tries to insert fuel from the selected slot into the generator's queue.""")
def insert(context: RobotContext, args: Arguments): Array[AnyRef] = { def insert(context: RobotContext, args: Arguments): Array[AnyRef] = {
val count = if (args.count > 0) args.checkInteger(0) else 64 val count = if (args.count > 0) args.checkInteger(0) else 64
val player = context.player val player = context.player
@ -48,7 +48,7 @@ class UpgradeGenerator(val owner: TileEntity) extends ManagedComponent {
result(true) result(true)
} }
@Callback @Callback(doc = """function():number -- Get the size of the item stack in the generator's queue.""")
def count(context: Context, args: Arguments): Array[AnyRef] = { def count(context: Context, args: Arguments): Array[AnyRef] = {
inventory match { inventory match {
case Some(stack) => result(stack.stackSize) case Some(stack) => result(stack.stackSize)
@ -56,7 +56,7 @@ class UpgradeGenerator(val owner: TileEntity) extends ManagedComponent {
} }
} }
@Callback @Callback(doc = """function([count:number]):boolean -- Tries to remove items from the generator's queue.""")
def remove(context: RobotContext, args: Arguments): Array[AnyRef] = { def remove(context: RobotContext, args: Arguments): Array[AnyRef] = {
val count = if (args.count > 0) args.checkInteger(0) else Int.MaxValue val count = if (args.count > 0) args.checkInteger(0) else Int.MaxValue
inventory match { inventory match {

View File

@ -11,7 +11,7 @@ class UpgradeNavigation(val owner: TileEntity, val xCenter: Int, val zCenter: In
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback @Callback(doc = """function():number, number, number -- Get the current relative position of the robot.""")
def getPosition(context: Context, args: Arguments): Array[AnyRef] = { def getPosition(context: Context, args: Arguments): Array[AnyRef] = {
val x = owner.xCoord val x = owner.xCoord
val y = owner.yCoord val y = owner.yCoord
@ -25,7 +25,7 @@ class UpgradeNavigation(val owner: TileEntity, val xCenter: Int, val zCenter: In
result(Unit, "out of range") result(Unit, "out of range")
} }
@Callback @Callback(doc = """function():number -- Get the current orientation of the robot.""")
def getFacing(context: Context, args: Arguments): Array[AnyRef] = { def getFacing(context: Context, args: Arguments): Array[AnyRef] = {
owner match { owner match {
case rotatable: Rotatable => result(rotatable.facing.ordinal) case rotatable: Rotatable => result(rotatable.facing.ordinal)
@ -33,7 +33,7 @@ class UpgradeNavigation(val owner: TileEntity, val xCenter: Int, val zCenter: In
} }
} }
@Callback @Callback(doc = """function():number -- Get the operational range of the navigation upgrade.""")
def getRange(context: Context, args: Arguments): Array[AnyRef] = { def getRange(context: Context, args: Arguments): Array[AnyRef] = {
result(size / 2) result(size / 2)
} }

View File

@ -12,7 +12,7 @@ class UpgradeSign(val owner: TileEntity) extends ManagedComponent {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback @Callback(doc = """function():string -- Get the text on the sign in front of the robot.""")
def getValue(context: Context, args: Arguments): Array[AnyRef] = { def getValue(context: Context, args: Arguments): Array[AnyRef] = {
val facing = owner match { val facing = owner match {
case rotatable: Rotatable => rotatable.facing case rotatable: Rotatable => rotatable.facing
@ -24,7 +24,7 @@ class UpgradeSign(val owner: TileEntity) extends ManagedComponent {
} }
} }
@Callback @Callback(doc = """function(value:string):string -- Set the text on the sign in front of the robot.""")
def setValue(context: Context, args: Arguments): Array[AnyRef] = { def setValue(context: Context, args: Arguments): Array[AnyRef] = {
val text = args.checkString(0).lines.padTo(4, "").map(line => if (line.length > 15) line.substring(0, 15) else line) val text = args.checkString(0).lines.padTo(4, "").map(line => if (line.length > 15) line.substring(0, 15) else line)
val facing = owner match { val facing = owner match {

View File

@ -20,10 +20,10 @@ class WirelessNetworkCard(val owner: TileEntity) extends NetworkCard {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback(direct = true) @Callback(direct = true, doc = """function():number -- Get the signal strength (range) used when sending messages.""")
def getStrength(context: Context, args: Arguments): Array[AnyRef] = result(strength) def getStrength(context: Context, args: Arguments): Array[AnyRef] = result(strength)
@Callback @Callback(doc = """function(strength:number):number -- Set the signal strength (range) used when sending messages.""")
def setStrength(context: Context, args: Arguments): Array[AnyRef] = { def setStrength(context: Context, args: Arguments): Array[AnyRef] = {
strength = math.max(args.checkDouble(0), math.min(0, Settings.get.maxWirelessRange)) strength = math.max(args.checkDouble(0), math.min(0, Settings.get.maxWirelessRange))
result(strength) result(strength)

View File

@ -218,7 +218,12 @@ class Machine(val owner: Machine.Owner) extends ManagedComponent with Context wi
counts(method) += 1 counts(method) += 1
} }
component.invoke(method, this, args: _*) component.invoke(method, this, args: _*)
case _ => throw new Exception("no such component") case _ => throw new IllegalArgumentException("no such component")
}
private[component] def doc(address: String, method: String) = Option(node.network.node(address)) match {
case Some(component: server.network.Component) if component.canBeSeenFrom(node) || component == node => component.doc(method)
case _ => throw new IllegalArgumentException("no such component")
} }
private[component] def addUser(name: String) { private[component] def addUser(name: String) {
@ -248,15 +253,15 @@ class Machine(val owner: Machine.Owner) extends ManagedComponent with Context wi
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback @Callback(doc = """function():boolean -- Starts the computer. Returns true if the state changed.""")
def start(context: Context, args: Arguments): Array[AnyRef] = def start(context: Context, args: Arguments): Array[AnyRef] =
result(!isPaused && start()) result(!isPaused && start())
@Callback @Callback(doc = """function():boolean -- Stops the computer. Returns true if the state changed.""")
def stop(context: Context, args: Arguments): Array[AnyRef] = def stop(context: Context, args: Arguments): Array[AnyRef] =
result(stop()) result(stop())
@Callback(direct = true) @Callback(direct = true, doc = """function():boolean -- Returns whether the computer is running.""")
def isRunning(context: Context, args: Arguments): Array[AnyRef] = def isRunning(context: Context, args: Arguments): Array[AnyRef] =
result(isRunning) result(isRunning)

View File

@ -1,5 +1,6 @@
package li.cil.oc.server.component.machine package li.cil.oc.server.component.machine
import com.google.common.base.Strings
import com.naef.jnlua._ import com.naef.jnlua._
import java.io.{IOException, FileNotFoundException} import java.io.{IOException, FileNotFoundException}
import java.util.logging.Level import java.util.logging.Level
@ -528,6 +529,29 @@ class NativeLuaArchitecture(val machine: Machine) extends Architecture {
}) })
lua.setField(-2, "invoke") lua.setField(-2, "invoke")
lua.pushScalaFunction(lua => {
val address = lua.checkString(1)
val method = lua.checkString(2)
try {
val doc = machine.doc(address, method)
if (Strings.isNullOrEmpty(doc))
lua.pushNil()
else
lua.pushString(doc)
1
} catch {
case e: NoSuchMethodException =>
lua.pushNil()
lua.pushString("no such method")
2
case t: Throwable =>
lua.pushNil()
lua.pushString(if (t.getMessage != null) t.getMessage else t.toString)
2
}
})
lua.setField(-2, "doc")
lua.setGlobal("component") lua.setGlobal("component")
initPerms() initPerms()

View File

@ -55,7 +55,10 @@ trait Buffered extends OutputStreamFileSystem {
} }
setLastModified(path, directory.lastModified()) setLastModified(path, directory.lastModified())
} }
recurse("", fileRoot) if (fileRoot.list() == null || fileRoot.list().length == 0) {
fileRoot.delete()
}
else recurse("", fileRoot)
super.load(nbt) super.load(nbt)
} }
@ -94,6 +97,9 @@ trait Buffered extends OutputStreamFileSystem {
} }
directory.setLastModified(lastModified(path)) directory.setLastModified(lastModified(path))
} }
recurse("") if (list("") == null || list("").length == 0) {
fileRoot.delete()
}
else recurse("")
} }
} }

View File

@ -99,6 +99,11 @@ trait Component extends network.Component with Node {
def methods = callbacks.keySet def methods = callbacks.keySet
def doc(name: String) = callbacks.get(name) match {
case Some(callback) => callback.doc
case _ => throw new NoSuchMethodException()
}
def invoke(method: String, context: Context, arguments: AnyRef*) = def invoke(method: String, context: Context, arguments: AnyRef*) =
callbacks.get(method) match { callbacks.get(method) match {
case Some(callback) => hosts(method) match { case Some(callback) => hosts(method) match {
@ -173,7 +178,7 @@ object Component {
val a = m.getAnnotation[network.Callback](classOf[network.Callback]) val a = m.getAnnotation[network.Callback](classOf[network.Callback])
val name = if (a.value != null && a.value.trim != "") a.value else m.getName val name = if (a.value != null && a.value.trim != "") a.value else m.getName
if (!callbacks.contains(name)) { if (!callbacks.contains(name)) {
callbacks += name -> new ComponentCallback(m, a.direct, a.limit) callbacks += name -> new ComponentCallback(m, a.direct, a.limit, a.doc)
} }
} }
) )
@ -201,11 +206,11 @@ object Component {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
abstract class Callback(val direct: Boolean, val limit: Int) { abstract class Callback(val direct: Boolean, val limit: Int, val doc: String = "") {
def apply(instance: Environment, context: Context, args: Arguments): Array[AnyRef] def apply(instance: Environment, context: Context, args: Arguments): Array[AnyRef]
} }
class ComponentCallback(val method: Method, direct: Boolean, limit: Int) extends Callback(direct, limit) { class ComponentCallback(val method: Method, direct: Boolean, limit: Int, doc: String) extends Callback(direct, limit, doc) {
override def apply(instance: Environment, context: Context, args: Arguments) = try { override def apply(instance: Environment, context: Context, args: Arguments) = try {
method.invoke(instance, context, args).asInstanceOf[Array[AnyRef]] method.invoke(instance, context, args).asInstanceOf[Array[AnyRef]]
} catch { } catch {

View File

@ -17,3 +17,10 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
-------------------------------------------------------------------------------
All images / textures and localization strings (resources) are put in the
public domain. More specicially, see CC0 1.0 Universal:
http://creativecommons.org/publicdomain/zero/1.0/

View File

@ -133,7 +133,7 @@ oc:tooltip.Disk=Sehr einfaches Speichermedium, das verwendet werden kann, um Dis
oc:tooltip.DiskDrive.CC=ComputerCraft-Disketten werden §aunterstützt§7. oc:tooltip.DiskDrive.CC=ComputerCraft-Disketten werden §aunterstützt§7.
oc:tooltip.DiskDrive=Erlaubt es, Disketten zu lesen und zu beschreiben. oc:tooltip.DiskDrive=Erlaubt es, Disketten zu lesen und zu beschreiben.
oc:tooltip.GraphicsCard=Erlaubt es, den angezeigten Inhalt von Bildschirmen zu ändern.[nl] Höchstauflösung: §f%sx%s§7.[nl] Maximale Farbtiefe: §f%s§7.[nl] Operationen/Tick: §f%s§7. oc:tooltip.GraphicsCard=Erlaubt es, den angezeigten Inhalt von Bildschirmen zu ändern.[nl] Höchstauflösung: §f%sx%s§7.[nl] Maximale Farbtiefe: §f%s§7.[nl] Operationen/Tick: §f%s§7.
oc:tooltip.InternetCard=Diese Karte erlaubt es, HTTP-Anfragen zu senden und echte TCP und UDP Sockets zu verwenden. oc:tooltip.InternetCard=Diese Karte erlaubt es, HTTP-Anfragen zu senden und echte TCP Sockets zu verwenden.
oc:tooltip.IronNugget=Ein Nugget, das aus Eisen besteht, darum wird es ja auch Eisennugget genannt, duh... oc:tooltip.IronNugget=Ein Nugget, das aus Eisen besteht, darum wird es ja auch Eisennugget genannt, duh...
oc:tooltip.Keyboard=Kann an Bildschirmen befestigt werden, um auf ihnen zu tippen. oc:tooltip.Keyboard=Kann an Bildschirmen befestigt werden, um auf ihnen zu tippen.
oc:tooltip.Memory=Braucht ein jeder Computer, um zu starten. Je mehr vorhanden, desto komplexere Programme können ausgeführt werden. oc:tooltip.Memory=Braucht ein jeder Computer, um zu starten. Je mehr vorhanden, desto komplexere Programme können ausgeführt werden.

View File

@ -133,7 +133,7 @@ oc:tooltip.Disk=Primitive medium that can be used to build persistent storage de
oc:tooltip.DiskDrive.CC=ComputerCraft floppies are §asupported§7. oc:tooltip.DiskDrive.CC=ComputerCraft floppies are §asupported§7.
oc:tooltip.DiskDrive=Allows reading and writing floppies. oc:tooltip.DiskDrive=Allows reading and writing floppies.
oc:tooltip.GraphicsCard=Used to change what's displayed on screens.[nl] Maximum resolution: §f%sx%s§7.[nl] Maximum color depth: §f%s§7.[nl] Operations/tick: §f%s§7. oc:tooltip.GraphicsCard=Used to change what's displayed on screens.[nl] Maximum resolution: §f%sx%s§7.[nl] Maximum color depth: §f%s§7.[nl] Operations/tick: §f%s§7.
oc:tooltip.InternetCard=This card allows making HTTP requests and using real TCP and UDP sockets. oc:tooltip.InternetCard=This card allows making HTTP requests and using real TCP sockets.
oc:tooltip.IronNugget=A nugget made of iron, that's why it's called an Iron Nugget, duh... oc:tooltip.IronNugget=A nugget made of iron, that's why it's called an Iron Nugget, duh...
oc:tooltip.Keyboard=Can be attached to screens to allow typing on them. oc:tooltip.Keyboard=Can be attached to screens to allow typing on them.
oc:tooltip.Memory=Required to get computers to run. The more you have, the more complex the programs you can run. oc:tooltip.Memory=Required to get computers to run. The more you have, the more complex the programs you can run.

View File

@ -259,7 +259,17 @@ sandbox._G = sandbox
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Start of non-standard stuff made available via package.preload. -- Start of non-standard stuff made available via package.preload.
local libcomponent = { local libcomponent
libcomponent = {
doc = function(address, method)
checkArg(1, address, "string")
checkArg(2, method, "string")
local result, reason = component.doc(address, method)
if not result and reason then
error(reason, 2)
end
return result
end,
invoke = function(address, method, ...) invoke = function(address, method, ...)
checkArg(1, address, "string") checkArg(1, address, "string")
checkArg(2, method, "string") checkArg(2, method, "string")
@ -288,9 +298,14 @@ local libcomponent = {
return nil, reason return nil, reason
end end
for method, direct in pairs(methods) do for method, direct in pairs(methods) do
proxy[method] = function(...) proxy[method] = setmetatable({}, {
__call = function(_, ...)
return invoke(direct, address, method, ...) return invoke(direct, address, method, ...)
end,
__tostring = function()
return libcomponent.doc(address, method) or "function"
end end
})
end end
return proxy return proxy
end, end,

View File

@ -95,7 +95,7 @@ function text.serialize(value, pretty)
["until"]=true, ["while"]=true} ["until"]=true, ["while"]=true}
local id = "^[%a_][%w_]*$" local id = "^[%a_][%w_]*$"
local ts = {} local ts = {}
local function s(v) local function s(v, l)
local t = type(v) local t = type(v)
if t == "nil" then if t == "nil" then
return "nil" return "nil"
@ -113,6 +113,8 @@ function text.serialize(value, pretty)
end end
elseif t == "string" then elseif t == "string" then
return string.format("%q", v) return string.format("%q", v)
elseif t == "table" and pretty and getmetatable(v) and getmetatable(v).__tostring then
return tostring(v)
elseif t == "table" then elseif t == "table" then
if ts[v] then if ts[v] then
if pretty then if pretty then
@ -122,24 +124,36 @@ function text.serialize(value, pretty)
end end
end end
ts[v] = true ts[v] = true
local i, r = 1, nil local f, i, r = 1, nil
for k, v in pairs(v) do if pretty then
local ks = {}
for k in pairs(v) do table.insert(ks, k) end
table.sort(ks)
local k = 0
f = function()
k = k + 1
return ks[k], ks[k] and v[ks[k]] or nil
end
else
f = pairs(v)
end
for k, v in f do
if r then if r then
r = r .. "," r = r .. "," .. (pretty and ("\n" .. string.rep(" ", l)) or "")
else else
r = "{" r = "{"
end end
local tk = type(k) local tk = type(k)
if tk == "number" and k == i then if tk == "number" and k == i then
i = i + 1 i = i + 1
r = r .. s(v) r = r .. s(v, l + 1)
else else
if tk == "string" and not kw[k] and string.match(k, id) then if tk == "string" and not kw[k] and string.match(k, id) then
r = r .. k r = r .. k
else else
r = r .. "[" .. s(k) .. "]" r = r .. "[" .. s(k, l + 1) .. "]"
end end
r = r .. "=" .. s(v) r = r .. "=" .. s(v, l + 1)
end end
end end
ts[v] = nil -- allow writing same table more than once ts[v] = nil -- allow writing same table more than once
@ -152,7 +166,7 @@ function text.serialize(value, pretty)
end end
end end
end end
local result = s(value) local result = s(value, 1)
local limit = type(pretty) == "number" and pretty or 1000 local limit = type(pretty) == "number" and pretty or 1000
if pretty and unicode.len(result) > limit then if pretty and unicode.len(result) > limit then
return result:sub(1, limit) .. "..." return result:sub(1, limit) .. "..."

View File

@ -101,7 +101,7 @@ opencomputers {
activeGC: true activeGC: true
# The sizes of the three tiers of RAM, in kilobytes. This list must # The sizes of the three tiers of RAM, in kilobytes. This list must
# contain exactly three entries, or it will be ignored. # contain exactly five entries, or it will be ignored.
ramSizes: [ ramSizes: [
64 64
128 128