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