Skip to main content

Контроллер ядра v2

Для чего это нужно

Эта программа предназначена для того чтобы в ядре энергии всегда было определенное количество энергии для реакторов, чтобы в ядре не было ее слишком много или слишком мало. При избытке программа повышает выход из ядра, при недостаче - понижает или совсем отключает.

Список компонентов

Компьютер
  1. Монитор (3-ий уровень) - 6шт
  2. Клавиатура - 1шт
  3. Преобразователь энергии - 1шт
  4. Системный блок (3-ий уровень) - 1шт
  5. Адаптер - 1шт
  6. EEPROM (Lua BIOS) - 1шт
  7. Видеокарта (3-ий уровень) - 1шт
  8. Центральный процессор (ЦП) (3-ий уровень) - 1шт
  9. Память (Уровень 3.5) - 2шт
  10. Жёсткий диск (3-ий уровень) (4МВ) - 1шт
  11. OpenOS (Operating System) - 1шт
Ядро энергии
  1. Само ядро энергии (как его построить)
  2. Флаксовый гейт - 1шт
  3. Энергетический пилон - 1шт
  4. Криостабилизированная флаксовая труба - смотреть по ситуации

Первые шаги

Обязательно первым делом включаем отображение чанков (F9) и для удобства выделяем область. Дальше мы строим ядро энергии (лучше сразу 7го тира, чтобы потом не перестраивать). Главное в одном чанке. Инструкция тут. Схематика тут.

Скриншот ядра

2026-03-18_01.06.24.png

Установка компьютера

Ставим все как на скриншоте, желательно тоже в одном чанке.

Не забываем за клавиатуру!

Скриншот установки пк и мониторов

2026-03-18_01.19.56.png

Компоненты внутри системного блока

image.png

Обратите внимание что EEPROM должен быть именно (Lua BIOS), для этого создайте обычный EEPROM и в верстаке соедините его с Руководством OpenComputers.
Тоже самое касается и дискеты, делаем обычную дискету и соединяем ее с Руководством OpenComputers и мы получим дискету OpenOS (Operating System).

Подключение к ядру

Скриншот подключения к ядру

2026-03-18_01.22.23.png

На что тут надо обратить внимание.

  • После установки Энергетического пилона поставьте на него сверху стекло и он активируется, смотрите внимательно на стрелки пилона, они переключаются при нажатии ПКМ на маленькое синее ядро, стрелки ОБЯЗАТЕЛЬНО должны идти наружу, это значит что пилон работает на отдачу энергии.
  • Так же нужно внимательно устанавливать Флаксовый гейт, ровно так как на скриншоте. Фиолетовый цвет (сверху гейта) - вход энергии, оранжевый (снизу) - выход.
  • После установки всех компонентов нам нужно соединить Пилон с Гейтом Криостабилизированной флаксовой трубой (обязательно ей, ведь у нее нет ограничений)

image.png

  • Снизу же у нас будет выход энергии, к этой трубе мы запитываем что-то что может потреблять много энергии и стабильно, чтобы не было переполнения ядра. Лучше всего использовать Генераторы материи, конвертировать при помощи Универсального конвертера.

2026-03-18_01.34.16_Power_Converter.png

Очень важно, следите за тем чтобы ядро энергии не переполнялось энергией, иначе реакторам некуда будет девать энергию и они взорвутся.
Если это будет проблемой - перепишу код и добавлю энергетическую мусорку, чтобы туда сливалась лишняя энергия.

Настройка компьютера

После всех подключений мы заходим в наш системный блок и нажимаем Включить

image.png

Сначала мы видим загрузку, после чего у нас появляется вот такое окно

image.png

Для начала нам нужно установить ОС на наш компьютер, для этого впишите эту команду.
Либо скопируйте и при помощи нажатия колесика мыши вставьте ее.

install

image.png

Дальше нажмите Enter и начнется установка ОС. После завершения установки программа предложит перезагрузить ПК, опять нажмите Enter.

image.png

После перезагрузки нам нужно вписать в первую очередь себя в администраторы ПК и только потом тех кто будет им пользоваться помимо вас при помощи этой команды

Чувствителен к регистру, если у игрока ник DesOope то и в команде нужно писать DesOope, а не desoope.

useradd ник

image.png

Это мы делали для того чтобы ПК могли пользоваться только вписанные в него пользователи.

После того как мы всех добавили мы пишем такую команду

edit .shrc

и дописываем в самом конце такую строку

gate.lua

image.png

И нажимаем Ctrl + S (сохранить) и Ctrl + W (закрыть).

Это нужно чтобы программа запускалась автоматически после перезагрузки.

Дальше создаем файл gate.lua

edit gate.lua

У нас открывается окно для ввода кода, мы вписываем туда этот код. (вставлять надо по 250 строк из-за ограничений вставки кода)

local component = require("component")
local event = require("event")
local computer = require("computer")
local unicode = require("unicode")
local term = require("term")
local keyboard = require("keyboard")
local gpu = component.gpu

--------------------------------------------------------------------------------
-- [КОНФИГУРАЦИЯ]
--------------------------------------------------------------------------------
local CFG = {
  targetEnergy = 1000 * 10^9, -- Цель: 1 T RF
  aggressiveness = 0.03,      -- Плавность реакции стабилизации
  
  -- Настройки кнопок
  btnStep = 10^9,             -- Шаг (1B)
  btnStepCtrl = 10 * 10^9,    -- Шаг с Ctrl (10B)
  btnStepShift = 100 * 10^9   -- Шаг с Shift (100B)
}

local COLORS = {
  bg = 0x111111, tileBg = 0x222222, tileHeader = 0x333333,
  text = 0xEEEEEE, label = 0x999999,
  good = 0x55FF55, warn = 0xFFAA00, bad = 0xFF5555,
  energy = 0x00AAFF, sat = 0xFFAA00, fuel = 0xFFFF55,
  btn = 0x444444, btnActive = 0x006699,
  graphLine = 0x444444,
  black = 0x000000
}

-- Проверка компонентов
if not component.isAvailable("draconic_rf_storage") then 
  print("ОШИБКА: Нет ядра (draconic_rf_storage)!") 
  os.exit() 
end
if not component.isAvailable("flux_gate") then 
  print("ОШИБКА: Нет гейта (flux_gate)!") 
  os.exit() 
end

local rfStorage = component.draconic_rf_storage
local fluxGate = component.flux_gate

local W, H = gpu.maxResolution()
gpu.setResolution(W, H)

--------------------------------------------------------------------------------
-- [ПЕРЕМЕННЫЕ И РАСЧЕТ МАКЕТА]
--------------------------------------------------------------------------------
local running = true
local buttons = {}

-- === НАСТРОЙКА СИММЕТРИИ ===
local M = 2 -- Отступ (Margin) со всех сторон
local panelH = 9 -- Высота верхних панелей

-- Расчет координат
local totalW = W - (M * 3) 
local panelW = math.floor(totalW / 2)

-- Левая панель
local x1 = M
local y1 = M

-- Правая панель
local x2 = x1 + panelW + M
local y2 = M

-- График
local graphX = M
local graphY = y1 + panelH + 1
local graphW = W - (M * 2)
local graphH = H - graphY - M - 2 

local energyHistory = {} 
for i = 1, graphW do energyHistory[i] = 0 end

local maxCoreCapacity = rfStorage.getMaxEnergyStored()

-- Фильтр (Плавность)
local filVal = 0
local function expRunningAvg(newVal)
  if math.abs(newVal - filVal) > 10^15 then filVal = newVal end
  filVal = filVal + ((newVal - filVal) * 0.05) 
  return filVal
end

--------------------------------------------------------------------------------
-- [ГРАФИКА - ФУНКЦИИ]
--------------------------------------------------------------------------------
local function rect(x, y, w, h, col) 
  gpu.setBackground(col)
  gpu.fill(x, y, w, h, " ") 
end

local function text(x, y, str, fg, bg) 
  if bg then gpu.setBackground(bg) end
  gpu.setForeground(fg)
  gpu.set(x, y, str) 
end

local function center(x, y, w, str, fg, bg)
  if bg then gpu.setBackground(bg) end
  gpu.fill(x, y, w, 1, " ") 
  local px = x + math.floor((w - unicode.len(str))/2)
  if fg then gpu.setForeground(fg) end
  gpu.set(px, y, str)
end

-- ВНИМАНИЕ: Эта функция очищает всю строку под собой.
local function textRight(x, y, w, str, fg, bg)
  if bg then gpu.setBackground(bg) end
  gpu.fill(x, y, w, 1, " ") 
  local len = unicode.len(str)
  local px = x + w - len
  if fg then gpu.setForeground(fg) end
  gpu.set(px, y, str)
end

local function fmt(num)
  if math.abs(num) >= 10^12 then return string.format("%.3f T", num/10^12)
  elseif math.abs(num) >= 10^9 then return string.format("%.3f B", num/10^9)
  elseif math.abs(num) >= 10^6 then return string.format("%.3f M", num/10^6)
  elseif math.abs(num) >= 10^3 then return string.format("%.3f K", num/10^3)
  else return string.format("%d", math.floor(num)) end
end

local function progressBar(x, y, w, pct, colBar, colBg)
  rect(x, y, w, 1, colBg)
  local barW = math.floor(w * (pct/100))
  if barW > w then barW = w end
  if barW > 0 then rect(x, y, barW, 1, colBar) end
end

local function btn(id, x, y, w, h, str, bg, fg)
  rect(x, y, w, h, bg)
  center(x, y + math.floor(h/2), w, str, fg or COLORS.text, bg)
  buttons[id] = {x=x, y=y, w=w, h=h}
end

--------------------------------------------------------------------------------
-- [ИНТЕРФЕЙС]
--------------------------------------------------------------------------------

local function drawStaticInterface()
  gpu.setBackground(COLORS.bg)
  term.clear()
  
  -- Левая панель
  rect(x1, y1, panelW, panelH, COLORS.tileBg)
  rect(x1, y1, panelW, 1, COLORS.tileHeader)
  center(x1, y1, panelW, "СОСТОЯНИЕ ЯДРА", COLORS.text, COLORS.tileHeader)
  
  text(x1+2, y1+2, "НАКОПЛЕНО:", COLORS.label, COLORS.tileBg)
  text(x1+2, y1+4, "ЦЕЛЬ СТАБ.:", COLORS.label, COLORS.tileBg)

  -- Правая панель
  rect(x2, y2, panelW, panelH, COLORS.tileBg)
  rect(x2, y2, panelW, 1, COLORS.tileHeader)
  center(x2, y2, panelW, "ЭНЕРГИЯ", COLORS.text, COLORS.tileHeader)

  text(x2+2, y2+2, "ТЕКУЩИЙ ПОТОК:", COLORS.label, COLORS.tileBg)
  text(x2+2, y2+4, "ВЫХОД ГЕЙТА:", COLORS.label, COLORS.tileBg)
  
  -- График
  rect(graphX, graphY, graphW, 1, COLORS.tileHeader) 
  center(graphX, graphY, graphW, " ГРАФИК ПОТОКА ", COLORS.label, COLORS.tileHeader)
  rect(graphX, graphY+1, graphW, graphH, COLORS.bg) 
  
  -- Подвал
  local footerY = H - 1
  btn("exit", M, footerY, 10, 1, "ВЫХОД", COLORS.bad)
  
  -- Кредиты
  local crX = W - 32
  local crY = H - 3
  text(crX, crY,   "Разработчик: DesOope", COLORS.label, COLORS.bg)
  text(crX, crY+1, "Проект: McSkill", COLORS.label, COLORS.bg)
  text(crX, crY+2, "Сервер: HitechClassic 1.7.10", COLORS.label, COLORS.bg)
end

local function drawGraph(delta)
    table.insert(energyHistory, delta)
    while #energyHistory > graphW do table.remove(energyHistory, 1) end
    
    local gTopY = graphY + 1
    local gBottomY = graphY + graphH
    local midY = gTopY + math.floor(graphH/2)
    
    if graphH < 2 then return end
    
    local maxVal = 1
    for _, v in ipairs(energyHistory) do
        if math.abs(v) > maxVal then maxVal = math.abs(v) end
    end
    
    for i = 1, graphW do
        local val = energyHistory[i] or 0
        local x = graphX + i - 1
        
        local h = 0
        if math.abs(val) > 0 then
            h = math.ceil( (math.abs(val) / maxVal) * (graphH/2) )
            if h > (graphH/2) then h = math.floor(graphH/2) end
        end

        local barTop, barBottom
        local color
        
        if val > 0 then
            barBottom = midY + 1 
            barTop = barBottom - h
            if barTop < gTopY then barTop = gTopY end
            color = COLORS.good
        elseif val < 0 then
            barTop = midY + 1
            barBottom = barTop + h
            if barBottom > gBottomY then barBottom = gBottomY end
            color = COLORS.bad
        else
            barTop = midY
            barBottom = midY + 1
            color = COLORS.bg 
        end

        if barTop > gTopY then
            gpu.setBackground(COLORS.bg)
            gpu.fill(x, gTopY, 1, barTop - gTopY, " ")
        end
        
        local barH = barBottom - barTop
        if val ~= 0 and barH > 0 then
            gpu.setBackground(color)
            gpu.fill(x, barTop, 1, barH, " ")
        elseif val == 0 then
            gpu.setBackground(COLORS.bg)
            gpu.setForeground(COLORS.graphLine)
            gpu.set(x, midY, "─")
        end
        
        if barBottom < gBottomY then
            gpu.setBackground(COLORS.bg)
            local clearH = gBottomY - barBottom + 1 
            gpu.fill(x, barBottom, 1, clearH, " ")
        end
    end
end

local function updateLiveDisplay(stored, target, delta, gateFlow)
  local valWidth = 16 
  local valX = x1 + panelW - valWidth - 2
  
  -- === ЛЕВАЯ ПАНЕЛЬ ===
  center(valX, y1+2, valWidth, fmt(stored).." RF", COLORS.energy, COLORS.tileBg)
  center(valX, y1+4, valWidth, fmt(target).." RF", COLORS.warn, COLORS.tileBg)
  
  local btnW = 3
  local btnPlusX = valX - btnW - 1
  btn("inc", btnPlusX, y1+4, btnW, 1, "+", COLORS.btn)
  local btnMinusX = btnPlusX - btnW - 1
  btn("dec", btnMinusX, y1+4, btnW, 1, "-", COLORS.btn)
  
  local maxPct = (stored / maxCoreCapacity) * 100
  if maxPct > 100 then maxPct = 100 end
  
  local barX = x1 + 2
  local barW = panelW - 4
  
  center(barX, y1+6, barW, string.format("%.2f%% (от макс. объема)", maxPct), COLORS.text, COLORS.tileBg)
  text(barX, y1+6, "0%", COLORS.label)
  
  local str100 = "100%"
  local x100 = barX + barW - unicode.len(str100)
  text(x100, y1+6, str100, COLORS.label)
  
  progressBar(barX, y1+7, barW, maxPct, COLORS.energy, 0x111111)

  -- === ПРАВАЯ ПАНЕЛЬ ===
  local valX2 = x2 + panelW - valWidth - 2
  
  local dColor = COLORS.text
  local sign = ""
  if delta > 0 then dColor = COLORS.good; sign = "+"
  elseif delta < 0 then dColor = COLORS.bad; sign = "" end 
  
  center(valX2, y2+2, valWidth, sign..fmt(delta).." RF/t", dColor, COLORS.tileBg)
  center(valX2, y2+4, valWidth, fmt(gateFlow).." RF/t", COLORS.text, COLORS.tileBg)
  
  -- === БОЛЬШОЙ СТАТУС БАР (ВНИЗУ) ===
  local statusStr = ""
  local statusBg = COLORS.btn
  local statusFg = COLORS.black
  
  -- НОВАЯ ЛОГИКА СТАТУСОВ
  if math.abs(stored - target) < 10^9 then
      -- Энергия в норме (равна цели)
      statusStr = "СТАБИЛЬНО"
      statusBg = COLORS.good
  else
      if stored < target then
          -- Нехватка энергии
          if delta > 0 then
             -- Но она растет = Хорошо
             statusStr = "ВОСПОЛНЕНИЕ"
             statusBg = COLORS.energy -- Синий
          else
             -- Она падает = Плохо
             statusStr = "ВНИМАНИЕ: РАЗРЯД"
             statusBg = COLORS.bad -- Красный
             statusFg = 0xFFFFFF 
          end
      else
          -- Избыток энергии
          if delta < 0 then
             -- Она падает (возвращается к цели) = Хорошо
             statusStr = "СБРОС ИЗЛИШКОВ"
             statusBg = COLORS.warn -- Оранжевый
          else
             -- Она растет дальше = Плохо
             statusStr = "КРИТИЧЕСКОЕ ПЕРЕПОЛНЕНИЕ"
             statusBg = COLORS.bad -- Красный
             statusFg = 0xFFFFFF
          end
      end
  end
  
  local stX = x2 + 2
  local stW = panelW - 4
  local stY = y2 + 6
  local stH = 3 
  
  gpu.setBackground(statusBg)
  gpu.fill(stX, stY, stW, stH, " ")
  center(stX, stY + 1, stW, statusStr, statusFg, statusBg)
  
  drawGraph(delta)
end

local function handleTouch(x, y)
  for id, b in pairs(buttons) do
    if x >= b.x and x < b.x + b.w and y >= b.y and y < b.y + b.h then
      if id == "exit" then 
          running = false 
      elseif id == "inc" or id == "dec" then
          local step = CFG.btnStep
          if keyboard.isControlDown() then step = CFG.btnStepCtrl
          elseif keyboard.isShiftDown() then step = CFG.btnStepShift end
          
          if id == "dec" then CFG.targetEnergy = CFG.targetEnergy - step end
          if id == "inc" then CFG.targetEnergy = CFG.targetEnergy + step end
          
          if CFG.targetEnergy < 0 then CFG.targetEnergy = 0 end
          computer.beep(1000, 0.05)
          
          rect(b.x, b.y, b.w, b.h, COLORS.good)
          os.sleep(0.05)
          rect(b.x, b.y, b.w, b.h, COLORS.btn)
      end
    end
  end
end

--------------------------------------------------------------------------------
-- [ГЛАВНЫЙ ЦИКЛ]
--------------------------------------------------------------------------------
drawStaticInterface()

local prevTime = computer.uptime()
local prevEnergy = rfStorage.getEnergyStored()

while running do
  local nowTime = computer.uptime()
  local dt = nowTime - prevTime
  
  if dt < 0.2 then 
      os.sleep(0.2)
      nowTime = computer.uptime()
      dt = nowTime - prevTime
  end
  
  local nowEnergy = rfStorage.getEnergyStored()
  local rawDiff = (nowEnergy - prevEnergy) / (dt * 20)
  
  local smoothedDiff = expRunningAvg(rawDiff)
  
  local currentGate = fluxGate.getFlow()
  local errorVal = nowEnergy - CFG.targetEnergy
  local correction = errorVal * CFG.aggressiveness
  local newGate = currentGate + smoothedDiff + correction
  
  if newGate < 0 then newGate = 0 end
  
  if math.abs(newGate - currentGate) > 500 then
      fluxGate.setSignalLowFlow(math.floor(newGate))
  end
  
  updateLiveDisplay(nowEnergy, CFG.targetEnergy, smoothedDiff, newGate)
  
  local sig = {event.pull(0.1, "touch")}
  if sig[1] then handleTouch(sig[3], sig[4]) end
  
  prevTime = nowTime
  prevEnergy = nowEnergy
end

gpu.setResolution(W, H)
gpu.setBackground(0x000000)
gpu.setForeground(0xFFFFFF)
term.clear()

И нажимаем Ctrl + S (сохранить) и Ctrl + W (закрыть).

После перезагружаем систему командой

reboot

После перезапуска у нас сразу откроется программа стабилизации ядра и мы будем видеть его состояние

image.png

Управление простое + и - для регулирования количества энергии в ядре
ЛКМ добавить или отнять 1B (млрд)
Ctrl+ЛКМ добавить или отнять 10B (млрд)
Shift+ЛКМ добавить или отнять 100B (млрд)

Когда количество энергии дойдет до той что вы выставили - лишняя энергия начнет выходить через Флаксовый гейт. 
Если цель энергии не достигнута - через гейт энергия не идет
Если энергии больше чем должно быть - выход гейта будет повышаться до тех пор пока ее количество не стабилизируется