Advertisement
emulackle

Reactor Controller

Apr 23rd, 2025
181
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. local version = "0.61"
  2. local tag = "reactorConfig"
  3. --[[
  4. Program made by DrunkenKas
  5.     See github: https://github.com/Kasra-G/ReactorController/#readme
  6.  
  7. The MIT License (MIT)
  8.  
  9. Copyright (c) 2021 Kasra Ghaffari
  10.  
  11. Permission is hereby granted, free of charge, to any person obtaining a copy
  12. of this software and associated documentation files (the "Software"), to deal
  13. in the Software without restriction, including without limitation the rights
  14. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. copies of the Software, and to permit persons to whom the Software is
  16. furnished to do so, subject to the following conditions:
  17.  
  18. The above copyright notice and this permission notice shall be included in
  19. all copies or substantial portions of the Software.
  20.  
  21. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. THE SOFTWARE.
  28. ]]
  29.  
  30. dofile("/usr/apis/touchpoint.lua")
  31.  
  32. local reactorVersion, reactor
  33. local mon, monSide
  34. local sizex, sizey, dim, oo, offy
  35. local btnOn, btnOff, invalidDim
  36. local minb, maxb
  37. local rod, rfLost
  38. local storedLastTick, storedThisTick, lastRFT = 0,0,0
  39. local fuelTemp, caseTemp, fuelUsage, waste, capacity = 0,0,0,0,1
  40. local t
  41. local displayingGraphMenu = false
  42.  
  43. local secondsToAverage = 2
  44.  
  45. local averageStoredThisTick = 0
  46. local averageLastRFT = 0
  47. local averageRod = 0
  48. local averageFuelUsage = 0
  49. local averageWaste = 0
  50. local averageFuelTemp = 0
  51. local averageCaseTemp = 0
  52. local averageRfLost = 0
  53.  
  54. -- table of which graphs to draw
  55. local graphsToDraw = {}
  56.  
  57. -- table of all the graphs
  58. local graphs =
  59. {
  60.     "Energy Buffer",
  61.     "Control Level",
  62.     "Temperatures",
  63. }
  64.  
  65. -- marks the offsets for each graph position
  66. -- { XOffset, <is_available> }
  67. local XOffs =
  68. {
  69.     { 4, true},
  70.     {27, true},
  71.     {50, true},
  72.     {73, true},
  73.     {96, true},
  74. }
  75.  
  76. -- Draw a box with no fill
  77. local function drawBox(size, xoff, yoff, color)
  78.     if (monSide == nil) then
  79.         return
  80.     end
  81.     local x,y = mon.getCursorPos()
  82.     mon.setBackgroundColor(color)
  83.     local horizLine = string.rep(" ", size[1])
  84.     mon.setCursorPos(xoff + 1, yoff + 1)
  85.     mon.write(horizLine)
  86.     mon.setCursorPos(xoff + 1, yoff + size[2])
  87.     mon.write(horizLine)
  88.  
  89.     -- Draw vertical lines
  90.     for i=0, size[2] - 1 do
  91.         mon.setCursorPos(xoff + 1, yoff + i + 1)
  92.         mon.write(" ")
  93.         mon.setCursorPos(xoff + size[1], yoff + i +1)
  94.         mon.write(" ")
  95.     end
  96.     mon.setCursorPos(x,y)
  97.     mon.setBackgroundColor(colors.black)
  98. end
  99.  
  100. --Draw a filled box
  101. local function drawFilledBox(size, xoff, yoff, colorOut, colorIn)
  102.     if (monSide == nil) then
  103.         return
  104.     end
  105.     local horizLine = string.rep(" ", size[1] - 2)
  106.     drawBox(size, xoff, yoff, colorOut)
  107.     local x,y = mon.getCursorPos()
  108.     mon.setBackgroundColor(colorIn)
  109.     for i=2, size[2] - 1 do
  110.         mon.setCursorPos(xoff + 2, yoff + i)
  111.         mon.write(horizLine)
  112.     end
  113.     mon.setBackgroundColor(colors.black)
  114.     mon.setCursorPos(x,y)
  115. end
  116.  
  117. --Draws text on the screen
  118. local function drawText(text, x1, y1, backColor, textColor)
  119.     if (monSide == nil) then
  120.         return
  121.     end
  122.     local x, y = mon.getCursorPos()
  123.     mon.setCursorPos(x1, y1)
  124.     mon.setBackgroundColor(backColor)
  125.     mon.setTextColor(textColor)
  126.     mon.write(text)
  127.     mon.setTextColor(colors.white)
  128.     mon.setBackgroundColor(colors.black)
  129.     mon.setCursorPos(x,y)
  130. end
  131.  
  132. --Helper method for adding buttons
  133. local function addButt(name, callBack, size, xoff, yoff, color1, color2)
  134.     t:add(name, callBack,
  135.             xoff + 1, yoff + 1,
  136.             size[1] + xoff, size[2] + yoff,
  137.             color1, color2)
  138. end
  139.  
  140. local function minAdd10()
  141.     minb = math.min(maxb - 10, minb + 10)
  142. end
  143. local function minSub10()
  144.     minb = math.max(0, minb - 10)
  145. end
  146. local function maxAdd10()
  147.     maxb = math.min(100, maxb + 10)
  148. end
  149. local function maxSub10()
  150.     maxb = math.max(minb + 10, maxb - 10)
  151. end
  152.  
  153. local function turnOff()
  154.     if (btnOn) then
  155.         t:toggleButton("Off")
  156.         t:toggleButton("On")
  157.         btnOff = true
  158.         btnOn = false
  159.         reactor.setActive(false)
  160.     end
  161. end
  162.  
  163. local function turnOn()
  164.     if (btnOff) then
  165.         t:toggleButton("Off")
  166.         t:toggleButton("On")
  167.         btnOff = false
  168.         btnOn = true
  169.         reactor.setActive(true)
  170.     end
  171. end
  172.  
  173. --adds buttons
  174. local function addButtons()
  175.     if (sizey == 24) then
  176.         oo = 1
  177.     end
  178.     addButt("On", turnOn, {8, 3}, dim + 7, 3 + oo,
  179.             colors.red, colors.lime)
  180.     addButt("Off", turnOff, {8, 3}, dim + 19, 3 + oo,
  181.             colors.red, colors.lime)
  182.     if (btnOn) then
  183.         t:toggleButton("On", true)
  184.     else
  185.         t:toggleButton("Off", true)
  186.     end
  187.     if (sizey > 24) then
  188.         addButt("+ 10", minAdd10, {8, 3}, dim + 7, 14 + oo,
  189.                 colors.purple, colors.pink)
  190.         addButt(" + 10 ", maxAdd10, {8, 3}, dim + 19, 14 + oo,
  191.                 colors.magenta, colors.pink)
  192.         addButt("- 10", minSub10, {8, 3}, dim + 7, 18 + oo,
  193.                 colors.purple, colors.pink)
  194.         addButt(" - 10 ", maxSub10, {8, 3}, dim + 19, 18 + oo,
  195.                 colors.magenta, colors.pink)
  196.     end
  197. end
  198.  
  199. --Resets the monitor
  200. local function resetMon()
  201.     if (monSide == nil) then
  202.         return
  203.     end
  204.     mon.setBackgroundColor(colors.black)
  205.     mon.clear()
  206.     mon.setTextScale(0.5)
  207.     mon.setCursorPos(1,1)
  208. end
  209.  
  210. local function getPercPower()
  211.     return averageStoredThisTick / capacity * 100
  212. end
  213.  
  214. local function rnd(num, dig)
  215.     return math.floor(10 ^ dig * num) / (10 ^ dig)
  216. end
  217.  
  218. local function getEfficiency()
  219.     return averageLastRFT / averageFuelUsage
  220. end
  221.  
  222. local function format(num)
  223.     if (num >= 1000000000) then
  224.         return string.format("%7.3f G", num / 1000000000)
  225.     elseif (num >= 1000000) then
  226.         return string.format("%7.3f M", num / 1000000)
  227.     elseif (num >= 1000) then
  228.         return string.format("%7.3f K", num / 1000)
  229.     elseif (num >= 1) then
  230.         return string.format("%7.3f ", num)
  231.     elseif (num >= .001) then
  232.         return string.format("%7.3f m", num * 1000)
  233.     elseif (num >= .000001) then
  234.         return string.format("%7.3f u", num * 1000000)
  235.     else
  236.         return string.format("%7.3f ", 0)
  237.     end
  238. end
  239.  
  240.  
  241. local function getAvailableXOff()
  242.     for i,v in pairs(XOffs) do
  243.         if (v[2] and v[1] < dim) then
  244.             v[2] = false
  245.             return v[1]
  246.         end
  247.     end
  248.     return -1
  249. end
  250.  
  251. local function getXOff(num)
  252.     for i,v in pairs(XOffs) do
  253.         if (v[1] == num) then
  254.             return v
  255.         end
  256.     end
  257.     return nil
  258. end
  259.  
  260. local function enableGraph(name)
  261.     if (graphsToDraw[name] ~= nil) then
  262.         return
  263.     end
  264.     local e = getAvailableXOff()
  265.     if (e ~= -1) then
  266.         graphsToDraw[name] = e
  267.         if (displayingGraphMenu) then
  268.             t:toggleButton(name)
  269.         end
  270.     end
  271. end
  272.  
  273. local function disableGraph(name)
  274.     if (graphsToDraw[name] == nil) then
  275.         return
  276.     end
  277.     if (displayingGraphMenu) then
  278.         t:toggleButton(name)
  279.     end
  280.     getXOff(graphsToDraw[name])[2] = true
  281.     graphsToDraw[name] = nil
  282. end
  283.  
  284. local function toggleGraph(name)
  285.     if (graphsToDraw[name] == nil) then
  286.         enableGraph(name)
  287.     else
  288.         disableGraph(name)
  289.     end
  290. end
  291.  
  292. local function addGraphButtons()
  293.     offy = oo - 14
  294.     for i,v in pairs(graphs) do
  295.         addButt(v, function() toggleGraph(v) end, {20, 3},
  296.                 dim + 7, offy + i * 3 - 1,
  297.                 colors.red, colors.lime)
  298.         if (graphsToDraw[v] ~= nil) then
  299.             t:toggleButton(v, true)
  300.         end
  301.     end
  302. end
  303.  
  304. local function drawGraphButtons()
  305.     drawBox({sizex - dim - 3, oo - offy - 1},
  306.             dim + 2, offy, colors.orange)
  307.     drawText(" Graph Controls ",
  308.             dim + 7, offy + 1,
  309.             colors.black, colors.orange)
  310. end
  311.  
  312. local function drawEnergyBuffer(xoff)
  313.     local srf = sizey - 9
  314.     local off = xoff
  315.     local right = off + 19 < dim
  316.     local poff = right and off + 15 or off - 6
  317.  
  318.     drawBox({15, srf + 2}, off - 1, 4, colors.gray)
  319.     local pwr = math.floor(getPercPower() / 100
  320.             * (srf))
  321.     drawFilledBox({13, srf}, off, 5,
  322.             colors.red, colors.red)
  323.     local rndpw = rnd(getPercPower(), 2)
  324.     local color = (rndpw < maxb and rndpw > minb) and colors.green
  325.             or (rndpw >= maxb and colors.orange or colors.blue)
  326.     if (pwr > 0) then
  327.         drawFilledBox({13, pwr + 1}, off, srf + 4 - pwr,
  328.                 color, color)
  329.     end
  330.     --drawPoint(off + 14, srf + 5 - pwr, pwr > 0 and color or colors.red)
  331.     drawText(string.format(right and "%.2f%%" or "%5.2f%%", rndpw), poff, srf + 5 - pwr,
  332.             colors.black, color)
  333.     drawText("Energy Buffer", off + 1, 4,
  334.             colors.black, colors.orange)
  335.     drawText(format(averageStoredThisTick).."RF", off + 1, srf + 5 - pwr,
  336.             pwr > 0 and color or colors.red, colors.black)
  337. end
  338.  
  339. local function drawControlLevel(xoff)
  340.     local srf = sizey - 9
  341.     local off = xoff
  342.     drawBox({15, srf + 2}, off - 1, 4, colors.gray)
  343.     drawFilledBox({13, srf}, off, 5,
  344.             colors.yellow, colors.yellow)
  345.     local rodTr = math.floor(averageRod / 100
  346.             * (srf))
  347.     drawText("Control Level", off + 1, 4,
  348.             colors.black, colors.orange)
  349.     if (rodTr > 0) then
  350.         drawFilledBox({9, rodTr}, off + 2, 5,
  351.                 colors.white, colors.white)
  352.     end
  353.     drawText(string.format("%6.2f%%", averageRod), off + 4, rodTr > 0 and rodTr + 5 or 6,
  354.             rodTr > 0 and colors.white or colors.yellow, colors.black)
  355.  
  356. end
  357.  
  358. local function drawTemperatures(xoff)
  359.     local srf = sizey - 9
  360.     local off = xoff
  361.     drawBox({15, srf + 2}, off, 4, colors.gray)
  362.     --drawFilledBox({12, srf}, off, 5,
  363.     --  colors.red, colors.red)
  364.  
  365.     local tempUnit = (reactorVersion == "Bigger Reactors") and "K" or "C"
  366.     local tempFormat = "%4s"..tempUnit
  367.  
  368.     local fuelRnd = math.floor(averageFuelTemp)
  369.     local caseRnd = math.floor(averageCaseTemp)
  370.     local fuelTr = math.floor(fuelRnd / 2000
  371.             * (srf))
  372.     local caseTr = math.floor(caseRnd / 2000
  373.             * (srf))
  374.     drawText(" Case ", off + 2, 5,
  375.             colors.gray, colors.lightBlue)
  376.     drawText(" Fuel ", off + 9, 5,
  377.             colors.gray, colors.magenta)
  378.     if (fuelTr > 0) then
  379.         fuelTr = math.min(fuelTr, srf)
  380.         drawFilledBox({6, fuelTr}, off + 8, srf + 5 - fuelTr,
  381.                 colors.magenta, colors.magenta)
  382.  
  383.         drawText(string.format(tempFormat, fuelRnd..""),
  384.                 off + 10, srf + 6 - fuelTr,
  385.                 colors.magenta, colors.black)
  386.     else
  387.         drawText(string.format(tempFormat, fuelRnd..""),
  388.                 off + 10, srf + 5,
  389.                 colors.black, colors.magenta)
  390.     end
  391.  
  392.     if (caseTr > 0) then
  393.         caseTr = math.min(caseTr, srf)
  394.         drawFilledBox({6, caseTr}, off + 1, srf + 5 - caseTr,
  395.                 colors.lightBlue, colors.lightBlue)
  396.         drawText(string.format(tempFormat, caseRnd..""),
  397.                 off + 3, srf + 6 - caseTr,
  398.                 colors.lightBlue, colors.black)
  399.     else
  400.         drawText(string.format(tempFormat, caseRnd..""),
  401.                 off + 3, srf + 5,
  402.                 colors.black, colors.lightBlue)
  403.     end
  404.  
  405.     drawText("Temperatures", off + 2, 4,
  406.             colors.black, colors.orange)
  407.     drawBox({1, srf}, off + 7, 5,
  408.             colors.gray)
  409. end
  410.  
  411. local function drawGraph(name, offset)
  412.     if (name == "Energy Buffer") then
  413.         drawEnergyBuffer(offset)
  414.     elseif (name == "Control Level") then
  415.         drawControlLevel(offset)
  416.     elseif (name == "Temperatures") then
  417.         drawTemperatures(offset)
  418.     end
  419. end
  420.  
  421. local function drawGraphs()
  422.     for i,v in pairs(graphsToDraw) do
  423.         if (v + 15 < dim) then
  424.             drawGraph(i,v)
  425.         end
  426.     end
  427. end
  428.  
  429. local function drawStatus()
  430.     if (dim <= -1) then
  431.         return
  432.     end
  433.     drawBox({dim, sizey - 2},
  434.             1, 1, colors.lightBlue)
  435.     drawText(" Reactor Graphs ", dim - 18, 2,
  436.             colors.black, colors.lightBlue)
  437.     drawGraphs()
  438. end
  439.  
  440. local function drawControls()
  441.     if (sizey == 24) then
  442.         drawBox({sizex - dim - 3, 9}, dim + 2, oo,
  443.                 colors.cyan)
  444.         drawText(" Reactor Controls ", dim + 7, oo + 1,
  445.                 colors.black, colors.cyan)
  446.         drawText("Reactor "..(btnOn and "Online" or "Offline"),
  447.                 dim + 10, 3 + oo,
  448.                 colors.black, btnOn and colors.green or colors.red)
  449.         return
  450.     end
  451.  
  452.     drawBox({sizex - dim - 3, 23}, dim + 2, oo,
  453.             colors.cyan)
  454.     drawText(" Reactor Controls ", dim + 7, oo + 1,
  455.             colors.black, colors.cyan)
  456.     drawFilledBox({20, 3}, dim + 7, 8 + oo,
  457.             colors.red, colors.red)
  458.     drawFilledBox({(maxb - minb) / 5, 3},
  459.             dim + 7 + minb / 5, 8 + oo,
  460.             colors.green, colors.green)
  461.     drawText(string.format("%3s", minb.."%"), dim + 6 + minb / 5, 12 + oo,
  462.             colors.black, colors.purple)
  463.     drawText(maxb.."%", dim + 8 + maxb / 5, 12 + oo,
  464.             colors.black, colors.magenta)
  465.     drawText("Buffer Target Range", dim + 8, 8 + oo,
  466.             colors.black, colors.orange)
  467.     drawText("Min", dim + 10, 14 + oo,
  468.             colors.black, colors.purple)
  469.     drawText("Max", dim + 22, 14 + oo,
  470.             colors.black, colors.magenta)
  471.     drawText("Reactor ".. (btnOn and "Online" or "Offline"),
  472.             dim + 10, 3 + oo,
  473.             colors.black, btnOn and colors.green or colors.red)
  474. end
  475.  
  476. local function drawStatistics()
  477.     local oS = sizey - 13
  478.     drawBox({sizex - dim - 3, sizey - oS - 1}, dim + 2, oS,
  479.             colors.blue)
  480.     drawText(" Reactor Statistics ", dim + 7, oS + 1,
  481.             colors.black, colors.blue)
  482.  
  483.     --statistics
  484.     drawText("Generating : "
  485.             ..format(averageLastRFT).."RF/t", dim + 5, oS + 3,
  486.             colors.black, colors.green)
  487.     drawText("RF Drain   "
  488.             ..(averageStoredThisTick <= averageLastRFT and "> " or ": ")
  489.             ..format(averageRfLost)
  490.             .."RF/t", dim + 5, oS + 5,
  491.             colors.black, colors.red)
  492.     drawText("Efficiency : "
  493.             ..format(getEfficiency()).."RF/B",
  494.             dim + 5, oS + 7,
  495.             colors.black, colors.green)
  496.     drawText("Fuel Usage : "
  497.             ..format(averageFuelUsage)
  498.             .."B/t", dim + 5, oS + 9,
  499.             colors.black, colors.green)
  500.     drawText("Waste      : "
  501.             ..string.format("%7d mB", waste),
  502.             dim + 5, oS + 11,
  503.             colors.black, colors.green)
  504. end
  505.  
  506. --Draw a scene
  507. local function drawScene()
  508.     if (monSide == nil) then
  509.         return
  510.     end
  511.     if (invalidDim) then
  512.         mon.write("Invalid Monitor Dimensions")
  513.         return
  514.     end
  515.  
  516.     if (displayingGraphMenu) then
  517.         drawGraphButtons()
  518.     end
  519.     drawControls()
  520.     drawStatus()
  521.     drawStatistics()
  522.     t:draw()
  523. end
  524.  
  525. --returns the side that a given peripheral type is connected to
  526. local function getPeripheral(name)
  527.     for i,v in pairs(peripheral.getNames()) do
  528.         if (peripheral.getType(v) == name) then
  529.             return v
  530.         end
  531.     end
  532.     return ""
  533. end
  534.  
  535. --Creates all the buttons and determines monitor size
  536. local function initMon()
  537.     monSide = getPeripheral("monitor")
  538.     if (monSide == nil or monSide == "") then
  539.         monSide = nil
  540.         return
  541.     end
  542.  
  543.     mon = peripheral.wrap(monSide)
  544.  
  545.     if mon == nil then
  546.         monSide = nil
  547.         return
  548.     end
  549.  
  550.     resetMon()
  551.     t = touchpoint.new(monSide)
  552.     sizex, sizey = mon.getSize()
  553.     oo = sizey - 37
  554.     dim = sizex - 33
  555.  
  556.     if (sizex == 36) then
  557.         dim = -1
  558.     end
  559.     if (pcall(addGraphButtons)) then
  560.         displayingGraphMenu = true
  561.     else
  562.         t = touchpoint.new(monSide)
  563.         displayingGraphMenu = false
  564.     end
  565.     local rtn = pcall(addButtons)
  566.     if (not rtn) then
  567.         t = touchpoint.new(monSide)
  568.         invalidDim = true
  569.     else
  570.         invalidDim = false
  571.     end
  572. end
  573.  
  574. local function setRods(level)
  575.     level = math.max(level, 0)
  576.     level = math.min(level, 100)
  577.     reactor.setAllControlRodLevels(level)
  578. end
  579.  
  580. local function lerp(start, finish, t)
  581.     -- Ensure t is in the range [0, 1]
  582.     t = math.max(0, math.min(1, t))
  583.  
  584.     -- Calculate the linear interpolation
  585.     return (1 - t) * start + t * finish
  586. end
  587.  
  588. -- Function to calculate the average of an array of values
  589. local function calculateAverage(array)
  590.     local sum = 0
  591.     for _, value in ipairs(array) do
  592.         sum = sum + value
  593.     end
  594.     return sum / #array
  595. end
  596.  
  597. -- Define PID controller parameters
  598. local pid = {
  599.     setpointRFT = 0,      -- Target RFT
  600.     setpointRF = 0,      -- Target RF
  601.     Kp = -.02,           -- Proportional gain (reduced from -0.08)
  602.     Ki = -.0005,          -- Integral gain (reduced from -0.0015)
  603.     Kd = -.005,         -- Derivative gain (reduced from -0.01)
  604.     integral = 0,       -- Integral term accumulator
  605.     lastError = 0,      -- Last error for derivative term
  606. }
  607.  
  608. local function iteratePID(pid, error)
  609.     local deadzone = 10
  610.     if math.abs(error) < deadzone then
  611.         return nil  -- No change needed
  612.     end
  613.  
  614.     -- Proportional term
  615.     local P = pid.Kp * error
  616.  
  617.     -- Integral term
  618.     pid.integral = pid.integral + pid.Ki * error
  619.     pid.integral = math.max(math.min(100, pid.integral), -100)
  620.  
  621.     -- Derivative term
  622.     local derivative = pid.Kd * (error - pid.lastError)
  623.  
  624.     -- Calculate control rod level
  625.     local rodLevel = math.max(math.min(P + pid.integral + derivative, 100), 0)
  626.  
  627.     -- Update PID controller state
  628.     pid.lastError = error
  629.     return rodLevel
  630. end
  631.  
  632. local function updateRods()
  633.     if (not btnOn) then
  634.         return
  635.     end
  636.     local currentRF = storedThisTick
  637.     local diffb = maxb - minb
  638.     local minRF = minb / 100 * capacity
  639.     local diffRF = diffb / 100 * capacity
  640.     local diffr = diffb / 100
  641.     local targetRFT = rfLost
  642.     local currentRFT = lastRFT
  643.     local targetRF = diffRF / 2 + minRF
  644.  
  645.     pid.setpointRFT = targetRFT
  646.     pid.setpointRF = targetRF / capacity * 1000
  647.  
  648.     local errorRFT = pid.setpointRFT - currentRFT
  649.     local errorRF = pid.setpointRF - currentRF / capacity * 1000
  650.  
  651.     local W_RFT = lerp(0.7, 0.3, (math.abs(targetRF - currentRF) / capacity / (diffr / 4)))
  652.     W_RFT = math.max(math.min(W_RFT, 1), 0)
  653.  
  654.     local W_RF = (1 - W_RFT)  -- Adjust the weight for energy error
  655.  
  656.     -- Combine the errors with weights
  657.     local combinedError = W_RFT * errorRFT + W_RF * errorRF
  658.     local error = combinedError
  659.     local rftRodLevel = iteratePID(pid, error)
  660.  
  661.     -- Set control rod levels
  662.     setRods(rftRodLevel)
  663. end
  664.  
  665. -- Saves the configuration of the reactor controller
  666. local function saveToConfig()
  667.     local file = fs.open(tag.."Serialized.txt", "w")
  668.     local configs = {
  669.         maxb = maxb,
  670.         minb = minb,
  671.         rod = rod,
  672.         btnOn = btnOn,
  673.         graphsToDraw = graphsToDraw,
  674.         XOffs = XOffs,
  675.     }
  676.     local serialized = textutils.serialize(configs)
  677.     file.write(serialized)
  678.     file.close()
  679. end
  680.  
  681. local storedThisTickValues = {}
  682. local lastRFTValues = {}
  683. local rodValues = {}
  684. local fuelUsageValues = {}
  685. local wasteValues = {}
  686. local fuelTempValues = {}
  687. local caseTempValues = {}
  688. local rfLostValues = {}
  689.  
  690. local function updateStats()
  691.     storedLastTick = storedThisTick
  692.     if (reactorVersion == "Big Reactors") then
  693.         storedThisTick = reactor.getEnergyStored()
  694.         lastRFT = reactor.getEnergyProducedLastTick()
  695.         rod = reactor.getControlRodLevel(0)
  696.         fuelUsage = reactor.getFuelConsumedLastTick() / 1000
  697.         waste = reactor.getWasteAmount()
  698.         fuelTemp = reactor.getFuelTemperature()
  699.         caseTemp = reactor.getCasingTemperature()
  700.         -- Big Reactors doesn't give us a way to directly query RF capacity through CC APIs
  701.         capacity = math.max(capacity, reactor.getEnergyStored)
  702.     elseif (reactorVersion == "Extreme Reactors") then
  703.         local bat = reactor.getEnergyStats()
  704.         local fuel = reactor.getFuelStats()
  705.  
  706.         storedThisTick = bat.energyStored
  707.         lastRFT = bat.energyProducedLastTick
  708.         capacity = bat.energyCapacity
  709.         rod = reactor.getControlRodLevel(0)
  710.         fuelUsage = fuel.fuelConsumedLastTick / 1000
  711.         waste = reactor.getWasteAmount()
  712.         fuelTemp = reactor.getFuelTemperature()
  713.         caseTemp = reactor.getCasingTemperature()
  714.     elseif (reactorVersion == "Bigger Reactors") then
  715.         storedThisTick = reactor.battery().stored()
  716.         lastRFT = reactor.battery().producedLastTick()
  717.         capacity = reactor.battery().capacity()
  718.         rod = reactor.getControlRod(0).level()
  719.         fuelUsage = reactor.fuelTank().burnedLastTick() / 1000
  720.         waste = reactor.fuelTank().waste()
  721.         fuelTemp = reactor.fuelTemperature()
  722.         caseTemp = reactor.casingTemperature()
  723.     end
  724.     rfLost = lastRFT + storedLastTick - storedThisTick
  725.     -- Add the values to the arrays
  726.     table.insert(storedThisTickValues, storedThisTick)
  727.     table.insert(lastRFTValues, lastRFT)
  728.     table.insert(rodValues, rod)
  729.     table.insert(fuelUsageValues, fuelUsage)
  730.     table.insert(wasteValues, waste)
  731.     table.insert(fuelTempValues, fuelTemp)
  732.     table.insert(caseTempValues, caseTemp)
  733.     table.insert(rfLostValues, rfLost)
  734.  
  735.     local maxIterations = 20 * secondsToAverage
  736.     while #storedThisTickValues > maxIterations do
  737.         table.remove(storedThisTickValues, 1)
  738.         table.remove(lastRFTValues, 1)
  739.         table.remove(rodValues, 1)
  740.         table.remove(fuelUsageValues, 1)
  741.         table.remove(wasteValues, 1)
  742.         table.remove(fuelTempValues, 1)
  743.         table.remove(caseTempValues, 1)
  744.         table.remove(rfLostValues, 1)
  745.     end
  746.  
  747.     -- Calculate running averages
  748.     averageStoredThisTick = calculateAverage(storedThisTickValues)
  749.     averageLastRFT = calculateAverage(lastRFTValues)
  750.     averageRod = calculateAverage(rodValues)
  751.     averageFuelUsage = calculateAverage(fuelUsageValues)
  752.     averageWaste = calculateAverage(wasteValues)
  753.     averageFuelTemp = calculateAverage(fuelTempValues)
  754.     averageCaseTemp = calculateAverage(caseTempValues)
  755.     averageRfLost = calculateAverage(rfLostValues)
  756. end
  757.  
  758. --Initialize variables from either a config file or the defaults
  759. local function loadFromConfig()
  760.     invalidDim = false
  761.     local legacyConfigExists = fs.exists(tag..".txt")
  762.     local newConfigExists = fs.exists(tag.."Serialized.txt")
  763.     if (newConfigExists) then
  764.         local file = fs.open(tag.."Serialized.txt", "r")
  765.         print("Config file "..tag.."Serialized.txt found! Using configurated settings")
  766.  
  767.         local serialized = file.readAll()
  768.         local deserialized = textutils.unserialise(serialized)
  769.        
  770.         maxb = deserialized.maxb
  771.         minb = deserialized.minb
  772.         rod = deserialized.rod
  773.         btnOn = deserialized.btnOn
  774.         graphsToDraw = deserialized.graphsToDraw
  775.         XOffs = deserialized.XOffs
  776.     elseif (legacyConfigExists) then
  777.         local file = fs.open(tag..".txt", "r")
  778.         local calibrated = file.readLine() == "true"
  779.  
  780.         --read calibration information
  781.         if (calibrated) then
  782.             _ = tonumber(file.readLine())
  783.             _ = tonumber(file.readLine())
  784.         end
  785.         maxb = tonumber(file.readLine())
  786.         minb = tonumber(file.readLine())
  787.         rod = tonumber(file.readLine())
  788.         btnOn = file.readLine() == "true"
  789.  
  790.         --read Graph data
  791.         for i in pairs(XOffs) do
  792.             local graph = file.readLine()
  793.             local v1 = tonumber(file.readLine())
  794.             local v2 = true
  795.             if (graph ~= "nil") then
  796.                 v2 = false
  797.                 graphsToDraw[graph] = v1
  798.             end
  799.  
  800.             XOffs[i] = {v1, v2}
  801.  
  802.         end
  803.         file.close()
  804.     else
  805.         print("Config file not found, generating default settings!")
  806.  
  807.         maxb = 70
  808.         minb = 30
  809.         rod = 80
  810.         btnOn = false
  811.         if (monSide == nil) then
  812.             btnOn = true
  813.         end
  814.         sizex, sizey = 100, 52
  815.         dim = sizex - 33
  816.         oo = sizey - 37
  817.         enableGraph("Energy Buffer")
  818.         enableGraph("Control Level")
  819.         enableGraph("Temperatures")
  820.     end
  821.     btnOff = not btnOn
  822.     reactor.setActive(btnOn)
  823. end
  824.  
  825. local function startTimer(ticksToUpdate, callback)
  826.     local timeToUpdate = ticksToUpdate * 0.05
  827.     local id = os.startTimer(timeToUpdate)
  828.     local fun = function(event)
  829.         if (event[1] == "timer" and event[2] == id) then
  830.             id = os.startTimer(timeToUpdate)
  831.             callback()
  832.         end
  833.     end
  834.     return fun
  835. end
  836.  
  837.  
  838. -- Main loop, handles all the events
  839. local function loop()
  840.     local ticksToUpdateStats = 1
  841.     local ticksToRedraw = 4
  842.    
  843.     local hasClicked = false
  844.  
  845.     local updateStatsTick = startTimer(
  846.         ticksToUpdateStats,
  847.         function()
  848.             updateStats()
  849.             updateRods()
  850.         end
  851.     )
  852.     local redrawTick = startTimer(
  853.         ticksToRedraw,
  854.         function()
  855.             if (not hasClicked) then
  856.                 resetMon()
  857.                 drawScene()
  858.             end
  859.             hasClicked = false
  860.         end
  861.     )
  862.     local handleResize = function(event)
  863.         if (event[1] == "monitor_resize") then
  864.             initMon()
  865.         end
  866.     end
  867.     local handleClick = function(event)
  868.         if (event[1] == "button_click") then
  869.             t.buttonList[event[2]].func()
  870.             saveToConfig()
  871.             resetMon()
  872.             drawScene()
  873.             hasClicked = true
  874.         end
  875.     end
  876.     while (true) do
  877.         local event = (monSide == nil) and { os.pullEvent() } or { t:handleEvents() }
  878.  
  879.         updateStatsTick(event)
  880.         redrawTick(event)
  881.         handleResize(event)
  882.         handleClick(event)
  883.     end
  884. end
  885.  
  886. local function detectReactor()
  887.     -- Bigger Reactors V1.
  888.     local reactor_bigger_v1 = getPeripheral("bigger-reactor")
  889.     reactor = reactor_bigger_v1 ~= nil and peripheral.wrap(reactor_bigger_v1)
  890.     if (reactor ~= nil) then
  891.         reactorVersion = "Bigger Reactors"
  892.         return true
  893.     end
  894.  
  895.     -- Bigger Reactors V2
  896.     local reactor_bigger_v2 = getPeripheral("BiggerReactors_Reactor")
  897.     reactor = reactor_bigger_v2 ~= nil and peripheral.wrap(reactor_bigger_v2)
  898.     if (reactor ~= nil) then
  899.         reactorVersion = "Bigger Reactors"
  900.         return true
  901.     end
  902.  
  903.     -- Big Reactors or Extreme Reactors
  904.     local reactor_extreme_or_big = getPeripheral("BigReactors-Reactor")
  905.     reactor = reactor_extreme_or_big ~= nil and peripheral.wrap(reactor_extreme_or_big)
  906.     if (reactor ~= nil) then
  907.         reactorVersion = (reactor.mbIsConnected ~= nil) and "Extreme Reactors" or "Big Reactors"
  908.         return true
  909.     end
  910.     return false
  911. end
  912.  
  913. --Entry point
  914. local function main()
  915.     term.setBackgroundColor(colors.black)
  916.     term.clear()
  917.     term.setCursorPos(1,1)
  918.  
  919.     local reactorDetected = false
  920.     while (not reactorDetected) do
  921.         reactorDetected = detectReactor()
  922.         if (not reactorDetected) then
  923.             print("Reactor not detected! Trying again...")
  924.             sleep(1)
  925.         end
  926.     end
  927.    
  928.     print("Reactor detected! Proceeding with initialization ")
  929.  
  930.     print("Loading config...")
  931.     loadFromConfig()
  932.     print("Initializing monitor if connected...")
  933.     initMon()
  934.     print("Writing config to disk...")
  935.     saveToConfig()
  936.     print("Reactor initialization done! Starting controller")
  937.     sleep(2)
  938.  
  939.     term.clear()
  940.     term.setCursorPos(1,1)
  941.     print("Reactor Controller Version "..version)
  942.     print("Reactor Mod: "..reactorVersion)
  943.     --main loop
  944.  
  945.     loop()
  946. end
  947.  
  948. main()
  949.  
  950. print("script exited")
  951. sleep(1)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement