Advertisement
iPlayG

Untitled

Jan 13th, 2024
1,702
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.12 KB | None | 0 0
  1. ---------------------------------------------------
  2. -- Mekanism Fission Reactor Monitoring Program   --
  3. -- Created for CC:Tweaked and Mekanism           --
  4. -- Originally created by InternetUnexplorer on   --
  5. -- GitHub. Modified for personal use, by         --
  6. -- iPlay_G on Minecraft, Derrick355 on GitHub.   --
  7. -- As the original program did not contain any   --
  8. -- license, this will not contain any license.   --
  9. -- However, this software is provided "AS-IS",   --
  10. -- with NO WARRANTY of ANY kind. There is no     --
  11. -- guarentee of fitness for a particular         --
  12. -- purpose.                                      --
  13. -- Feel free to use it, but I, nor the           --
  14. -- original author are responsible for any       --
  15. -- issues arising from the use of this program.  --
  16. --                    -=@=-                      --
  17. -- Thank you for downloading this program.       --
  18. ---------------------------------------------------
  19.  
  20.  
  21. --- NOTES ---
  22. -- If you see 'CRITICAL' on your monitor as the
  23. -- state, that is OK. Critical is what real
  24. -- reactors are considered when operating normally.
  25.  
  26. -- It is generally recommended to edit settings
  27. -- in an IDE or text editor for ease of use.
  28.  
  29. -- It is assumed you have a 6 wide, 4 tall monitor
  30. -- attached via a modem.
  31.  
  32. -- References to an analog lever are common, since
  33. -- I used the Create mod, however if you don't
  34. -- have it, any way to input a variable-power
  35. -- redstone signal should work.
  36.  
  37. -- Binary levers are just vanillia levers.
  38.  
  39.  
  40. --- RECOMMENDED & ASSUMED COMPUTER I/O SETUP ---
  41. -- TOP: Binary lever, used to enable/disable manual burn rate control
  42. -- LEFT: Analog lever, used as coarse adjust on burn control
  43. -- RIGHT: Analog lever, used as fine adjust on burn control
  44. -- BOTTOM: Binary lever, used as reactor on/off control
  45. -- BACK: Modem to connect to reactor, turbine, and monitor
  46. -- FRONT: Alarm or siren. Outputs a redstone signal if turbine power falls below a set threshold.
  47.  
  48.  
  49. --- VARIABLE SETTINGS ---
  50. -- Set the multiplier for the burn rate coarse setting.
  51. -- Default = 75
  52. burn_rate_coarse_multi = 75
  53.  
  54. -- Set the multiplier for the burn rate fine setting.
  55. -- Default = 5
  56. burn_rate_fine_multi = 5
  57.  
  58. -- Maximum auto burn rate to establish
  59. -- Default = 120
  60. burn_rate_auto_max = 120
  61.  
  62. -- What turbine power percent value should burn rate be max at?
  63. -- For this value and all lower, burn rate will be at the max defined above.
  64. -- Default = 0.5 (for 50%)
  65. min_turbine_power = 0.50
  66.  
  67. -- What turbine power percent value should burn rate be zero at?
  68. -- For this value and all higher, burn rate will be at zero.
  69. -- Default = 0.75 (for 75%)
  70. max_turbine_power = 0.75
  71.  
  72. -- What value should the alarm go off if turbine power falls below?
  73. -- Default = 0.46
  74. turbine_min_power = 0.46
  75.  
  76. -- What is the monitor called on the network?
  77. -- Default = monitor_0
  78. monitor_name = "monitor_2"
  79.  
  80. -- Are you playing on a server with Advanced peripherals?
  81. -- This is used so that if a server is restarting the computer can
  82. -- shot down the reactor. Note, the server must issue some kind of
  83. -- restart warning beforehand.
  84. -- Default = true
  85. on_server = true
  86.  
  87. -- If the above is true, you must configure this line.
  88. -- What message in chat should the program look for to see if the server
  89. -- is restarting?
  90. -- Default = "SCRAM"
  91. restart_message = "SCRAM"
  92.  
  93. -- Do not modify anything past this line unless you know what you are doing.
  94.  
  95. ------------------------------------------------
  96.  
  97. local state, data, reactor, turbine, info_window, rules_window
  98.  
  99. local STATES = {
  100.     READY = 1, -- Reactor is off and can be started with the lever
  101.     RUNNING = 2, -- Reactor is running and all rules are met
  102.     ESTOP = 3, -- Reactor is stopped due to rule(s) being violated
  103.     UNKNOWN = 4, -- Reactor or turbine peripherals are missing
  104. }
  105.  
  106. ------------------------------------------------
  107.  
  108. local function check_for_restart_scram()
  109.     if fs.exists("disk/scrammed") then
  110.         incoming_restart = true
  111.         fs.delete("disk/scrammed")
  112.         fs.makeDir("disk/notify_restart")
  113.     else
  114.         incoming_restart = false
  115.     end
  116.     return incoming_restart
  117. end
  118.  
  119. incoming_restart = check_for_restart_scram()
  120.  
  121. local function check_for_restart_notify()
  122.     if fs.exists("disk/notify_restart") then
  123.         notify_restart = true
  124.         fs.delete("disk/notify_restart")
  125.     else
  126.         notify_restart = false
  127.     end
  128.     return notify_restart
  129. end
  130.  
  131. notify_restart = check_for_restart_notify()
  132.  
  133. local function pollChatbox()
  134.     while true do
  135.         local box = peripheral.find('chatBox', function(_, chatbox) return chatbox.getOperationCooldown('chatMessage') == 0 end)
  136.         if box then
  137.             return box
  138.         end
  139.         sleep(0.1)
  140.     end
  141. end
  142.  
  143. ------------------------------------------------
  144.  
  145. local rules = {}
  146.  
  147. local function add_rule(name, fn)
  148.     table.insert(rules, function()
  149.         local ok, rule_met, value = pcall(fn)
  150.         if ok and value ~= false then
  151.             return rule_met, string.format("%s ( %s)", name, value)
  152.     elseif ok then
  153.         return rule_met, string.format("%s (%s)", name, value)
  154.         else
  155.             return false, name
  156.         end
  157.     end)
  158. end
  159.  
  160. add_rule("REACTOR TEMPERATURE      <=  1100K  ", function()
  161.     local value = string.format("%3dK", math.ceil(data.reactor_temp))
  162.     return data.reactor_temp <= 1100, value
  163. end)
  164.  
  165. add_rule("REACTOR DAMAGE           <=    10%  ", function()
  166.     local value = string.format("%3d%%", math.ceil(data.reactor_damage * 100))
  167.     return data.reactor_damage <= 0.10, value
  168. end)
  169.  
  170. add_rule("REACTOR COOLANT LEVEL    >=    95%  ", function()
  171.     local value = string.format("%3d%%", math.floor(data.reactor_coolant * 100))
  172.     return data.reactor_coolant >= 0.95, value
  173. end)
  174.  
  175. add_rule("REACTOR WASTE LEVEL      <=    90%  ", function()
  176.     local value = string.format("%3d%%", math.ceil(data.reactor_waste * 100))
  177.     return data.reactor_waste <= 0.90, value
  178. end)
  179.  
  180. add_rule("TURBINE ENERGY LEVEL     <=    95%  ", function()
  181.     local value = string.format("%3d%%", math.ceil(data.turbine_energy * 100))
  182.     return data.turbine_energy <= 0.95, value
  183. end)
  184.  
  185. if on_server then
  186.     add_rule("INCOMING SERVER RESTART  ==  FALSE  ", function()
  187.         return not incoming_restart, notify_restart
  188.     end)
  189. end
  190.  
  191. local function all_rules_met()
  192.     for i, rule in ipairs(rules) do
  193.         if not rule() then
  194.             return false
  195.         end
  196.     end
  197.     -- Allow manual emergency stop with SCRAM button
  198.     return state ~= STATES.RUNNING or data.reactor_on
  199. end
  200.  
  201. ------------------------------------------------
  202.  
  203. local function update_data()
  204.     coarse_adjust = (tonumber(redstone.getAnalogInput("left")) * burn_rate_coarse_multi)
  205.     fine_adjust = (tonumber(redstone.getAnalogInput("right")) * burn_rate_fine_multi)
  206.     set_burn_rate = (coarse_adjust + fine_adjust)
  207.  
  208.     data = {
  209.         lever_on = redstone.getInput("bottom"),
  210.         burn_rate_limit = set_burn_rate,
  211.         burn_rate_limited = redstone.getInput("top"),
  212.  
  213.         reactor_on = reactor.getStatus(),
  214.         reactor_burn_rate = reactor.getBurnRate(),
  215.         reactor_max_burn_rate = reactor.getMaxBurnRate(),
  216.         reactor_temp = reactor.getTemperature(),
  217.         reactor_damage = reactor.getDamagePercent(),
  218.         reactor_coolant = reactor.getCoolantFilledPercentage(),
  219.         reactor_waste = reactor.getWasteFilledPercentage(),
  220.  
  221.         turbine_energy = turbine.getEnergyFilledPercentage(),
  222.         turbine_power = turbine.getEnergy(),
  223.         turbine_power = turbine.getEnergy(),
  224.         max_turbine_power = turbine.getMaxEnergy()
  225.     }
  226.  
  227. end
  228. ------------------------------------------------
  229.  
  230. local monitor = peripheral.wrap(monitor_name)
  231.  
  232. term.redirect(monitor)
  233.  
  234. local function colored(text, fg, bg)
  235.     term.setTextColor(fg or colors.white)
  236.     term.setBackgroundColor(bg or colors.black)
  237.     term.write(string.upper(text))
  238. end
  239.  
  240. local function make_section(name, x, y, w, h, color)
  241.     for row = 1, h do
  242.         term.setCursorPos(x, y + row - 1)
  243.         local char = (row == 1 or row == h) and "\127" or " "
  244.         colored("\127" .. string.rep(char, w - 2) .. "\127", color or colors.gray)
  245.     end
  246.  
  247.     term.setCursorPos(x + 2, y)
  248.     colored(" " .. name .. " ")
  249.  
  250.     return window.create(term.current(), x + 2, y + 2, w - 4, h - 4)
  251. end
  252.  
  253. local function update_info()
  254.     local prev_term = term.redirect(info_window)
  255.  
  256.     term.clear()
  257.     term.setCursorPos(1, 1)
  258.  
  259.     if state == STATES.UNKNOWN then
  260.         colored("ERROR RETRIEVING DATA", colors.red)
  261.         return
  262.     end
  263.  
  264.     colored("REACTOR: ")
  265.     colored(data.reactor_on and "CRITICAL" or "SHUTDOWN", data.reactor_on and colors.green or colors.red)
  266.     colored(" LEVER: ")
  267.     colored(data.lever_on and "POWERED" or "SECURED", data.lever_on and colors.green or colors.red)
  268.     colored(" BURN RATE: ")
  269.     if data.burn_rate_limited == false then
  270.         colored(string.format("%4.1f", data.reactor_burn_rate), colors.blue)
  271.     else
  272.         colored(string.format("%4.1f", data.reactor_burn_rate), colors.yellow)
  273.     end
  274.     colored("/", colors.lightGray)
  275.     colored(string.format("%4.0f", data.reactor_max_burn_rate), colors.blue)
  276.  
  277.     term.setCursorPos(34, 2)
  278.     colored("SET LIMIT: ")
  279.     if data.burn_rate_limited then
  280.         colored(string.format("%4.1f", data.burn_rate_limit), colors.green)
  281.     else
  282.         colored(string.format("%4.1f", data.burn_rate_limit), colors.gray)
  283.     end
  284.  
  285.     term.setCursorPos(1, 4)
  286.  
  287.     colored("STATUS: ")
  288.     if state == STATES.READY then
  289.         colored("READY - PULL LEVER TO STARTUP", colors.blue)
  290.     elseif state == STATES.RUNNING then
  291.         colored("RUNNING - PULL LEVER TO SHUTDOWN", colors.green)
  292.     elseif state == STATES.ESTOP and not all_rules_met() then
  293.         colored("SCRAM - SAFETY RULE VIOLATED", colors.red)
  294.     elseif state == STATES.ESTOP then
  295.         colored("SCRAM - TOGGLE LEVER TO RESET", colors.red)
  296.     end -- STATES.UNKNOWN cases handled above
  297.  
  298.     term.setCursorPos(1, 6)
  299.    
  300.     colored("STORED POWER: ")
  301.     colored(string.format("%4.0f", (data.turbine_power*4/1000000)), colors.green)
  302.     colored(" MFE", colors.green)
  303.     colored("/", colors.lightGray)
  304.  
  305.     colored(string.format("%4.0f", (data.max_turbine_power*4/1000000)), colors.blue)
  306.     colored(" MFE", colors.blue)
  307.     colored(" (")
  308.     colored(string.format("%5.2f", (data.turbine_energy*100)), colors.green)
  309.     colored("%", colors.green)
  310.     colored(")")
  311.  
  312.     term.redirect(prev_term)
  313. end
  314.  
  315.  
  316. local estop_reasons = {}
  317.  
  318. local function update_rules()
  319.     local prev_term = term.redirect(rules_window)
  320.  
  321.     term.clear()
  322.  
  323.     if state ~= STATES.ESTOP then
  324.         estop_reasons = {}
  325.     end
  326.  
  327.     for i, rule in ipairs(rules) do
  328.         local ok, text = rule()
  329.         term.setCursorPos(1, i)
  330.         if ok and not estop_reasons[i] then
  331.             colored("[ SAFE ] ", colors.green)
  332.             colored(text, colors.lightGray)
  333.         else
  334.             colored("[ FAIL ] ", colors.red)
  335.             colored(text, colors.red)
  336.             estop_reasons[i] = true
  337.         end
  338.     end
  339.  
  340.     term.redirect(prev_term)
  341. end
  342.  
  343. ------------------------------------------------
  344.  
  345. local function main_loop()
  346.     -- Search for peripherals again if one or both are missing
  347.     if not state or state == STATES.UNKNOWN then
  348.         reactor = peripheral.find("fissionReactorLogicAdapter")
  349.         turbine = peripheral.find("turbineValve")
  350.     end
  351.  
  352.     if not pcall(update_data) then
  353.         -- Error getting data (either reactor or turbine is nil?)
  354.         data = {}
  355.         state = STATES.UNKNOWN
  356.     elseif data.reactor_on == nil then
  357.         -- Reactor is not connected
  358.         state = STATES.UNKNOWN
  359.     elseif data.turbine_energy == nil then
  360.         -- Turbine is not connected
  361.         state = STATES.UNKNOWN
  362.     elseif not state then
  363.         -- Program just started, get current state from lever
  364.         state = data.lever_on and STATES.RUNNING or STATES.READY
  365.     elseif state == STATES.READY and data.lever_on then
  366.         -- READY -> RUNNING
  367.         state = STATES.RUNNING
  368.         -- Activate reactor
  369.         incoming_restart = false
  370.         pcall(reactor.activate)
  371.         data.reactor_on = true
  372.     elseif state == STATES.RUNNING and not data.lever_on then
  373.         -- RUNNING -> READY
  374.         state = STATES.READY
  375.     elseif state == STATES.ESTOP and not data.lever_on then
  376.         -- ESTOP -> READY
  377.         state = STATES.READY
  378.     elseif state == STATES.UNKNOWN then
  379.         -- UNKNOWN -> ESTOP
  380.         state = data.lever_on and STATES.ESTOP or STATES.READY
  381.         estop_reasons = {}
  382.     end
  383.  
  384.     -- Always enter ESTOP if safety rules are not met
  385.     if state ~= STATES.UNKNOWN and not all_rules_met() then
  386.         state = STATES.ESTOP
  387.     end
  388.  
  389.     -- SCRAM reactor if not running
  390.     if state ~= STATES.RUNNING and reactor then
  391.         pcall(reactor.scram)
  392.     end
  393.  
  394.     -- Make Windows
  395.     local width = term.getSize()
  396.     if state == STATES.ESTOP then
  397.         window_color = colors.red
  398.     elseif state == STATES.READY then
  399.         window_color = colors.green
  400.     else
  401.         window_color = colors.gray
  402.     end
  403.     info_window = make_section("INFORMATION", 2, 2, width - 2, 10, window_color)
  404.     rules_window = make_section("SAFETY RULES", 2, 13, width - 2, 13, window_color)
  405.  
  406.     -- Update info and rules windows
  407.     pcall(update_info)
  408.     pcall(update_rules)
  409.  
  410.     -- Update max burn rate to keep turbine below 75% energy.
  411.     if state ~= STATES.UNKNOWN and data.burn_rate_limited == false then
  412.    
  413.         local tgt_burn_pct = math.min(math.max(0.0, 1 - (data.turbine_energy - min_turbine_power) / (max_turbine_power - min_turbine_power)), 1.0)
  414.         pcall(reactor.setBurnRate, tgt_burn_pct * burn_rate_auto_max)
  415.     elseif state ~= STATES.UNKNOWN and data.burn_rate_limited == true then
  416.         pcall(reactor.setBurnRate, data.burn_rate_limit) -- Let burn rate be limited by an analog lever
  417.     end
  418.  
  419.     if data.turbine_energy < turbine_min_power then --Sound an alarm that's attached to the front of the computer if turbine power falls below 45%.
  420.         redstone.setOutput("right", true)
  421.     else
  422.         redstone.setOutput("right", false)
  423.     end
  424.     sleep() -- Other calls should already yield, this is just in case
  425.     return main_loop()
  426. end
  427.  
  428. term.setPaletteColor(colors.black, 0x000000)
  429. term.setPaletteColor(colors.gray, 0x343434)
  430. term.setPaletteColor(colors.lightGray, 0xababab)
  431. term.setPaletteColor(colors.red, 0xdb2d20)
  432. term.setPaletteColor(colors.green, 0x01a252)
  433. term.setPaletteColor(colors.blue, 0x01a0e4)
  434. term.clear()
  435.  
  436.  
  437. function scram_on_restart()
  438.     chatBox = peripheral.find("chatBox")
  439.     local event, username, message, uuid, isHidden = os.pullEvent("chat")
  440.     pollChatbox().sendMessage("username: " .. username .. " message: `".. message .. "`")
  441.     if message == restart_message then
  442.         --fs.copy("/disk/scram.lua", "/disk/scrammed.lua")
  443.         fs.makeDir("/disk/scrammed")
  444.         pollChatbox().sendMessage("SCRAM aye")
  445.     end
  446. end
  447.  
  448. if on_server then
  449.     parallel.waitForAny(main_loop, scram_on_restart)
  450. else
  451.     parallel.waitForAny(main_loop, function()
  452.         os.pullEventRaw("terminate")
  453.     end)
  454. end
  455.  
  456. os.reboot()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement