Advertisement
iPlayG

Untitled

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