Advertisement
l0nax

Untitled

Feb 16th, 2022 (edited)
785
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.93 KB | None | 0 0
  1. -- Config
  2.  
  3. local maxUsedSlotsPerCell = 55
  4. local paddingPercent = 100
  5.  
  6. local systemDriveNames = {
  7.   -- "ae2:drive_8",
  8.   "ae2:drive_9",
  9.   -- "ae2:drive_12",
  10.   -- "ae2:drive_13",
  11.   "ae2:drive_10",
  12.   "ae2:drive_11",
  13. }
  14.  
  15. local workspaceNames = {
  16.   ioPort = "ae2:io_port_0",
  17.   interface = "ae2:interface_1",
  18.   chest = "ae2:chest_0",
  19.   drives = {
  20.     "ae2:drive_13",
  21.     "ae2:drive_12",
  22.     "ae2:drive_8",
  23.   }
  24. }
  25.  
  26. local capacityByName = {
  27.   ["ae2:storage_cell_1k"] = 1024,
  28.   ["ae2:storage_cell_4k"] = 4096,
  29.   ["ae2:storage_cell_16k"] = 16384,
  30.   ["ae2:storage_cell_64k"] = 65536
  31. }
  32.  
  33. -- /Config
  34.  
  35. -- Util Functions
  36.  
  37. local clock = os.clock
  38. local function sleep(n)  -- seconds
  39.   local t0 = clock()
  40.   while clock() - t0 <= n do end
  41. end
  42.  
  43. local function map(array, func)
  44.   local new_array = {}
  45.   for i,v in pairs(array) do
  46.     new_array[i] = func(v, i)
  47.   end
  48.   return new_array
  49. end
  50.  
  51. local function values(obj)
  52.   local result = {}
  53.   for _, v in pairs(obj) do
  54.     table.insert(result, v)
  55.   end
  56.   return result
  57. end
  58.  
  59. local function groupBy(array, prop)
  60.   local result = {}
  61.   for _, element in pairs(array) do
  62.     if element[prop] ~= nil then
  63.       if result[element[prop]] == nil then
  64.         result[element[prop]] = {}
  65.       end
  66.       table.insert(result[element[prop]], element)
  67.     end
  68.   end
  69.   return result
  70. end
  71.  
  72. -- /Util Functions
  73.  
  74. -- Peripherals
  75.  
  76. local systemDrives = map(systemDriveNames, function(driveName)
  77.   return peripheral.wrap(driveName)
  78. end)
  79. local workspace = {
  80.   ioPort = peripheral.wrap(workspaceNames.ioPort),
  81.   interface = peripheral.wrap(workspaceNames.interface),
  82.   chest = peripheral.wrap(workspaceNames.chest),
  83.   drives = map(workspaceNames.drives, function(driveName)
  84.     return peripheral.wrap(driveName)
  85.   end)
  86. }
  87.  
  88. -- /Peripherals
  89.  
  90. -- Classes
  91.  
  92. -- Cell
  93.  
  94. local cells = {}
  95. local additionallyRequiredCells = {}
  96. local Cell = {}
  97. Cell.__index = Cell
  98.  
  99. Cell.capacities = (function()
  100.   local capacities = values(capacityByName)
  101.   table.sort(capacities, function(a, b) return a < b end)
  102.   return capacities
  103. end)()
  104.  
  105. function Cell.sortByUnusedBytesDesc(a, b)
  106.   return b:getNumUnusedBytes() < a:getNumUnusedBytes()
  107. end
  108.  
  109. function Cell.sortByCapacity(a, b)
  110.   return a.capacity < b.capacity
  111. end
  112.  
  113. function Cell.sortByCapacityDesc(a, b)
  114.   return b.capacity < a.capacity
  115. end
  116.  
  117. function Cell.loadAll()
  118.   for driveNum, systemDrive in ipairs(systemDrives) do
  119.     local systemCells = systemDrive.list()
  120.     local toSlotNum = 1
  121.     for _, cell in pairs(systemCells) do
  122.       table.insert(cells, Cell.new(capacityByName[cell.name], driveNum, toSlotNum))
  123.       toSlotNum = toSlotNum + 1
  124.     end
  125.   end
  126.   table.remove(cells, #cells)
  127. end
  128.  
  129. function Cell.new(capacity, driveNum, slotNum)
  130.   local self = setmetatable({}, Cell)
  131.   self.capacity = capacity
  132.   self.driveNum = driveNum
  133.   self.slotNum = slotNum
  134.   self.inventory = {}
  135.   return self
  136. end
  137.  
  138. function Cell.getSmallestCellNeededForStack(stack)
  139.   for _, capacity in ipairs(Cell.capacities) do
  140.     local cell = Cell.new(capacity)
  141.     if cell:hasSpaceFor(stack) then
  142.       return cell
  143.     end
  144.   end
  145. end
  146.  
  147. function Cell:getNumUsedBytes()
  148.   local bytesUsed = 0
  149.   for _, stackData in pairs(self.inventory) do
  150.     bytesUsed = bytesUsed + self:getBytesForStack(stackData)
  151.   end
  152.   return bytesUsed
  153. end
  154.  
  155. function Cell:add(stack)
  156.   table.insert(self.inventory, stack)
  157.   if self:getNumUsedBytes() > self.capacity then
  158.     error("Unexpected error: inventory has exceeded capacity")
  159.   end
  160. end
  161.  
  162. function Cell:getBytesForStack(stack)
  163.   return (self.capacity / 128) + math.ceil(stack.count / 8)
  164. end
  165.  
  166. function Cell:hasSpaceFor(stack)
  167.   local bytesUsed = self:getNumUsedBytes()
  168.   local hasEnoughBytes = bytesUsed + self:getBytesForStack(stack) < self.capacity
  169.   local hasEnoughSlots = self:getNumUnusedSlots() > 0
  170.   return hasEnoughBytes and hasEnoughSlots
  171. end
  172.  
  173. function Cell:getNumUnusedBytes()
  174.   return self.capacity - self:getNumUsedBytes()
  175. end
  176.  
  177. function Cell:getNumUnusedSlots()
  178.   return maxUsedSlotsPerCell - #self.inventory
  179. end
  180.  
  181. function Cell:clearAndPutInWorkspaceChest()
  182.   local drive = workspace.drives[self.driveNum]
  183.   drive.pushItems(workspaceNames.ioPort, self.slotNum)
  184.   while workspace.ioPort.list()[7] == nil do
  185.     sleep(0.1)
  186.   end
  187.   workspace.ioPort.pushItems(workspaceNames.chest, 7)
  188. end
  189.  
  190. function Cell:exportInventoryToWorkspaceChest()
  191.   for _, stack in ipairs(self.inventory) do
  192.     stack:exportToWorkspaceChest()
  193.   end
  194. end
  195.  
  196. local outputDrives = {}
  197. for _, drive in pairs(systemDrives) do
  198.   table.insert(outputDrives, drive)
  199. end
  200. local currentOutputDrive = table.remove(outputDrives, 1)
  201. function Cell:moveBackToSystem()
  202.   currentOutputDrive.pullItems(workspaceNames.chest, 2)
  203.   if #currentOutputDrive.list() == 10 then
  204.     currentOutputDrive = table.remove(outputDrives, 1)
  205.   end
  206. end
  207.  
  208. -- Stack
  209.  
  210. local stacks = {}
  211. local Stack = {}
  212. Stack.__index = Stack
  213.  
  214. function Stack.sortByCountDesc(a, b)
  215.   return b.count < a.count
  216. end
  217.  
  218. function Stack.loadAll()
  219.   local handledItemTypes = {}
  220.   local allItemTypes = workspace.interface.listAvailableItems()
  221.   for _, itemType in pairs(allItemTypes) do
  222.     if handledItemTypes[itemType.name] == nil then
  223.       handledItemTypes[itemType.name] = 1
  224.       local ccStacks = workspace.interface.findItems(itemType.name)
  225.       for _, ccStack in pairs(ccStacks) do
  226.         table.insert(stacks, Stack.new(ccStack))
  227.       end
  228.     end
  229.   end
  230. end
  231.  
  232. function Stack.new(ccStack)
  233.   local self = setmetatable({}, Stack)
  234.   self.ccStack = ccStack
  235.   self.metadata = ccStack.getMetadata()
  236.   self.displayName = self.metadata.displayName
  237.   self.count = (1+paddingPercent/100)*self.metadata.count
  238.   return self
  239. end
  240.  
  241. function Stack:addToCellWithLargestUnusuedSpace()
  242.   table.sort(cells, Cell.sortByUnusedBytesDesc)
  243.   for _, cell in ipairs(cells) do
  244.     if cell:hasSpaceFor(self) then
  245.       cell:add(self)
  246.       return
  247.     end
  248.   end
  249.   local newCell = Cell.getSmallestCellNeededForStack(self)
  250.   newCell:add(self)
  251.   table.insert(cells, newCell)
  252.   table.insert(additionallyRequiredCells, newCell)
  253.   error("No cell found to add stack to")
  254. end
  255.  
  256. function Stack:exportAllToWorkspaceChest()
  257.   local amountToExport = self.metadata.count
  258.   print("  Exporting "..amountToExport.." "..self.displayName.."...")
  259.   local amountExported = 0
  260.   while amountExported < amountToExport do
  261.     amountExported = amountExported + self.ccStack.export(workspaceNames.chest)
  262.   end
  263. end
  264.  
  265. -- /Classes
  266.  
  267. -- Main
  268.  
  269. print("Scanning for cells...")
  270. Cell.loadAll()
  271.  
  272. print("Moving cells to workspace...")
  273. print(textutils.serialize(workspaceNames.drives))
  274. local function moveDrivesFromSystemToWorkspace()
  275.   for driveNum, systemDrive in ipairs(systemDrives) do
  276.     local systemCells = systemDrive.list()
  277.     for fromSlotNum, _ in pairs(systemCells) do
  278.       print(driveNum)
  279.       systemDrive.pushItems(workspaceNames.drives[driveNum], fromSlotNum)
  280.     end
  281.   end
  282. end
  283.  
  284. moveDrivesFromSystemToWorkspace()
  285.  
  286. print("Scanning for stacks...")
  287. Stack.loadAll()
  288.  
  289. print("Planning...")
  290. table.sort(stacks, Stack.sortByCountDesc)
  291. for _, stack in ipairs(stacks) do
  292.   stack:addToCellWithLargestUnusuedSpace()
  293. end
  294.  
  295. if #additionallyRequiredCells > 0 then
  296.   print("Needed cells:")
  297.   local requiredCellsByCapacity = groupBy(additionallyRequiredCells, 'capacity')
  298.   for _, capacity in ipairs(Cell.capacities) do
  299.     if requiredCellsByCapacity[capacity] ~= nil and #requiredCellsByCapacity[capacity] > 0 then
  300.       print("  "..#requiredCellsByCapacity[capacity].." "..(capacity/1024).."k cells")
  301.     end
  302.   end
  303.   error("Add the above cells to continue")
  304. end
  305.  
  306. print("Executing plan...")
  307.  
  308. table.sort(cells, Cell.sortByCapacity)
  309.  
  310. for _, cell in ipairs(cells) do
  311.   print("clearing and putting in workspace...")
  312.   cell:clearAndPutInWorkspaceChest()
  313.   print("moving stacks to chest...")
  314.   for _, stack in ipairs(cell.inventory) do
  315.     stack:exportAllToWorkspaceChest()
  316.   end
  317.   print("moving cell back to system...")
  318.   cell:moveBackToSystem()
  319. end
  320.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement