Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- ============================================================
- -- AE2 STORAGE WALL
- -- FTB Evolution 1.21.1
- --
- -- CC:Tweaked + Advanced Peripherals ME Bridge
- --
- -- Storage-only version:
- -- ITEMS | FLUIDS
- -- CHEMICALS | RADIATION
- --
- -- Features:
- -- * 1.5 text scale for readability at distance
- -- * No crafting section
- -- * Uses virtually all vertical space
- -- * Flicker-free differential rendering
- -- * Exact MEGA radioactive cell detection
- -- * AE2 Things no-type-limit DISKs excluded from slot total
- -- * Other addon storage types shown in footer if present
- -- ============================================================
- local CONFIG = {
- refresh = 1.5,
- -- The previous screenshot is still physically too small.
- -- 1.5 makes the text 50% larger than 1.0.
- textScale = 1.5,
- }
- -- ============================================================
- -- PERIPHERALS
- -- ============================================================
- local bridge =
- peripheral.find("me_bridge")
- or peripheral.find("meBridge")
- local monitor =
- peripheral.find("monitor")
- if not bridge then
- error("No ME Bridge found")
- end
- if not monitor then
- error("No monitor found")
- end
- monitor.setTextScale(CONFIG.textScale)
- monitor.setCursorBlink(false)
- -- ============================================================
- -- COLOURS
- -- ============================================================
- local C = {
- bg = colors.black,
- headerBg = colors.gray,
- divider = colors.gray,
- text = colors.white,
- muted = colors.lightGray,
- dim = colors.gray,
- item = colors.cyan,
- fluid = colors.lightBlue,
- chemical = colors.purple,
- radiation = colors.orange,
- other = colors.yellow,
- good = colors.lime,
- warning = colors.yellow,
- bad = colors.red,
- emptyBar = colors.gray,
- }
- -- ============================================================
- -- DIFFERENTIAL FRAME BUFFER
- --
- -- We NEVER clear the physical monitor during normal refresh.
- --
- -- The complete new UI is rendered into an invisible window.
- -- We then compare every line against the previous frame and
- -- only send changed rows to the physical monitor.
- -- ============================================================
- local buffer = nil
- local bufferW = 0
- local bufferH = 0
- local previousFrame = {}
- local function makeBuffer()
- local w, h = monitor.getSize()
- if buffer and
- w == bufferW and
- h == bufferH then
- return
- end
- bufferW = w
- bufferH = h
- buffer =
- window.create(
- monitor,
- 1,
- 1,
- w,
- h,
- false
- )
- previousFrame = {}
- -- Only clear when initially starting or the monitor
- -- dimensions genuinely change.
- monitor.setBackgroundColor(C.bg)
- monitor.clear()
- monitor.setCursorBlink(false)
- end
- local function beginFrame()
- makeBuffer()
- buffer.setVisible(false)
- buffer.setCursorBlink(false)
- buffer.setBackgroundColor(C.bg)
- buffer.setTextColor(C.text)
- -- This clears ONLY THE HIDDEN WINDOW.
- -- The actual wall monitor remains untouched.
- buffer.clear()
- end
- local function commitFrame()
- for y = 1, bufferH do
- local text, fg, bg =
- buffer.getLine(y)
- local old =
- previousFrame[y]
- if not old
- or old.text ~= text
- or old.fg ~= fg
- or old.bg ~= bg then
- monitor.setCursorPos(1, y)
- monitor.blit(text, fg, bg)
- previousFrame[y] = {
- text = text,
- fg = fg,
- bg = bg,
- }
- end
- end
- monitor.setCursorBlink(false)
- end
- -- ============================================================
- -- BRIDGE CALL
- -- ============================================================
- local function bridgeCall(method, ...)
- local fn = bridge[method]
- if type(fn) ~= "function" then
- return nil
- end
- local ok, a, b, c =
- pcall(fn, ...)
- if not ok then
- return nil
- end
- return a, b, c
- end
- -- ============================================================
- -- BASIC HELPERS
- -- ============================================================
- local function clamp(v, minV, maxV)
- if v < minV then
- return minV
- end
- if v > maxV then
- return maxV
- end
- return v
- end
- local function countTable(t)
- if type(t) ~= "table" then
- return 0
- end
- local n = 0
- for _ in pairs(t) do
- n = n + 1
- end
- return n
- end
- local function fit(text, width)
- text = tostring(text or "")
- if width <= 0 then
- return ""
- end
- if #text <= width then
- return text
- end
- if width <= 3 then
- return text:sub(1, width)
- end
- return text:sub(1, width - 2) .. ".."
- end
- local function formatBytes(bytes)
- bytes = tonumber(bytes) or 0
- if bytes >= 1024 ^ 4 then
- return string.format(
- "%.1fTiB",
- bytes / 1024 ^ 4
- )
- elseif bytes >= 1024 ^ 3 then
- return string.format(
- "%.1fGiB",
- bytes / 1024 ^ 3
- )
- elseif bytes >= 1024 ^ 2 then
- return string.format(
- "%.1fMiB",
- bytes / 1024 ^ 2
- )
- elseif bytes >= 1024 then
- return string.format(
- "%.1fKiB",
- bytes / 1024
- )
- else
- return tostring(
- math.floor(bytes)
- ) .. "B"
- end
- end
- local function percentColour(p)
- if p >= 0.90 then
- return C.bad
- elseif p >= 0.70 then
- return C.warning
- else
- return C.good
- end
- end
- -- ============================================================
- -- DRAW HELPERS
- -- ============================================================
- local function writeAt(
- x,
- y,
- text,
- fg,
- bg,
- maxWidth
- )
- if y < 1 or y > bufferH then
- return
- end
- if x < 1 or x > bufferW then
- return
- end
- text = tostring(text or "")
- if maxWidth then
- text = fit(text, maxWidth)
- end
- if x + #text - 1 > bufferW then
- text =
- text:sub(
- 1,
- bufferW - x + 1
- )
- end
- if #text <= 0 then
- return
- end
- buffer.setCursorPos(x, y)
- buffer.setTextColor(
- fg or C.text
- )
- buffer.setBackgroundColor(
- bg or C.bg
- )
- buffer.write(text)
- end
- local function fill(
- x,
- y,
- width,
- colour
- )
- if y < 1 or y > bufferH then
- return
- end
- if x < 1 then
- width =
- width - (1 - x)
- x = 1
- end
- width =
- math.min(
- width,
- bufferW - x + 1
- )
- if width <= 0 then
- return
- end
- buffer.setCursorPos(x, y)
- buffer.setBackgroundColor(colour)
- buffer.write(
- string.rep(" ", width)
- )
- buffer.setBackgroundColor(C.bg)
- end
- local function center(
- x,
- y,
- width,
- text,
- fg,
- bg
- )
- text =
- fit(
- tostring(text or ""),
- width
- )
- local start =
- x
- + math.max(
- 0,
- math.floor(
- (width - #text) / 2
- )
- )
- writeAt(
- start,
- y,
- text,
- fg,
- bg
- )
- end
- local function rightText(
- y,
- text,
- fg,
- bg
- )
- text = tostring(text or "")
- writeAt(
- math.max(
- 1,
- bufferW - #text + 1
- ),
- y,
- text,
- fg,
- bg
- )
- end
- local function drawBar(
- x,
- y,
- width,
- percent,
- colour
- )
- percent =
- clamp(
- tonumber(percent) or 0,
- 0,
- 1
- )
- local filled =
- math.floor(
- width * percent + 0.5
- )
- fill(
- x,
- y,
- width,
- C.emptyBar
- )
- if filled > 0 then
- fill(
- x,
- y,
- filled,
- colour
- )
- end
- end
- -- ============================================================
- -- CELL IDENTITY
- -- ============================================================
- local function cellItemId(cell)
- if type(cell) ~= "table" then
- return ""
- end
- local item = cell.item
- if type(item) == "string" then
- return item
- end
- if type(item) == "table" then
- return tostring(
- item.name
- or item.id
- or item.registryName
- or ""
- )
- end
- return tostring(
- cell.name or ""
- )
- end
- local function cellDisplayName(cell)
- if type(cell) ~= "table" then
- return ""
- end
- local item = cell.item
- if type(item) == "table" then
- return tostring(
- item.displayName
- or item.label
- or ""
- )
- end
- return ""
- end
- local function storageType(cell)
- if type(cell) ~= "table" then
- return ""
- end
- return tostring(
- cell.type
- or cell.cellType
- or ""
- ):lower()
- end
- -- ============================================================
- -- UNLIMITED TYPE CELLS / DISKS
- --
- -- They still count towards byte capacity.
- -- They DO NOT contribute to the type-slot capacity figure.
- -- ============================================================
- local function isUnlimitedTypeStorage(cell)
- local id =
- cellItemId(cell):lower()
- -- AE2 Things DISKs
- if id:find(
- "^ae2things:"
- )
- and id:find(
- "disk",
- 1,
- true
- ) then
- return true
- end
- -- ExtendedAE infinity storage, if present.
- if id:find(
- "^extendedae:"
- )
- and id:find(
- "infinity",
- 1,
- true
- )
- and id:find(
- "cell",
- 1,
- true
- ) then
- return true
- end
- return false
- end
- -- ============================================================
- -- CELL CLASSIFICATION
- -- ============================================================
- local function classifyCell(cell)
- local id =
- cellItemId(cell):lower()
- local display =
- cellDisplayName(cell):lower()
- local typ =
- storageType(cell)
- local identity =
- id .. " " .. display
- -- ========================================================
- -- RADIATION FIRST
- --
- -- Exact MEGA Cells 1.21.1 registry ID:
- --
- -- megacells:radioactive_chemical_cell
- --
- -- This MUST be tested before ordinary chemical storage
- -- because the underlying AE key type is chemical.
- -- ========================================================
- if id ==
- "megacells:radioactive_chemical_cell" then
- return "radiation"
- end
- -- Additional robust fallback in case a future MEGA build
- -- alters how Advanced Peripherals exposes the Item Object.
- if id:find(
- "^megacells:"
- )
- and id:find(
- "radioactive",
- 1,
- true
- )
- and id:find(
- "chemical",
- 1,
- true
- ) then
- return "radiation"
- end
- if identity:find(
- "radioactive chemical",
- 1,
- true
- ) then
- return "radiation"
- end
- if identity:find(
- "radioactive_chemical",
- 1,
- true
- ) then
- return "radiation"
- end
- if typ:find(
- "radioactive",
- 1,
- true
- )
- or typ:find(
- "radiation",
- 1,
- true
- ) then
- return "radiation"
- end
- -- ========================================================
- -- FLUID
- -- ========================================================
- if typ == "ae2:f"
- or typ == "fluid"
- or typ:find(
- "fluid",
- 1,
- true
- ) then
- return "fluid"
- end
- -- ========================================================
- -- CHEMICAL
- --
- -- All chemical key variants are deliberately folded into
- -- this single group. This fixes the duplicate CHEMICAL
- -- panel from the previous script.
- -- ========================================================
- if typ == "ae2:chemical"
- or typ == "chemical"
- or typ:find(
- "chemical",
- 1,
- true
- )
- or typ:find(
- "gas",
- 1,
- true
- )
- or id:find(
- "chemical_storage_cell",
- 1,
- true
- ) then
- return "chemical"
- end
- -- ========================================================
- -- ITEM
- -- ========================================================
- if typ == "ae2:i"
- or typ == "item"
- or typ:find(
- ":item",
- 1,
- true
- ) then
- return "item"
- end
- return "other:" .. typ
- end
- -- ============================================================
- -- STORAGE GROUPS
- -- ============================================================
- local function newGroup(
- key,
- title,
- colour
- )
- return {
- key = key,
- title = title,
- colour = colour,
- cells = 0,
- used = 0,
- capacity = 0,
- typeCapacity = 0,
- unlimitedCells = 0,
- unlimitedCapacity = 0,
- resourceTypes = 0,
- resourceAmount = 0,
- externalStorage = false,
- }
- end
- local function addCell(
- group,
- cell
- )
- local used =
- tonumber(
- cell.usedBytes
- or cell.used
- ) or 0
- local capacity =
- tonumber(
- cell.bytes
- or cell.capacity
- ) or 0
- group.cells =
- group.cells + 1
- group.used =
- group.used + used
- group.capacity =
- group.capacity + capacity
- if isUnlimitedTypeStorage(cell) then
- group.unlimitedCells =
- group.unlimitedCells + 1
- group.unlimitedCapacity =
- group.unlimitedCapacity
- + capacity
- -- Deliberately DO NOT add totalBytes.
- return
- end
- local types =
- tonumber(
- cell.totalBytes
- )
- if types and types > 0 then
- group.typeCapacity =
- group.typeCapacity
- + types
- end
- end
- -- ============================================================
- -- RADIOACTIVE CHEMICAL DETECTION
- -- ============================================================
- local function isRadioactiveChemical(chemical)
- if type(chemical) ~= "table" then
- return false
- end
- local radioactivity =
- tonumber(
- chemical.radioactivity
- ) or 0
- if radioactivity > 0 then
- return true
- end
- -- Fallback for anything whose AP object fails to expose
- -- radioactivity for some reason.
- local name =
- tostring(
- chemical.name or ""
- ):lower()
- if name:find(
- "nuclear_waste",
- 1,
- true
- )
- or name:find(
- "spent_nuclear_waste",
- 1,
- true
- )
- or name:find(
- "polonium",
- 1,
- true
- )
- or name:find(
- "plutonium",
- 1,
- true
- ) then
- return true
- end
- return false
- end
- -- ============================================================
- -- COLLECT STORAGE DATA
- -- ============================================================
- local function gatherStorage()
- local groups = {
- item =
- newGroup(
- "item",
- "ITEMS",
- C.item
- ),
- fluid =
- newGroup(
- "fluid",
- "FLUIDS",
- C.fluid
- ),
- chemical =
- newGroup(
- "chemical",
- "CHEMICALS",
- C.chemical
- ),
- radiation =
- newGroup(
- "radiation",
- "RADIATION",
- C.radiation
- ),
- }
- local others = {}
- -- ========================================================
- -- CELLS
- -- ========================================================
- local cells =
- bridgeCall("getCells")
- if type(cells) ~= "table" then
- cells = {}
- end
- for _, cell in pairs(cells) do
- local category =
- classifyCell(cell)
- local group =
- groups[category]
- if group then
- addCell(
- group,
- cell
- )
- else
- if not others[category] then
- local typ =
- storageType(cell)
- local title =
- typ:match(":(.+)$")
- or typ
- or "OTHER"
- title =
- title
- :gsub("_", " ")
- :upper()
- others[category] =
- newGroup(
- category,
- title,
- C.other
- )
- end
- addCell(
- others[category],
- cell
- )
- end
- end
- -- ========================================================
- -- NETWORK RESOURCE TYPES
- -- ========================================================
- local items =
- bridgeCall(
- "getItems",
- {}
- )
- groups.item.resourceTypes =
- countTable(items)
- local fluids =
- bridgeCall(
- "getFluids",
- {}
- )
- groups.fluid.resourceTypes =
- countTable(fluids)
- local chemicals =
- bridgeCall(
- "getChemicals",
- {}
- )
- if type(chemicals) == "table" then
- for _, chemical in pairs(chemicals) do
- local amount =
- tonumber(
- chemical.count
- or chemical.amount
- ) or 0
- if isRadioactiveChemical(
- chemical
- ) then
- groups.radiation.resourceTypes =
- groups.radiation.resourceTypes
- + 1
- groups.radiation.resourceAmount =
- groups.radiation.resourceAmount
- + amount
- else
- groups.chemical.resourceTypes =
- groups.chemical.resourceTypes
- + 1
- groups.chemical.resourceAmount =
- groups.chemical.resourceAmount
- + amount
- end
- end
- end
- -- ========================================================
- -- EXTERNAL STORAGE
- --
- -- A Storage Bus means the network type count does not
- -- necessarily equal the slots occupied inside cells.
- -- ========================================================
- local externalItems =
- tonumber(
- bridgeCall(
- "getUsedExternItemCount"
- )
- ) or 0
- local externalFluids =
- tonumber(
- bridgeCall(
- "getUsedExternFluidStorage"
- )
- ) or 0
- local externalChemicals =
- tonumber(
- bridgeCall(
- "getUsedExternChemicalStorage"
- )
- ) or 0
- groups.item.externalStorage =
- externalItems > 0
- groups.fluid.externalStorage =
- externalFluids > 0
- groups.chemical.externalStorage =
- externalChemicals > 0
- groups.radiation.externalStorage =
- externalChemicals > 0
- return groups, others
- end
- -- ============================================================
- -- TYPE TEXT
- -- ============================================================
- local function getTypeText(
- group,
- width
- )
- if group.typeCapacity <= 0 then
- if group.resourceTypes > 0 then
- return
- tostring(
- group.resourceTypes
- )
- .. " TYPES"
- end
- return "0 TYPES"
- end
- -- If an unlimited DISK is present, a network-wide type
- -- count cannot tell us how many types are specifically
- -- occupying the limited cells.
- --
- -- Show both facts without pretending they're the same:
- --
- -- NET 2393 SLOTS 630
- --
- if group.unlimitedCells > 0
- or group.externalStorage then
- if width >= 21 then
- return
- "NET "
- .. tostring(
- group.resourceTypes
- )
- .. " SLOTS "
- .. tostring(
- group.typeCapacity
- )
- else
- return
- "NET"
- .. tostring(
- group.resourceTypes
- )
- .. " S"
- .. tostring(
- group.typeCapacity
- )
- end
- end
- return
- "TYPES "
- .. tostring(
- group.resourceTypes
- )
- .. "/"
- .. tostring(
- group.typeCapacity
- )
- end
- -- ============================================================
- -- STORAGE PANEL
- -- ============================================================
- local function drawStoragePanel(
- x,
- y,
- width,
- height,
- group
- )
- if width <= 0 or height <= 0 then
- return
- end
- -- ========================================================
- -- PANEL HEADER
- -- ========================================================
- fill(
- x,
- y,
- width,
- C.headerBg
- )
- center(
- x,
- y,
- width,
- group.title,
- group.colour,
- C.headerBg
- )
- if height <= 1 then
- return
- end
- -- ========================================================
- -- NO CELL
- -- ========================================================
- if group.cells <= 0 then
- local centreY =
- y
- + math.floor(
- height / 2
- )
- center(
- x,
- centreY - 1,
- width,
- "NO CELL",
- C.dim
- )
- if group.resourceTypes > 0 then
- center(
- x,
- centreY,
- width,
- "NET "
- .. tostring(
- group.resourceTypes
- )
- .. " TYPES",
- C.muted
- )
- end
- return
- end
- -- Cell is detected but AP gave no byte capacity.
- if group.capacity <= 0 then
- local centreY =
- y
- + math.floor(
- height / 2
- )
- center(
- x,
- centreY - 1,
- width,
- "CELL DETECTED",
- group.colour
- )
- center(
- x,
- centreY,
- width,
- "NO CAPACITY DATA",
- C.warning
- )
- return
- end
- local percentage =
- clamp(
- group.used /
- group.capacity,
- 0,
- 1
- )
- local free =
- math.max(
- 0,
- group.capacity
- - group.used
- )
- local colour =
- percentColour(
- percentage
- )
- -- ========================================================
- -- COMPACT PANEL
- -- ========================================================
- if height <= 6 then
- center(
- x,
- y + 1,
- width,
- formatBytes(group.used)
- .. "/"
- .. formatBytes(
- group.capacity
- ),
- C.text
- )
- center(
- x,
- y + 2,
- width,
- "FREE "
- .. formatBytes(free)
- .. " "
- .. string.format(
- "%.1f%%",
- percentage * 100
- ),
- colour
- )
- center(
- x,
- y + 3,
- width,
- getTypeText(
- group,
- width
- ),
- C.text
- )
- local detail =
- tostring(
- group.cells
- )
- .. " CELL"
- if group.cells ~= 1 then
- detail =
- detail .. "S"
- end
- if group.unlimitedCapacity > 0 then
- detail =
- "DISK "
- .. formatBytes(
- group.unlimitedCapacity
- )
- end
- center(
- x,
- y + 4,
- width,
- detail,
- C.muted
- )
- drawBar(
- x + 1,
- y + height - 1,
- math.max(
- 1,
- width - 2
- ),
- percentage,
- colour
- )
- return
- end
- -- ========================================================
- -- FULL PANEL
- -- ========================================================
- center(
- x,
- y + 1,
- width,
- "USED / CAPACITY",
- C.muted
- )
- center(
- x,
- y + 2,
- width,
- formatBytes(group.used)
- .. " / "
- .. formatBytes(
- group.capacity
- ),
- C.text
- )
- center(
- x,
- y + 3,
- width,
- "FREE "
- .. formatBytes(free)
- .. " "
- .. string.format(
- "%.1f%%",
- percentage * 100
- ),
- colour
- )
- center(
- x,
- y + 4,
- width,
- getTypeText(
- group,
- width
- ),
- C.text
- )
- local detail
- if group.unlimitedCapacity > 0 then
- detail =
- "DISK "
- .. formatBytes(
- group.unlimitedCapacity
- )
- else
- detail =
- tostring(
- group.cells
- )
- .. " CELL"
- if group.cells ~= 1 then
- detail =
- detail .. "S"
- end
- end
- center(
- x,
- y + 5,
- width,
- detail,
- C.muted
- )
- -- Use ALL remaining vertical rows as a thick storage bar.
- for barY =
- y + 6,
- y + height - 1 do
- drawBar(
- x + 1,
- barY,
- math.max(
- 1,
- width - 2
- ),
- percentage,
- colour
- )
- end
- end
- -- ============================================================
- -- OTHER STORAGE FOOTER
- -- ============================================================
- local function makeOtherText(others)
- local entries = {}
- for _, group in pairs(others) do
- if group.cells > 0 then
- entries[#entries + 1] = {
- title = group.title,
- text =
- fit(
- group.title,
- 8
- )
- .. " "
- .. formatBytes(
- group.used
- )
- .. "/"
- .. formatBytes(
- group.capacity
- )
- }
- end
- end
- table.sort(
- entries,
- function(a, b)
- return
- a.title
- < b.title
- end
- )
- if #entries == 0 then
- return nil
- end
- local strings = {}
- for _, entry in ipairs(entries) do
- strings[#strings + 1] =
- entry.text
- end
- return
- "OTHER "
- .. table.concat(
- strings,
- " | "
- )
- end
- -- ============================================================
- -- HEADER
- -- ============================================================
- local function drawHeader()
- fill(
- 1,
- 1,
- bufferW,
- C.headerBg
- )
- writeAt(
- 2,
- 1,
- "AE2 STORAGE",
- C.text,
- C.headerBg
- )
- local online =
- bridgeCall(
- "isOnline"
- )
- if online == nil then
- online =
- bridgeCall(
- "isConnected"
- )
- end
- local status =
- online == false
- and "OFFLINE"
- or "ONLINE"
- rightText(
- 1,
- status,
- online == false
- and C.bad
- or C.good,
- C.headerBg
- )
- end
- -- ============================================================
- -- MAIN UI
- -- ============================================================
- local function drawFrame()
- beginFrame()
- local groups, others =
- gatherStorage()
- drawHeader()
- local otherText =
- makeOtherText(others)
- local footerRows =
- otherText
- and 1
- or 0
- -- Everything below row 1 is storage.
- local contentTop = 2
- local contentBottom =
- bufferH
- - footerRows
- local contentHeight =
- contentBottom
- - contentTop
- + 1
- -- One solid divider between left/right halves.
- local leftWidth =
- math.floor(
- (bufferW - 1) / 2
- )
- local dividerX =
- leftWidth + 1
- local rightX =
- dividerX + 1
- local rightWidth =
- bufferW - rightX + 1
- -- Split vertically into two equally large storage rows.
- local topHeight =
- math.floor(
- contentHeight / 2
- )
- local bottomHeight =
- contentHeight
- - topHeight
- local topY =
- contentTop
- local bottomY =
- contentTop
- + topHeight
- -- ========================================================
- -- TOP ROW
- -- ========================================================
- drawStoragePanel(
- 1,
- topY,
- leftWidth,
- topHeight,
- groups.item
- )
- drawStoragePanel(
- rightX,
- topY,
- rightWidth,
- topHeight,
- groups.fluid
- )
- -- ========================================================
- -- BOTTOM ROW
- -- ========================================================
- drawStoragePanel(
- 1,
- bottomY,
- leftWidth,
- bottomHeight,
- groups.chemical
- )
- drawStoragePanel(
- rightX,
- bottomY,
- rightWidth,
- bottomHeight,
- groups.radiation
- )
- -- ========================================================
- -- CENTRE DIVIDER
- -- ========================================================
- for y =
- contentTop,
- contentBottom do
- fill(
- dividerX,
- y,
- 1,
- C.divider
- )
- end
- -- ========================================================
- -- OTHER ADDON STORAGE
- -- Only consumes a row if such storage actually exists.
- -- ========================================================
- if otherText then
- fill(
- 1,
- bufferH,
- bufferW,
- C.headerBg
- )
- center(
- 1,
- bufferH,
- bufferW,
- otherText,
- C.other,
- C.headerBg
- )
- end
- commitFrame()
- end
- -- ============================================================
- -- ERROR DISPLAY
- -- ============================================================
- local function drawError(err)
- beginFrame()
- center(
- 1,
- math.max(
- 1,
- math.floor(
- bufferH / 2
- )
- ),
- bufferW,
- "STORAGE MONITOR ERROR",
- C.bad
- )
- center(
- 1,
- math.max(
- 1,
- math.floor(
- bufferH / 2
- ) + 1
- ),
- bufferW,
- tostring(err),
- C.muted
- )
- commitFrame()
- end
- -- ============================================================
- -- LOOP
- -- ============================================================
- while true do
- local ok, err =
- pcall(drawFrame)
- if not ok then
- drawError(err)
- end
- sleep(CONFIG.refresh)
- end
Add Comment
Please, Sign In to add comment