This is a read-only snapshot of the ComputerCraft forums,
taken in April 2020.
[Solved]Need help with multishell script. {READ THIS, NEED HELP}
Started by TheJebForge, 17 January 2015 - 04:43 PMPosted 17 January 2015 - 05:43 PM
I'm made the custom multishell script and the drawing happening very slow! I mean, to draw the Image. With the script, the computer drawing it in 2 seconds! In clean computer, the computer drawing it in >1 sec! Why can it be?
Edited on 22 January 2015 - 01:13 PM
Posted 17 January 2015 - 05:51 PM
There is the code of custom multishell!
Code of Manager.lua
The code of custom functions
-- Setup process switching
local parentTerm = term.current()
local w,h = parentTerm.getSize()
local tProcesses = {}
local nCurrentProcess = nil
local nRunningProcess = nil
local bShowMenu = false
local bWindowsResized = false
local function selectProcess( n )
if nCurrentProcess ~= n then
if nCurrentProcess then
local tOldProcess = tProcesses[ nCurrentProcess ]
tOldProcess.window.setVisible( false )
end
nCurrentProcess = n
if nCurrentProcess then
local tNewProcess = tProcesses[ nCurrentProcess ]
tNewProcess.window.setVisible( true )
tNewProcess.bInteracted = true
end
end
end
local function setProcessTitle( n, sTitle )
tProcesses[ n ].sTitle = sTitle
end
local function resumeProcess( nProcess, sEvent, ... )
local tProcess = tProcesses[ nProcess ]
local sFilter = tProcess.sFilter
if sFilter == nil or sFilter == sEvent or sEvent == "terminate" then
local nPreviousProcess = nRunningProcess
nRunningProcess = nProcess
term.redirect( tProcess.terminal )
local ok, result = coroutine.resume( tProcess.co, sEvent, ... )
tProcess.terminal = term.current()
if ok then
tProcess.sFilter = result
else
printError( result )
end
nRunningProcess = nPreviousProcess
end
end
local function launchProcess( tProgramEnv, sProgramPath, ... )
local tProgramArgs = { ... }
local nProcess = #tProcesses + 1
local tProcess = {}
tProcess.sTitle = fs.getName( sProgramPath )
if bShowMenu then
tProcess.window = window.create( parentTerm, 1, 2, w, h-1, false )
else
tProcess.window = window.create( parentTerm, 1, 1, w, h, false )
end
tProcess.co = coroutine.create( function()
os.run( tProgramEnv, sProgramPath, unpack( tProgramArgs ) )
if not tProcess.bInteracted then
term.setCursorBlink( false )
print( "Press any key to continue" )
os.pullEvent( "char" )
end
end )
tProcess.sFilter = nil
tProcess.terminal = tProcess.window
tProcess.bInteracted = false
tProcesses[ nProcess ] = tProcess
resumeProcess( nProcess )
return nProcess
end
local function cullProcess( nProcess )
local tProcess = tProcesses[ nProcess ]
if coroutine.status( tProcess.co ) == "dead" then
if nCurrentProcess == nProcess then
selectProcess( nil )
end
table.remove( tProcesses, nProcess )
if nCurrentProcess == nil then
if nProcess > 1 then
selectProcess( nProcess - 1 )
elseif #tProcesses > 0 then
selectProcess( 1 )
end
end
return true
end
return false
end
local function cullProcesses()
local culled = false
for n=#tProcesses,1,-1 do
culled = culled or cullProcess( n )
end
return culled
end
-- Setup the main menu
local menuMainTextColor, menuMainBgColor, menuOtherTextColor, menuOtherBgColor
if parentTerm.isColor() then
menuMainTextColor, menuMainBgColor = colors.yellow, colors.black
menuOtherTextColor, menuOtherBgColor = colors.black, colors.gray
else
menuMainTextColor, menuMainBgColor = colors.white, colors.black
menuOtherTextColor, menuOtherBgColor = colors.black, colors.white
end
local function redrawMenu()
if bShowMenu then
local nat = term.native()
nat.setBackgroundColor(128)
nat.setTextColor(256)
nat.setCursorPos(1,1)
nat.clearLine()
nat.write("NxOS")
if #tProcesses > 1 then
nat.setCursorPos(50,1)
nat.write("X")
end
end
end
local function stopProcess(nProcess)
local tProcess = tProcesses[n]
if nCurrentProcess > nProcess then
table.remove( tProcesses, nProcess )
nCurrentProcess = nCurrentProcess - 1
local tNewProcess = tProcesses[ nCurrentProcess ]
tNewProcess.window.setVisible( true )
tNewProcess.bInteracted = true
else
table.remove( tProcesses, nProcess )
if nProcess > 1 then
nCurrentProcess = nProcess - 1
local tNewProcess = tProcesses[ nCurrentProcess ]
tNewProcess.window.setVisible( true )
tNewProcess.bInteracted = true
redrawMenu()
elseif #tProcesses > 0 then
nCurrentProcess = 1
local tNewProcess = tProcesses[ nCurrentProcess ]
tNewProcess.window.setVisible( true )
tNewProcess.bInteracted = true
redrawMenu()
end
end
sleep(0.01)
end
local function resizeWindows()
local windowY, windowHeight
if bShowMenu then
windowY = 2
windowHeight = h-1
else
windowY = 1
windowHeight = h
end
for n=1,#tProcesses do
local tProcess = tProcesses[n]
local window = tProcess.window
local x,y = tProcess.window.getCursorPos()
if y > windowHeight then
tProcess.window.scroll( y - windowHeight )
tProcess.window.setCursorPos( x, windowHeight )
end
tProcess.window.reposition( 1, windowY, w, windowHeight )
end
bWindowsResized = true
end
local function setMenuVisible( bVis )
if bShowMenu ~= bVis then
bShowMenu = bVis
resizeWindows()
redrawMenu()
end
end
local multishell = {}
function multishell.getFocus()
return nCurrentProcess
end
function multishell.setFocus( n )
if n >= 1 and n <= #tProcesses then
selectProcess( n )
redrawMenu()
return true
end
return false
end
function multishell.getTitle( n )
if n >= 1 and n <= #tProcesses then
return tProcesses[n].sTitle
end
return nil
end
function multishell.setTitle( n, sTitle )
if n >= 1 and n <= #tProcesses then
setProcessTitle( n, sTitle )
redrawMenu()
end
end
function multishell.stopProcess(n)
if #tProcesses > 1 then
stopProcess(n)
else
err("Only 1 process there! (Press any button to con.)")
os.pullEvent("key")
end
end
function multishell.getCurrent()
return nRunningProcess
end
function multishell.launch( tProgramEnv, sProgramPath, ... )
if #tProcesses < 16 then
local previousTerm = term.current()
setMenuVisible( (#tProcesses + 1) >= 2 )
local nResult = launchProcess( tProgramEnv, sProgramPath, ... )
redrawMenu()
term.redirect( previousTerm )
return nResult
else
err("Too many processes ran!")
print("Press Anu Button")
os.pullEvent("key")
end
end
function multishell.getCount()
return #tProcesses
end
function multishell.setMenuVisible( bol )
setMenuVisible( bol )
end
-- Begin
setMenuVisible( false )
redrawMenu()
selectProcess( launchProcess( {
["shell"] = shell,
["multishell"] = multishell,
}, "/rom/programs/shell" ) )
redrawMenu()
-- Run processes
while #tProcesses > 0 do
-- Get the event
local tEventData = { os.pullEventRaw() }
local sEvent = tEventData[1]
if sEvent == "term_resize" then
-- Resize event
w,h = parentTerm.getSize()
resizeWindows()
redrawMenu()
elseif sEvent == "char" or sEvent == "key" or sEvent == "paste" or sEvent == "terminate" then
-- Keyboard event
-- Passthrough to current process
resumeProcess( nCurrentProcess, unpack( tEventData ) )
if cullProcess( nCurrentProcess ) then
setMenuVisible( #tProcesses >= 1 )
redrawMenu()
end
elseif sEvent == "mouse_click" then
-- Click event
local button, x, y = tEventData[2], tEventData[3], tEventData[4]
if x >= 1 and x <= 5 and y == 1 and bShowMenu and not (tProcesses[#tProcesses].sTitle == "Manager.lua") then
selectProcess( multishell.launch({
["shell"] = shell,
["multishell"] = multishell,
},"/NxOS/Core/Manager.lua"))
end
if x == 50 and y == 1 and bShowMenu and #tProcesses > 1 then
stopProcess(nCurrentProcess)
end
-- Passthrough to current process
resumeProcess( nCurrentProcess, sEvent, button, x, (bShowMenu and y-1) or y )
if cullProcess( nCurrentProcess ) then
setMenuVisible( #tProcesses >= 1 )
redrawMenu()
end
elseif sEvent == "mouse_drag" or sEvent == "mouse_scroll" then
-- Other mouse event
local p1, x, y = tEventData[2], tEventData[3], tEventData[4]
if not (bShowMenu and y == 1) then
-- Passthrough to current process
resumeProcess( nCurrentProcess, sEvent, p1, x, (bShowMenu and y-1) or y )
if cullProcess( nCurrentProcess ) then
setMenuVisible( #tProcesses >= 1 )
redrawMenu()
end
end
else
-- Other event
-- Passthrough to all processes
local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event
for n=1,nLimit do
resumeProcess( n, unpack( tEventData ) )
end
if cullProcesses() then
setMenuVisible( #tProcesses >= 1 )
redrawMenu()
end
end
if bWindowsResized then
-- Pass term_resize to all processes
local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event
for n=1,nLimit do
resumeProcess( n, "term_resize" )
end
bWindowsResized = false
if cullProcesses() then
setMenuVisible( #tProcesses >= 1 )
redrawMenu()
end
end
end
-- Shutdown
term.redirect( parentTerm )
Code of Manager.lua
function p(x,y,color)
paintutils.drawPixel(x,y,color)
end
function l(x,y,endx,endy,color)
paintutils.drawLine(x,y,endx,endy,color)
end
function fg(app)
shell.switchTab(shell.openTab("test"))
end
function sCP(x,y)
term.setCursorPos(x,y)
end
function cl()
term.clear()
end
function blink(bol)
term.setCursorBlink(bol)
end
function box(x,y,endx,endy,color)
for i = 1,(endx - x + 1),1 do
for j = 1,(endy - y + 1),1 do
p(x - 1 + i, y - 1 + j,color)
end
end
end
function tpr(text,x,y)
term.setCursorPos(x,y)
term.write(text)
end
function cpr(text,y)
local w,h = term.getSize()
local x = w / 2 - string.len(text) / 2
tpr(text,x,y)
end
function bg(color)
term.setBackgroundColor(color)
end
function tg(color)
term.setTextColor(color)
end
function reloadConfig()
config = {}
fil = fs.open("NxOS/Core/Data/UserPreferences.lua","r")
local temp = fil.readLine()
local t = 0
while temp do
t = t + 1
config[t] = temp
temp = fil.readLine()
end
fil.close()
end
function modConfig(id,text)
config[id] = text
fil = fs.open("NxOS/Core/Data/UserPreferences.lua","w")
for i = 1, #config,1 do
fil.writeLine(config[i])
end
fil.close()
end
box(1,1,51,18,1)
tg(32768)
tpr("ID",2,1)
tpr("Name",5,1)
-- Vars
pwm = 0
local function PwMenu()
box(2,14,11,17,256)
tg(32768)
tpr("ShutDown",3,15)
tpr("Reboot",4,16)
while true do
local event,b,x,y = os.pullEvent()
if event == "mouse_click" then
if x >= 2 and x <= 11 and y <= 17 and y >= 14 and b == 1 then
if y == 16 then
os.reboot()
end
if y == 15 then
os.shutdown()
end
else
break
end
end
end
end
local function refresh()
for i = 1,16, 1 do
l(2,i+1,50,i+1,1)
end
for i = 1, multishell.getCount() do
l(2,i+1,50,i+1,256)
end
if pwm == 0 then
bg(256)
tpr("Power ^",2,18)
else
bg(128)
tpr("Power v",2,18)
end
bg(256)
for i = 1, multishell.getCount(),1 do
tpr(i,2,i+1)
tpr(multishell.getTitle(i),5,i+1)
bg(128)
tg(32768)
if multishell.getTitle(i) == multishell.getTitle(multishell.getCurrent()) then
else
tpr("Sw.To",43,i+1)
end
if i > 1 then
if multishell.getCurrent() == i then
else
tpr("X",49,i+1)
end
end
bg(256)
tg(32768)
end
end
refresh()
while true do
local event,b,x,y = os.pullEvent()
if event == "mouse_click" then
if x >= 2 and x <= 13 and b == 1 then
end
if x >= 2 and x <= 8 and y == 18 and b == 1 then
pwm = 1
refresh()
PwMenu()
pwm = 0
box(1,14,20,18,1)
refresh()
end
for i = 1, multishell.getCount(),1 do
if x == 49 and y == (i + 1) and b == 1 and i > 1 then
if multishell.getCurrent() == i then
else
multishell.stopProcess(i)
sleep(0.01)
refresh()
end
end
end
if x >= 43 and x <= 47 and b == 1 then
if y == 2 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 3 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 4 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 5 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 6 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 7 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 8 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 9 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 10 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 11 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 12 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 13 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 14 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 15 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 16 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
if y == 17 then
if multishell.getCurrent() == y - 1 then
else
shell.switchTab(y - 1)
return
end
end
end
end
end
The code of custom functions
function p(x,y,color)
paintutils.drawPixel(x,y,color)
end
function l(x,y,endx,endy,color)
paintutils.drawLine(x,y,endx,endy,color)
end
function fg(app)
local dir = shell.dir() .. "/"
shell.run("cd /")
shell.run("fg "..app)
shell.run("cd "..dir)
end
function bbg(app)
local dir = shell.dir() .. "/"
shell.run("cd /")
shell.run("bg "..app)
shell.run("cd "..dir)
end
function sCP(x,y)
term.setCursorPos(x,y)
end
function cl()
term.clear()
end
function blink(bol)
term.setCursorBlink(bol)
end
function box(x,y,endx,endy,color)
for i = 1,(endx - x + 1),1 do
for j = 1,(endy - y + 1),1 do
p(x - 1 + i, y - 1 + j,color)
end
end
end
function tpr(text,x,y)
term.setCursorPos(x,y)
term.write(text)
end
function cpr(text,y)
local w,h = term.getSize()
local x = w / 2 - string.len(text) / 2
tpr(text,x,y)
end
function bg(color)
term.setBackgroundColor(color)
end
function tg(color)
term.setTextColor(color)
end
function reloadConfig()
config = {}
fil = fs.open("NxOS/Core/Data/UserPreferences.lua","r")
local temp = fil.readLine()
local t = 0
while temp do
t = t + 1
config[t] = temp
temp = fil.readLine()
end
fil.close()
end
function modConfig(id,text)
config[id] = text
fil = fs.open("NxOS/Core/Data/UserPreferences.lua","w")
for i = 1, #config,1 do
fil.writeLine(config[i])
end
fil.close()
end
Posted 17 January 2015 - 05:54 PM
I'm not sure what exactly you are doing.I'm made the custom multishell script and the drawing happening very slow! I mean, to draw the Image. With the script, the computer drawing it in 2 seconds! In clean computer, the computer drawing it in <1 sec! Why can it be?
About all multishell program have their applications one layer higher which means one level lower in performance.
otherwise the applications themselves need to be compatible to the specific multishell. it's because the call is "routed" one time more often than usual. it makes drawing slow. there are even benchmarks to prove this behaviour.
OMG, please spoiler them or better put a link to a gist or pastebin(cause syntax highlighting)
Posted 17 January 2015 - 05:55 PM
Can someone please fix my script! I'm will be very thankful!
Posted 17 January 2015 - 06:00 PM
Can someone please fix my script! I'm will be very thankful!
Dude, you need to tell more about your actual problem. you can't expect us to be solving your problems magically without even knowing the problem
It seems rather rude to me(maybe I'm sensitive right now), that you call to us to fix your problems.
and also, if you change to container your code, please edit your title as well.
Posted 17 January 2015 - 06:02 PM
Problem is in performance! Sorry, but I don't even understand why the performance is went down! Can you tell me why the performance is low there? Thanks, anyway…
Posted 17 January 2015 - 06:05 PM
You stated there are two cases, which defer in their performance. Could you try to explain them in more detail? That would help the problem solving, because right now I see a ton of code, which at some point may have an issue. So when is it fast, and when is it slow?Problem is in performance! Sorry, but I don't even understand why the performance is went down! Can you tell me why the performance is low there? Thanks, anyway…
Posted 17 January 2015 - 06:08 PM
When I'm trying to use FOR with any visual function, the performance going down! For example, I'm trying to draw the wallpaper by paintutils.drawImage(img,x,y), the wallpaper prints in 2 seconds. But on computer where the script isn't installed the wallpaper draws in >1 sec!
Edited on 17 January 2015 - 05:09 PM
Posted 17 January 2015 - 06:15 PM
First things first your manager code has ~100 lines of identical if … elseif … statements. There is an or keyword (or you can do if y >= 17 and y <= 2 then … end).
On computers without multishell you draw like this: terminal API (term.draw) > native terminal object
On multishell you have: terminal API > window API > native terminal
On your code you have: terminal API > window API > window API > native terminal.
Multiple layers of multishell will slow slow down things a lot, though I don't see why it would take 2 seconds (ClamShell have a buffer implemented for scrolling and there is not that much performance difference).
On computers without multishell you draw like this: terminal API (term.draw) > native terminal object
On multishell you have: terminal API > window API > native terminal
On your code you have: terminal API > window API > window API > native terminal.
Multiple layers of multishell will slow slow down things a lot, though I don't see why it would take 2 seconds (ClamShell have a buffer implemented for scrolling and there is not that much performance difference).
Edited on 17 January 2015 - 05:16 PM
Posted 17 January 2015 - 06:18 PM
Ok, I don't "really" see an issue with that. Performance loss is completely normal when switching form single-shell to multishell. Although 2 seconds are a really really long time, I wouldn't assume, that there's a solution to solve it without rewriting like the half of it.
Posted 17 January 2015 - 06:18 PM
Ohhh! That why! Thanks! I'll try that!
Posted 17 January 2015 - 06:24 PM
I'm tried to change nat to parentTerm (in redraw), and the performance has became a bit higher! Now the wallpaper drawing in 1,5 seconds…
But the problem hasn't gone…
But the problem hasn't gone…
Edited on 17 January 2015 - 05:26 PM
Posted 17 January 2015 - 06:26 PM
what are you measuring that with? are you on an emulator?I'm tried to change nat to parentTerm (in redraw), and the performance has became a bit higher! Now the wallpaper drawing in 1,5 seconds…
Posted 17 January 2015 - 06:29 PM
Yeah, emu. (CCEMUREDUX)
Posted 17 January 2015 - 06:31 PM
what are you measuring that with?
Edited on 17 January 2015 - 05:31 PM
Posted 17 January 2015 - 06:32 PM
Huh?
What are you talking about?.
What are you talking about?.
Edited on 17 January 2015 - 05:35 PM
Posted 17 January 2015 - 06:35 PM
Your 1,5 Seconds. are you reading them off of something? do you use a physical clock? os.clock? http-reqests to timeservers?
Posted 17 January 2015 - 06:37 PM
stopwatch app on my phone
Posted 20 January 2015 - 03:47 PM
So anyone can help me?
Posted 21 January 2015 - 02:39 AM
One way in which your code loses efficiency is in how you handle your "shortname" functions. Every function call your script performs takes time (this would apply even if you were calling empty functions).
For example, this:
… takes more time to execute than this:
… because you are doubling the amount of function calls you're performing.
On the other hand, if you do this:
… it'll actually run even faster, because referencing paintutils.drawLine involves a lookup into the paintutils table - but if you save the function pointer directly into l, then calling l skips that table lookup in future!
Localising the l variable should speed things up further when you go to use it.
Edit:
Then there's this sort of thing:
Consider what the drawPixel function does: it moves the cursor, it sets the background colour, then it draws a single space. Drawing a 10x10 box would call it a hundred times. That's a hundred times you're moving the cursor, a hundred times you're setting the background colour, and a hundred individual calls you're making to draw spaces.
Now let's say you did it like this:
You'd only set the background colour once, and only trigger one cursor-move and screen-write per line.
For example, this:
function l(x,y,endx,endy,color) -- l is a new function which runs the paintutils.drawLine function
paintutils.drawLine(x,y,endx,endy,color)
end
.
.
.
for i = 1, multishell.getCount() do
l(2,i+1,50,i+1,256) -- call l, which then calls paintutils.drawLine = 2 calls
end
… takes more time to execute than this:
for i = 1, multishell.getCount() do
paintutils.drawLine(2,i+1,50,i+1,256) -- just call paintutils.drawLine = 1 call
end
… because you are doubling the amount of function calls you're performing.
On the other hand, if you do this:
local l = paintutils.drawLine -- l and paintutils.drawLine now lead to the same copy of the function stored in RAM
.
.
.
for i = 1, multishell.getCount() do
l(2,i+1,50,i+1,256) -- runs the drawLine function directly = 1 call
end
… it'll actually run even faster, because referencing paintutils.drawLine involves a lookup into the paintutils table - but if you save the function pointer directly into l, then calling l skips that table lookup in future!
Localising the l variable should speed things up further when you go to use it.
Edit:
Then there's this sort of thing:
function box(x,y,endx,endy,color)
for i = 1,(endx - x + 1),1 do
for j = 1,(endy - y + 1),1 do
p(x - 1 + i, y - 1 + j,color) -- p calls paintutils.drawPixel()
end
end
end
Consider what the drawPixel function does: it moves the cursor, it sets the background colour, then it draws a single space. Drawing a 10x10 box would call it a hundred times. That's a hundred times you're moving the cursor, a hundred times you're setting the background colour, and a hundred individual calls you're making to draw spaces.
Now let's say you did it like this:
function box(x,y,endx,endy,color)
term.setBackgroundColour(color)
for j = y, endy do
term.setCursorPos(x, j)
term.write(string.rep(" ", endx - x + 1))
end
end
You'd only set the background colour once, and only trigger one cursor-move and screen-write per line.
Edited on 21 January 2015 - 02:20 AM
Posted 22 January 2015 - 02:12 PM
Thanks! It's became more faster than I have before!
Edited on 22 January 2015 - 01:14 PM