mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-15 02:12:42 -04:00
forbid access to string metatable for sandbox; minor restructuring of libraries (mostly sorting by name); saving managed environments attached to an adapter. this is not very reliable, sadly, since there are way too many ways neighbors can change outside our control (chunks only partially loaded, types removed across games due to other mod changes, mods that move blocks such as RIM, ...); making some effort to re-attach peripherals using their previous address; removed connection code on chunk load in network manager, since this is also handled by the check in the tile entities' update function
This commit is contained in:
parent
fcdb75e4bc
commit
ab785eb3ac
@ -57,7 +57,10 @@ sandbox = {
|
||||
dofile = nil, -- in lib/base.lua
|
||||
error = error,
|
||||
_G = nil, -- see below
|
||||
getmetatable = getmetatable,
|
||||
getmetatable = function(t)
|
||||
if type(t) == "string" then return nil end
|
||||
return getmetatable(t)
|
||||
end,
|
||||
ipairs = ipairs,
|
||||
load = function(ld, source, mode, env)
|
||||
assert((mode or "t") == "t", "unsupported mode")
|
||||
@ -143,8 +146,8 @@ sandbox = {
|
||||
uchar = string.uchar,
|
||||
|
||||
trim = function(s) -- from http://lua-users.org/wiki/StringTrim
|
||||
local from = s:match("^%s*()")
|
||||
return from > #s and "" or s:match(".*%S", from)
|
||||
local from = string.match(s, "^%s*()")
|
||||
return from > #s and "" or string.match(s, ".*%S", from)
|
||||
end
|
||||
},
|
||||
|
||||
|
@ -22,9 +22,9 @@ for path, proxy in pairs(mounts) do
|
||||
local used, total = proxy.spaceUsed(), proxy.spaceTotal()
|
||||
local available, percent
|
||||
if total == "unlimited" then
|
||||
used = "N/A"
|
||||
used = used or "N/A"
|
||||
available = "unlimited"
|
||||
percent = 0
|
||||
percent = "0%"
|
||||
else
|
||||
available = total - used
|
||||
percent = used / total
|
||||
|
@ -1,4 +1,4 @@
|
||||
local listeners, timers = {}, {}
|
||||
local event, listeners, timers = {}, {}, {}
|
||||
|
||||
local function matches(signal, name, filter)
|
||||
if name and not (type(signal[1]) == "string" and signal[1]:match(name))
|
||||
@ -58,7 +58,14 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
event = {}
|
||||
function event.cancel(timerId)
|
||||
checkArg(1, timerId, "number")
|
||||
if timers[timerId] then
|
||||
timers[timerId] = nil
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[ Error handler for ALL event callbacks. If this throws an error or is not,
|
||||
set the computer will immediately shut down. ]]
|
||||
@ -103,36 +110,6 @@ function event.listen(name, callback)
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function event.cancel(timerId)
|
||||
checkArg(1, timerId, "number")
|
||||
if timers[timerId] then
|
||||
timers[timerId] = nil
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function event.timer(interval, callback, times)
|
||||
checkArg(1, interval, "number")
|
||||
checkArg(2, callback, "function")
|
||||
checkArg(3, times, "number", "nil")
|
||||
local id
|
||||
repeat
|
||||
id = math.floor(math.random(1, 0x7FFFFFFF))
|
||||
until not timers[id]
|
||||
timers[id] = {
|
||||
interval = interval,
|
||||
after = os.uptime() + interval,
|
||||
callback = callback,
|
||||
times = times or 1
|
||||
}
|
||||
return id
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function event.pull(...)
|
||||
local args = table.pack(...)
|
||||
local seconds, name, filter
|
||||
@ -182,3 +159,24 @@ function event.shouldInterrupt()
|
||||
keyboard.isAltDown() and
|
||||
keyboard.isKeyDown(keyboard.keys.c)
|
||||
end
|
||||
|
||||
function event.timer(interval, callback, times)
|
||||
checkArg(1, interval, "number")
|
||||
checkArg(2, callback, "function")
|
||||
checkArg(3, times, "number", "nil")
|
||||
local id
|
||||
repeat
|
||||
id = math.floor(math.random(1, 0x7FFFFFFF))
|
||||
until not timers[id]
|
||||
timers[id] = {
|
||||
interval = interval,
|
||||
after = os.uptime() + interval,
|
||||
callback = callback,
|
||||
times = times or 1
|
||||
}
|
||||
return id
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
_G.event = event
|
||||
|
@ -1,3 +1,4 @@
|
||||
local filesystem, fileStream = {}, {}
|
||||
local isAutorunEnabled = true
|
||||
local mtab = {children={}}
|
||||
|
||||
@ -58,8 +59,6 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
filesystem = {}
|
||||
|
||||
function filesystem.autorun(enabled)
|
||||
if enabled ~= nil then
|
||||
checkArg(1, enabled, "boolean")
|
||||
@ -204,8 +203,6 @@ function filesystem.umount(fsOrPath)
|
||||
return result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function filesystem.exists(path)
|
||||
local node, rest = findNode(path)
|
||||
if not rest then -- virtual directory
|
||||
@ -269,8 +266,6 @@ function filesystem.list(path)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function filesystem.makeDirectory(path)
|
||||
local node, rest = findNode(path)
|
||||
if node.fs and rest then
|
||||
@ -336,10 +331,6 @@ function filesystem.copy(fromPath, toPath)
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local fileStream = {}
|
||||
|
||||
function fileStream:close()
|
||||
self.fs.close(self.handle)
|
||||
self.handle = nil
|
||||
@ -366,8 +357,6 @@ function fileStream:write(str)
|
||||
return self.fs.write(self.handle, str)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function filesystem.open(path, mode)
|
||||
checkArg(1, path, "string")
|
||||
mode = tostring(mode or "r")
|
||||
@ -407,24 +396,20 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
fs = filesystem
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local function onComponentAdded(_, address, componentType)
|
||||
if componentType == "filesystem" then
|
||||
local proxy = component.proxy(address)
|
||||
if proxy then
|
||||
local name = address:sub(1, 3)
|
||||
while fs.exists(fs.concat("/mnt", name)) and
|
||||
while filesystem.exists(filesystem.concat("/mnt", name)) and
|
||||
name:len() < address:len() -- just to be on the safe side
|
||||
do
|
||||
name = address:sub(1, name:len() + 1)
|
||||
end
|
||||
name = fs.concat("/mnt", name)
|
||||
fs.mount(proxy, name)
|
||||
name = filesystem.concat("/mnt", name)
|
||||
filesystem.mount(proxy, name)
|
||||
if isAutorunEnabled then
|
||||
shell.execute(fs.concat(name, "autorun"), proxy)
|
||||
shell.execute(filesystem.concat(name, "autorun"), proxy)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -432,10 +417,13 @@ end
|
||||
|
||||
local function onComponentRemoved(_, address, componentType)
|
||||
if componentType == "filesystem" then
|
||||
fs.umount(address)
|
||||
filesystem.umount(address)
|
||||
end
|
||||
end
|
||||
|
||||
_G.filesystem = filesystem
|
||||
_G.fs = filesystem
|
||||
|
||||
return function()
|
||||
event.listen("component_added", onComponentAdded)
|
||||
event.listen("component_removed", onComponentRemoved)
|
||||
|
@ -1,4 +1,19 @@
|
||||
local file = {}
|
||||
local io, file = {}, {}
|
||||
|
||||
function file.new(mode, stream, nogc)
|
||||
local result = {
|
||||
mode = mode or "r",
|
||||
stream = stream,
|
||||
buffer = "",
|
||||
bufferSize = math.max(128, math.min(8 * 1024, os.freeMemory() / 8)),
|
||||
bufferMode = "full"
|
||||
}
|
||||
local metatable = {
|
||||
__index = file,
|
||||
__metatable = "file"
|
||||
}
|
||||
return setmetatable(result, metatable)
|
||||
end
|
||||
|
||||
function file:close()
|
||||
if self.mode ~= "r" and self.mode ~= "rb" then
|
||||
@ -252,23 +267,6 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function file.new(mode, stream, nogc)
|
||||
local result = {
|
||||
mode = mode or "r",
|
||||
stream = stream,
|
||||
buffer = "",
|
||||
bufferSize = math.max(128, math.min(8 * 1024, os.freeMemory() / 8)),
|
||||
bufferMode = "full"
|
||||
}
|
||||
local metatable = {
|
||||
__index = file,
|
||||
__metatable = "file"
|
||||
}
|
||||
return setmetatable(result, metatable)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local stdinStream = {handle="stdin"}
|
||||
local stdoutStream = {handle="stdout"}
|
||||
local stdinHistory = {}
|
||||
@ -302,8 +300,6 @@ stdoutStream.seek = badFileDescriptor
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
io = {}
|
||||
|
||||
io.stdin = file.new("r", stdinStream, true)
|
||||
io.stdout = file.new("w", stdoutStream, true)
|
||||
io.stderr = io.stdout
|
||||
@ -420,3 +416,7 @@ end
|
||||
function io.write(...)
|
||||
return io.output():write(...)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
_G.io = io
|
||||
|
@ -1,9 +1,4 @@
|
||||
local pressedChars = {}
|
||||
local pressedCodes = {}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
keyboard = {}
|
||||
local keyboard, pressedChars, pressedCodes = {}, {}, {}
|
||||
|
||||
keyboard.keys = {
|
||||
["1"] = 0x02,
|
||||
@ -140,10 +135,20 @@ for k, v in pairs(keyboard.keys) do
|
||||
keyboard.keys[v] = k
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function keyboard.isAltDown()
|
||||
return (pressedCodes[keyboard.keys.lmenu] or pressedCodes[keyboard.keys.rmenu]) ~= nil
|
||||
end
|
||||
|
||||
function keyboard.isControl(char)
|
||||
return type(char) == "number" and (char < 0x20 or (char >= 0x7F and char <= 0x9F))
|
||||
end
|
||||
|
||||
function keyboard.isControlDown()
|
||||
return (pressedCodes[keyboard.keys.lcontrol] or pressedCodes[keyboard.keys.rcontrol]) ~= nil
|
||||
end
|
||||
|
||||
function keyboard.isKeyDown(charOrCode)
|
||||
checkArg(1, charOrCode, "string", "number")
|
||||
if type(charOrCode) == "string" then
|
||||
@ -153,14 +158,6 @@ function keyboard.isKeyDown(charOrCode)
|
||||
end
|
||||
end
|
||||
|
||||
function keyboard.isControlDown()
|
||||
return (pressedCodes[keyboard.keys.lcontrol] or pressedCodes[keyboard.keys.rcontrol]) ~= nil
|
||||
end
|
||||
|
||||
function keyboard.isAltDown()
|
||||
return (pressedCodes[keyboard.keys.lmenu] or pressedCodes[keyboard.keys.rmenu]) ~= nil
|
||||
end
|
||||
|
||||
function keyboard.isShiftDown()
|
||||
return (pressedCodes[keyboard.keys.lshift] or pressedCodes[keyboard.keys.rshift]) ~= nil
|
||||
end
|
||||
@ -188,6 +185,8 @@ local function onComponentUnavailable(_, componentType)
|
||||
end
|
||||
end
|
||||
|
||||
_G.keyboard = keyboard
|
||||
|
||||
return function()
|
||||
event.listen("key_down", onKeyDown)
|
||||
event.listen("key_up", onKeyUp)
|
||||
|
@ -1,25 +0,0 @@
|
||||
local function stringToSide(side)
|
||||
if type(side) == "string" and rs.sides[side] then
|
||||
return rs.sides[side]
|
||||
end
|
||||
return side
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
redstone = {}
|
||||
rs = redstone
|
||||
|
||||
rs.sides = {
|
||||
[0] = "bottom",
|
||||
[1] = "top",
|
||||
[2] = "back",
|
||||
[3] = "front",
|
||||
[4] = "right",
|
||||
[5] = "left"
|
||||
}
|
||||
for k, v in pairs(rs.sides) do
|
||||
rs.sides[v] = k
|
||||
end
|
||||
rs.sides.up = rs.sides.top
|
||||
rs.sides.down = rs.sides.bottom
|
@ -1,3 +1,4 @@
|
||||
local shell = {}
|
||||
local cwd = "/"
|
||||
local path = {"/bin/", "/usr/bin/", "/home/bin/"}
|
||||
local aliases = {dir="ls", move="mv", rename="mv", copy="cp", del="rm",
|
||||
@ -48,8 +49,6 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
shell = {}
|
||||
|
||||
function shell.alias(alias, ...)
|
||||
checkArg(1, alias, "string")
|
||||
local result = aliases[alias]
|
||||
@ -170,3 +169,7 @@ function shell.which(program)
|
||||
return nil, "program not found"
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
_G.shell = shell
|
||||
|
17
assets/opencomputers/lua/rom/lib/sides.lua
Normal file
17
assets/opencomputers/lua/rom/lib/sides.lua
Normal file
@ -0,0 +1,17 @@
|
||||
local sides = {
|
||||
[0] = "bottom",
|
||||
[1] = "top",
|
||||
[2] = "back",
|
||||
[3] = "front",
|
||||
[4] = "right",
|
||||
[5] = "left"
|
||||
}
|
||||
for k, v in pairs(sides) do
|
||||
sides[v] = k
|
||||
end
|
||||
sides.up = sides.top
|
||||
sides.down = sides.bottom
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
_G.sides = sides
|
@ -1,3 +1,4 @@
|
||||
local term = {}
|
||||
local gpuAvailable, screenAvailable = false, false
|
||||
local cursorX, cursorY = 1, 1
|
||||
local cursorBlink = nil
|
||||
@ -17,12 +18,6 @@ end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
term = {}
|
||||
|
||||
function term.isAvailable()
|
||||
return gpuAvailable and screenAvailable
|
||||
end
|
||||
|
||||
function term.clear()
|
||||
if term.isAvailable() then
|
||||
local w, h = gpu().getResolution()
|
||||
@ -75,7 +70,9 @@ function term.cursorBlink(enabled)
|
||||
return cursorBlink ~= nil
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
function term.isAvailable()
|
||||
return gpuAvailable and screenAvailable
|
||||
end
|
||||
|
||||
function term.read(history)
|
||||
checkArg(1, history, "table", "nil")
|
||||
@ -379,6 +376,8 @@ local function onComponentUnavailable(_, componentType)
|
||||
end
|
||||
end
|
||||
|
||||
_G.term = term
|
||||
|
||||
return function()
|
||||
event.listen("component_available", onComponentAvailable)
|
||||
event.listen("component_unavailable", onComponentUnavailable)
|
||||
|
@ -21,14 +21,14 @@ class Proxy {
|
||||
Blocks.init()
|
||||
Items.init()
|
||||
|
||||
api.Driver.add(driver.CommandBlock)
|
||||
api.Driver.add(driver.FileSystem)
|
||||
api.Driver.add(driver.GraphicsCard)
|
||||
api.Driver.add(driver.Memory)
|
||||
api.Driver.add(driver.NetworkCard)
|
||||
api.Driver.add(driver.RedstoneCard)
|
||||
api.Driver.add(driver.CommandBlock)
|
||||
api.Driver.add(driver.PowerSupply)
|
||||
api.Driver.add(driver.Peripheral)
|
||||
api.Driver.add(driver.PowerSupply)
|
||||
api.Driver.add(driver.RedstoneCard)
|
||||
|
||||
MinecraftForge.EVENT_BUS.register(Computer)
|
||||
MinecraftForge.EVENT_BUS.register(network.Network)
|
||||
|
@ -4,22 +4,19 @@ import dan200.computer.api.{ILuaContext, IComputerAccess, IPeripheral}
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.api.Network
|
||||
import li.cil.oc.api.network._
|
||||
import li.cil.oc.server
|
||||
import li.cil.oc.server.driver
|
||||
import net.minecraft.nbt.{NBTTagString, NBTTagList, NBTTagCompound}
|
||||
import net.minecraft.nbt.{NBTTagList, NBTTagCompound}
|
||||
import net.minecraftforge.common.ForgeDirection
|
||||
import scala.Some
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
import scala.collection.mutable
|
||||
|
||||
// TODO persist managed environments of attached blocks somehow...
|
||||
|
||||
class Adapter extends Rotatable with Environment with IPeripheral {
|
||||
val node = api.Network.newNode(this, Visibility.Network).create()
|
||||
|
||||
private val blocks = Array.fill[Option[(ManagedEnvironment, api.driver.Block)]](6)(None)
|
||||
|
||||
private val blocksAddresses = Array.fill[String](6)(java.util.UUID.randomUUID.toString)
|
||||
private val blocksData = Array.fill[Option[BlockData]](6)(None)
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@ -39,27 +36,33 @@ class Adapter extends Rotatable with Environment with IPeripheral {
|
||||
val (x, y, z) = (xCoord + d.offsetX, yCoord + d.offsetY, zCoord + d.offsetZ)
|
||||
driver.Registry.driverFor(worldObj, x, y, z) match {
|
||||
case Some(newDriver) => blocks(d.ordinal()) match {
|
||||
case Some((environment, driver)) =>
|
||||
case Some((oldEnvironment, driver)) =>
|
||||
if (newDriver != driver) {
|
||||
// This is... odd. Maybe moved by some other mod?
|
||||
node.disconnect(environment.node)
|
||||
val newEnvironment = newDriver.createEnvironment(worldObj, x, y, z)
|
||||
newEnvironment.node.asInstanceOf[server.network.Node].address = blocksAddresses(d.ordinal())
|
||||
node.connect(newEnvironment.node)
|
||||
blocks(d.ordinal()) = Some((newEnvironment, newDriver))
|
||||
node.disconnect(oldEnvironment.node)
|
||||
val environment = newDriver.createEnvironment(worldObj, x, y, z)
|
||||
blocks(d.ordinal()) = Some((environment, newDriver))
|
||||
blocksData(d.ordinal()) = Some(new BlockData(environment.getClass.getName, new NBTTagCompound()))
|
||||
node.connect(environment.node)
|
||||
} // else: the more things change, the more they stay the same.
|
||||
case _ =>
|
||||
// A challenger appears.
|
||||
val environment = newDriver.createEnvironment(worldObj, x, y, z)
|
||||
environment.node.asInstanceOf[server.network.Node].address = blocksAddresses(d.ordinal())
|
||||
node.connect(environment.node)
|
||||
blocks(d.ordinal()) = Some((environment, newDriver))
|
||||
blocksData(d.ordinal()) match {
|
||||
case Some(data) if data.name == environment.getClass.getName =>
|
||||
environment.load(data.data)
|
||||
case _ =>
|
||||
}
|
||||
blocksData(d.ordinal()) = Some(new BlockData(environment.getClass.getName, new NBTTagCompound()))
|
||||
node.connect(environment.node)
|
||||
}
|
||||
case _ => blocks(d.ordinal()) match {
|
||||
case Some((environment, driver)) =>
|
||||
// We had something there, but it's gone now...
|
||||
blocks(d.ordinal()) = None
|
||||
node.disconnect(environment.node)
|
||||
environment.save(blocksData(d.ordinal()).get.data)
|
||||
blocks(d.ordinal()) = None
|
||||
case _ => // Nothing before, nothing now.
|
||||
}
|
||||
}
|
||||
@ -108,13 +111,16 @@ class Adapter extends Rotatable with Environment with IPeripheral {
|
||||
super.readFromNBT(nbt)
|
||||
node.load(nbt)
|
||||
|
||||
val addressesNbt = nbt.getTagList("oc.adapter.addresses")
|
||||
(0 until (addressesNbt.tagCount min blocksAddresses.length)).
|
||||
map(addressesNbt.tagAt).
|
||||
map(_.asInstanceOf[NBTTagString].data).
|
||||
val blocksNbt = nbt.getTagList("oc.adapter.blocks")
|
||||
(0 until (blocksNbt.tagCount min blocksData.length)).
|
||||
map(blocksNbt.tagAt).
|
||||
map(_.asInstanceOf[NBTTagCompound]).
|
||||
zipWithIndex.
|
||||
foreach {
|
||||
case (a, i) => blocksAddresses(i) = a
|
||||
case (blockNbt, i) =>
|
||||
if (blockNbt.hasKey("name") && blockNbt.hasKey("data")) {
|
||||
blocksData(i) = Some(new BlockData(blockNbt.getString("name"), blockNbt.getCompoundTag("data")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,11 +128,22 @@ class Adapter extends Rotatable with Environment with IPeripheral {
|
||||
super.writeToNBT(nbt)
|
||||
node.save(nbt)
|
||||
|
||||
val addressesNbt = new NBTTagList()
|
||||
for (i <- 0 until blocksAddresses.length) {
|
||||
addressesNbt.appendTag(new NBTTagString(null, blocksAddresses(i)))
|
||||
val blocksNbt = new NBTTagList()
|
||||
for (i <- 0 until blocks.length) {
|
||||
val blockNbt = new NBTTagCompound()
|
||||
blocksData(i) match {
|
||||
case Some(data) =>
|
||||
blocks(i) match {
|
||||
case Some((environment, _)) => environment.save(data.data)
|
||||
case _ =>
|
||||
}
|
||||
blockNbt.setString("name", data.name)
|
||||
blockNbt.setCompoundTag("data", data.data)
|
||||
case _ =>
|
||||
}
|
||||
blocksNbt.appendTag(blockNbt)
|
||||
}
|
||||
nbt.setTag("oc.adapter.addresses", addressesNbt)
|
||||
nbt.setTag("oc.adapter.blocks", blocksNbt)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
@ -183,4 +200,9 @@ class Adapter extends Rotatable with Environment with IPeripheral {
|
||||
throw new IllegalArgumentException("bad argument #%d (number in [1, 65535] expected)".format(index + 1))
|
||||
port
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
private class BlockData(val name: String, val data: NBTTagCompound)
|
||||
|
||||
}
|
||||
|
@ -187,12 +187,29 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
||||
for (component <- addedComponents) {
|
||||
if (component.canBeSeenFrom(owner.node)) {
|
||||
components += component.address -> component.name
|
||||
signal("component_added", component.address, component.name)
|
||||
// Skip the signal if we're not initialized yet, since we'd generate a
|
||||
// duplicate in the startup script otherwise.
|
||||
if (kernelMemory > 0)
|
||||
signal("component_added", component.address, component.name)
|
||||
}
|
||||
}
|
||||
addedComponents.clear()
|
||||
}
|
||||
|
||||
private def verifyComponents() {
|
||||
val invalid = mutable.Set.empty[String]
|
||||
for ((address, name) <- components) {
|
||||
if (owner.node.network.node(address) == null) {
|
||||
OpenComputers.log.warning("A component of type " + name + " disappeared!")
|
||||
signal("component_removed", address, name)
|
||||
invalid += address
|
||||
}
|
||||
}
|
||||
for (address <- invalid) {
|
||||
components -= address
|
||||
}
|
||||
}
|
||||
|
||||
def update() {
|
||||
// Add components that were added since the last update to the actual list
|
||||
// of components if we can see them. We use this delayed approach to avoid
|
||||
@ -205,8 +222,11 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
||||
processAddedComponents()
|
||||
|
||||
// Are we waiting for the world to settle?
|
||||
if (lastUpdate == 0 && System.currentTimeMillis() < sleepUntil)
|
||||
return
|
||||
if (lastUpdate == 0)
|
||||
if (System.currentTimeMillis() < sleepUntil)
|
||||
return
|
||||
else
|
||||
verifyComponents()
|
||||
|
||||
// Update last time run to let our executor thread know it doesn't have to
|
||||
// pause.
|
||||
@ -1021,7 +1041,7 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
||||
0
|
||||
}
|
||||
else {
|
||||
System.nanoTime() - cpuStart
|
||||
System.nanoTime() - cpuStart
|
||||
}
|
||||
cpuTime += runtime
|
||||
|
||||
|
@ -3,6 +3,8 @@ package li.cil.oc.server.component
|
||||
import dan200.computer.api.{IMount, IWritableMount, IComputerAccess, IPeripheral}
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.api.network._
|
||||
import li.cil.oc.server.network.{Node => MutableNode}
|
||||
import net.minecraft.nbt.{NBTTagString, NBTTagCompound}
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
import scala.collection.mutable
|
||||
|
||||
@ -13,6 +15,9 @@ class Peripheral(peripheral: IPeripheral) extends ManagedComponent with ICompute
|
||||
|
||||
private val mounts = mutable.Map.empty[String, ManagedEnvironment]
|
||||
|
||||
// Used to restore mounts to their previous addresses after save/load.
|
||||
private val mountAddresses = mutable.Map.empty[String, String]
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@LuaCallback(value = "getType", asynchronous = true)
|
||||
@ -53,6 +58,31 @@ class Peripheral(peripheral: IPeripheral) extends ManagedComponent with ICompute
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def load(nbt: NBTTagCompound) {
|
||||
super.load(nbt)
|
||||
|
||||
if (nbt.hasKey("oc.peripheral.addresses")) {
|
||||
val addressesNbt = nbt.getCompoundTag("oc.peripheral.addresses")
|
||||
for (tag <- addressesNbt.getTags) tag match {
|
||||
case addressNbt: NBTTagString =>
|
||||
mountAddresses += addressNbt.getName -> addressNbt.data
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def save(nbt: NBTTagCompound) {
|
||||
super.save(nbt)
|
||||
|
||||
val addressesNbt = new NBTTagCompound()
|
||||
for ((location, env) <- mounts) {
|
||||
addressesNbt.setString(location, env.node.address)
|
||||
}
|
||||
nbt.setCompoundTag("oc.peripheral.addresses", addressesNbt)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
def getID = -1
|
||||
|
||||
def getAttachmentName = node.address
|
||||
@ -71,6 +101,10 @@ class Peripheral(peripheral: IPeripheral) extends ManagedComponent with ICompute
|
||||
if (!mounts.contains(desiredLocation)) {
|
||||
val env = api.FileSystem.asManagedEnvironment(fs, desiredLocation)
|
||||
env.node.asInstanceOf[Component].setVisibility(Visibility.Network)
|
||||
if (mountAddresses.contains(desiredLocation)) {
|
||||
env.node.asInstanceOf[MutableNode].address = mountAddresses(desiredLocation)
|
||||
mountAddresses -= desiredLocation
|
||||
}
|
||||
node.connect(env.node)
|
||||
mounts += desiredLocation -> env
|
||||
desiredLocation
|
||||
@ -79,7 +113,9 @@ class Peripheral(peripheral: IPeripheral) extends ManagedComponent with ICompute
|
||||
|
||||
def unmount(location: String) {
|
||||
mounts.remove(location) match {
|
||||
case Some(env) => env.node.remove()
|
||||
case Some(env) =>
|
||||
mountAddresses -= location
|
||||
env.node.remove()
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
@ -84,13 +84,13 @@ trait Component extends api.network.Component with Persistable {
|
||||
|
||||
override def load(nbt: NBTTagCompound) {
|
||||
super.load(nbt)
|
||||
if (nbt.hasKey("visibility"))
|
||||
visibility_ = Visibility.values()(nbt.getInteger("visibility"))
|
||||
if (nbt.hasKey("oc.component.visibility"))
|
||||
visibility_ = Visibility.values()(nbt.getInteger("oc.component.visibility"))
|
||||
}
|
||||
|
||||
override def save(nbt: NBTTagCompound) {
|
||||
super.save(nbt)
|
||||
nbt.setInteger("visibility", visibility_.ordinal())
|
||||
nbt.setInteger("oc.component.visibility", visibility_.ordinal())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,10 +332,6 @@ object Network extends api.detail.NetworkAPI {
|
||||
def onChunkUnload(e: ChunkEvent.Unload) =
|
||||
onUnload(e.world, e.getChunk.chunkTileEntityMap.values.asScala.map(_.asInstanceOf[TileEntity]))
|
||||
|
||||
@ForgeSubscribe
|
||||
def onChunkLoad(e: ChunkEvent.Load) =
|
||||
onLoad(e.world, e.getChunk.chunkTileEntityMap.values.asScala.map(_.asInstanceOf[TileEntity]))
|
||||
|
||||
private def onUnload(w: World, tileEntities: Iterable[TileEntity]) = if (!w.isRemote) {
|
||||
// TODO add a more efficient batch remove operation? something along the lines of if #remove > #nodes*factor remove all, re-add remaining?
|
||||
tileEntities.
|
||||
@ -344,10 +340,6 @@ object Network extends api.detail.NetworkAPI {
|
||||
foreach(t => t.node.remove())
|
||||
}
|
||||
|
||||
private def onLoad(w: World, tileEntities: Iterable[TileEntity]) = if (!w.isRemote) {
|
||||
tileEntities.foreach(t => joinOrCreateNetwork(w, t.xCoord, t.yCoord, t.zCoord))
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
private class Vertex(val data: MutableNode) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user