├── assets
├── 多联核电.jpg
├── 5联MOX核电.png
└── mox99堆.jpg
├── coolantcellThread.lua
├── README.md
├── database.lua
├── config.lua
├── action.lua
└── justStart.lua
/assets/多联核电.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljhljll/GTNH-NuclearCooler/HEAD/assets/多联核电.jpg
--------------------------------------------------------------------------------
/assets/5联MOX核电.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljhljll/GTNH-NuclearCooler/HEAD/assets/5联MOX核电.png
--------------------------------------------------------------------------------
/assets/mox99堆.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljhljll/GTNH-NuclearCooler/HEAD/assets/mox99堆.jpg
--------------------------------------------------------------------------------
/coolantcellThread.lua:
--------------------------------------------------------------------------------
1 | local action = require("action")
2 | local config = require("config")
3 | local component = require("component")
4 | local coroutine = require("coroutine")
5 |
6 | -- 获取电量锁存器信号
7 | local function getLatchRedstoneSingal()
8 | local latchRedstone = component.proxy(config.energyLatchRedstone)
9 | local singalTable = latchRedstone.getInput()
10 | for side, num in pairs(singalTable) do
11 | if num > 0 then
12 | return true
13 | end
14 | end
15 | return false
16 | end
17 | -- 运行核电堆
18 | local function runningReactorChamber(rc)
19 | while true do
20 | -- 是否开启耐久及物品名检测
21 | local canCheck = true
22 | -- 配置文件中如果开启全局电量检测(energyLatchRedstone==-1)
23 | -- 并且该项配置开启了电量控制(rc.energy == true)
24 | -- 则根据电量锁存器的状态开关核电
25 | if config.energyLatchRedstone ~= -1 and rc.energy then
26 | if not getLatchRedstoneSingal() then
27 | action.stopReactorChamberByRc(rc)
28 | canCheck = false
29 | end
30 | end
31 | if canCheck then
32 | local scheme = config.scheme[rc.scheme]
33 | action.checkReactorChamberDMG(rc, scheme)
34 | action.startReactorChamber(rc)
35 | end
36 | coroutine.yield()
37 | end
38 | end
39 |
40 | return {
41 | runningReactorChamber = runningReactorChamber
42 | }
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GTNH-NuclearCooler
2 |
3 | 基本使用流程:
4 | 1. 准备一套OC(高级机箱、内存条、显示器、键盘、磁盘驱动器、红石IO端口2个、一些线缆、BIOS、高级处理器(cpu)、基础显卡、转运器、适配器等等
5 | 2. 装机后将lua文件放入存档中的opencomputers/{设备id}下
6 | 3. 编辑config.lua,释义已在文件中标注,使用oc中的分析器右键红石端口可以直接复制它的地址id
7 | 文件中的方向是可通过开F3等方式来获取(请以转运器为基准来区分方向)
8 | 4. 开机启动!
9 |
10 | 搭建的结构参考:
11 |
12 | 
13 |
14 | 
15 |
16 | # 必看常见问题
17 | 1. 请不要使用windows记事本编辑器进行config.lua的修改,会导致程序无法使用
18 | 2. 默认的config.lua中包含了mox99%强冷堆、4连强冷铀堆的默认配置,请按照自己的组件地址进行修改
19 |
20 |
21 | - [x] 删去无用的散热代码
22 | - [x] 完成99%核电测试及处理
23 | - [x] 简化结构使其得以更少的组件管理更多的核电
24 | - [x] 自行控制反应堆是否参与电量控制
25 | - [x] 16套4连核电低tps运行30*24小时不停机稳定运行
26 | - [x] 半云使用协程优化核电堆检测逻辑
27 | - [x] 增加温控功能
28 | - [x] 优化核电状态打印
29 | - [x] 优化justStart管理协查的代码,增加协查重启机制
30 |
31 | # config.lua配置项
32 |
33 | 游戏中按F3+H开启显示物品拓展信息即可找到物品代码
34 |
35 | | 配置项名 | 取值 | 默认 | 说明 |
36 | | ------------------------ | --------- | ------------------------------ | ------------------------------------------------------------ |
37 | | `name` | `string` | 不填写则取核电仓地址值 | 用于日志打印时的核电堆名称标识 |
38 | | `scheme` | `string` | slyb | 可选`slyb`\|`mox`\|`yghhw` |
39 | | `thresholdHeat` | `number` | -1 | 开启预热功能,无需开启则填写-1或nil
示例: 99%=9900 |
40 | | `preheatItem` | `string` | gregtech:gt.reactorUraniumQuad | 用于预热的材料,对应四连铀棒的物品代码 |
41 | | `reactorChamberAddr` | `string` | | 核电仓地址(使用`调试器`shift+右键连接核电仓的`适配器`获取) |
42 | | `reactorChamberSide` | `number` | | 以`转运器`为基准,`核电仓`所对应的方向值 |
43 | | `switchRedstone` | `string` | | 控制该核电仓的`红石端口`地址 |
44 | | `reactorChamberSideToRS` | `number` | `reactorChamberSide`的取值 | 以`switchRedstone`对应的`红石端口`为基准,`核电仓`所对应的方向值 |
45 | | `transforAddr` | `string` | | 转运器地址 |
46 | | `inputSide` | `number` | | 以`转运器`为基准,输入原材料的箱子方向值 |
47 | | `outputSide` | `number` | | 以`转运器`为基准,输出低耐久冷却单元的箱子方向值 |
48 | | `changeItemOutputSide` | `number` | | 以`转运器`为基准,输出枯竭燃料棒方向值 |
49 | | `tempSide` | `number` | | 以`转运器`为基准,存放预加热的物品的箱子方向值 |
50 | | `energy` | `boolean` | nil | 是否参与电量控制
`true`:是
`nil\|false`:否 |
51 | | `aborted` | `boolean` | nil | 是否进行过热检测
`true`:是
`nil\|false`:否 |
52 |
53 |
54 |
55 | 方向取值:
56 |
57 | 底面: 0 对应方向:down、negy
58 |
59 | 顶面: 1 对应方向:up、posy
60 |
61 | 背面: 2 对应方向:north、negz
62 |
63 | 前面: 3 对应方向:south、posz、forward
64 |
65 | 右面: 4 对应方向:west、negx
66 |
67 | 左面: 5 对应方向:east、posx
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/database.lua:
--------------------------------------------------------------------------------
1 | local component = require("component")
2 | local config = require("config")
3 |
4 | -- 缓存全局变量
5 | local globalRedstoneSide = nil
6 | local globalRedstoneProxy = nil
7 | local reactorChambers = {}
8 | -- 缓存组件代理
9 | local componentCache = {}
10 |
11 | local function getGlobalRedstoneSide()
12 | return globalRedstoneSide
13 | end
14 |
15 | -- 获取组件代理(带缓存)
16 | local function getComponentProxy(address)
17 | if not componentCache[address] then
18 | componentCache[address] = component.proxy(address)
19 | end
20 | return componentCache[address]
21 | end
22 |
23 | -- 获取全局红石信号
24 | local function getGlobalRedstone()
25 | if not globalRedstoneProxy then
26 | globalRedstoneProxy = getComponentProxy(config.globalRedstone)
27 | end
28 |
29 | if getGlobalRedstoneSide() ~= nil then
30 | return globalRedstoneProxy.getInput(getGlobalRedstoneSide()) > 0
31 | end
32 |
33 | local signal = globalRedstoneProxy.getInput()
34 | for side, num in pairs(signal) do
35 | if num > 0 then
36 | globalRedstoneSide = side
37 | return true
38 | end
39 | end
40 | return false
41 | end
42 |
43 |
44 | -- 验证和规范化反应堆配置
45 | local function validateReactorConfig(config, index)
46 | local validated = {
47 | running = false,
48 | energy = config.energy ~= false,
49 | reactorChamberSideToRS = config.reactorChamberSideToRS or config.reactorChamberSide,
50 | name = config.name or config.reactorChamberAddr,
51 | aborted = false
52 | }
53 |
54 | -- 复制原始配置
55 | for k, v in pairs(config) do
56 | validated[k] = v
57 | end
58 |
59 | return validated
60 | end
61 |
62 | -- 硬件验证
63 | local function validateHardware(reactorConfig)
64 | local requiredComponents = {
65 | reactorChamberAddr = "反应堆仓",
66 | switchRedstone = "红石开关",
67 | transforAddr = "转运器"
68 | }
69 |
70 | for componentField, componentName in pairs(requiredComponents) do
71 | local address = reactorConfig[componentField]
72 | if not address or not getComponentProxy(address) then
73 | print(string.format("警告: 配置 %s 的 %s 组件无效", reactorConfig.name, componentName))
74 | return false
75 | end
76 | end
77 |
78 | return true
79 | end
80 |
81 | local function scanAdaptor()
82 | local reactorChamberList = config.reactorChamberList
83 | print("读取到" .. #reactorChamberList .. "个核电配置")
84 |
85 | -- 清理旧数据
86 | for k in pairs(reactorChambers) do reactorChambers[k] = nil end
87 | componentCache = {}
88 |
89 | for i = 1, #reactorChamberList do
90 | local config = reactorChamberList[i]
91 |
92 | -- 验证硬件
93 | if not validateHardware(config) then
94 | print(string.format("跳过无效配置 %d: %s", i, config.name or "未命名"))
95 | goto continue
96 | end
97 |
98 | -- 验证和规范化配置
99 | reactorChambers[i] = validateReactorConfig(config, i)
100 |
101 | print(string.format("配置 %d 使用模式: %s 预热堆温: %s 电量控制: %s",
102 | i,
103 | reactorChambers[i].scheme,
104 | reactorChambers[i].thresholdHeat or "无",
105 | tostring(reactorChambers[i].energy)))
106 |
107 | ::continue::
108 | end
109 |
110 | print(string.format("成功加载 %d 个有效反应堆配置", #reactorChambers))
111 | end
112 |
113 | -- 清理缓存
114 | local function clearCache()
115 | componentCache = {}
116 | globalRedstoneProxy = nil
117 | globalRedstoneSide = nil
118 | end
119 |
120 | -- 获取反应堆状态统计
121 | local function getReactorStats()
122 | local stats = {
123 | total = #reactorChambers,
124 | running = 0,
125 | aborted = 0,
126 | withEnergyControl = 0
127 | }
128 |
129 | for _, reactor in ipairs(reactorChambers) do
130 | -- 正在运行的数量
131 | if reactor.running then
132 | stats.running = stats.running + 1
133 | end
134 | -- 因为温度过热而停机的数量
135 | if reactor.aborted then
136 | stats.aborted = stats.aborted + 1
137 | end
138 | -- 开启了电量控制的数量
139 | if reactor.energy then
140 | stats.withEnergyControl = stats.withEnergyControl + 1
141 | end
142 | end
143 |
144 | return stats
145 | end
146 |
147 | return {
148 | scanAdaptor = scanAdaptor,
149 | reactorChambers = reactorChambers,
150 | getGlobalRedstone = getGlobalRedstone,
151 | getComponentProxy = getComponentProxy,
152 | clearCache = clearCache,
153 | getReactorStats = getReactorStats
154 | }
155 |
--------------------------------------------------------------------------------
/config.lua:
--------------------------------------------------------------------------------
1 | return {
2 | -- 核电模式
3 | scheme = {
4 | -- 模式名(slyb)
5 | slyb = {
6 | -- 所使用到的资源
7 | resource = {
8 | {
9 | name = "gregtech:gt.360k_Helium_Coolantcell",
10 | changeName = -1,
11 | dmg = 90,
12 | count = 14,
13 | slot = { 3, 6, 9, 10, 15, 22, 26, 29, 33, 40, 45, 46, 49, 52 }
14 | },
15 | {
16 | -- name = "gregtech:gt.reactorUraniumQuad",
17 | name = "gregtech:gt.rodUranium4",
18 | -- changeName = "IC2:reactorUraniumQuaddepleted",
19 | changeName = "gregtech:gt.depletedRodUranium4",
20 | dmg = -1,
21 | count = 40,
22 | slot = {
23 | 1, 2, 4, 5, 7, 8, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 23, 24, 25, 27, 28, 30, 31, 32, 34, 35, 36, 37,
24 | 38, 39, 41, 42, 43, 44, 47, 48, 50, 51, 53, 54 }
25 | }
26 | }
27 | },
28 | mox = {
29 | resource = {
30 | {
31 | name = "gregtech:gt.360k_Helium_Coolantcell",
32 | changeName = -1,
33 | dmg = 90,
34 | count = 14,
35 | slot = { 3, 6, 9, 10, 15, 22, 26, 29, 33, 40, 45, 46, 49, 52 }
36 | },
37 | {
38 | name = "gregtech:gt.reactorMOXQuad",
39 | changeName = "IC2:reactorMOXQuaddepleted",
40 | dmg = -1,
41 | count = 40,
42 | slot = {
43 | 1, 2, 4, 5, 7, 8, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 23, 24, 25, 27, 28, 30, 31, 32, 34, 35, 36, 37,
44 | 38, 39, 41, 42, 43, 44, 47, 48, 50, 51, 53, 54 }
45 | }
46 | }
47 | },
48 | yghhw = {
49 | resource = {
50 | {
51 | name = "gregtech:gt.360k_Helium_Coolantcell",
52 | changeName = -1,
53 | dmg = 90,
54 | count = 9,
55 | slot = { 5, 9, 11, 25, 31, 37, 45, 47, 51 }
56 | },
57 | {
58 | name = "gregtech:gt.Quad_Thoriumcell",
59 | changeName = "gregtech:gt.Quad_ThoriumcellDep",
60 | dmg = -1,
61 | count = 26,
62 | slot = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54 }
63 | },
64 | {
65 | name = "gregtech:gt.glowstoneCell",
66 | changeName = "gregtech:gt.sunnariumCell",
67 | dmg = -1,
68 | count = 18,
69 | slot = { 1, 3, 7, 13, 15, 17, 19, 21, 23, 27, 29, 33, 35, 39, 41, 43, 49, 53 }
70 | }
71 | }
72 | }
73 |
74 | },
75 | -- 是否开启控制台日志清理
76 | clearLog = true,
77 | -- 每n秒清理一次控制台日志
78 | cleatLogInterval = 30,
79 | --[[
80 | 是否开启电量控制(提供一个红石端口,向该端口开启红石信号后开启核电)
81 | 填入电量控制红石端口的地址,默认不启用(-1)
82 | --]]
83 | energyLatchRedstone = "535435c8-1019-440a-8b22-b8bc1b6cf9a5",
84 | -- 全局红石开关地址(必填)
85 | globalRedstone = "00b0cb29-bc9a-488a-8605-22a31028ed95",
86 | --[[
87 | 核电堆配置,可同时配置多台核电并在启动时自己选择开启哪几台,例如下边有2个核电配置,输入1 2即可开两台,只输入2则只启动第二个配置的核电
88 | 方向取值可开启f3来看当前的朝向:
89 | 底面: 0 对应方向:down、negy
90 | 顶面: 1 对应方向:up、posy
91 | 背面: 2 对应方向:north、negz
92 | 前面: 3 对应方向:south、posz、forward
93 | 右面: 4 对应方向:west、negx
94 | 左面: 5 对应方向:east、posx
95 | --]]
96 | reactorChamberList = {
97 | {
98 | name = "上堆", -- 核电堆命名(用于日志打印显示对应的名称)
99 | scheme = "slyb", -- 模式
100 | thresholdHeat = -1, -- 预热堆温
101 | preheatItem = "gregtech:gt.reactorUraniumQuad", -- 预热燃料
102 | reactorChamberAddr = "e044a135-4d27-4403-902e-b0d8d66b1c53", -- 核电仓地址
103 | reactorChamberSide = 1, -- 核电仓方向
104 | switchRedstone = "49b24209-57c8-445d-8e9e-473fec29f3de", -- 开关核电的红石端口地址
105 | reactorChamberSideToRS = 1, -- 核电仓相对于红石信号器的方向 旧版本更新的话默认填写nil即可会取{reactorChamberSide}的方向
106 | transforAddr = "4a9956c3-7f70-4b30-a0c8-dd6e25affabd", -- 转运器地址
107 | inputSide = 3, -- 输入原材料的箱子位置
108 | outputSide = 3, -- 输出低耐久冷却单元的箱子位置
109 | changeItemOutputSide = 3, -- 输出枯竭燃料棒
110 | tempSide = 3, -- 堆加热的东西的箱子位置
111 | energy = nil -- 是否参与电量控制,默认不填写或者为nil代表参与电量控制,只有在缺电时才会开启,设置为false则无视电量持续监测运行
112 | },
113 | {
114 | name = "右堆", -- 核电堆命名(用于日志打印显示对应的名称)
115 | scheme = "slyb", -- 模式
116 | thresholdHeat = -1, -- 预热堆温
117 | preheatItem = "gregtech:gt.reactorUraniumQuad", -- 预热燃料
118 | reactorChamberAddr = "3ba763f9-5c55-4be9-8ccc-5f321f702b17", -- 核电仓地址
119 | reactorChamberSide = 4, -- 核电仓方向
120 | switchRedstone = "49b24209-57c8-445d-8e9e-473fec29f3de", -- 开关核电的红石端口地址
121 | reactorChamberSideToRS = 4, -- 核电仓相对于红石信号器的方向 旧版本更新的话默认填写nil即可会取{reactorChamberSide}的方向
122 | transforAddr = "4a9956c3-7f70-4b30-a0c8-dd6e25affabd", -- 转运器地址
123 | inputSide = 3, -- 输入原材料的箱子位置
124 | outputSide = 3, -- 输出低耐久冷却单元的箱子位置
125 | changeItemOutputSide = 3, -- 输出枯竭燃料棒
126 | tempSide = 3, -- 堆加热的东西的箱子位置
127 | energy = nil -- 是否参与电量控制,默认不填写或者为nil代表参与电量控制,只有在缺电时才会开启,设置为false则无视电量持续监测运行
128 | },
129 | {
130 | name = "下堆", -- 核电堆命名(用于日志打印显示对应的名称)
131 | scheme = "slyb", -- 模式
132 | thresholdHeat = -1, -- 预热堆温
133 | preheatItem = "gregtech:gt.reactorUraniumQuad", -- 预热燃料
134 | reactorChamberAddr = "3a2fa58e-b862-4df5-ae99-b67e13fea876", -- 核电仓地址
135 | reactorChamberSide = 0, -- 核电仓方向
136 | switchRedstone = "49b24209-57c8-445d-8e9e-473fec29f3de", -- 开关核电的红石端口地址
137 | reactorChamberSideToRS = 0, -- 核电仓相对于红石信号器的方向 旧版本更新的话默认填写nil即可会取{reactorChamberSide}的方向
138 | transforAddr = "4a9956c3-7f70-4b30-a0c8-dd6e25affabd", -- 转运器地址
139 | inputSide = 3, -- 输入原材料的箱子位置
140 | outputSide = 3, -- 输出低耐久冷却单元的箱子位置
141 | changeItemOutputSide = 3, -- 输出枯竭燃料棒
142 | tempSide = 3, -- 堆加热的东西的箱子位置
143 | energy = nil -- 是否参与电量控制,默认不填写或者为nil代表参与电量控制,只有在缺电时才会开启,设置为false则无视电量持续监测运行
144 | },
145 | {
146 | name = "左堆", -- 核电堆命名(用于日志打印显示对应的名称)
147 | scheme = "slyb", -- 模式
148 | thresholdHeat = -1, -- 预热堆温
149 | preheatItem = "gregtech:gt.reactorUraniumQuad", -- 预热燃料
150 | reactorChamberAddr = "9b49cef2-44e8-42b8-8ac8-e8e91223de01", -- 核电仓地址
151 | reactorChamberSide = 5, -- 核电仓方向
152 | switchRedstone = "49b24209-57c8-445d-8e9e-473fec29f3de", -- 开关核电的红石端口地址
153 | reactorChamberSideToRS = 5, -- 核电仓相对于红石信号器的方向 旧版本更新的话默认填写nil即可会取{reactorChamberSide}的方向
154 | transforAddr = "4a9956c3-7f70-4b30-a0c8-dd6e25affabd", -- 转运器地址
155 | inputSide = 3, -- 输入原材料的箱子位置
156 | outputSide = 3, -- 输出低耐久冷却单元的箱子位置
157 | changeItemOutputSide = 3, -- 输出枯竭燃料棒
158 | tempSide = 3, -- 堆加热的东西的箱子位置
159 | energy = nil -- 是否参与电量控制,默认不填写或者为nil代表参与电量控制,只有在缺电时才会开启,设置为false则无视电量持续监测运行
160 | }
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/action.lua:
--------------------------------------------------------------------------------
1 | local component = require("component")
2 | local database = require("database")
3 | local config = require("config")
4 | local coroutine = require("coroutine")
5 | local computer = require("computer")
6 |
7 | local function coroutineSleep(time)
8 | local DDL = computer.uptime() + time
9 | while computer.uptime() < DDL do
10 | coroutine.yield()
11 | end
12 | end
13 |
14 | local function checkItemCount(runningTable)
15 | for i = 1, #runningTable, 1 do
16 | local rc = database.reactorChambers[runningTable[i]]
17 | local inputBox = component.proxy(rc.transforAddr).getAllStacks(rc.inputSide).getAll()
18 | local resource = config.scheme[rc.scheme].resource
19 | for j = 1, #resource, 1 do
20 | local num = 0
21 | for index, item in pairs(inputBox) do
22 | if item.name and item.name == resource[j].name then
23 | num = num + item.size
24 | end
25 | if num >= resource[j].count then break end
26 | end
27 | if num < resource[j].count then
28 | print(rc.name .. "所需的材料:" .. resource[j].name .. "小于" .. resource[j].count)
29 | os.exit(0)
30 | end
31 | end
32 | end
33 | end
34 |
35 | local function stopReactorChamberByRc(rc, isBlock)
36 | local redstone = component.proxy(rc.switchRedstone)
37 | if redstone.getOutput(rc.reactorChamberSideToRS) == 0 then
38 | return
39 | end
40 | rc.running = false
41 | -- setOutput为非直接调用,其正确输出对应的红石信号需要至少1tick时间
42 | redstone.setOutput(rc.reactorChamberSideToRS, 0)
43 | if isBlock then
44 | repeat
45 | coroutineSleep(0.5)
46 | local singal = redstone.getOutput(rc.reactorChamberSideToRS)
47 | until (singal == 0)
48 | end
49 | print(rc.name .. " is shutdown")
50 | end
51 |
52 | local function stopAllReactorChamber(isBlock)
53 | for i = 1, #database.reactorChambers, 1 do
54 | stopReactorChamberByRc(database.reactorChambers[i], isBlock)
55 | end
56 | end
57 |
58 | local function remove(transforAddr, sourceSide, slot, outpuSide)
59 | local transposer = component.proxy(transforAddr)
60 | repeat
61 | local removeCount = transposer.transferItem(sourceSide, outpuSide, 1, slot)
62 | if removeCount == 0 then
63 | print("箱子已满,无法输出物品")
64 | end
65 | coroutine.yield()
66 | until (removeCount > 0)
67 | end
68 |
69 | local function insert(transforAddr, sourceSide, targetSlot, outputSide, name, dmg)
70 | local transposer = component.proxy(transforAddr)
71 | while true do
72 | local sourceBox = transposer.getAllStacks(sourceSide).getAll()
73 | for index, item in pairs(sourceBox) do
74 | if item.name == name and (dmg == -1 or item.damage < dmg) then
75 | local insertCount = transposer.transferItem(sourceSide, outputSide, 1, index + 1, targetSlot)
76 | if insertCount > 0 then
77 | return
78 | end
79 | end
80 | end
81 | sourceBox = nil
82 | print("材料箱未找到物品:" .. name)
83 | coroutine.yield()
84 | end
85 | end
86 |
87 | local function startReactorChamber(rc, isBlock)
88 | if isBlock == nil then
89 | isBlock = true
90 | end
91 |
92 | local rcRedstone = component.proxy(rc.switchRedstone)
93 | if rcRedstone.getOutput(rc.reactorChamberSideToRS) > 0 then
94 | return
95 | end
96 | if rc.aborted then
97 | print(string.format(
98 | "%s was over-heated, it cannot start. You can manually cooldown it and then restart the program.", rc.name))
99 | return
100 | end
101 | rc.running = true
102 | rcRedstone.setOutput(rc.reactorChamberSideToRS, 15)
103 |
104 | if isBlock then
105 | repeat
106 | coroutine.yield()
107 | local singal = rcRedstone.getOutput(rc.reactorChamberSideToRS)
108 | until (singal > 0)
109 | end
110 |
111 | print(rc.name .. " is running")
112 | end
113 |
114 | local function preheatInsert(transforAddr, sourceSide, targetSlot, outputSide, name, dmg)
115 | local transposer = component.proxy(transforAddr)
116 | while true do
117 | local sourceBox = transposer.getAllStacks(sourceSide).getAll()
118 | for index, item in pairs(sourceBox) do
119 | if item.name == name and (dmg == -1 or item.damage < dmg) then
120 | local insertCount = transposer.transferItem(sourceSide, outputSide, 1, index + 1, targetSlot)
121 | if insertCount > 0 then
122 | return
123 | end
124 | end
125 | end
126 | sourceBox = nil
127 | print("材料箱未找到物品:" .. name)
128 | os.sleep(0)
129 | end
130 | end
131 |
132 | local function preheatRemove(transforAddr, sourceSide, slot, outpuSide)
133 | local transposer = component.proxy(transforAddr)
134 | repeat
135 | local removeCount = transposer.transferItem(sourceSide, outpuSide, 1, slot)
136 | if removeCount == 0 then
137 | print("箱子已满,无法输出物品")
138 | end
139 | os.sleep(0)
140 | until (removeCount > 0)
141 | end
142 |
143 | local function preheatRc(rc)
144 | local rcComponent = component.proxy(rc.reactorChamberAddr)
145 | if rcComponent.getHeat() >= rc.thresholdHeat then return true end
146 | preheatInsert(rc.transforAddr, rc.tempSide, 1, rc.reactorChamberSide, rc.preheatItem, -1)
147 | startReactorChamber(rc, false)
148 | repeat
149 | local heat = rcComponent.getHeat()
150 | if not database.getGlobalRedstone() then
151 | break
152 | end
153 | until (heat >= rc.thresholdHeat)
154 | stopReactorChamberByRc(rc, false)
155 | preheatRemove(rc.transforAddr, rc.reactorChamberSide, 1, rc.tempSide)
156 | end
157 |
158 | -- 向核电仓中转移原材料
159 | local function insertItemsIntoReactorChamber(runningTable)
160 | checkItemCount(runningTable)
161 | for k = 1, #runningTable, 1 do -- 原先这里是for i = 1, #runningTable, 1 do,内促内循环还有一个循环变量i,容易出问题
162 | local rc = database.reactorChambers[runningTable[k]]
163 | local transposer = component.proxy(rc.transforAddr)
164 | local sourceBoxitemList = transposer.getAllStacks(rc.inputSide).getAll()
165 | local resource = config.scheme[rc.scheme].resource
166 |
167 | if rc.thresholdHeat ~= -1 then
168 | preheatRc(rc)
169 | if not database.getGlobalRedstone() then
170 | print("终止初始化")
171 | os.exit(0)
172 | end
173 | print(rc.name .. " 预热完成")
174 | end
175 |
176 | for i = 1, #resource do
177 | local nowIndex = 0
178 | -- pairs性能比#table性能差,由于此处需要多层循环遍历,故使用numeric for
179 | for j = 1, #resource[i].slot, 1 do
180 | while nowIndex < #sourceBoxitemList do
181 | local item = sourceBoxitemList[nowIndex]
182 | if item.name == resource[i].name then
183 | transposer.transferItem(rc.inputSide, rc.reactorChamberSide, 1, nowIndex + 1, resource[i].slot
184 | [j])
185 | if transposer.getSlotStackSize(rc.inputSide, nowIndex + 1) == 0 then
186 | nowIndex = nowIndex + 1
187 | end
188 | break
189 | end
190 | nowIndex = nowIndex + 1
191 | end
192 | end
193 | end
194 | print(string.format("完成了对核反应堆 %s 的初次材料转移", rc.name))
195 | end
196 | end
197 |
198 | ---移出{transforAddr}在{rcSide}方向上的第{targetSlot}的物品到{outputSide}容器中,并将耐久阈值小于{dmg}的{itemName}放入{targetSlot}
199 | ---@param transforAddr string
200 | ---@param sourceSide integer
201 | ---@param targetSlot integer
202 | ---@param outputSide integer
203 | ---@param itemName string
204 | ---@param dmg integer
205 | local function removeAndInsert(transforAddr, rcSide, sourceSide, targetSlot, outputSide, itemName, dmg)
206 | remove(transforAddr, rcSide, targetSlot, outputSide)
207 | insert(transforAddr, sourceSide, targetSlot, rcSide, itemName, dmg)
208 | end
209 |
210 | local function checkItemChangeName(cfgResource, rc)
211 | local transposer = component.proxy(rc.transforAddr)
212 | local rcBox = transposer.getAllStacks(rc.reactorChamberSide).getAll()
213 | for i = 1, #cfgResource.slot, 1 do
214 | local boxSlot = cfgResource.slot[i]
215 | -- 名称已变化
216 | if rcBox[boxSlot - 1].name ~= cfgResource.name
217 | and rcBox[boxSlot - 1].name == cfgResource.changeName then
218 | stopReactorChamberByRc(rc, true)
219 | removeAndInsert(rc.transforAddr,
220 | rc.reactorChamberSide,
221 | rc.inputSide,
222 | boxSlot,
223 | rc.changeItemOutputSide,
224 | cfgResource.name, -1)
225 | goto continue
226 | end
227 | -- 是否为空位
228 | if rcBox[boxSlot - 1].name == nil then
229 | stopReactorChamberByRc(rc, true)
230 | insert(rc.transforAddr, rc.inputSide, boxSlot, rc.reactorChamberSide, cfgResource.name, -1)
231 | end
232 | ::continue::
233 | end
234 | end
235 |
236 | local function checkItemDmg(cfgResource, rc)
237 | local transposer = component.proxy(rc.transforAddr)
238 | local rcBox = transposer.getAllStacks(rc.reactorChamberSide).getAll()
239 | for i = 1, #cfgResource.slot, 1 do
240 | local boxSlot = cfgResource.slot[i]
241 | -- 耐久是否达到阈值
242 | if rcBox[boxSlot - 1].damage ~= nil then
243 | if rcBox[boxSlot - 1].damage >= cfgResource.dmg then
244 | stopReactorChamberByRc(rc, true)
245 | removeAndInsert(rc.transforAddr, rc.reactorChamberSide, rc.inputSide, boxSlot, rc.outputSide,
246 | cfgResource.name, cfgResource.dmg)
247 | goto continue
248 | end
249 | end
250 | -- 是否为空位
251 | if rcBox[boxSlot - 1].damage == nil then
252 | stopReactorChamberByRc(rc, true)
253 | insert(rc.transforAddr, rc.inputSide, boxSlot, rc.reactorChamberSide, cfgResource.name, -1)
254 | end
255 | ::continue::
256 | end
257 | end
258 |
259 | local function checkReactorChamberDMG(rc, scheme)
260 | for i = 1, #scheme.resource do
261 | -- 检测耐久
262 | if scheme.resource[i].dmg ~= -1 then
263 | checkItemDmg(scheme.resource[i], rc)
264 | goto continue
265 | end
266 | -- 检测替换物
267 | if scheme.resource[i].changeName ~= -1 then
268 | checkItemChangeName(scheme.resource[i], rc)
269 | end
270 | ::continue::
271 | end
272 | end
273 |
274 | return {
275 | coroutineSleep = coroutineSleep,
276 | checkItemCount = checkItemCount,
277 | insertItemsIntoReactorChamber = insertItemsIntoReactorChamber,
278 | stopAllReactorChamber = stopAllReactorChamber,
279 | checkReactorChamberDMG = checkReactorChamberDMG,
280 | startReactorChamber = startReactorChamber,
281 | stopReactorChamberByRc = stopReactorChamberByRc,
282 | preheatRc = preheatRc
283 | }
284 |
--------------------------------------------------------------------------------
/justStart.lua:
--------------------------------------------------------------------------------
1 | local database = require("database")
2 | local action = require("action")
3 | local detection = require("coolantcellThread")
4 | local config = require("config")
5 | local coroutine = require("coroutine")
6 | local computer = require("computer")
7 | local component = require("component")
8 |
9 | -- 协程类型定义
10 | local COROUTINE_TYPES = {
11 | REACTOR = 0,
12 | LOGGER = 1,
13 | HEAT_MONITOR = 2
14 | }
15 |
16 | local function printResidentMessages()
17 | local time = computer.uptime()
18 | local diffSeconds = math.floor(time - database.startTimeStamp)
19 | local days = math.floor(diffSeconds / 86400)
20 | local hours = math.floor((diffSeconds % 86400) / 3600)
21 | local minutes = math.floor((diffSeconds % 3600) / 60)
22 | print(string.format("本核电站已安全运行 %d 天 %d 时 %d 分。道路千万条,安全第一条;核电不规范,回档两行泪。", days, hours, minutes))
23 | end
24 |
25 | local function printOverHeated(rcTable)
26 | local outputLines = {}
27 | for i = 1, #rcTable do
28 | local rc = database.reactorChambers[rcTable[i]]
29 | if not rc then goto continue end
30 |
31 | local rcComponent = component.proxy(rc.reactorChamberAddr)
32 | if not rcComponent then goto continue end
33 |
34 | local heat = rcComponent.getHeat()
35 | if rc.aborted then
36 | table.insert(outputLines,
37 | string.format("The heat of %s is %d K, it is aborted due to over-heated", rc.name, heat))
38 | else
39 | table.insert(outputLines, string.format("The heat of %s is %d K", rc.name, heat))
40 | end
41 | ::continue::
42 | end
43 |
44 | -- 一次性输出所有行,减少I/O操作
45 | for _, line in ipairs(outputLines) do
46 | print(line)
47 | end
48 | outputLines = nil -- 清理内存
49 | end
50 |
51 | -- 温度监控器,过热强制关机避免爆炸
52 | local function heatMonitor(rcTable)
53 | local checkInterval = 0.1 -- 检查间隔
54 | local lastCheck = 0
55 |
56 | while true do
57 | local currentTime = computer.uptime()
58 | if currentTime - lastCheck >= checkInterval then
59 | for i = 1, #rcTable do
60 | local rc = database.reactorChambers[rcTable[i]]
61 | if not rc or rc.scheme == "mox" or not rc.aborted then
62 | goto continue_reactor
63 | end
64 |
65 | local rcComponent = component.proxy(rc.reactorChamberAddr)
66 | if not rcComponent then goto continue_reactor end
67 |
68 | local heat = rcComponent.getHeat()
69 | local threshold = rc.thresholdHeat or 0
70 |
71 | if heat >= threshold + 100 or heat >= 9960 then
72 | print(string.format("警告: %s 温度过高 (%d K),执行紧急停堆!", rc.name, heat))
73 | rc.aborted = true
74 | action.stopReactorChamberByRc(rc, false)
75 | end
76 | ::continue_reactor::
77 | end
78 | lastCheck = currentTime
79 | end
80 | coroutine.yield()
81 | end
82 | end
83 |
84 | -- 清理控制台打印信息,防止内存溢出
85 | local function clearAndIntervalMessages(rcTable)
86 | local clearLogInterval = math.max(config.cleatLogInterval or 30, 5)
87 |
88 | while true do
89 | action.coroutineSleep(clearLogInterval)
90 | os.execute("cls")
91 |
92 | -- 批量处理输出,减少协程yield
93 | printResidentMessages()
94 | printOverHeated(rcTable)
95 | print(string.format("下一次清屏计划在 %d 秒后", clearLogInterval))
96 |
97 | -- 只在最后yield一次
98 | coroutine.yield()
99 | end
100 | end
101 |
102 | -- 协程管理器
103 | local CoroutineManager = {
104 | creators = {
105 | [COROUTINE_TYPES.REACTOR] = function(rc)
106 | return function() detection.runningReactorChamber(rc) end
107 | end,
108 | [COROUTINE_TYPES.LOGGER] = function(rcTable)
109 | return function() clearAndIntervalMessages(rcTable) end
110 | end,
111 | [COROUTINE_TYPES.HEAT_MONITOR] = function(rcTable)
112 | return function() heatMonitor(rcTable) end
113 | end
114 | }
115 | }
116 |
117 | function CoroutineManager.restartCoroutine(coroutineData, rcTable)
118 | local creator = CoroutineManager.creators[coroutineData.type]
119 | if not creator then return nil end
120 |
121 | local newCoro = coroutine.create(creator(rcTable[coroutineData.index] or rcTable))
122 | return newCoro
123 | end
124 |
125 | -- 处理协程错误并重启
126 | local function handleCoroutineError(coroutineData, rcTable)
127 | print(string.format("协程 %d (类型: %d) 发生错误,正在重启...", coroutineData.index, coroutineData.type))
128 |
129 | -- 关闭旧协程
130 | if coroutine.status(coroutineData.coroutine) ~= "dead" then
131 | coroutineData.coroutine = nil
132 | end
133 |
134 | -- 创建新协程
135 | local newCoro = CoroutineManager.restartCoroutine(coroutineData, rcTable)
136 | if newCoro then
137 | coroutineData.coroutine = newCoro
138 | local success, err = coroutine.resume(newCoro)
139 | if not success then
140 | print(string.format("协程重启失败: %s", err))
141 | return false
142 | end
143 | return true
144 | else
145 | print(string.format("无法重启协程: 未知的协程类型 %d", coroutineData.type))
146 | return false
147 | end
148 | end
149 |
150 | -- 主协程调度器
151 | local function runCoroutineScheduler(coroutines, rcTable)
152 | local running = true
153 |
154 | while running do
155 | -- 检查全局开关
156 | if not database.getGlobalRedstone() then
157 | print("检测到全局开关关闭,准备安全停机...")
158 | running = false
159 | break
160 | end
161 |
162 | -- 调度所有协程
163 | for i = 1, #coroutines do
164 | local coroData = coroutines[i]
165 | if coroutine.status(coroData.coroutine) ~= "dead" then
166 | local success, err = coroutine.resume(coroData.coroutine)
167 | if not success then
168 | handleCoroutineError(coroData, rcTable)
169 | end
170 | end
171 | end
172 |
173 | os.sleep(0) -- 最高效的调度间隔
174 | end
175 |
176 | return running
177 | end
178 |
179 | -- 安全停机流程
180 | local function emergencyShutdown(rcTable)
181 | print("开始执行紧急停机程序...")
182 |
183 | local shutdownCoroutines = {}
184 | for i = 1, #rcTable do
185 | shutdownCoroutines[i] = coroutine.create(function()
186 | local rc = database.reactorChambers[rcTable[i]]
187 | if rc then
188 | action.stopReactorChamberByRc(rc, true)
189 | end
190 | end)
191 | coroutine.resume(shutdownCoroutines[i])
192 | end
193 |
194 | -- 等待所有反应堆停机
195 | local shutdownTimeout = computer.uptime() + 30 -- 30秒超时
196 | while computer.uptime() < shutdownTimeout do
197 | local stoppedCount = 0
198 | for i = 1, #shutdownCoroutines do
199 | local status = coroutine.status(shutdownCoroutines[i])
200 | if status == "dead" then
201 | stoppedCount = stoppedCount + 1
202 | else
203 | coroutine.resume(shutdownCoroutines[i])
204 | end
205 | end
206 |
207 | if stoppedCount == #rcTable then
208 | print("所有反应堆已安全停机")
209 | return true
210 | end
211 |
212 | os.sleep(0.1)
213 | end
214 |
215 | print("警告:停机超时,部分反应堆可能未完全关闭")
216 | return false
217 | end
218 |
219 | local function reactorChamberStart(rcTable)
220 | os.execute("cls")
221 | print(string.format("启动 %d 个核反应堆控制程序...", #rcTable))
222 |
223 | local coroutines = {}
224 |
225 | -- 创建反应堆监控协程
226 | for i = 1, #rcTable do
227 | local rc = database.reactorChambers[rcTable[i]]
228 | coroutines[i] = {
229 | coroutine = coroutine.create(function() detection.runningReactorChamber(rc) end),
230 | type = COROUTINE_TYPES.REACTOR,
231 | index = i
232 | }
233 | end
234 |
235 | -- 创建日志协程
236 | coroutines[#coroutines + 1] = {
237 | coroutine = coroutine.create(function() clearAndIntervalMessages(rcTable) end),
238 | type = COROUTINE_TYPES.LOGGER,
239 | index = #coroutines + 1
240 | }
241 |
242 | -- 创建温度监控协程
243 | coroutines[#coroutines + 1] = {
244 | coroutine = coroutine.create(function() heatMonitor(rcTable) end),
245 | type = COROUTINE_TYPES.HEAT_MONITOR,
246 | index = #coroutines + 1
247 | }
248 |
249 | -- 运行主调度器
250 | local running = runCoroutineScheduler(coroutines, rcTable)
251 |
252 | -- 清理协程资源
253 | for _, coroData in ipairs(coroutines) do
254 | if coroutine.status(coroData.coroutine) ~= "dead" then
255 | coroData.coroutine = nil
256 | end
257 | end
258 | coroutines = nil
259 |
260 | -- 执行停机
261 | if not running then
262 | emergencyShutdown(rcTable)
263 | end
264 |
265 | print("核反应堆控制系统已关闭")
266 | end
267 |
268 | -- 验证用户输入的反应堆配置
269 | local function validateReactorConfig(choices)
270 | local validChoices = {}
271 | local maxConfig = #config.reactorChamberList
272 |
273 | for _, choice in ipairs(choices) do
274 | if choice >= 1 and choice <= maxConfig then
275 | table.insert(validChoices, choice)
276 | else
277 | print(string.format("警告: 配置 %d 无效,跳过 (有效范围: 1-%d)", choice, maxConfig))
278 | end
279 | end
280 |
281 | if #validChoices == 0 then
282 | print("错误: 没有有效的反应堆配置")
283 | return nil
284 | end
285 |
286 | return validChoices
287 | end
288 | -- 主入口
289 | local function justStart()
290 | print("=== GTNH 核反应堆控制系统 ===")
291 | print("(0) 直接启动 (1) 配置启动 (-1) 退出")
292 |
293 | local model = io.read()
294 | if model == "-1" then
295 | print("退出系统")
296 | return
297 | end
298 |
299 | if model ~= "0" and model ~= "1" then
300 | print("无效选择,退出系统")
301 | return
302 | end
303 |
304 | print("请输入要启动的反应堆配置编号 (1-" .. #config.reactorChamberList .. "),用空格分隔:")
305 | local input = io.read()
306 |
307 | -- 解析用户输入
308 | local choices = {}
309 | for num in input:gmatch("%d+") do
310 | table.insert(choices, tonumber(num))
311 | end
312 |
313 | -- 验证配置
314 | local runningTable = validateReactorConfig(choices)
315 | if not runningTable then
316 | return
317 | end
318 |
319 | print(string.format("准备启动以下反应堆: %s", table.concat(runningTable, ", ")))
320 |
321 | database.startTimeStamp = computer.uptime()
322 |
323 | if model == "1" then
324 | print("执行初始材料装载...")
325 | local success, err = pcall(action.insertItemsIntoReactorChamber, runningTable)
326 | if not success then
327 | print(string.format("材料装载失败: %s", err))
328 | return
329 | end
330 | print("材料装载完成")
331 | end
332 |
333 | reactorChamberStart(runningTable)
334 | end
335 |
336 | -- 系统初始化和安全检查
337 | local function systemInit()
338 | print("系统初始化中...")
339 |
340 | -- 检查全局开关状态
341 | if not database.getGlobalRedstone() then
342 | print("错误: 未开启全局安全开关")
343 | action.stopAllReactorChamber(false)
344 | os.exit(1)
345 | end
346 |
347 | -- 扫描硬件适配器
348 | local success, err = pcall(database.scanAdaptor)
349 | if not success then
350 | print(string.format("硬件扫描失败: %s", err))
351 | os.exit(1)
352 | end
353 |
354 | print("系统初始化完成")
355 | print(string.format("发现 %d 个反应堆配置", #database.reactorChambers))
356 | end
357 |
358 | -- 主程序入口
359 | local function main()
360 | -- 系统初始化
361 | systemInit()
362 |
363 | -- 确保所有反应堆处于关闭状态
364 | action.stopAllReactorChamber(false)
365 |
366 | -- 启动用户界面
367 | justStart()
368 | end
369 |
370 | -- 启动主程序
371 | main()
372 |
--------------------------------------------------------------------------------