AndyE7

Untitled

Sep 1st, 2026 (edited)
16
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 33.46 KB | None | 0 0
  1. -- ============================================================
  2. -- AE2 STORAGE WALL
  3. -- FTB Evolution 1.21.1
  4. --
  5. -- CC:Tweaked + Advanced Peripherals ME Bridge
  6. --
  7. -- Storage-only version:
  8. -- ITEMS | FLUIDS
  9. -- CHEMICALS | RADIATION
  10. --
  11. -- Features:
  12. -- * 1.5 text scale for readability at distance
  13. -- * No crafting section
  14. -- * Uses virtually all vertical space
  15. -- * Flicker-free differential rendering
  16. -- * Exact MEGA radioactive cell detection
  17. -- * AE2 Things no-type-limit DISKs excluded from slot total
  18. -- * Other addon storage types shown in footer if present
  19. -- ============================================================
  20.  
  21. local CONFIG = {
  22. refresh = 1.5,
  23.  
  24. -- The previous screenshot is still physically too small.
  25. -- 1.5 makes the text 50% larger than 1.0.
  26. textScale = 1.5,
  27. }
  28.  
  29. -- ============================================================
  30. -- PERIPHERALS
  31. -- ============================================================
  32.  
  33. local bridge =
  34. peripheral.find("me_bridge")
  35. or peripheral.find("meBridge")
  36.  
  37. local monitor =
  38. peripheral.find("monitor")
  39.  
  40. if not bridge then
  41. error("No ME Bridge found")
  42. end
  43.  
  44. if not monitor then
  45. error("No monitor found")
  46. end
  47.  
  48. monitor.setTextScale(CONFIG.textScale)
  49. monitor.setCursorBlink(false)
  50.  
  51. -- ============================================================
  52. -- COLOURS
  53. -- ============================================================
  54.  
  55. local C = {
  56. bg = colors.black,
  57.  
  58. headerBg = colors.gray,
  59. divider = colors.gray,
  60.  
  61. text = colors.white,
  62. muted = colors.lightGray,
  63. dim = colors.gray,
  64.  
  65. item = colors.cyan,
  66. fluid = colors.lightBlue,
  67. chemical = colors.purple,
  68. radiation = colors.orange,
  69. other = colors.yellow,
  70.  
  71. good = colors.lime,
  72. warning = colors.yellow,
  73. bad = colors.red,
  74.  
  75. emptyBar = colors.gray,
  76. }
  77.  
  78. -- ============================================================
  79. -- DIFFERENTIAL FRAME BUFFER
  80. --
  81. -- We NEVER clear the physical monitor during normal refresh.
  82. --
  83. -- The complete new UI is rendered into an invisible window.
  84. -- We then compare every line against the previous frame and
  85. -- only send changed rows to the physical monitor.
  86. -- ============================================================
  87.  
  88. local buffer = nil
  89. local bufferW = 0
  90. local bufferH = 0
  91.  
  92. local previousFrame = {}
  93.  
  94. local function makeBuffer()
  95. local w, h = monitor.getSize()
  96.  
  97. if buffer and
  98. w == bufferW and
  99. h == bufferH then
  100. return
  101. end
  102.  
  103. bufferW = w
  104. bufferH = h
  105.  
  106. buffer =
  107. window.create(
  108. monitor,
  109. 1,
  110. 1,
  111. w,
  112. h,
  113. false
  114. )
  115.  
  116. previousFrame = {}
  117.  
  118. -- Only clear when initially starting or the monitor
  119. -- dimensions genuinely change.
  120. monitor.setBackgroundColor(C.bg)
  121. monitor.clear()
  122. monitor.setCursorBlink(false)
  123. end
  124.  
  125. local function beginFrame()
  126. makeBuffer()
  127.  
  128. buffer.setVisible(false)
  129. buffer.setCursorBlink(false)
  130. buffer.setBackgroundColor(C.bg)
  131. buffer.setTextColor(C.text)
  132.  
  133. -- This clears ONLY THE HIDDEN WINDOW.
  134. -- The actual wall monitor remains untouched.
  135. buffer.clear()
  136. end
  137.  
  138. local function commitFrame()
  139. for y = 1, bufferH do
  140. local text, fg, bg =
  141. buffer.getLine(y)
  142.  
  143. local old =
  144. previousFrame[y]
  145.  
  146. if not old
  147. or old.text ~= text
  148. or old.fg ~= fg
  149. or old.bg ~= bg then
  150.  
  151. monitor.setCursorPos(1, y)
  152. monitor.blit(text, fg, bg)
  153.  
  154. previousFrame[y] = {
  155. text = text,
  156. fg = fg,
  157. bg = bg,
  158. }
  159. end
  160. end
  161.  
  162. monitor.setCursorBlink(false)
  163. end
  164.  
  165. -- ============================================================
  166. -- BRIDGE CALL
  167. -- ============================================================
  168.  
  169. local function bridgeCall(method, ...)
  170. local fn = bridge[method]
  171.  
  172. if type(fn) ~= "function" then
  173. return nil
  174. end
  175.  
  176. local ok, a, b, c =
  177. pcall(fn, ...)
  178.  
  179. if not ok then
  180. return nil
  181. end
  182.  
  183. return a, b, c
  184. end
  185.  
  186. -- ============================================================
  187. -- BASIC HELPERS
  188. -- ============================================================
  189.  
  190. local function clamp(v, minV, maxV)
  191. if v < minV then
  192. return minV
  193. end
  194.  
  195. if v > maxV then
  196. return maxV
  197. end
  198.  
  199. return v
  200. end
  201.  
  202. local function countTable(t)
  203. if type(t) ~= "table" then
  204. return 0
  205. end
  206.  
  207. local n = 0
  208.  
  209. for _ in pairs(t) do
  210. n = n + 1
  211. end
  212.  
  213. return n
  214. end
  215.  
  216. local function fit(text, width)
  217. text = tostring(text or "")
  218.  
  219. if width <= 0 then
  220. return ""
  221. end
  222.  
  223. if #text <= width then
  224. return text
  225. end
  226.  
  227. if width <= 3 then
  228. return text:sub(1, width)
  229. end
  230.  
  231. return text:sub(1, width - 2) .. ".."
  232. end
  233.  
  234. local function formatBytes(bytes)
  235. bytes = tonumber(bytes) or 0
  236.  
  237. if bytes >= 1024 ^ 4 then
  238. return string.format(
  239. "%.1fTiB",
  240. bytes / 1024 ^ 4
  241. )
  242.  
  243. elseif bytes >= 1024 ^ 3 then
  244. return string.format(
  245. "%.1fGiB",
  246. bytes / 1024 ^ 3
  247. )
  248.  
  249. elseif bytes >= 1024 ^ 2 then
  250. return string.format(
  251. "%.1fMiB",
  252. bytes / 1024 ^ 2
  253. )
  254.  
  255. elseif bytes >= 1024 then
  256. return string.format(
  257. "%.1fKiB",
  258. bytes / 1024
  259. )
  260.  
  261. else
  262. return tostring(
  263. math.floor(bytes)
  264. ) .. "B"
  265. end
  266. end
  267.  
  268. local function percentColour(p)
  269. if p >= 0.90 then
  270. return C.bad
  271. elseif p >= 0.70 then
  272. return C.warning
  273. else
  274. return C.good
  275. end
  276. end
  277.  
  278. -- ============================================================
  279. -- DRAW HELPERS
  280. -- ============================================================
  281.  
  282. local function writeAt(
  283. x,
  284. y,
  285. text,
  286. fg,
  287. bg,
  288. maxWidth
  289. )
  290. if y < 1 or y > bufferH then
  291. return
  292. end
  293.  
  294. if x < 1 or x > bufferW then
  295. return
  296. end
  297.  
  298. text = tostring(text or "")
  299.  
  300. if maxWidth then
  301. text = fit(text, maxWidth)
  302. end
  303.  
  304. if x + #text - 1 > bufferW then
  305. text =
  306. text:sub(
  307. 1,
  308. bufferW - x + 1
  309. )
  310. end
  311.  
  312. if #text <= 0 then
  313. return
  314. end
  315.  
  316. buffer.setCursorPos(x, y)
  317.  
  318. buffer.setTextColor(
  319. fg or C.text
  320. )
  321.  
  322. buffer.setBackgroundColor(
  323. bg or C.bg
  324. )
  325.  
  326. buffer.write(text)
  327. end
  328.  
  329. local function fill(
  330. x,
  331. y,
  332. width,
  333. colour
  334. )
  335. if y < 1 or y > bufferH then
  336. return
  337. end
  338.  
  339. if x < 1 then
  340. width =
  341. width - (1 - x)
  342.  
  343. x = 1
  344. end
  345.  
  346. width =
  347. math.min(
  348. width,
  349. bufferW - x + 1
  350. )
  351.  
  352. if width <= 0 then
  353. return
  354. end
  355.  
  356. buffer.setCursorPos(x, y)
  357. buffer.setBackgroundColor(colour)
  358.  
  359. buffer.write(
  360. string.rep(" ", width)
  361. )
  362.  
  363. buffer.setBackgroundColor(C.bg)
  364. end
  365.  
  366. local function center(
  367. x,
  368. y,
  369. width,
  370. text,
  371. fg,
  372. bg
  373. )
  374. text =
  375. fit(
  376. tostring(text or ""),
  377. width
  378. )
  379.  
  380. local start =
  381. x
  382. + math.max(
  383. 0,
  384. math.floor(
  385. (width - #text) / 2
  386. )
  387. )
  388.  
  389. writeAt(
  390. start,
  391. y,
  392. text,
  393. fg,
  394. bg
  395. )
  396. end
  397.  
  398. local function rightText(
  399. y,
  400. text,
  401. fg,
  402. bg
  403. )
  404. text = tostring(text or "")
  405.  
  406. writeAt(
  407. math.max(
  408. 1,
  409. bufferW - #text + 1
  410. ),
  411. y,
  412. text,
  413. fg,
  414. bg
  415. )
  416. end
  417.  
  418. local function drawBar(
  419. x,
  420. y,
  421. width,
  422. percent,
  423. colour
  424. )
  425. percent =
  426. clamp(
  427. tonumber(percent) or 0,
  428. 0,
  429. 1
  430. )
  431.  
  432. local filled =
  433. math.floor(
  434. width * percent + 0.5
  435. )
  436.  
  437. fill(
  438. x,
  439. y,
  440. width,
  441. C.emptyBar
  442. )
  443.  
  444. if filled > 0 then
  445. fill(
  446. x,
  447. y,
  448. filled,
  449. colour
  450. )
  451. end
  452. end
  453.  
  454. -- ============================================================
  455. -- CELL IDENTITY
  456. -- ============================================================
  457.  
  458. local function cellItemId(cell)
  459. if type(cell) ~= "table" then
  460. return ""
  461. end
  462.  
  463. local item = cell.item
  464.  
  465. if type(item) == "string" then
  466. return item
  467. end
  468.  
  469. if type(item) == "table" then
  470. return tostring(
  471. item.name
  472. or item.id
  473. or item.registryName
  474. or ""
  475. )
  476. end
  477.  
  478. return tostring(
  479. cell.name or ""
  480. )
  481. end
  482.  
  483. local function cellDisplayName(cell)
  484. if type(cell) ~= "table" then
  485. return ""
  486. end
  487.  
  488. local item = cell.item
  489.  
  490. if type(item) == "table" then
  491. return tostring(
  492. item.displayName
  493. or item.label
  494. or ""
  495. )
  496. end
  497.  
  498. return ""
  499. end
  500.  
  501. local function storageType(cell)
  502. if type(cell) ~= "table" then
  503. return ""
  504. end
  505.  
  506. return tostring(
  507. cell.type
  508. or cell.cellType
  509. or ""
  510. ):lower()
  511. end
  512.  
  513. -- ============================================================
  514. -- UNLIMITED TYPE CELLS / DISKS
  515. --
  516. -- They still count towards byte capacity.
  517. -- They DO NOT contribute to the type-slot capacity figure.
  518. -- ============================================================
  519.  
  520. local function isUnlimitedTypeStorage(cell)
  521. local id =
  522. cellItemId(cell):lower()
  523.  
  524. -- AE2 Things DISKs
  525. if id:find(
  526. "^ae2things:"
  527. )
  528. and id:find(
  529. "disk",
  530. 1,
  531. true
  532. ) then
  533.  
  534. return true
  535. end
  536.  
  537. -- ExtendedAE infinity storage, if present.
  538. if id:find(
  539. "^extendedae:"
  540. )
  541. and id:find(
  542. "infinity",
  543. 1,
  544. true
  545. )
  546. and id:find(
  547. "cell",
  548. 1,
  549. true
  550. ) then
  551.  
  552. return true
  553. end
  554.  
  555. return false
  556. end
  557.  
  558. -- ============================================================
  559. -- CELL CLASSIFICATION
  560. -- ============================================================
  561.  
  562. local function classifyCell(cell)
  563. local id =
  564. cellItemId(cell):lower()
  565.  
  566. local display =
  567. cellDisplayName(cell):lower()
  568.  
  569. local typ =
  570. storageType(cell)
  571.  
  572. local identity =
  573. id .. " " .. display
  574.  
  575. -- ========================================================
  576. -- RADIATION FIRST
  577. --
  578. -- Exact MEGA Cells 1.21.1 registry ID:
  579. --
  580. -- megacells:radioactive_chemical_cell
  581. --
  582. -- This MUST be tested before ordinary chemical storage
  583. -- because the underlying AE key type is chemical.
  584. -- ========================================================
  585.  
  586. if id ==
  587. "megacells:radioactive_chemical_cell" then
  588.  
  589. return "radiation"
  590. end
  591.  
  592. -- Additional robust fallback in case a future MEGA build
  593. -- alters how Advanced Peripherals exposes the Item Object.
  594. if id:find(
  595. "^megacells:"
  596. )
  597. and id:find(
  598. "radioactive",
  599. 1,
  600. true
  601. )
  602. and id:find(
  603. "chemical",
  604. 1,
  605. true
  606. ) then
  607.  
  608. return "radiation"
  609. end
  610.  
  611. if identity:find(
  612. "radioactive chemical",
  613. 1,
  614. true
  615. ) then
  616.  
  617. return "radiation"
  618. end
  619.  
  620. if identity:find(
  621. "radioactive_chemical",
  622. 1,
  623. true
  624. ) then
  625.  
  626. return "radiation"
  627. end
  628.  
  629. if typ:find(
  630. "radioactive",
  631. 1,
  632. true
  633. )
  634. or typ:find(
  635. "radiation",
  636. 1,
  637. true
  638. ) then
  639.  
  640. return "radiation"
  641. end
  642.  
  643. -- ========================================================
  644. -- FLUID
  645. -- ========================================================
  646.  
  647. if typ == "ae2:f"
  648. or typ == "fluid"
  649. or typ:find(
  650. "fluid",
  651. 1,
  652. true
  653. ) then
  654.  
  655. return "fluid"
  656. end
  657.  
  658. -- ========================================================
  659. -- CHEMICAL
  660. --
  661. -- All chemical key variants are deliberately folded into
  662. -- this single group. This fixes the duplicate CHEMICAL
  663. -- panel from the previous script.
  664. -- ========================================================
  665.  
  666. if typ == "ae2:chemical"
  667. or typ == "chemical"
  668. or typ:find(
  669. "chemical",
  670. 1,
  671. true
  672. )
  673. or typ:find(
  674. "gas",
  675. 1,
  676. true
  677. )
  678. or id:find(
  679. "chemical_storage_cell",
  680. 1,
  681. true
  682. ) then
  683.  
  684. return "chemical"
  685. end
  686.  
  687. -- ========================================================
  688. -- ITEM
  689. -- ========================================================
  690.  
  691. if typ == "ae2:i"
  692. or typ == "item"
  693. or typ:find(
  694. ":item",
  695. 1,
  696. true
  697. ) then
  698.  
  699. return "item"
  700. end
  701.  
  702. return "other:" .. typ
  703. end
  704.  
  705. -- ============================================================
  706. -- STORAGE GROUPS
  707. -- ============================================================
  708.  
  709. local function newGroup(
  710. key,
  711. title,
  712. colour
  713. )
  714. return {
  715. key = key,
  716. title = title,
  717. colour = colour,
  718.  
  719. cells = 0,
  720.  
  721. used = 0,
  722. capacity = 0,
  723.  
  724. typeCapacity = 0,
  725.  
  726. unlimitedCells = 0,
  727. unlimitedCapacity = 0,
  728.  
  729. resourceTypes = 0,
  730. resourceAmount = 0,
  731.  
  732. externalStorage = false,
  733. }
  734. end
  735.  
  736. local function addCell(
  737. group,
  738. cell
  739. )
  740. local used =
  741. tonumber(
  742. cell.usedBytes
  743. or cell.used
  744. ) or 0
  745.  
  746. local capacity =
  747. tonumber(
  748. cell.bytes
  749. or cell.capacity
  750. ) or 0
  751.  
  752. group.cells =
  753. group.cells + 1
  754.  
  755. group.used =
  756. group.used + used
  757.  
  758. group.capacity =
  759. group.capacity + capacity
  760.  
  761. if isUnlimitedTypeStorage(cell) then
  762. group.unlimitedCells =
  763. group.unlimitedCells + 1
  764.  
  765. group.unlimitedCapacity =
  766. group.unlimitedCapacity
  767. + capacity
  768.  
  769. -- Deliberately DO NOT add totalBytes.
  770. return
  771. end
  772.  
  773. local types =
  774. tonumber(
  775. cell.totalBytes
  776. )
  777.  
  778. if types and types > 0 then
  779. group.typeCapacity =
  780. group.typeCapacity
  781. + types
  782. end
  783. end
  784.  
  785. -- ============================================================
  786. -- RADIOACTIVE CHEMICAL DETECTION
  787. -- ============================================================
  788.  
  789. local function isRadioactiveChemical(chemical)
  790. if type(chemical) ~= "table" then
  791. return false
  792. end
  793.  
  794. local radioactivity =
  795. tonumber(
  796. chemical.radioactivity
  797. ) or 0
  798.  
  799. if radioactivity > 0 then
  800. return true
  801. end
  802.  
  803. -- Fallback for anything whose AP object fails to expose
  804. -- radioactivity for some reason.
  805. local name =
  806. tostring(
  807. chemical.name or ""
  808. ):lower()
  809.  
  810. if name:find(
  811. "nuclear_waste",
  812. 1,
  813. true
  814. )
  815. or name:find(
  816. "spent_nuclear_waste",
  817. 1,
  818. true
  819. )
  820. or name:find(
  821. "polonium",
  822. 1,
  823. true
  824. )
  825. or name:find(
  826. "plutonium",
  827. 1,
  828. true
  829. ) then
  830.  
  831. return true
  832. end
  833.  
  834. return false
  835. end
  836.  
  837. -- ============================================================
  838. -- COLLECT STORAGE DATA
  839. -- ============================================================
  840.  
  841. local function gatherStorage()
  842. local groups = {
  843. item =
  844. newGroup(
  845. "item",
  846. "ITEMS",
  847. C.item
  848. ),
  849.  
  850. fluid =
  851. newGroup(
  852. "fluid",
  853. "FLUIDS",
  854. C.fluid
  855. ),
  856.  
  857. chemical =
  858. newGroup(
  859. "chemical",
  860. "CHEMICALS",
  861. C.chemical
  862. ),
  863.  
  864. radiation =
  865. newGroup(
  866. "radiation",
  867. "RADIATION",
  868. C.radiation
  869. ),
  870. }
  871.  
  872. local others = {}
  873.  
  874. -- ========================================================
  875. -- CELLS
  876. -- ========================================================
  877.  
  878. local cells =
  879. bridgeCall("getCells")
  880.  
  881. if type(cells) ~= "table" then
  882. cells = {}
  883. end
  884.  
  885. for _, cell in pairs(cells) do
  886. local category =
  887. classifyCell(cell)
  888.  
  889. local group =
  890. groups[category]
  891.  
  892. if group then
  893. addCell(
  894. group,
  895. cell
  896. )
  897. else
  898. if not others[category] then
  899. local typ =
  900. storageType(cell)
  901.  
  902. local title =
  903. typ:match(":(.+)$")
  904. or typ
  905. or "OTHER"
  906.  
  907. title =
  908. title
  909. :gsub("_", " ")
  910. :upper()
  911.  
  912. others[category] =
  913. newGroup(
  914. category,
  915. title,
  916. C.other
  917. )
  918. end
  919.  
  920. addCell(
  921. others[category],
  922. cell
  923. )
  924. end
  925. end
  926.  
  927. -- ========================================================
  928. -- NETWORK RESOURCE TYPES
  929. -- ========================================================
  930.  
  931. local items =
  932. bridgeCall(
  933. "getItems",
  934. {}
  935. )
  936.  
  937. groups.item.resourceTypes =
  938. countTable(items)
  939.  
  940. local fluids =
  941. bridgeCall(
  942. "getFluids",
  943. {}
  944. )
  945.  
  946. groups.fluid.resourceTypes =
  947. countTable(fluids)
  948.  
  949. local chemicals =
  950. bridgeCall(
  951. "getChemicals",
  952. {}
  953. )
  954.  
  955. if type(chemicals) == "table" then
  956. for _, chemical in pairs(chemicals) do
  957. local amount =
  958. tonumber(
  959. chemical.count
  960. or chemical.amount
  961. ) or 0
  962.  
  963. if isRadioactiveChemical(
  964. chemical
  965. ) then
  966. groups.radiation.resourceTypes =
  967. groups.radiation.resourceTypes
  968. + 1
  969.  
  970. groups.radiation.resourceAmount =
  971. groups.radiation.resourceAmount
  972. + amount
  973. else
  974. groups.chemical.resourceTypes =
  975. groups.chemical.resourceTypes
  976. + 1
  977.  
  978. groups.chemical.resourceAmount =
  979. groups.chemical.resourceAmount
  980. + amount
  981. end
  982. end
  983. end
  984.  
  985. -- ========================================================
  986. -- EXTERNAL STORAGE
  987. --
  988. -- A Storage Bus means the network type count does not
  989. -- necessarily equal the slots occupied inside cells.
  990. -- ========================================================
  991.  
  992. local externalItems =
  993. tonumber(
  994. bridgeCall(
  995. "getUsedExternItemCount"
  996. )
  997. ) or 0
  998.  
  999. local externalFluids =
  1000. tonumber(
  1001. bridgeCall(
  1002. "getUsedExternFluidStorage"
  1003. )
  1004. ) or 0
  1005.  
  1006. local externalChemicals =
  1007. tonumber(
  1008. bridgeCall(
  1009. "getUsedExternChemicalStorage"
  1010. )
  1011. ) or 0
  1012.  
  1013. groups.item.externalStorage =
  1014. externalItems > 0
  1015.  
  1016. groups.fluid.externalStorage =
  1017. externalFluids > 0
  1018.  
  1019. groups.chemical.externalStorage =
  1020. externalChemicals > 0
  1021.  
  1022. groups.radiation.externalStorage =
  1023. externalChemicals > 0
  1024.  
  1025. return groups, others
  1026. end
  1027.  
  1028. -- ============================================================
  1029. -- TYPE TEXT
  1030. -- ============================================================
  1031.  
  1032. local function getTypeText(
  1033. group,
  1034. width
  1035. )
  1036. if group.typeCapacity <= 0 then
  1037. if group.resourceTypes > 0 then
  1038. return
  1039. tostring(
  1040. group.resourceTypes
  1041. )
  1042. .. " TYPES"
  1043. end
  1044.  
  1045. return "0 TYPES"
  1046. end
  1047.  
  1048. -- If an unlimited DISK is present, a network-wide type
  1049. -- count cannot tell us how many types are specifically
  1050. -- occupying the limited cells.
  1051. --
  1052. -- Show both facts without pretending they're the same:
  1053. --
  1054. -- NET 2393 SLOTS 630
  1055. --
  1056. if group.unlimitedCells > 0
  1057. or group.externalStorage then
  1058.  
  1059. if width >= 21 then
  1060. return
  1061. "NET "
  1062. .. tostring(
  1063. group.resourceTypes
  1064. )
  1065. .. " SLOTS "
  1066. .. tostring(
  1067. group.typeCapacity
  1068. )
  1069. else
  1070. return
  1071. "NET"
  1072. .. tostring(
  1073. group.resourceTypes
  1074. )
  1075. .. " S"
  1076. .. tostring(
  1077. group.typeCapacity
  1078. )
  1079. end
  1080. end
  1081.  
  1082. return
  1083. "TYPES "
  1084. .. tostring(
  1085. group.resourceTypes
  1086. )
  1087. .. "/"
  1088. .. tostring(
  1089. group.typeCapacity
  1090. )
  1091. end
  1092.  
  1093. -- ============================================================
  1094. -- STORAGE PANEL
  1095. -- ============================================================
  1096.  
  1097. local function drawStoragePanel(
  1098. x,
  1099. y,
  1100. width,
  1101. height,
  1102. group
  1103. )
  1104. if width <= 0 or height <= 0 then
  1105. return
  1106. end
  1107.  
  1108. -- ========================================================
  1109. -- PANEL HEADER
  1110. -- ========================================================
  1111.  
  1112. fill(
  1113. x,
  1114. y,
  1115. width,
  1116. C.headerBg
  1117. )
  1118.  
  1119. center(
  1120. x,
  1121. y,
  1122. width,
  1123. group.title,
  1124. group.colour,
  1125. C.headerBg
  1126. )
  1127.  
  1128. if height <= 1 then
  1129. return
  1130. end
  1131.  
  1132. -- ========================================================
  1133. -- NO CELL
  1134. -- ========================================================
  1135.  
  1136. if group.cells <= 0 then
  1137. local centreY =
  1138. y
  1139. + math.floor(
  1140. height / 2
  1141. )
  1142.  
  1143. center(
  1144. x,
  1145. centreY - 1,
  1146. width,
  1147. "NO CELL",
  1148. C.dim
  1149. )
  1150.  
  1151. if group.resourceTypes > 0 then
  1152. center(
  1153. x,
  1154. centreY,
  1155. width,
  1156. "NET "
  1157. .. tostring(
  1158. group.resourceTypes
  1159. )
  1160. .. " TYPES",
  1161. C.muted
  1162. )
  1163. end
  1164.  
  1165. return
  1166. end
  1167.  
  1168. -- Cell is detected but AP gave no byte capacity.
  1169. if group.capacity <= 0 then
  1170. local centreY =
  1171. y
  1172. + math.floor(
  1173. height / 2
  1174. )
  1175.  
  1176. center(
  1177. x,
  1178. centreY - 1,
  1179. width,
  1180. "CELL DETECTED",
  1181. group.colour
  1182. )
  1183.  
  1184. center(
  1185. x,
  1186. centreY,
  1187. width,
  1188. "NO CAPACITY DATA",
  1189. C.warning
  1190. )
  1191.  
  1192. return
  1193. end
  1194.  
  1195. local percentage =
  1196. clamp(
  1197. group.used /
  1198. group.capacity,
  1199. 0,
  1200. 1
  1201. )
  1202.  
  1203. local free =
  1204. math.max(
  1205. 0,
  1206. group.capacity
  1207. - group.used
  1208. )
  1209.  
  1210. local colour =
  1211. percentColour(
  1212. percentage
  1213. )
  1214.  
  1215. -- ========================================================
  1216. -- COMPACT PANEL
  1217. -- ========================================================
  1218.  
  1219. if height <= 6 then
  1220. center(
  1221. x,
  1222. y + 1,
  1223. width,
  1224. formatBytes(group.used)
  1225. .. "/"
  1226. .. formatBytes(
  1227. group.capacity
  1228. ),
  1229. C.text
  1230. )
  1231.  
  1232. center(
  1233. x,
  1234. y + 2,
  1235. width,
  1236. "FREE "
  1237. .. formatBytes(free)
  1238. .. " "
  1239. .. string.format(
  1240. "%.1f%%",
  1241. percentage * 100
  1242. ),
  1243. colour
  1244. )
  1245.  
  1246. center(
  1247. x,
  1248. y + 3,
  1249. width,
  1250. getTypeText(
  1251. group,
  1252. width
  1253. ),
  1254. C.text
  1255. )
  1256.  
  1257. local detail =
  1258. tostring(
  1259. group.cells
  1260. )
  1261. .. " CELL"
  1262.  
  1263. if group.cells ~= 1 then
  1264. detail =
  1265. detail .. "S"
  1266. end
  1267.  
  1268. if group.unlimitedCapacity > 0 then
  1269. detail =
  1270. "DISK "
  1271. .. formatBytes(
  1272. group.unlimitedCapacity
  1273. )
  1274. end
  1275.  
  1276. center(
  1277. x,
  1278. y + 4,
  1279. width,
  1280. detail,
  1281. C.muted
  1282. )
  1283.  
  1284. drawBar(
  1285. x + 1,
  1286. y + height - 1,
  1287. math.max(
  1288. 1,
  1289. width - 2
  1290. ),
  1291. percentage,
  1292. colour
  1293. )
  1294.  
  1295. return
  1296. end
  1297.  
  1298. -- ========================================================
  1299. -- FULL PANEL
  1300. -- ========================================================
  1301.  
  1302. center(
  1303. x,
  1304. y + 1,
  1305. width,
  1306. "USED / CAPACITY",
  1307. C.muted
  1308. )
  1309.  
  1310. center(
  1311. x,
  1312. y + 2,
  1313. width,
  1314. formatBytes(group.used)
  1315. .. " / "
  1316. .. formatBytes(
  1317. group.capacity
  1318. ),
  1319. C.text
  1320. )
  1321.  
  1322. center(
  1323. x,
  1324. y + 3,
  1325. width,
  1326. "FREE "
  1327. .. formatBytes(free)
  1328. .. " "
  1329. .. string.format(
  1330. "%.1f%%",
  1331. percentage * 100
  1332. ),
  1333. colour
  1334. )
  1335.  
  1336. center(
  1337. x,
  1338. y + 4,
  1339. width,
  1340. getTypeText(
  1341. group,
  1342. width
  1343. ),
  1344. C.text
  1345. )
  1346.  
  1347. local detail
  1348.  
  1349. if group.unlimitedCapacity > 0 then
  1350. detail =
  1351. "DISK "
  1352. .. formatBytes(
  1353. group.unlimitedCapacity
  1354. )
  1355. else
  1356. detail =
  1357. tostring(
  1358. group.cells
  1359. )
  1360. .. " CELL"
  1361.  
  1362. if group.cells ~= 1 then
  1363. detail =
  1364. detail .. "S"
  1365. end
  1366. end
  1367.  
  1368. center(
  1369. x,
  1370. y + 5,
  1371. width,
  1372. detail,
  1373. C.muted
  1374. )
  1375.  
  1376. -- Use ALL remaining vertical rows as a thick storage bar.
  1377. for barY =
  1378. y + 6,
  1379. y + height - 1 do
  1380.  
  1381. drawBar(
  1382. x + 1,
  1383. barY,
  1384. math.max(
  1385. 1,
  1386. width - 2
  1387. ),
  1388. percentage,
  1389. colour
  1390. )
  1391. end
  1392. end
  1393.  
  1394. -- ============================================================
  1395. -- OTHER STORAGE FOOTER
  1396. -- ============================================================
  1397.  
  1398. local function makeOtherText(others)
  1399. local entries = {}
  1400.  
  1401. for _, group in pairs(others) do
  1402. if group.cells > 0 then
  1403. entries[#entries + 1] = {
  1404. title = group.title,
  1405. text =
  1406. fit(
  1407. group.title,
  1408. 8
  1409. )
  1410. .. " "
  1411. .. formatBytes(
  1412. group.used
  1413. )
  1414. .. "/"
  1415. .. formatBytes(
  1416. group.capacity
  1417. )
  1418. }
  1419. end
  1420. end
  1421.  
  1422. table.sort(
  1423. entries,
  1424. function(a, b)
  1425. return
  1426. a.title
  1427. < b.title
  1428. end
  1429. )
  1430.  
  1431. if #entries == 0 then
  1432. return nil
  1433. end
  1434.  
  1435. local strings = {}
  1436.  
  1437. for _, entry in ipairs(entries) do
  1438. strings[#strings + 1] =
  1439. entry.text
  1440. end
  1441.  
  1442. return
  1443. "OTHER "
  1444. .. table.concat(
  1445. strings,
  1446. " | "
  1447. )
  1448. end
  1449.  
  1450. -- ============================================================
  1451. -- HEADER
  1452. -- ============================================================
  1453.  
  1454. local function drawHeader()
  1455. fill(
  1456. 1,
  1457. 1,
  1458. bufferW,
  1459. C.headerBg
  1460. )
  1461.  
  1462. writeAt(
  1463. 2,
  1464. 1,
  1465. "AE2 STORAGE",
  1466. C.text,
  1467. C.headerBg
  1468. )
  1469.  
  1470. local online =
  1471. bridgeCall(
  1472. "isOnline"
  1473. )
  1474.  
  1475. if online == nil then
  1476. online =
  1477. bridgeCall(
  1478. "isConnected"
  1479. )
  1480. end
  1481.  
  1482. local status =
  1483. online == false
  1484. and "OFFLINE"
  1485. or "ONLINE"
  1486.  
  1487. rightText(
  1488. 1,
  1489. status,
  1490. online == false
  1491. and C.bad
  1492. or C.good,
  1493. C.headerBg
  1494. )
  1495. end
  1496.  
  1497. -- ============================================================
  1498. -- MAIN UI
  1499. -- ============================================================
  1500.  
  1501. local function drawFrame()
  1502. beginFrame()
  1503.  
  1504. local groups, others =
  1505. gatherStorage()
  1506.  
  1507. drawHeader()
  1508.  
  1509. local otherText =
  1510. makeOtherText(others)
  1511.  
  1512. local footerRows =
  1513. otherText
  1514. and 1
  1515. or 0
  1516.  
  1517. -- Everything below row 1 is storage.
  1518. local contentTop = 2
  1519.  
  1520. local contentBottom =
  1521. bufferH
  1522. - footerRows
  1523.  
  1524. local contentHeight =
  1525. contentBottom
  1526. - contentTop
  1527. + 1
  1528.  
  1529. -- One solid divider between left/right halves.
  1530. local leftWidth =
  1531. math.floor(
  1532. (bufferW - 1) / 2
  1533. )
  1534.  
  1535. local dividerX =
  1536. leftWidth + 1
  1537.  
  1538. local rightX =
  1539. dividerX + 1
  1540.  
  1541. local rightWidth =
  1542. bufferW - rightX + 1
  1543.  
  1544. -- Split vertically into two equally large storage rows.
  1545. local topHeight =
  1546. math.floor(
  1547. contentHeight / 2
  1548. )
  1549.  
  1550. local bottomHeight =
  1551. contentHeight
  1552. - topHeight
  1553.  
  1554. local topY =
  1555. contentTop
  1556.  
  1557. local bottomY =
  1558. contentTop
  1559. + topHeight
  1560.  
  1561. -- ========================================================
  1562. -- TOP ROW
  1563. -- ========================================================
  1564.  
  1565. drawStoragePanel(
  1566. 1,
  1567. topY,
  1568. leftWidth,
  1569. topHeight,
  1570. groups.item
  1571. )
  1572.  
  1573. drawStoragePanel(
  1574. rightX,
  1575. topY,
  1576. rightWidth,
  1577. topHeight,
  1578. groups.fluid
  1579. )
  1580.  
  1581. -- ========================================================
  1582. -- BOTTOM ROW
  1583. -- ========================================================
  1584.  
  1585. drawStoragePanel(
  1586. 1,
  1587. bottomY,
  1588. leftWidth,
  1589. bottomHeight,
  1590. groups.chemical
  1591. )
  1592.  
  1593. drawStoragePanel(
  1594. rightX,
  1595. bottomY,
  1596. rightWidth,
  1597. bottomHeight,
  1598. groups.radiation
  1599. )
  1600.  
  1601. -- ========================================================
  1602. -- CENTRE DIVIDER
  1603. -- ========================================================
  1604.  
  1605. for y =
  1606. contentTop,
  1607. contentBottom do
  1608.  
  1609. fill(
  1610. dividerX,
  1611. y,
  1612. 1,
  1613. C.divider
  1614. )
  1615. end
  1616.  
  1617. -- ========================================================
  1618. -- OTHER ADDON STORAGE
  1619. -- Only consumes a row if such storage actually exists.
  1620. -- ========================================================
  1621.  
  1622. if otherText then
  1623. fill(
  1624. 1,
  1625. bufferH,
  1626. bufferW,
  1627. C.headerBg
  1628. )
  1629.  
  1630. center(
  1631. 1,
  1632. bufferH,
  1633. bufferW,
  1634. otherText,
  1635. C.other,
  1636. C.headerBg
  1637. )
  1638. end
  1639.  
  1640. commitFrame()
  1641. end
  1642.  
  1643. -- ============================================================
  1644. -- ERROR DISPLAY
  1645. -- ============================================================
  1646.  
  1647. local function drawError(err)
  1648. beginFrame()
  1649.  
  1650. center(
  1651. 1,
  1652. math.max(
  1653. 1,
  1654. math.floor(
  1655. bufferH / 2
  1656. )
  1657. ),
  1658. bufferW,
  1659. "STORAGE MONITOR ERROR",
  1660. C.bad
  1661. )
  1662.  
  1663. center(
  1664. 1,
  1665. math.max(
  1666. 1,
  1667. math.floor(
  1668. bufferH / 2
  1669. ) + 1
  1670. ),
  1671. bufferW,
  1672. tostring(err),
  1673. C.muted
  1674. )
  1675.  
  1676. commitFrame()
  1677. end
  1678.  
  1679. -- ============================================================
  1680. -- LOOP
  1681. -- ============================================================
  1682.  
  1683. while true do
  1684. local ok, err =
  1685. pcall(drawFrame)
  1686.  
  1687. if not ok then
  1688. drawError(err)
  1689. end
  1690.  
  1691. sleep(CONFIG.refresh)
  1692. end
Add Comment
Please, Sign In to add comment