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 (млрд)

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