Guest User

Untitled

a guest
Dec 29th, 2014
258
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.85 KB | None | 0 0
  1. -- Print out the program usage
  2. function printUsage()
  3.   print("Usage: bme <sidename> <filename>")
  4.   print("     <sidename> Side of ME Controller eg. top")
  5.   print("     <filename> File containing stock")
  6.   print("                definitions. If the does not")
  7.   print("                exist, it will be created.")
  8.   print("")
  9.   print("Usage: bme help")
  10.   print("     Get help")
  11. end
  12.  
  13. -- Print out help instructions
  14. function printHelp()
  15.   print("There is no help yet.")
  16. end
  17.  
  18. -- Loads definitions (intent) from file
  19. -- into the LEVELDICT global variable.
  20. function loadIntent(file)
  21.   local f = fs.open(file, "r")
  22.   if f == nil then
  23.     print("The file '"..file.."' could not be loaded.")
  24.     return {}
  25.   end
  26.   local r = {}
  27.   local line = f.readLine()
  28.   local n = 1
  29.   while line ~= nil do
  30.     if line ~= "" then
  31.       local index = 1
  32.       local name
  33.       for i in string.gmatch(line, "[a-zA-Z%s]+") do
  34.         name = i
  35.       end
  36.      
  37.       local le = {}
  38.       for i in string.gmatch(line, "%d+") do
  39.         le[index] = i
  40.         index = index + 1
  41.       end
  42.       r[n] = {}
  43.       r[n].id = tonumber(le[1])
  44.       r[n].name = name
  45.       r[n].meta = tonumber(le[2])
  46.       r[n].amt = tonumber(le[3])
  47.       r[n].aug = 0
  48.       r[n].c = 0
  49.       r[n].cc = 0
  50.       n = n + 1
  51.     end
  52.     line = f.readLine()
  53.   end
  54.   f.close()
  55.   return r
  56. end
  57.  
  58. -- Saves definitons in the LEVELDICT global variable into the
  59. -- given file. The previous contents of the file are lost.
  60. function saveIntent(file)
  61.   local f = fs.open(file, "w")
  62.   assert (f ~= nil, "The intent file could not be opened to write to.")
  63.   for i,tab in ipairs(LEVELDICT) do
  64.     f.writeLine(tab.name..":"..tab.id..":"..tab.meta..":"..tab.amt)
  65.   end
  66.   f.close()
  67. end
  68.  
  69. -- Check the LEVELDICT definitions against the current stock
  70. -- including pending jobs. Submit crafting requests when necessary.
  71. -- This method will be slow for a large LEVELDICT.
  72. function stockCycle()
  73.   local t0 = os.clock()
  74.   local jobs = ME.getJobList()
  75.   local jobsNameMap = {}
  76.   for k,v in pairs(jobs) do
  77.     jobsNameMap["" .. v.id .. v.dmg] = v.qty
  78.   end
  79.   for _, tab in ipairs(LEVELDICT) do
  80.     if tab.name ~= "size" then
  81.       tab.c = ME.countOfItemType(tab.id, tab.meta)
  82.       if jobsNameMap[""..tab.id .. tab.meta] ~= nil then
  83.         tab.cc = jobsNameMap[""..tab.id .. tab.meta]
  84.       else
  85.         tab.cc = 0
  86.       end
  87.       local effectiveAmt = tab.c + tab.cc
  88.       if effectiveAmt < tab.amt then
  89.         ME.requestCrafting({id=tab.id,qty=tab.amt-effectiveAmt,dmg=tab.meta})
  90.       end
  91.       tab.aug = 0
  92.     end
  93.   end
  94.   os.queueEvent("stock_complete")
  95.   if os.clock()-t0 > INTERVAL then
  96.     os.queueEvent("notif", "Warning: the stock cycle took more time to complete than the stock interval. This is unsafe and may eventually lead to system failure.")
  97.   end
  98. end
  99.  
  100. -- Asks the user for a strong. The cursor position
  101. -- should be set before calling this method.
  102. function getString()
  103.   local n = io.read()
  104.   while n == nil or n == "" do
  105.     print("Input somehting")
  106.     term.write(" : ")
  107.     n = io.read()
  108.   end
  109.   return n
  110. end
  111.  
  112. -- Asks the user for a number. The cursor position
  113. -- should be set before calling this method.
  114. function getNumber()
  115.   local n = tonumber(io.read())
  116.   while n == nil or n < 0 do
  117.     print("Input a number")
  118.     term.write(" : ")
  119.     n = tonumber(io.read())
  120.   end
  121.   return n
  122. end
  123.  
  124. -------------------------------------------------
  125. -- GUI Methods
  126. -------------------------------------------------
  127.  
  128. -- Draws the title bar at the top which contains the
  129. -- name of the application and the time.
  130. function paintTitleBar()
  131.   paintutils.drawLine(1,1,WIDTH,1, colors.blue)
  132.   term.setTextColor(colors.white)
  133.   term.setCursorPos(2, 1)
  134.   term.write("bitRAKE's ME Manager")
  135.   term.setCursorPos(WIDTH-8,1)
  136.   term.write(textutils.formatTime(os.time(), false))
  137. end
  138.  
  139. -- Draws the notification bar at the bottom. It will
  140. -- display the given message and ME system capacity.
  141. function paintNotificationBar(msg, cap)
  142.   paintutils.drawLine(1,HEIGHT,WIDTH,HEIGHT, colors.lightBlue)
  143.   term.setCursorPos(2, HEIGHT)
  144.   term.setTextColor(colors.black)
  145.   term.write(msg)
  146.   local captext = cap .. "% Cap."
  147.   term.setCursorPos(WIDTH-string.len(captext), HEIGHT)
  148.   term.write(captext)
  149. end
  150.  
  151. -- Clears the pixels and buttons on the left side menu.
  152. function clearMenu(width)
  153.   for i=2,HEIGHT-1 do
  154.     paintutils.drawLine(1,i,width,i,colors.white)
  155.     for j=1,width do
  156.       BUTTONS[j][i] = nil
  157.     end
  158.   end
  159. end
  160.  
  161. -- Draws the left menu depending on which definition (or none)
  162. -- is selected.
  163. function paintMenu(selected)
  164.   local rightPos = math.floor(WIDTH/2-6)
  165.   clearMenu(rightPos)
  166.   paintutils.drawLine(1,3,rightPos,3,colors.lightBlue)
  167.   if selected < 0 then
  168.     term.setCursorPos(1,2)
  169.     term.setBackgroundColor(colors.white)
  170.     term.write("Main Menu")
  171.     term.setTextColor(colors.black)
  172.     term.setBackgroundColor(colors.lightGray)
  173.     term.setCursorPos(2,5)
  174.     term.write("New Definition")
  175.     BUTTONS.add(2,5,17, "create")
  176.     term.setCursorPos(2,7)
  177.     if PAUSED then
  178.       term.write("Resume Stocking")
  179.       BUTTONS.add(2,7,15,"resume")
  180.     else
  181.       term.write("Pause Stocking")
  182.       BUTTONS.add(2,7,13,"pause")
  183.     end
  184.     term.setCursorPos(rightPos-5,HEIGHT-2)
  185.     term.write("Exit")
  186.     BUTTONS.add(rightPos-5, HEIGHT-2, 4, "exit")
  187.   else
  188.     term.setTextColor(colors.black)
  189.     term.setBackgroundColor(colors.white)
  190.     term.setCursorPos(1, 2)
  191.     term.write(LEVELDICT[selected].name)
  192.     term.setCursorPos(2,5)
  193.     term.setBackgroundColor(colors.lightGray)
  194.     term.write("Edit")
  195.     BUTTONS.add(2,5,4,"ed")
  196.     term.setCursorPos(2,7)
  197.     term.write("Remove Entry")
  198.     BUTTONS.add(2,7,12,"rm")
  199.     term.setCursorPos(rightPos-7,HEIGHT-2)
  200.     term.write("Cancel")
  201.     BUTTONS.add(rightPos-7,HEIGHT-2,6,"cancel")
  202.    
  203.     term.setBackgroundColor(colors.white)
  204.     term.setCursorPos(1,9)
  205.     print(" ID:        "..LEVELDICT[selected].id ..":".. LEVELDICT[selected].meta)
  206.     print(" Stored:    "..LEVELDICT[selected].c)
  207.     print(" Crafting:  "..LEVELDICT[selected].cc)
  208.   end
  209. end
  210.  
  211. -- Asks the user to update the selected definition using the
  212. -- space in the left menu
  213. function editEntry(id)
  214.   assert(type(id) == "number", "editEntry expects a number")
  215.   local rightPos = math.floor(WIDTH/2-6)
  216.   clearMenu(rightPos)
  217.   paintutils.drawLine(1,3,rightPos,3,colors.lightBlue)
  218.   term.setTextColor(colors.black)
  219.   term.setBackgroundColor(colors.white)
  220.   term.setCursorPos(1, 2)
  221.   term.write("Edit "..LEVELDICT[id].name)
  222.   term.setCursorPos(1,5)
  223.   term.write("Current Level: "..LEVELDICT[id].amt)
  224.   term.setCursorPos(1,6)
  225.   term.write("New Level: ")
  226.   local nl = getNumber()
  227.   LEVELDICT[id].amt = nl
  228.   os.queueEvent("notif", "New level for "..LEVELDICT[id].name..": "..nl)
  229. end
  230.  
  231. -- Asks the user to create a new definition using the space
  232. -- in the left menu
  233. function createEntry()
  234.   local rightPos = math.floor(WIDTH/2-6)
  235.   clearMenu(rightPos)
  236.   paintutils.drawLine(1,3,rightPos,3,colors.lightBlue)
  237.   term.setTextColor(colors.black)
  238.   term.setBackgroundColor(colors.white)
  239.   term.setCursorPos(1,2)
  240.   term.write("New Definition")
  241.   term.setCursorPos(1, 5)
  242.   print("Item Name: ")
  243.   local name = getString()
  244.  
  245.   clearMenu(rightPos)
  246.   paintutils.drawLine(1,3,rightPos,3,colors.lightBlue)
  247.   term.setTextColor(colors.black)
  248.   term.setBackgroundColor(colors.white)
  249.   term.setCursorPos(1,2)
  250.   term.write("New Definition")
  251.   term.setCursorPos(1, 5)
  252.   print("Item ID: ")
  253.   local id = getNumber()
  254.  
  255.   clearMenu(rightPos)
  256.   paintutils.drawLine(1,3,rightPos,3,colors.lightBlue)
  257.   term.setTextColor(colors.black)
  258.   term.setBackgroundColor(colors.white)
  259.   term.setCursorPos(1,2)
  260.   term.write("New Definition")
  261.   term.setCursorPos(1, 5)
  262.   print("Item Meta (or 0): ")
  263.   local meta = getNumber()
  264.  
  265.   clearMenu(rightPos)
  266.   paintutils.drawLine(1,3,rightPos,3,colors.lightBlue)
  267.   term.setTextColor(colors.black)
  268.   term.setBackgroundColor(colors.white)
  269.   term.setCursorPos(1,2)
  270.   term.write("New Definition")
  271.   term.setCursorPos(1, 5)
  272.   print("Stock Level: ")
  273.   local level = getNumber()
  274.   local next = #LEVELDICT + 1
  275.   LEVELDICT[next] = {}
  276.   LEVELDICT[next].name = name
  277.   LEVELDICT[next].id = id
  278.   LEVELDICT[next].meta = meta
  279.   LEVELDICT[next].amt = level
  280.   LEVELDICT[next].c = 0
  281.   LEVELDICT[next].cc = 0
  282.   os.queueEvent("notif", "New definition for "..name)
  283. end
  284.  
  285. -- Clears the pixels in the right menu (intent list)
  286. function clearIntentList(leftPos)
  287.   for j=4,HEIGHT-1 do
  288.     paintutils.drawLine(leftPos, j, WIDTH, j, colors.white)
  289.   end
  290. end
  291.  
  292. -- Draws the intent list (left menu) using the LEVELDICT
  293. -- global variable.
  294. function paintIntentList(index, selected)
  295.   local leftPos = math.floor(WIDTH/2-4)
  296.   local vheight = HEIGHT-5
  297.   paintutils.drawLine(leftPos-1, 2, leftPos-1, HEIGHT-1, colors.gray)
  298.   paintutils.drawLine(leftPos,2,WIDTH,2,colors.white)
  299.   term.setCursorPos(leftPos,2)
  300.   term.setTextColor(colors.black)
  301.   term.setBackgroundColor(colors.white)
  302.   if PAUSED then
  303.     term.write("Stocking: ")
  304.     term.setTextColor(colors.red)
  305.     term.write("Paused")
  306.   else
  307.     term.write("Stocking: ")
  308.   end
  309.   paintutils.drawLine(leftPos,3,WIDTH,3,colors.lightBlue)
  310.  
  311.   clearIntentList(leftPos)
  312.   term.setTextColor(colors.black)
  313.   local j = 1
  314.   local tov = math.min(index+vheight, #LEVELDICT)
  315.   for i=index,tov do
  316.     local tab = LEVELDICT[i]
  317.     if tab.c < tab.amt then
  318.       paintutils.drawPixel(leftPos, j+3,colors.red)
  319.     else
  320.       paintutils.drawPixel(leftPos,j+3,colors.green)
  321.     end
  322.     term.setBackgroundColor(colors.white)
  323.     if i == selected then term.setBackgroundColor(colors.yellow) end
  324.     local text = tab.name..": "..tab.c.."/"..tab.amt
  325.     BUTTONS.add(leftPos,j + 3,WIDTH-leftPos, i)
  326.     term.write(text)
  327.     j = j + 1
  328.   end
  329.   -- ScrollBar
  330.   if #LEVELDICT > 0 then
  331.     paintutils.drawLine(WIDTH,4,WIDTH,HEIGHT-1,colors.gray)
  332.     paintutils.drawPixel(WIDTH,vheight*index/#LEVELDICT + 4,colors.black)
  333.   end
  334. end
  335.  
  336. -------------------------------------------------
  337. -- Control Loops
  338. -------------------------------------------------
  339.  
  340. -- This simply run the stockCycle on INTERVAL as long
  341. -- as stocking is not paused.
  342. function stockerLoop()
  343.   local tid = os.startTimer(1)
  344.   local done = false
  345.  
  346.   while not done do
  347.     local e,p1,p2,p3 = os.pullEvent()
  348.     if e == "timer" and p1 == tid then
  349.       if not PAUSED then
  350.         stockCycle()
  351.       end
  352.       os.queueEvent("notif", "Ready")
  353.       tid = os.startTimer(INTERVAL)
  354.     end
  355.   end
  356. end
  357.  
  358. -- This loop handles UI
  359. function UILoop()
  360.   -- Setup the SCROLLS mask (so that the right menu will be scrollable)
  361.   SCROLLS.add(math.floor(WIDTH/2-4), 4, WIDTH-1, HEIGHT-1, "intent_scroll")
  362.   -- UI Variables
  363.   local si = 1
  364.   local selected = -1
  365.   local cap = 0
  366.  
  367.   term.setBackgroundColor(colors.white)
  368.   term.clear()
  369.   paintTitleBar()
  370.   paintIntentList(si, selected)
  371.   paintMenu(selected)
  372.  
  373.   local tid = os.startTimer(2)
  374.   local captid = os.startTimer(5)
  375.   os.queueEvent("notif", "Welcome!")
  376.   while true do
  377.     local e,p1,p2 = os.pullEvent()
  378.     if e == "notif" then
  379.       paintNotificationBar(p1, cap)
  380.     elseif e == "timer" then
  381.       if p1 == tid then
  382.         term.setBackgroundColor(colors.white)
  383.         term.setCursorPos(1,1)
  384.         term.clearLine()
  385.         paintTitleBar()
  386.         paintIntentList(si, selected)
  387.         tid = os.startTimer(INTERVAL)
  388.       elseif p1 == captid then
  389.         local tb = ME.getTotalBytes()
  390.         local fb = ME.getFreeBytes()
  391.         cap = math.floor((tb-fb)/tb*100)
  392.         paintNotificationBar("Ready", cap)
  393.         captid = os.startTimer(60)
  394.       end
  395.     elseif e == "intent_scroll" then
  396.       si = si + p1
  397.       if si < 1 then si = 1 end
  398.       if si > #LEVELDICT then si = #LEVELDICT end
  399.       paintIntentList(si, selected)
  400.     elseif e == "button" then
  401.       if type(p1) == "number" then
  402.         selected = p1
  403.         paintIntentList(si, selected)
  404.         paintMenu(selected)
  405.       elseif p1 == "cancel" then
  406.         selected = -1
  407.         paintIntentList(si, selected)
  408.         paintMenu(selected)
  409.       elseif p1 == "create" then
  410.         createEntry()
  411.         selected = #LEVELDICT
  412.         paintMenu(selected)
  413.         paintIntentList(si, selected)
  414.         saveIntent(INTENTFILE)
  415.         tid = os.startTimer(1)
  416.       elseif p1 == "pause" then
  417.         PAUSED = true
  418.         paintMenu(selected)
  419.         paintIntentList(si, selected)
  420.       elseif p1 == "resume" then
  421.         PAUSED = false
  422.         paintMenu(selected)
  423.         paintIntentList(si, selected)
  424.       elseif p1 == "ed" then
  425.         editEntry(selected)
  426.         paintMenu(selected)
  427.         paintIntentList(si, selected)
  428.         tid = os.startTimer(1) -- Restart the timer
  429.       elseif p1 == "rm" then
  430.         table.remove(LEVELDICT, selected)
  431.         selected = -1
  432.         paintMenu(selected)
  433.         paintIntentList(si, selected)
  434.         saveIntent(INTENTFILE)
  435.         tid = os.startTimer(1) -- Restart the timer
  436.       elseif p1 == "exit" then
  437.         return
  438.       end
  439.     end
  440.   end
  441. end
  442.  
  443. -- Loop that handles raw user input and then dispatches
  444. -- meaningful events using the BUTTONS and SCROLLS masks
  445. function inputLoop()
  446.   while true do
  447.     local e, p1, p2, p3 = os.pullEvent()
  448.     if e == "mouse_click" then
  449.       if BUTTONS[p2][p3] ~= nil then
  450.         os.queueEvent("button", BUTTONS[p2][p3])
  451.       end
  452.     elseif e == "mouse_scroll" then
  453.       if SCROLLS[p2][p3] ~= nil then
  454.         os.queueEvent(SCROLLS[p2][p3], p1)
  455.       end
  456.     end
  457.   end
  458. end
  459.  
  460. -------------------------------------------------
  461. -- Global Variables
  462. -------------------------------------------------
  463. ARGS = {...}
  464. INTERVAL = 10
  465. PAUSED = false
  466. WIDTH, HEIGHT = term.getSize()
  467. INTENTFILE = ""
  468. LEVELDICT = {}
  469. BUTTONS = {}
  470. SCROLLS = {}
  471.  
  472. for i=1,WIDTH do
  473.   BUTTONS[i] = {}
  474.   SCROLLS[i] = {}
  475. end
  476.  
  477. -- Add a button to the button mask
  478. function BUTTONS.add(x, y, len, name)
  479.   for i=1,len do
  480.     BUTTONS[x+i-1][y] = name
  481.   end
  482. end
  483.  
  484. -- Add a scroll region to the scroll mask
  485. function SCROLLS.add(x1, y1, x2, y2, name)
  486.   for i=x1, x2 do
  487.     for j=y1,y2 do
  488.       SCROLLS[i][j] = name
  489.     end
  490.   end
  491. end
  492.  
  493. -------------------------------------------------
  494. -- Main Program
  495. -------------------------------------------------
  496. if #ARGS < 1  or #ARGS > 2 then
  497.   printUsage()
  498.   return
  499. end
  500.  
  501. if #ARGS == 1 then
  502.   if ARGS[1] == "help" then
  503.     printHelp()
  504.     return
  505.   else
  506.     printUsage()
  507.     return
  508.   end
  509. elseif #ARGS == 2 then
  510.   INTENTFILE = ARGS[2]
  511.   LEVELDICT = loadIntent(INTENTFILE)
  512.   ME = peripheral.wrap(ARGS[1])
  513.   if ME == nil then
  514.     print("No peripheral was found on the specified side.")
  515.     return
  516.   end
  517. else
  518.   printUsage()
  519.   return
  520. end
  521.  
  522. -- Start all of the control loops in parallel
  523. parallel.waitForAny(stockerLoop, UILoop, inputLoop)
  524.  
  525. -- Clean the screen if the program exits as expected.
  526. term.setBackgroundColor(colors.black)
  527. term.setCursorPos(1,1)
  528. term.clear()
Advertisement
Add Comment
Please, Sign In to add comment