mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-09 15:25:56 -04:00
changed os.clock to be the actual cpu time of the computer and introduced os.uptime as the replacement of the old functionality; dofile now properly throws when loading fails; graphicscard now stores the screen its bound to in the component, which allows for the computer to display messages after it crashed (by sending a display request to neighbors -> graphicscards installed in it); fixed potential timeout in os.signal; wrappers for pcall and xpcall to enforce timeout when they return, too
This commit is contained in:
parent
a73ed001dd
commit
d363d0322d
@ -590,7 +590,7 @@ end
|
|||||||
function dofile(filename)
|
function dofile(filename)
|
||||||
local program, reason = loadfile(filename)
|
local program, reason = loadfile(filename)
|
||||||
if not program then
|
if not program then
|
||||||
return nil, reason
|
return error(reason)
|
||||||
end
|
end
|
||||||
return program()
|
return program()
|
||||||
end
|
end
|
||||||
|
@ -1,48 +1,52 @@
|
|||||||
driver.gpu = {}
|
driver.gpu = {}
|
||||||
|
|
||||||
function driver.gpu.setResolution(gpu, screen, w, h)
|
|
||||||
send(gpu, "gpu.resolution=", screen, w, h)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.gpu.getResolution(gpu, screen)
|
|
||||||
return send(gpu, "gpu.resolution", screen)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.gpu.getResolutions(gpu, screen)
|
|
||||||
return send(gpu, "gpu.resolutions", screen)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.gpu.set(gpu, screen, col, row, value)
|
|
||||||
send(gpu, "gpu.set", screen, col, row, value)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.gpu.fill(gpu, screen, col, row, w, h, value)
|
|
||||||
send(gpu, "gpu.fill", screen, col, row, w, h, value:sub(1, 1))
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.gpu.copy(gpu, screen, col, row, w, h, tx, ty)
|
|
||||||
send(gpu, "gpu.copy", screen, col, row, w, h, tx, ty)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.gpu.bind(gpu, screen)
|
function driver.gpu.bind(gpu, screen)
|
||||||
return {
|
checkArg(1, gpu, "string")
|
||||||
setResolution = function(w, h)
|
checkArg(2, screen, "string")
|
||||||
driver.gpu.setResolution(gpu, screen, w, h)
|
return send(gpu, "gpu.bind", screen)
|
||||||
end,
|
end
|
||||||
getResolution = function()
|
|
||||||
return driver.gpu.getResolution(gpu, screen)
|
function driver.gpu.resolution(gpu, w, h)
|
||||||
end,
|
checkArg(1, gpu, "string")
|
||||||
getResolutions = function()
|
if w and h then
|
||||||
return driver.gpu.getResolutions(gpu, screen)
|
checkArg(2, w, "number")
|
||||||
end,
|
checkArg(3, h, "number")
|
||||||
set = function(col, row, value)
|
return send(gpu, "gpu.resolution=", w, h)
|
||||||
driver.gpu.set(gpu, screen, col, row, value)
|
else
|
||||||
end,
|
return send(gpu, "gpu.resolution")
|
||||||
fill = function(col, ro, w, h, value)
|
end
|
||||||
driver.gpu.fill(gpu, screen, col, ro, w, h, value)
|
end
|
||||||
end,
|
|
||||||
copy = function(col, row, w, h, tx, ty)
|
function driver.gpu.resolutions(gpu)
|
||||||
driver.gpu.copy(gpu, screen, col, row, w, h, tx, ty)
|
checkArg(1, gpu, "string")
|
||||||
end
|
return send(gpu, "gpu.resolutions")
|
||||||
}
|
end
|
||||||
end
|
|
||||||
|
function driver.gpu.set(gpu, col, row, value)
|
||||||
|
checkArg(1, gpu, "string")
|
||||||
|
checkArg(2, col, "number")
|
||||||
|
checkArg(3, row, "number")
|
||||||
|
checkArg(4, value, "string")
|
||||||
|
return send(gpu, "gpu.set", col, row, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.gpu.fill(gpu, col, row, w, h, value)
|
||||||
|
checkArg(1, gpu, "string")
|
||||||
|
checkArg(2, col, "number")
|
||||||
|
checkArg(3, row, "number")
|
||||||
|
checkArg(4, w, "number")
|
||||||
|
checkArg(5, h, "number")
|
||||||
|
checkArg(6, value, "string")
|
||||||
|
return send(gpu, "gpu.fill", col, row, w, h, value:sub(1, 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.gpu.copy(gpu, col, row, w, h, tx, ty)
|
||||||
|
checkArg(1, gpu, "string")
|
||||||
|
checkArg(2, col, "number")
|
||||||
|
checkArg(3, row, "number")
|
||||||
|
checkArg(4, w, "number")
|
||||||
|
checkArg(5, h, "number")
|
||||||
|
checkArg(6, tx, "number")
|
||||||
|
checkArg(7, ty, "number")
|
||||||
|
return send(gpu, "gpu.copy", col, row, w, h, tx, ty)
|
||||||
|
end
|
||||||
|
@ -91,6 +91,7 @@ local sandbox = {
|
|||||||
date = os.date,
|
date = os.date,
|
||||||
difftime = os.difftime,
|
difftime = os.difftime,
|
||||||
time = os.time,
|
time = os.time,
|
||||||
|
uptime = os.uptime,
|
||||||
freeMemory = os.freeMemory,
|
freeMemory = os.freeMemory,
|
||||||
totalMemory = os.totalMemory,
|
totalMemory = os.totalMemory,
|
||||||
address = os.address,
|
address = os.address,
|
||||||
@ -138,7 +139,7 @@ function sandbox.checkArg(n, have, ...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
local msg = "bad argument #" .. n .. " (" .. table.concat({...}, " or ") .. " expected, got " .. have .. ")"
|
local msg = "bad argument #" .. n .. " (" .. table.concat({...}, " or ") .. " expected, got " .. have .. ")"
|
||||||
error(debug.traceback(msg, 3), 2)
|
error(debug.traceback(msg, 2), 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
@ -204,6 +205,18 @@ function sandbox.coroutine.yield(...)
|
|||||||
return coroutine.yield(nil, ...)
|
return coroutine.yield(nil, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function sandbox.pcall(...)
|
||||||
|
local result = table.pack(pcall(...))
|
||||||
|
checkDeadline()
|
||||||
|
return table.unpack(result, 1, result.n)
|
||||||
|
end
|
||||||
|
|
||||||
|
function sandbox.xpcall(...)
|
||||||
|
local result = table.pack(xpcall(...))
|
||||||
|
checkDeadline()
|
||||||
|
return table.unpack(result, 1, result.n)
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
function sandbox.os.shutdown()
|
function sandbox.os.shutdown()
|
||||||
@ -215,13 +228,13 @@ function sandbox.os.reboot()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function sandbox.os.signal(name, timeout)
|
function sandbox.os.signal(name, timeout)
|
||||||
local waitUntil = os.clock() + (type(timeout) == "number" and timeout or math.huge)
|
local waitUntil = os.uptime() + (type(timeout) == "number" and timeout or math.huge)
|
||||||
while os.clock() < waitUntil do
|
repeat
|
||||||
local signal = table.pack(coroutine.yield(waitUntil - os.clock()))
|
local signal = table.pack(coroutine.yield(waitUntil - os.uptime()))
|
||||||
if signal.n > 0 and (name == signal[1] or name == nil) then
|
if signal.n > 0 and (name == signal[1] or name == nil) then
|
||||||
return table.unpack(signal, 1, signal.n)
|
return table.unpack(signal, 1, signal.n)
|
||||||
end
|
end
|
||||||
end
|
until os.uptime() >= waitUntil
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
@ -55,7 +55,7 @@ function event.fire(name, ...)
|
|||||||
end
|
end
|
||||||
local elapsed = {}
|
local elapsed = {}
|
||||||
for id, info in pairs(timers) do
|
for id, info in pairs(timers) do
|
||||||
if info.after < os.clock() then
|
if info.after < os.uptime() then
|
||||||
table.insert(elapsed, info.callback)
|
table.insert(elapsed, info.callback)
|
||||||
timers[id] = nil
|
timers[id] = nil
|
||||||
end
|
end
|
||||||
@ -70,7 +70,7 @@ end
|
|||||||
|
|
||||||
function event.timer(timeout, callback)
|
function event.timer(timeout, callback)
|
||||||
local id = #timers + 1
|
local id = #timers + 1
|
||||||
timers[id] = {after = os.clock() + timeout, callback = callback}
|
timers[id] = {after = os.uptime() + timeout, callback = callback}
|
||||||
return id
|
return id
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ end
|
|||||||
function coroutine.sleep(seconds)
|
function coroutine.sleep(seconds)
|
||||||
seconds = seconds or math.huge
|
seconds = seconds or math.huge
|
||||||
checkArg(1, seconds, "number")
|
checkArg(1, seconds, "number")
|
||||||
local target = os.clock() + seconds
|
local target = os.uptime() + seconds
|
||||||
repeat
|
repeat
|
||||||
local closest = target
|
local closest = target
|
||||||
for _, info in pairs(timers) do
|
for _, info in pairs(timers) do
|
||||||
@ -106,6 +106,6 @@ function coroutine.sleep(seconds)
|
|||||||
closest = info.after
|
closest = info.after
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
event.fire(os.signal(nil, closest - os.clock()))
|
event.fire(os.signal(nil, closest - os.uptime()))
|
||||||
until os.clock() >= target
|
until os.uptime() >= target
|
||||||
end
|
end
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
local gpu = nil
|
local gpuAddress, screenAddress, keyboardAddress = nil, nil, nil
|
||||||
local gpuAddress, screenAddress, keyboardAddress = false, false, false
|
|
||||||
local width, height = 0, 0
|
local width, height = 0, 0
|
||||||
local cursorX, cursorY = 1, 1
|
local cursorX, cursorY = 1, 1
|
||||||
local cursorBlink = nil
|
local cursorBlink = nil
|
||||||
|
|
||||||
local function bindIfPossible()
|
local function rebind(gpu, screen)
|
||||||
if gpuAddress and screenAddress then
|
if gpu == gpuAddress and screen == screenAddress then
|
||||||
if not gpu then
|
return
|
||||||
gpu = driver.gpu.bind(gpuAddress, screenAddress)
|
end
|
||||||
width, height = gpu.getResolution()
|
local oldGpu, oldScreen = gpuAddress, screenAddress
|
||||||
event.fire("term_available")
|
gpuAddress, screenAddress = gpu, screen
|
||||||
end
|
if gpu and screen then
|
||||||
elseif gpu then
|
driver.gpu.bind(gpuAddress, screenAddress)
|
||||||
gpu, width, height = nil, 0, 0
|
width, height = driver.gpu.resolution(gpuAddress)
|
||||||
|
event.fire("term_available")
|
||||||
|
elseif gpuAddress and screenAddress then
|
||||||
|
width, height = 0, 0
|
||||||
event.fire("term_unavailable")
|
event.fire("term_unavailable")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -21,16 +23,20 @@ end
|
|||||||
|
|
||||||
term = {}
|
term = {}
|
||||||
|
|
||||||
|
function term.available()
|
||||||
|
return gpuAddress and screenAddress
|
||||||
|
end
|
||||||
|
|
||||||
function term.clear()
|
function term.clear()
|
||||||
if gpu then
|
if term.available() then
|
||||||
gpu.fill(1, 1, width, height, " ")
|
driver.gpu.fill(term.gpu(), 1, 1, width, height, " ")
|
||||||
end
|
end
|
||||||
cursorX, cursorY = 1, 1
|
cursorX, cursorY = 1, 1
|
||||||
end
|
end
|
||||||
|
|
||||||
function term.clearLine()
|
function term.clearLine()
|
||||||
if gpu then
|
if term.available() then
|
||||||
gpu.fill(1, cursorY, width, 1, " ")
|
driver.gpu.fill(term.gpu(), 1, cursorY, width, 1, " ")
|
||||||
end
|
end
|
||||||
cursorX = 1
|
cursorX = 1
|
||||||
end
|
end
|
||||||
@ -47,10 +53,10 @@ function term.cursorBlink(enabled)
|
|||||||
if type(enabled) == "boolean" and enabled ~= (cursorBlink ~= nil) then
|
if type(enabled) == "boolean" and enabled ~= (cursorBlink ~= nil) then
|
||||||
local function toggleBlink()
|
local function toggleBlink()
|
||||||
cursorBlink.state = not cursorBlink.state
|
cursorBlink.state = not cursorBlink.state
|
||||||
if gpu then
|
if term.available() then
|
||||||
-- 0x2588 is a solid block.
|
-- 0x2588 is a solid block.
|
||||||
local char = cursorBlink.state and string.char(0x2588) or " "
|
local char = cursorBlink.state and string.char(0x2588) or " "
|
||||||
gpu.set(cursorX, cursorY, char)
|
driver.gpu.set(term.gpu(), cursorX, cursorY, char)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if enabled then
|
if enabled then
|
||||||
@ -67,25 +73,29 @@ function term.cursorBlink(enabled)
|
|||||||
return cursorBlink ~= nil
|
return cursorBlink ~= nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function term.gpu(address)
|
function term.gpu(...)
|
||||||
if address ~= nil and ({boolean=true, string=true})[type(address)] then
|
local args = table.pack(...)
|
||||||
gpuAddress = address
|
if args.n > 0 then
|
||||||
bindIfPossible()
|
checkArg(1, args[1], "string", "nil")
|
||||||
|
rebind(args[1], term.screen())
|
||||||
end
|
end
|
||||||
return gpuAddress, gpu
|
return gpuAddress
|
||||||
end
|
end
|
||||||
|
|
||||||
function term.keyboard(address)
|
function term.keyboard(...)
|
||||||
if address ~= nil and ({boolean=true, string=true})[type(address)] then
|
local args = table.pack(...)
|
||||||
keyboardAddress = address
|
if args.n > 0 then
|
||||||
|
checkArg(1, args[1], "string", "nil")
|
||||||
|
keyboardAddress = args[1]
|
||||||
end
|
end
|
||||||
return keyboardAddress
|
return keyboardAddress
|
||||||
end
|
end
|
||||||
|
|
||||||
function term.screen(address)
|
function term.screen(...)
|
||||||
if address ~= nil and ({boolean=true, string=true})[type(address)] then
|
local args = table.pack(...)
|
||||||
screenAddress = address
|
if args.n > 0 then
|
||||||
bindIfPossible()
|
checkArg(1, args[1], "string", "nil")
|
||||||
|
rebind(term.gpu(), args[1])
|
||||||
end
|
end
|
||||||
return screenAddress
|
return screenAddress
|
||||||
end
|
end
|
||||||
@ -97,7 +107,7 @@ end
|
|||||||
function term.write(value, wrap)
|
function term.write(value, wrap)
|
||||||
value = tostring(value)
|
value = tostring(value)
|
||||||
local w, h = width, height
|
local w, h = width, height
|
||||||
if value:len() == 0 or not gpu or w < 1 or h < 1 then
|
if value:len() == 0 or not term.available() or w < 1 or h < 1 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
value = value:gsub("\t", " ")
|
value = value:gsub("\t", " ")
|
||||||
@ -107,8 +117,8 @@ function term.write(value, wrap)
|
|||||||
cursorY = cursorY + 1
|
cursorY = cursorY + 1
|
||||||
end
|
end
|
||||||
if cursorY > h then
|
if cursorY > h then
|
||||||
gpu.copy(1, 1, w, h, 0, -1)
|
driver.gpu.copy(term.gpu(), 1, 1, w, h, 0, -1)
|
||||||
gpu.fill(1, h, w, 1, " ")
|
driver.gpu.fill(term.gpu(), 1, h, w, 1, " ")
|
||||||
cursorY = h
|
cursorY = h
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -116,12 +126,12 @@ function term.write(value, wrap)
|
|||||||
while wrap and line:len() > w - cursorX + 1 do
|
while wrap and line:len() > w - cursorX + 1 do
|
||||||
local partial = line:sub(1, w - cursorX + 1)
|
local partial = line:sub(1, w - cursorX + 1)
|
||||||
line = line:sub(partial:len() + 1)
|
line = line:sub(partial:len() + 1)
|
||||||
gpu.set(cursorX, cursorY, partial)
|
driver.gpu.set(term.gpu(), cursorX, cursorY, partial)
|
||||||
cursorX = cursorX + partial:len()
|
cursorX = cursorX + partial:len()
|
||||||
checkCursor()
|
checkCursor()
|
||||||
end
|
end
|
||||||
if line:len() > 0 then
|
if line:len() > 0 then
|
||||||
gpu.set(cursorX, cursorY, line)
|
driver.gpu.set(term.gpu(), cursorX, cursorY, line)
|
||||||
cursorX = cursorX + line:len()
|
cursorX = cursorX + line:len()
|
||||||
end
|
end
|
||||||
if nl:len() == 1 then
|
if nl:len() == 1 then
|
||||||
@ -136,34 +146,34 @@ end
|
|||||||
|
|
||||||
event.listen("component_added", function(_, address)
|
event.listen("component_added", function(_, address)
|
||||||
local type = component.type(address)
|
local type = component.type(address)
|
||||||
if type == "gpu" and not gpuAddress then
|
if type == "gpu" and not term.gpu() then
|
||||||
term.gpu(address)
|
term.gpu(address)
|
||||||
elseif type == "screen" and not screenAddress then
|
elseif type == "screen" and not term.screen() then
|
||||||
term.screen(address)
|
term.screen(address)
|
||||||
elseif type == "keyboard" and not keyboardAddress then
|
elseif type == "keyboard" and not term.keyboard() then
|
||||||
term.keyboard(address)
|
term.keyboard(address)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
event.listen("component_removed", function(_, address)
|
event.listen("component_removed", function(_, address)
|
||||||
if gpuAddress == address then
|
if term.gpu() == address then
|
||||||
term.gpu(false)
|
term.gpu(nil)
|
||||||
for address in component.list() do
|
for address in component.list() do
|
||||||
if component.type(address) == "gpu" then
|
if component.type(address) == "gpu" then
|
||||||
term.gpu(address)
|
term.gpu(address)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif screenAddress == address then
|
elseif term.screen() == address then
|
||||||
term.screen(false)
|
term.screen(nil)
|
||||||
for address in component.list() do
|
for address in component.list() do
|
||||||
if component.type(address) == "screen" then
|
if component.type(address) == "screen" then
|
||||||
term.screen(address)
|
term.screen(address)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif keyboardAddress == address then
|
elseif term.keyboard() == address then
|
||||||
term.keyboard(false)
|
term.keyboard(nil)
|
||||||
for address in component.list() do
|
for address in component.list() do
|
||||||
if component.type(address) == "keyboard" then
|
if component.type(address) == "keyboard" then
|
||||||
term.keyboard(address)
|
term.keyboard(address)
|
||||||
@ -174,7 +184,7 @@ event.listen("component_removed", function(_, address)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
event.listen("screen_resized", function(_, address, w, h)
|
event.listen("screen_resized", function(_, address, w, h)
|
||||||
if address == screenAddress then
|
if term.screen() == address then
|
||||||
width = w
|
width = w
|
||||||
height = h
|
height = h
|
||||||
end
|
end
|
||||||
|
@ -6,15 +6,15 @@ local isRunning = false
|
|||||||
local function onKeyDown(_, address, char, code)
|
local function onKeyDown(_, address, char, code)
|
||||||
if isRunning then return end -- ignore events while running a command
|
if isRunning then return end -- ignore events while running a command
|
||||||
if address ~= term.keyboard() then return end
|
if address ~= term.keyboard() then return end
|
||||||
local _, gpu = term.gpu()
|
if not term.available() then return end
|
||||||
if not gpu then return end
|
|
||||||
local x, y = term.cursor()
|
local x, y = term.cursor()
|
||||||
|
local w, h = term.size()
|
||||||
local keys = driver.keyboard.keys
|
local keys = driver.keyboard.keys
|
||||||
if code == keys.back then
|
if code == keys.back then
|
||||||
if command:len() == 0 then return end
|
if command:len() == 0 then return end
|
||||||
command = command:sub(1, -2)
|
command = command:sub(1, -2)
|
||||||
term.cursor(command:len() + 3, y) -- from leading "> "
|
term.cursor(command:len() + 3, y) -- from leading "> "
|
||||||
gpu.set(x - 1, y, " ") -- overwrite cursor blink
|
driver.gpu.set(term.gpu(), x - 1, y, " ") -- overwrite cursor blink
|
||||||
elseif code == keys.enter then
|
elseif code == keys.enter then
|
||||||
if command:len() == 0 then return end
|
if command:len() == 0 then return end
|
||||||
term.cursorBlink(false)
|
term.cursorBlink(false)
|
||||||
@ -39,7 +39,7 @@ local function onKeyDown(_, address, char, code)
|
|||||||
term.cursorBlink(true)
|
term.cursorBlink(true)
|
||||||
elseif code == keys.up then
|
elseif code == keys.up then
|
||||||
command = lastCommand
|
command = lastCommand
|
||||||
gpu.fill(3, y, screenWidth, 1, " ")
|
driver.gpu.fill(term.gpu(), 3, y, w, 1, " ")
|
||||||
term.cursor(3, y)
|
term.cursor(3, y)
|
||||||
term.write(command)
|
term.write(command)
|
||||||
term.cursor(command:len() + 3, y)
|
term.cursor(command:len() + 3, y)
|
||||||
|
@ -70,16 +70,22 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
private var timeStarted = 0L // Game-world time for os.clock().
|
private var timeStarted = 0L // Game-world time [ms] for os.uptime().
|
||||||
|
|
||||||
private var worldTime = 0L // Game-world time for os.time().
|
private var worldTime = 0L // Game-world time for os.time().
|
||||||
|
|
||||||
private var lastUpdate = 0L // Real-world time for pause detection.
|
private var lastUpdate = 0L // Real-world time [ms] for pause detection.
|
||||||
|
|
||||||
private var sleepUntil = Double.PositiveInfinity // Real-world time.
|
private var cpuTime = 0L // Pseudo-real-world time [ns] for os.clock().
|
||||||
|
|
||||||
|
private var cpuStart = 0L // Pseudo-real-world time [ns] for os.clock().
|
||||||
|
|
||||||
|
private var sleepUntil = Double.PositiveInfinity // Real-world time [ms].
|
||||||
|
|
||||||
private var wasRunning = false // To signal stops synchronously.
|
private var wasRunning = false // To signal stops synchronously.
|
||||||
|
|
||||||
|
private var message: Option[String] = None // For error messages.
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
def recomputeMemory() = if (lua != null)
|
def recomputeMemory() = if (lua != null)
|
||||||
@ -154,10 +160,19 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
worldTime = owner.world.getWorldInfo.getWorldTotalTime
|
worldTime = owner.world.getWorldInfo.getWorldTotalTime
|
||||||
|
|
||||||
// Signal stops to the network. This is used to close file handles, for example.
|
// Signal stops to the network. This is used to close file handles, for example.
|
||||||
if (wasRunning && !isRunning)
|
if (wasRunning && !isRunning) {
|
||||||
owner.network.foreach(_.sendToVisible(owner, "computer.stopped"))
|
owner.network.foreach(_.sendToVisible(owner, "computer.stopped"))
|
||||||
|
owner.network.foreach(_.sendToNeighbors(owner, "gpu.fill", 1.0, 1.0, Double.PositiveInfinity, Double.PositiveInfinity, " ".getBytes("UTF-8")))
|
||||||
|
}
|
||||||
wasRunning = isRunning
|
wasRunning = isRunning
|
||||||
|
|
||||||
|
if (message.isDefined) owner.network.foreach(network => {
|
||||||
|
for ((line, row) <- message.get.lines.zipWithIndex) {
|
||||||
|
network.sendToNeighbors(owner, "gpu.set", 1.0, 1.0 + row, line.getBytes("UTF-8"))
|
||||||
|
}
|
||||||
|
message = None
|
||||||
|
})
|
||||||
|
|
||||||
// Check if we should switch states.
|
// Check if we should switch states.
|
||||||
stateMonitor.synchronized(state match {
|
stateMonitor.synchronized(state match {
|
||||||
// Computer is rebooting.
|
// Computer is rebooting.
|
||||||
@ -204,16 +219,14 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
// This can happen if we run out of memory while converting a Java
|
// This can happen if we run out of memory while converting a Java
|
||||||
// exception to a string (which we have to do to avoid keeping
|
// exception to a string (which we have to do to avoid keeping
|
||||||
// userdata on the stack, which cannot be persisted).
|
// userdata on the stack, which cannot be persisted).
|
||||||
OpenComputers.log.warning("Out of memory!") // TODO remove this when we have a component that can display crash messages
|
message = Some("not enough memory")
|
||||||
//owner.network.foreach(_.sendToVisible(owner, "computer.crashed", "not enough memory"))
|
|
||||||
close()
|
close()
|
||||||
case e: java.lang.Error if e.getMessage == "not enough memory" =>
|
case e: java.lang.Error if e.getMessage == "not enough memory" =>
|
||||||
OpenComputers.log.warning("Out of memory!") // TODO remove this when we have a component that can display crash messages
|
message = Some("not enough memory")
|
||||||
// TODO get this to the world as a computer.crashed message. problem: synchronizing it.
|
|
||||||
//owner.network.foreach(_.sendToVisible(owner, "computer.crashed", "not enough memory"))
|
|
||||||
close()
|
close()
|
||||||
case e: Throwable => {
|
case e: Throwable => {
|
||||||
OpenComputers.log.log(Level.WARNING, "Faulty Lua implementation for synchronized calls.", e)
|
OpenComputers.log.log(Level.WARNING, "Faulty Lua implementation for synchronized calls.", e)
|
||||||
|
message = Some("protocol error")
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,6 +286,9 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
rom.foreach(_.load(nbt.getCompoundTag("rom")))
|
rom.foreach(_.load(nbt.getCompoundTag("rom")))
|
||||||
kernelMemory = nbt.getInteger("kernelMemory")
|
kernelMemory = nbt.getInteger("kernelMemory")
|
||||||
timeStarted = nbt.getLong("timeStarted")
|
timeStarted = nbt.getLong("timeStarted")
|
||||||
|
cpuTime = nbt.getLong("cpuTime")
|
||||||
|
if (nbt.hasKey("message"))
|
||||||
|
message = Some(nbt.getString("message"))
|
||||||
|
|
||||||
// Clean up some after we're done and limit memory again.
|
// Clean up some after we're done and limit memory again.
|
||||||
lua.gc(LuaState.GcAction.COLLECT, 0)
|
lua.gc(LuaState.GcAction.COLLECT, 0)
|
||||||
@ -353,6 +369,9 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
nbt.setCompoundTag("rom", romNbt)
|
nbt.setCompoundTag("rom", romNbt)
|
||||||
nbt.setInteger("kernelMemory", kernelMemory)
|
nbt.setInteger("kernelMemory", kernelMemory)
|
||||||
nbt.setLong("timeStarted", timeStarted)
|
nbt.setLong("timeStarted", timeStarted)
|
||||||
|
nbt.setLong("cpuTime", cpuTime)
|
||||||
|
if (message.isDefined)
|
||||||
|
nbt.setString("message", message.get)
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
case e: Throwable => {
|
case e: Throwable => {
|
||||||
@ -417,12 +436,9 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
lua.getGlobal("os")
|
lua.getGlobal("os")
|
||||||
|
|
||||||
// Custom os.clock() implementation returning the time the computer has
|
// Custom os.clock() implementation returning the time the computer has
|
||||||
// been running, instead of the native library...
|
// been actively running, instead of the native library...
|
||||||
lua.pushScalaFunction(lua => {
|
lua.pushScalaFunction(lua => {
|
||||||
// World time is in ticks, and each second has 20 ticks. Since we
|
lua.pushNumber((cpuTime + (System.nanoTime() - cpuStart)) * 10e-10)
|
||||||
// want os.clock() to return real seconds, though, we'll divide it
|
|
||||||
// accordingly.
|
|
||||||
lua.pushNumber((worldTime - timeStarted) / 20.0)
|
|
||||||
1
|
1
|
||||||
})
|
})
|
||||||
lua.setField(-2, "clock")
|
lua.setField(-2, "clock")
|
||||||
@ -438,6 +454,16 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
})
|
})
|
||||||
lua.setField(-2, "time")
|
lua.setField(-2, "time")
|
||||||
|
|
||||||
|
// The time the computer has been running, as opposed to the CPU time.
|
||||||
|
lua.pushScalaFunction(lua => {
|
||||||
|
// World time is in ticks, and each second has 20 ticks. Since we
|
||||||
|
// want os.uptime() to return real seconds, though, we'll divide it
|
||||||
|
// accordingly.
|
||||||
|
lua.pushNumber((worldTime - timeStarted) / 20.0)
|
||||||
|
1
|
||||||
|
})
|
||||||
|
lua.setField(-2, "uptime")
|
||||||
|
|
||||||
// Allow the system to read how much memory it uses and has available.
|
// Allow the system to read how much memory it uses and has available.
|
||||||
lua.pushScalaFunction(lua => {
|
lua.pushScalaFunction(lua => {
|
||||||
lua.pushInteger(lua.getTotalMemory - kernelMemory)
|
lua.pushInteger(lua.getTotalMemory - kernelMemory)
|
||||||
@ -592,7 +618,7 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
// underlying system (which may change across releases). Add some buffer
|
// underlying system (which may change across releases). Add some buffer
|
||||||
// to avoid the init script eating up all the rest immediately.
|
// to avoid the init script eating up all the rest immediately.
|
||||||
lua.gc(LuaState.GcAction.COLLECT, 0)
|
lua.gc(LuaState.GcAction.COLLECT, 0)
|
||||||
kernelMemory = (lua.getTotalMemory - lua.getFreeMemory) + 2048
|
kernelMemory = (lua.getTotalMemory - lua.getFreeMemory) + 8 * 1024
|
||||||
recomputeMemory()
|
recomputeMemory()
|
||||||
|
|
||||||
// Clear any left-over signals from a previous run.
|
// Clear any left-over signals from a previous run.
|
||||||
@ -621,6 +647,8 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
kernelMemory = 0
|
kernelMemory = 0
|
||||||
signals.clear()
|
signals.clear()
|
||||||
timeStarted = 0
|
timeStarted = 0
|
||||||
|
cpuTime = 0
|
||||||
|
cpuStart = 0
|
||||||
future = None
|
future = None
|
||||||
sleepUntil = Long.MaxValue
|
sleepUntil = Long.MaxValue
|
||||||
|
|
||||||
@ -628,6 +656,8 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
owner.markAsChanged()
|
owner.markAsChanged()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
private def execute(value: Computer.State.Value) {
|
private def execute(value: Computer.State.Value) {
|
||||||
assert(future.isEmpty)
|
assert(future.isEmpty)
|
||||||
sleepUntil = Long.MaxValue
|
sleepUntil = Long.MaxValue
|
||||||
@ -666,6 +696,7 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Resume the Lua state and remember the number of results we get.
|
// Resume the Lua state and remember the number of results we get.
|
||||||
|
cpuStart = System.nanoTime()
|
||||||
val results = if (callReturn) {
|
val results = if (callReturn) {
|
||||||
// If we were doing a synchronized call, continue where we left off.
|
// If we were doing a synchronized call, continue where we left off.
|
||||||
assert(lua.getTop == 2)
|
assert(lua.getTop == 2)
|
||||||
@ -685,6 +716,7 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
lua.resume(1, 1 + signal.args.length)
|
lua.resume(1, 1 + signal.args.length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cpuTime += System.nanoTime() - cpuStart
|
||||||
|
|
||||||
// Check if the kernel is still alive.
|
// Check if the kernel is still alive.
|
||||||
stateMonitor.synchronized(if (lua.status(1) == LuaState.YIELD) {
|
stateMonitor.synchronized(if (lua.status(1) == LuaState.YIELD) {
|
||||||
@ -746,9 +778,7 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
else {
|
else {
|
||||||
// This can trigger another out of memory error if the original
|
// This can trigger another out of memory error if the original
|
||||||
// error was an out of memory error.
|
// error was an out of memory error.
|
||||||
OpenComputers.log.warning("Computer crashed.\n" + lua.toString(3)) // TODO remove this when we have a component that can display crash messages
|
message = Some(lua.toString(3))
|
||||||
// TODO get this to the world as a computer.crashed message. problem: synchronizing it.
|
|
||||||
//owner.network.sendToAll(owner, "computer.crashed", lua.toString(3))
|
|
||||||
}
|
}
|
||||||
close()
|
close()
|
||||||
})
|
})
|
||||||
@ -756,16 +786,13 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
|
|||||||
catch {
|
catch {
|
||||||
case e: LuaRuntimeException =>
|
case e: LuaRuntimeException =>
|
||||||
OpenComputers.log.warning("Kernel crashed. This is a bug!\n" + e.toString + "\tat " + e.getLuaStackTrace.mkString("\n\tat "))
|
OpenComputers.log.warning("Kernel crashed. This is a bug!\n" + e.toString + "\tat " + e.getLuaStackTrace.mkString("\n\tat "))
|
||||||
|
message = Some("kernel panic")
|
||||||
close()
|
close()
|
||||||
case e: LuaMemoryAllocationException =>
|
case e: LuaMemoryAllocationException =>
|
||||||
OpenComputers.log.warning("Out of memory!") // TODO remove this when we have a component that can display crash messages
|
message = Some("not enough memory")
|
||||||
// TODO get this to the world as a computer.crashed message. problem: synchronizing it.
|
|
||||||
//owner.network.sendToAll(owner, "computer.crashed", "not enough memory")
|
|
||||||
close()
|
close()
|
||||||
case e: java.lang.Error if e.getMessage == "not enough memory" =>
|
case e: java.lang.Error if e.getMessage == "not enough memory" =>
|
||||||
OpenComputers.log.warning("Out of memory!") // TODO remove this when we have a component that can display crash messages
|
message = Some("not enough memory")
|
||||||
// TODO get this to the world as a computer.crashed message. problem: synchronizing it.
|
|
||||||
//owner.network.sendToAll(owner, "computer.crashed", "not enough memory")
|
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
package li.cil.oc.server.component
|
package li.cil.oc.server.component
|
||||||
|
|
||||||
import li.cil.oc.api.network.{Node, Visibility, Message}
|
import li.cil.oc.api.network.{Node, Visibility, Message}
|
||||||
|
import li.cil.oc.common.component.ScreenEnvironment
|
||||||
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
|
||||||
class GraphicsCard extends Node {
|
class GraphicsCard extends Node {
|
||||||
val supportedResolutions = List(List(40, 24), List(80, 24))
|
val supportedResolutions = List(List(40, 24), List(80, 24))
|
||||||
|
|
||||||
|
private var screen: Option[String] = None
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override def name = "gpu"
|
override def name = "gpu"
|
||||||
|
|
||||||
override def visibility = Visibility.Neighbors
|
override def visibility = Visibility.Neighbors
|
||||||
@ -12,32 +18,66 @@ class GraphicsCard extends Node {
|
|||||||
override def receive(message: Message) = {
|
override def receive(message: Message) = {
|
||||||
super.receive(message)
|
super.receive(message)
|
||||||
message.data match {
|
message.data match {
|
||||||
case Array(screen: Array[Byte], w: Double, h: Double) if message.name == "gpu.resolution=" =>
|
case Array(address: Array[Byte]) if message.name == "gpu.bind" =>
|
||||||
|
network.fold(None: Option[Array[Any]])(network => {
|
||||||
|
network.node(new String(address, "UTF-8")) match {
|
||||||
|
case None => Some(Array(Unit, "invalid address"))
|
||||||
|
case Some(node: ScreenEnvironment) =>
|
||||||
|
screen = node.address
|
||||||
|
Some(Array(true.asInstanceOf[Any]))
|
||||||
|
case _ => Some(Array(Unit, "not a screen"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
case Array() if message.name == "network.disconnect" && message.source.address == screen => screen = None; None
|
||||||
|
case Array(w: Double, h: Double) if message.name == "gpu.resolution=" =>
|
||||||
if (supportedResolutions.contains((w.toInt, h.toInt)))
|
if (supportedResolutions.contains((w.toInt, h.toInt)))
|
||||||
trySend(new String(screen, "UTF-8"), "screen.resolution=", w.toInt, h.toInt)
|
trySend("screen.resolution=", w.toInt, h.toInt)
|
||||||
else
|
else
|
||||||
Some(Array(Unit, "unsupported resolution"))
|
Some(Array(Unit, "unsupported resolution"))
|
||||||
case Array(screen: Array[Byte]) if message.name == "gpu.resolution" =>
|
case Array() if message.name == "gpu.resolution" => trySend("screen.resolution")
|
||||||
trySend(new String(screen, "UTF-8"), "screen.resolution")
|
case Array() if message.name == "gpu.resolutions" => trySend("screen.resolutions") match {
|
||||||
case Array(screen: Array[Byte]) if message.name == "gpu.resolutions" =>
|
case Some(Array(resolutions@_*)) =>
|
||||||
trySend(new String(screen, "UTF-8"), "screen.resolutions") match {
|
Some(Array(supportedResolutions.intersect(resolutions): _*))
|
||||||
case Some(Array(resolutions@_*)) =>
|
case _ => None
|
||||||
Some(Array(supportedResolutions.intersect(resolutions): _*))
|
}
|
||||||
case _ => None
|
case Array(x: Double, y: Double, value: Array[Byte]) if message.name == "gpu.set" =>
|
||||||
}
|
trySend("screen.set", x.toInt - 1, y.toInt - 1, new String(value, "UTF-8"))
|
||||||
case Array(screen: Array[Byte], x: Double, y: Double, value: Array[Byte]) if message.name == "gpu.set" =>
|
case Array(x: Double, y: Double, w: Double, h: Double, value: Array[Byte]) if message.name == "gpu.fill" =>
|
||||||
trySend(new String(screen, "UTF-8"), "screen.set", x.toInt - 1, y.toInt - 1, new String(value, "UTF-8"))
|
|
||||||
case Array(screen: Array[Byte], x: Double, y: Double, w: Double, h: Double, value: Array[Byte]) if message.name == "gpu.fill" =>
|
|
||||||
val s = new String(value, "UTF-8")
|
val s = new String(value, "UTF-8")
|
||||||
if (s.length == 1)
|
if (s.length == 1)
|
||||||
trySend(new String(screen, "UTF-8"), "screen.fill", x.toInt - 1, y.toInt - 1, w.toInt, h.toInt, s.charAt(0))
|
trySend("screen.fill", x.toInt - 1, y.toInt - 1, w.toInt, h.toInt, s.charAt(0))
|
||||||
else
|
else
|
||||||
Some(Array(Unit, "invalid fill value"))
|
Some(Array(Unit, "invalid fill value"))
|
||||||
case Array(screen: Array[Byte], x: Double, y: Double, w: Double, h: Double, tx: Double, ty: Double) if message.name == "gpu.copy" =>
|
case Array(x: Double, y: Double, w: Double, h: Double, tx: Double, ty: Double) if message.name == "gpu.copy" =>
|
||||||
trySend(new String(screen, "UTF-8"), "screen.copy", x.toInt - 1, y.toInt - 1, w.toInt, h.toInt, tx.toInt, ty.toInt)
|
trySend("screen.copy", x.toInt - 1, y.toInt - 1, w.toInt, h.toInt, tx.toInt, ty.toInt)
|
||||||
case _ => None
|
case _ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def trySend(target: String, name: String, data: Any*) = network.fold(None: Option[Array[Any]])(net => net.sendToAddress(this, target, name, data: _*))
|
override protected def onDisconnect() = {
|
||||||
|
super.onDisconnect()
|
||||||
|
screen = None
|
||||||
|
}
|
||||||
|
|
||||||
|
override def load(nbt: NBTTagCompound) = {
|
||||||
|
super.load(nbt)
|
||||||
|
if (nbt.hasKey("screen"))
|
||||||
|
screen = Some(nbt.getString("screen"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override def save(nbt: NBTTagCompound) = {
|
||||||
|
super.save(nbt)
|
||||||
|
if (screen.isDefined)
|
||||||
|
nbt.setString("screen", screen.get)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
private def trySend(name: String, data: Any*): Option[Array[Any]] =
|
||||||
|
screen match {
|
||||||
|
case None => Some(Array(Unit, "no screen"))
|
||||||
|
case Some(screenAddress) => network.fold(None: Option[Array[Any]])(net => {
|
||||||
|
net.sendToAddress(this, screenAddress, name, data: _*)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
@ -26,6 +26,8 @@ class Network private(private val addressedNodes: mutable.Map[String, Network.No
|
|||||||
addressedNodes.values.foreach(_.data.network = Some(this))
|
addressedNodes.values.foreach(_.data.network = Some(this))
|
||||||
unaddressedNodes.foreach(_.data.network = Some(this))
|
unaddressedNodes.foreach(_.data.network = Some(this))
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override def connect(nodeA: api.network.Node, nodeB: api.network.Node) = {
|
override def connect(nodeA: api.network.Node, nodeB: api.network.Node) = {
|
||||||
val containsA = contains(nodeA)
|
val containsA = contains(nodeA)
|
||||||
val containsB = contains(nodeB)
|
val containsB = contains(nodeB)
|
||||||
@ -104,6 +106,8 @@ class Network private(private val addressedNodes: mutable.Map[String, Network.No
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override def node(address: String) = addressedNodes.get(address) match {
|
override def node(address: String) = addressedNodes.get(address) match {
|
||||||
case Some(node) => Some(node.data)
|
case Some(node) => Some(node.data)
|
||||||
case _ => None
|
case _ => None
|
||||||
@ -130,6 +134,8 @@ class Network private(private val addressedNodes: mutable.Map[String, Network.No
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override def sendToAddress(source: api.network.Node, target: String, name: String, data: Any*) = {
|
override def sendToAddress(source: api.network.Node, target: String, name: String, data: Any*) = {
|
||||||
if (source.network.isEmpty || source.network.get != this)
|
if (source.network.isEmpty || source.network.get != this)
|
||||||
throw new IllegalArgumentException("Source node must be in this network.")
|
throw new IllegalArgumentException("Source node must be in this network.")
|
||||||
@ -157,6 +163,8 @@ class Network private(private val addressedNodes: mutable.Map[String, Network.No
|
|||||||
else None
|
else None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
private def contains(node: api.network.Node) = (node.address match {
|
private def contains(node: api.network.Node) = (node.address match {
|
||||||
case None => unaddressedNodes.find(_.data == node)
|
case None => unaddressedNodes.find(_.data == node)
|
||||||
case Some(address) => addressedNodes.get(address)
|
case Some(address) => addressedNodes.get(address)
|
||||||
@ -306,6 +314,18 @@ object Network extends api.detail.NetworkAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def getNetworkNode(world: IBlockAccess, x: Int, y: Int, z: Int): Option[TileEntity with api.network.Node] =
|
||||||
|
Option(Block.blocksList(world.getBlockId(x, y, z))) match {
|
||||||
|
case Some(block) if block.hasTileEntity(world.getBlockMetadata(x, y, z)) =>
|
||||||
|
world.getBlockTileEntity(x, y, z) match {
|
||||||
|
case tileEntity: TileEntity with api.network.Node => Some(tileEntity)
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
@ForgeSubscribe
|
@ForgeSubscribe
|
||||||
def onChunkUnload(e: ChunkEvent.Unload) =
|
def onChunkUnload(e: ChunkEvent.Unload) =
|
||||||
onUnload(e.world, e.getChunk.chunkTileEntityMap.values.asScala.map(_.asInstanceOf[TileEntity]))
|
onUnload(e.world, e.getChunk.chunkTileEntityMap.values.asScala.map(_.asInstanceOf[TileEntity]))
|
||||||
@ -326,15 +346,7 @@ object Network extends api.detail.NetworkAPI {
|
|||||||
tileEntities.foreach(t => joinOrCreateNetwork(w, t.xCoord, t.yCoord, t.zCoord))
|
tileEntities.foreach(t => joinOrCreateNetwork(w, t.xCoord, t.yCoord, t.zCoord))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def getNetworkNode(world: IBlockAccess, x: Int, y: Int, z: Int): Option[TileEntity with api.network.Node] =
|
// ----------------------------------------------------------------------- //
|
||||||
Option(Block.blocksList(world.getBlockId(x, y, z))) match {
|
|
||||||
case Some(block) if block.hasTileEntity(world.getBlockMetadata(x, y, z)) =>
|
|
||||||
world.getBlockTileEntity(x, y, z) match {
|
|
||||||
case tileEntity: TileEntity with api.network.Node => Some(tileEntity)
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Node(val data: api.network.Node) {
|
private class Node(val data: api.network.Node) {
|
||||||
val edges = ArrayBuffer.empty[Edge]
|
val edges = ArrayBuffer.empty[Edge]
|
||||||
@ -382,6 +394,8 @@ object Network extends api.detail.NetworkAPI {
|
|||||||
}) filter (_.nonEmpty) map (_.get)
|
}) filter (_.nonEmpty) map (_.get)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
private class Message(@BeanProperty val source: api.network.Node,
|
private class Message(@BeanProperty val source: api.network.Node,
|
||||||
@BeanProperty val name: String,
|
@BeanProperty val name: String,
|
||||||
@BeanProperty val data: Array[Any] = Array()) extends api.network.Message {
|
@BeanProperty val data: Array[Any] = Array()) extends api.network.Message {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user