diff --git a/src/main/resources/assets/opencomputers/lua/kernel.lua b/src/main/resources/assets/opencomputers/lua/kernel.lua index 32eb82351..ceb789397 100644 --- a/src/main/resources/assets/opencomputers/lua/kernel.lua +++ b/src/main/resources/assets/opencomputers/lua/kernel.lua @@ -27,21 +27,6 @@ end ------------------------------------------------------------------------------- -local running = setmetatable({}, {__mode="k"}) - -local function findProcess(co) - co = co or coroutine.running() - for _, process in pairs(running) do - for _, instance in pairs(process.instances) do - if instance == co then - return process - end - end - end -end - -------------------------------------------------------------------------------- - local function spcall(...) local result = table.pack(pcall(...)) if not result[1] then @@ -71,7 +56,6 @@ sandbox = { if not system.allowBytecode() then mode = "t" end - env = env or select(2, libprocess.running()) return load(ld, source, mode, env or sandbox) end, loadfile = nil, -- in boot/*_base.lua @@ -100,11 +84,7 @@ sandbox = { end, coroutine = { - create = function(f) - local co = coroutine.create(f) - table.insert(findProcess().instances, co) - return co - end, + create = coroutine.create, resume = function(co, ...) -- custom resume part for bubbling sysyields checkArg(1, co, "thread") local args = table.pack(...) @@ -194,8 +174,8 @@ sandbox = { pi = math.pi, pow = math.pow, rad = math.rad, - random = function(low, high) - return spcall(math.random, low, high) + random = function(...) + return spcall(math.random, ...) end, randomseed = function(seed) spcall(math.randomseed, seed) @@ -288,7 +268,7 @@ libcomponent = { doc = function(address, method) checkArg(1, address, "string") checkArg(2, method, "string") - local result, reason = component.doc(address, method) + local result, reason = spcall(component.doc, address, method) if not result and reason then error(reason, 2) end @@ -297,7 +277,7 @@ libcomponent = { invoke = function(address, method, ...) checkArg(1, address, "string") checkArg(2, method, "string") - local methods, reason = component.methods(address) + local methods, reason = spcall(component.methods, address) if not methods then return nil, reason end @@ -310,7 +290,7 @@ libcomponent = { end, list = function(filter) checkArg(1, filter, "string", "nil") - local list = component.list(filter) + local list = spcall(component.list, filter) local key = nil return function() key = next(list, key) @@ -321,12 +301,12 @@ libcomponent = { end, proxy = function(address) checkArg(1, address, "string") - local type, reason = component.type(address) + local type, reason = spcall(component.type, address) if not type then return nil, reason end local proxy = {address = address, type = type} - local methods, reason = component.methods(address) + local methods, reason = spcall(component.methods, address) if not methods then return nil, reason end @@ -340,6 +320,7 @@ libcomponent = { return component.type(address) end } +sandbox.component = libcomponent local libcomputer = { isRobot = computer.isRobot, @@ -352,6 +333,11 @@ local libcomputer = { energy = computer.energy, maxEnergy = computer.maxEnergy, + getBootAddress = computer.getBootAddress, + setBootAddress = function(address) + return spcall(computer.setBootAddress, address) + end, + users = computer.users, addUser = function(name) return spcall(computer.addUser, name) @@ -377,51 +363,7 @@ local libcomputer = { until computer.uptime() >= deadline end } - -libprocess = { - load = function(path, env, init, name) - checkArg(1, path, "string") - checkArg(2, env, "table", "nil") - checkArg(3, init, "function", "nil") - checkArg(4, name, "string", "nil") - - local process = findProcess() - if process then - env = env or process.env - end - env = setmetatable({}, {__index=env or sandbox}) - local code, reason = sandbox.loadfile(path, "t", env) - if not code then - return nil, reason - end - - local thread = coroutine.create(function(...) - if init then - init() - end - return code(...) - end) - running[thread] = { - path = path, - command = name, - env = env, - parent = process, - instances = setmetatable({thread}, {__mode="v"}) - } - return thread - end, - running = function(level) - level = level or 1 - local process = findProcess() - while level > 1 and process do - process = process.parent - level = level - 1 - end - if process then - return process.path, process.env, process.command - end - end -} +sandbox.computer = libcomputer local libunicode = { char = function(...) @@ -446,91 +388,48 @@ local libunicode = { return spcall(unicode.upper, s) end } +sandbox.unicode = libunicode ------------------------------------------------------------------------------- local function bootstrap() - -- Minimalistic hard-coded pure async proxy for our ROM. - local rom = {} - function rom.invoke(method, ...) - return invoke(true, computer.romAddress(), method, ...) - end - function rom.open(file) return rom.invoke("open", file) end - function rom.read(handle) return rom.invoke("read", handle, math.huge) end - function rom.close(handle) return rom.invoke("close", handle) end - function rom.inits(file) return ipairs(rom.invoke("list", "boot")) end - function rom.isDirectory(path) return rom.invoke("isDirectory", path) end - - -- Custom low-level loadfile/dofile implementation reading from our ROM. - local function loadfile(file) - local handle, reason = rom.open(file) + local function tryLoadFrom(address) + function boot_invoke(method, ...) + local result = table.pack(pcall(invoke, true, address, method, ...)) + if not result[1] then + return nil, result[2] + else + return table.unpack(result, 2, result.n) + end + end + local handle, reason = boot_invoke("open", "/init.lua") if not handle then - error(reason) + return nil, reason end local buffer = "" repeat - local data, reason = rom.read(handle) + local data, reason = boot_invoke("read", handle, math.huge) if not data and reason then - error(reason) + return nil, reason end buffer = buffer .. (data or "") until not data - rom.close(handle) - return load(buffer, "=" .. file, "t", sandbox) + boot_invoke("close", handle) + return load(buffer, "=init", "t", sandbox) end - local function dofile(file) - local program, reason = loadfile(file) - if program then - local result = table.pack(pcall(program)) - if result[1] then - return table.unpack(result, 2, result.n) - else - error(result[2]) - end - else - error(reason) - end + local init, reason + if computer.getBootAddress() then + init, reason = tryLoadFrom(computer.getBootAddress()) + end + if not init then + computer.setBootAddress() + init, reason = tryLoadFrom(computer.romAddress()) + end + if not init then + error(reason) end - -- Load file system related libraries we need to load other stuff moree - -- comfortably. This is basically wrapper stuff for the file streams - -- provided by the filesystem components. - local package = dofile("/lib/package.lua") - - -- Initialize the package module with some of our own APIs. - package.preload["buffer"] = loadfile("/lib/buffer.lua") - package.preload["component"] = function() return libcomponent end - package.preload["computer"] = function() return libcomputer end - package.preload["filesystem"] = loadfile("/lib/filesystem.lua") - package.preload["io"] = loadfile("/lib/io.lua") - package.preload["process"] = function() return libprocess end - package.preload["unicode"] = function() return libunicode end - - -- Inject the package and io modules into the global namespace, as in Lua. - sandbox.package = package - sandbox.io = sandbox.require("io") - - -- Mount the ROM and temporary file systems to allow working on the file - -- system module from this point on. - sandbox.require("filesystem").mount(computer.romAddress(), "/") - if computer.tmpAddress() then - sandbox.require("filesystem").mount(computer.tmpAddress(), "/tmp") - end - - -- Run library startup scripts. These mostly initialize event handlers. - local scripts = {} - for _, file in rom.inits() do - local path = "boot/" .. file - if not rom.isDirectory(path) then - table.insert(scripts, path) - end - end - table.sort(scripts) - for i = 1, #scripts do - dofile(scripts[i]) - end - - return coroutine.create(function() dofile("/init.lua") end), {n=0} + return coroutine.create(init), {n=0} end local function wrapUserdata(values) @@ -582,18 +481,12 @@ end ------------------------------------------------------------------------------- local function main() - -- Make all calls in the bootstrapper direct to speed up booting. - local realInvoke = invoke - invoke = function(_, ...) return realInvoke(true, ...) end - - local co, args = bootstrap() - - -- Step out of the fast lane, all the basic stuff should now be loaded. - invoke = realInvoke - -- Yield once to get a memory baseline. coroutine.yield() + -- After memory footprint to avoid init.lua bumping the baseline. + local co, args = bootstrap() + while true do deadline = computer.realTime() + system.timeout() debug.sethook(co, checkDeadline, "", hookInterval) diff --git a/src/main/resources/assets/opencomputers/lua/rom/bin/cp.lua b/src/main/resources/assets/opencomputers/lua/rom/bin/cp.lua index 232ca1795..9351e81ee 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/bin/cp.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/bin/cp.lua @@ -13,11 +13,43 @@ local to = shell.resolve(args[2]) if fs.isDirectory(to) then to = to .. "/" .. fs.name(from) end -if fs.exists(to) and not options.f then - io.stderr:write("target file exists") - return + +local function status(from, to) + if options.v then + print(from .. " -> " .. to) + end end -local result, reason = fs.copy(from, to) + +local result, reason + +local function recurse(fromPath, toPath) + status(fromPath, toPath) + if fs.isDirectory(fromPath) then + if fs.exists(toPath) and not fs.isDirectory(toPath) then + if not options.f then + return nil, "target file exists" + end + fs.remove(toPath) + end + fs.makeDirectory(toPath) + for file in fs.list(fromPath) do + local result, reason = recurse(fs.concat(fromPath, file), fs.concat(toPath, file)) + if not result then + return nil, reason + end + end + return true + else + if fs.exists(toPath) then + if fs.isDirectory(toPath) or not options.f then + return nil, "target file exists" + end + fs.remove(toPath) + end + return fs.copy(fromPath, toPath) + end +end +result, reason = recurse(from, to) if not result then - io.stderr:write(reason) + error(reason) end \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/lua/rom/bin/install.lua b/src/main/resources/assets/opencomputers/lua/rom/bin/install.lua new file mode 100644 index 000000000..14bd4ef1f --- /dev/null +++ b/src/main/resources/assets/opencomputers/lua/rom/bin/install.lua @@ -0,0 +1,60 @@ +local component = require("component") +local computer = require("computer") +local event = require("event") +local unicode = require("unicode") + +local candidates = {} +for address in component.list("filesystem") do + local dev = component.proxy(address) + if not dev.isReadOnly() and dev.address ~= computer.tmpAddress() then + table.insert(candidates, dev) + end +end + +if #candidates == 0 then + print("No writable disks found, aborting.") + return +end + +for i = 1, #candidates do + print(i .. ") " .. candidates[i].address) +end + +print("To select the device to install to, please enter a number between 1 and " .. #candidates .. ".") +print("Press 'q' to cancel the installation.") +local choice +repeat + local _, address, char, code = event.pull("key") + if component.isPrimary(address) then + local value = unicode.char(char) + if value == "q" then + return + end + local number = tonumber(value) + if number and number > 0 and number <= #candidates then + choice = number + else + end + end +until choice +choice = candidates[choice] + +print("Installing OpenOS to device " .. choice.address) +local rom = "/mnt/" .. computer.romAddress():sub(1, 3) .. "/" +local mnt = "/mnt/" .. choice.address:sub(1, 3) .. "/" +local function install(what, path) + print("Installing " .. what .. "...") + local result, reason = os.execute("cp -vf " .. rom .. path .. " " .. mnt) + if not result then + error(reason, 0) + end +end +install("programs", "bin") +install("boot scripts", "boot") +install("libraries", "lib") +install("additional files", "usr") +install("startup script", "init.lua") +computer.setBootAddress(choice.address) + +print("All done! Rebooting from device now...") +computer.shutdown(true) \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/lua/rom/bin/lua.lua b/src/main/resources/assets/opencomputers/lua/rom/bin/lua.lua index 2dbb77ba1..bf84eb772 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/bin/lua.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/bin/lua.lua @@ -1,7 +1,7 @@ local component = require("component") local package = require("package") local term = require("term") -local text = require("text") +local serialization = require("serialization") local function optrequire(...) local success, module = pcall(require, ...) @@ -49,7 +49,7 @@ while term.isAvailable() do io.stderr:write(tostring(result[2]) .. "\n") else for i = 2, result.n do - term.write(text.serialize(result[i], true) .. "\t", true) + term.write(serialization.serialize(result[i], true) .. "\t", true) end if term.getCursor() > 1 then term.write("\n") diff --git a/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua b/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua index 342f9f04b..ae48cb646 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua @@ -120,10 +120,11 @@ if #args == 0 and (io.input() == io.stdin or options.i) and not options.c then return elseif command ~= "" then local result, reason = execute(command) + if term.getCursor() > 1 then + term.write("\n") + end if not result then io.stderr:write((tostring(reason) or "unknown error").. "\n") - elseif term.getCursor() > 1 then - term.write("\n") end end end @@ -132,7 +133,7 @@ else -- execute command. local result = table.pack(execute(table.unpack(args))) if not result[1] then - error(result[2]) + error(result[2], 0) end return table.unpack(result, 2) end \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/lua/rom/init.lua b/src/main/resources/assets/opencomputers/lua/rom/init.lua index 99afa57f3..525532436 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/init.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/init.lua @@ -1,13 +1,147 @@ -local component = require("component") +do + local component = component + local computer = computer + local unicode = unicode + + -- Low level dofile implementation to read filesystem libraries. + local rom = {} + function rom.invoke(method, ...) + return component.invoke(computer.romAddress(), method, ...) + end + function rom.open(file) return rom.invoke("open", file) end + function rom.read(handle) return rom.invoke("read", handle, math.huge) end + function rom.close(handle) return rom.invoke("close", handle) end + function rom.inits(file) return ipairs(rom.invoke("list", "boot")) end + function rom.isDirectory(path) return rom.invoke("isDirectory", path) end + + -- Report boot progress if possible. + local gpu, screen = component.list("gpu")(), component.list("screen")() + local w, h + if gpu and screen then + component.invoke(gpu, "bind", screen) + w, h = component.invoke(gpu, "getResolution") + component.invoke(gpu, "setResolution", w, h) + component.invoke(gpu, "setBackground", 0x000000) + component.invoke(gpu, "setForeground", 0xFFFFFF) + component.invoke(gpu, "fill", 1, 1, w, h, " ") + end + local y = 1 + local function status(msg) + if gpu and screen then + component.invoke(gpu, "set", 1, y, msg) + if y == h then + component.invoke(gpu, "copy", 1, 2, w, h - 1, 0, -1) + component.invoke(gpu, "fill", 1, h, w, 1, " ") + else + y = y + 1 + end + end + end + + status("Booting " .. _OSVERSION .. "...") + + -- Custom low-level loadfile/dofile implementation reading from our ROM. + local function loadfile(file) + status("> " .. file) + local handle, reason = rom.open(file) + if not handle then + error(reason) + end + local buffer = "" + repeat + local data, reason = rom.read(handle) + if not data and reason then + error(reason) + end + buffer = buffer .. (data or "") + until not data + rom.close(handle) + return load(buffer, "=" .. file) + end + + local function dofile(file) + local program, reason = loadfile(file) + if program then + local result = table.pack(pcall(program)) + if result[1] then + return table.unpack(result, 2, result.n) + else + error(result[2]) + end + else + error(reason) + end + end + + status("Initializing package management...") + + -- Load file system related libraries we need to load other stuff moree + -- comfortably. This is basically wrapper stuff for the file streams + -- provided by the filesystem components. + local package = dofile("/lib/package.lua") + + do + -- Unclutter global namespace now that we have the package module. + _G.component = nil + _G.computer = nil + _G.process = nil + _G.unicode = nil + + -- Initialize the package module with some of our own APIs. + package.preload["buffer"] = loadfile("/lib/buffer.lua") + package.preload["component"] = function() return component end + package.preload["computer"] = function() return computer end + package.preload["filesystem"] = loadfile("/lib/filesystem.lua") + package.preload["io"] = loadfile("/lib/io.lua") + package.preload["unicode"] = function() return unicode end + + -- Inject the package and io modules into the global namespace, as in Lua. + _G.package = package + _G.io = require("io") + end + + status("Initializing file system...") + + -- Mount the ROM and temporary file systems to allow working on the file + -- system module from this point on. + local filesystem = require("filesystem") + filesystem.mount(computer.getBootAddress() or computer.romAddress(), "/") + if computer.tmpAddress() then + filesystem.mount(computer.tmpAddress(), "/tmp") + end + + status("Running boot scripts...") + + -- Run library startup scripts. These mostly initialize event handlers. + local scripts = {} + for _, file in rom.inits() do + local path = "boot/" .. file + if not rom.isDirectory(path) then + table.insert(scripts, path) + end + end + table.sort(scripts) + for i = 1, #scripts do + dofile(scripts[i]) + end + + -- Initialize process module. + require("process").install("/init.lua", "init") + + status("Initializing components...") + + for c, t in component.list() do + computer.pushSignal("component_added", c, t) + end + os.sleep(0.5) -- Allow signal processing by libraries. + computer.pushSignal("init") -- so libs know components are initialized. + + status("Starting shell...") +end + local computer = require("computer") local event = require("event") -for c, t in component.list() do - computer.pushSignal("component_added", c, t) -end -os.sleep(0.5) -- Allow signal processing by libraries. -computer.pushSignal("init") -- so libs know components are initialized. - while true do require("term").clear() io.write(_OSVERSION .. " (" .. math.floor(computer.totalMemory() / 1024) .. "k RAM)\n") diff --git a/src/main/resources/assets/opencomputers/lua/rom/lib/io.lua b/src/main/resources/assets/opencomputers/lua/rom/lib/io.lua index ea2e4f115..17949be11 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/lib/io.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/lib/io.lua @@ -2,7 +2,7 @@ local io, file = {}, {} local input, output local programs = setmetatable({}, {__mode="k"}) -- maps program envs to i/o -function io.progs() return programs end + local function findOverride(filter) local override pcall(function() diff --git a/src/main/resources/assets/opencomputers/lua/rom/lib/process.lua b/src/main/resources/assets/opencomputers/lua/rom/lib/process.lua new file mode 100644 index 000000000..cc53a6fb5 --- /dev/null +++ b/src/main/resources/assets/opencomputers/lua/rom/lib/process.lua @@ -0,0 +1,85 @@ +local process = {} + +------------------------------------------------------------------------------- + +local running = setmetatable({}, {__mode="k"}) + +local function findProcess(co) + co = co or coroutine.running() + for _, process in pairs(running) do + for _, instance in pairs(process.instances) do + if instance == co then + return process + end + end + end +end + +------------------------------------------------------------------------------- + +function process.load(path, env, init, name) + checkArg(1, path, "string") + checkArg(2, env, "table", "nil") + checkArg(3, init, "function", "nil") + checkArg(4, name, "string", "nil") + + local process = findProcess() + if process then + env = env or process.env + end + env = setmetatable({}, {__index=env or _G}) + local code, reason = loadfile(path, "t", env) + if not code then + return nil, reason + end + + local thread = coroutine.create(function(...) + if init then + init() + end + return code(...) + end) + running[thread] = { + path = path, + command = name, + env = env, + parent = process, + instances = setmetatable({thread}, {__mode="v"}) + } + return thread +end + +function process.running(level) + level = level or 1 + local process = findProcess() + while level > 1 and process do + process = process.parent + level = level - 1 + end + if process then + return process.path, process.env, process.command + end +end + +function process.install(path, name) + local coroutine_create = coroutine.create + _G.coroutine.create = function(f) + local co = coroutine_create(f) + table.insert(findProcess().instances, co) + return co + end + local load = load + _G.load = function(ld, source, mode, env) + env = env or select(2, process.running()) + return load(ld, source, mode, env) + end + local thread = coroutine.running() + running[thread] = { + path = path, + command = name, + env = _ENV, + instances = setmetatable({thread}, {__mode="v"}) + } +end + +return process \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/lua/rom/lib/shell.lua b/src/main/resources/assets/opencomputers/lua/rom/lib/shell.lua index a8b0c20d6..7c15bf721 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/lib/shell.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/lib/shell.lua @@ -1,6 +1,4 @@ -local event = require("event") local fs = require("filesystem") -local process = require("process") local text = require("text") local unicode = require("unicode") @@ -165,10 +163,6 @@ function shell.parse(...) return args, options end -function shell.running(level) -- deprecated - return require("process").running(level) -end - ------------------------------------------------------------------------------- return shell diff --git a/src/main/resources/assets/opencomputers/lua/rom/lib/text.lua b/src/main/resources/assets/opencomputers/lua/rom/lib/text.lua index c8d4c2510..0eae2c924 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/lib/text.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/lib/text.lua @@ -17,7 +17,6 @@ end function text.padRight(value, length) checkArg(1, value, "string", "nil") checkArg(2, length, "number") - local unicode = require("unicode") if not value or unicode.len(value) == 0 then return string.rep(" ", length) else @@ -28,7 +27,6 @@ end function text.padLeft(value, length) checkArg(1, value, "string", "nil") checkArg(2, length, "number") - local unicode = require("unicode") if not value or unicode.len(value) == 0 then return string.rep(" ", length) else @@ -99,14 +97,6 @@ function text.tokenize(value) return tokens end -function text.serialize(value, pretty) -- deprecated, use serialization module - return require("serialization").serialize(value, pretty) -end - -function text.unserialize(data) -- deprecated, use serialization module - return require("serialization").unserialize(data) -end - ------------------------------------------------------------------------------- return text diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index 73a382d79..ad5667068 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -110,11 +110,11 @@ opencomputers { # there are six levels of RAM, they still fall into the three tiers of # items (level 1, 2 = tier 1, level 3, 4 = tier 2, level 5, 6 = tier 3). ramSizes: [ - 64 - 96 - 128 + 192 256 + 384 512 + 768 1024 ] diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 69eb7a133..aede14b72 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -38,17 +38,11 @@ class Settings(config: Config) { val startupDelay = config.getDouble("computer.startupDelay") max 0.05 val activeGC = config.getBoolean("computer.activeGC") val ramSizes = Array(config.getIntList("computer.ramSizes"): _*) match { - case Array(tier1, tier2, tier3) => - // For compatibility with older config files. - Array(tier1: Int, (tier1: Int) * 3 / 2, tier2: Int, tier3: Int, tier3 * 2: Int, tier3 * 4: Int) - case Array(tier1, tier3, tier4, tier5, tier6) => - // For compatibility with older config files. - Array(tier1: Int, (tier1: Int) * 3 / 2, tier3: Int, tier4: Int, tier5: Int, tier6: Int) case Array(tier1, tier2, tier3, tier4, tier5, tier6) => Array(tier1: Int, tier2: Int, tier3: Int, tier4: Int, tier5: Int, tier6: Int) case _ => OpenComputers.log.warning("Bad number of RAM sizes, ignoring.") - Array(64, 96, 128, 256, 512, 1024) + Array(192, 256, 384, 512, 768, 1024) } val ramScaleFor64Bit = config.getDouble("computer.ramScaleFor64Bit") max 1 val cpuComponentSupport = Array(config.getIntList("computer.cpuComponentCount"): _*) match { diff --git a/src/main/scala/li/cil/oc/client/Sound.scala b/src/main/scala/li/cil/oc/client/Sound.scala index 356724ea7..e67213960 100644 --- a/src/main/scala/li/cil/oc/client/Sound.scala +++ b/src/main/scala/li/cil/oc/client/Sound.scala @@ -167,8 +167,10 @@ object Sound { } def stop() { - soundSystem.stop(source) - soundSystem.removeSource(source) + if (soundSystem != null) { + soundSystem.stop(source) + soundSystem.removeSource(source) + } } } diff --git a/src/main/scala/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala b/src/main/scala/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala index 9140c649a..8cad81bf4 100644 --- a/src/main/scala/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala +++ b/src/main/scala/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala @@ -17,6 +17,8 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu private[machine] val ramScale = if (LuaStateFactory.is64Bit) Settings.get.ramScaleFor64Bit else 1.0 + private[machine] var bootAddress = "" + private val persistence = new PersistenceAPI(this) private val apis = Array( @@ -28,6 +30,8 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu new UnicodeAPI(this), new UserdataAPI(this)) + private var lastCollection = 0L + // ----------------------------------------------------------------------- // override def name() = "Lua" @@ -73,9 +77,10 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu // The kernel thread will always be at stack index one. assert(lua.isThread(1)) - if (Settings.get.activeGC) { + if (Settings.get.activeGC && (machine.worldTime - lastCollection) > 20) { // Help out the GC a little. The emergency GC has a few limitations // that will make it free less memory than doing a full step manually. + lastCollection = machine.worldTime lua.gc(LuaState.GcAction.COLLECT, 0) } diff --git a/src/main/scala/li/cil/oc/server/component/machine/luac/ComputerAPI.scala b/src/main/scala/li/cil/oc/server/component/machine/luac/ComputerAPI.scala index ea1b948b1..41ea0e3d9 100644 --- a/src/main/scala/li/cil/oc/server/component/machine/luac/ComputerAPI.scala +++ b/src/main/scala/li/cil/oc/server/component/machine/luac/ComputerAPI.scala @@ -38,6 +38,23 @@ class ComputerAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) { }) lua.setField(-2, "address") + // Get/set address of boot device. + lua.pushScalaFunction(lua => { + owner.bootAddress match { + case "" => lua.pushNil() + case address => lua.pushString(address) + } + 1 + }) + lua.setField(-2, "getBootAddress") + + lua.pushScalaFunction(lua => { + if (lua.isNoneOrNil(1)) owner.bootAddress = "" + else owner.bootAddress = lua.checkString(1) + 0 + }) + lua.setField(-2, "setBootAddress") + lua.pushScalaFunction(lua => { // This is *very* unlikely, but still: avoid this getting larger than // what we report as the total memory.