Advertisement
feryaz

AE2 Storage defragmentation

Jan 26th, 2017
6,005
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.81 KB | None | 0 0
  1. --[[
  2. Applied Energistics 2 Storage defragmentation
  3. Version: 0.2
  4. Author: feryaz
  5. ]]--
  6. -- Some waiting times are just to show a message on the monitor, set to false for faster fragmenting; wont change import and export speeds
  7. local ambientSleeps = 0.1
  8.  
  9. -- Wrap drive of buffer network
  10. local bufferDrive = peripheral.wrap("tiledrive_7")
  11.  
  12. -- Wrap monitor
  13. local mon = peripheral.wrap("right")
  14.  
  15. -- Wrap OpenPeripheralSelector to display item icon, set to 'false' if you dont have it
  16. local selector = peripheral.wrap("top")
  17.  
  18. -- Wrap interface of buffer network
  19. local bufferInterface = peripheral.wrap("left")
  20.  
  21. -- Cardinal direction from main network interface to buffer network interface (UP/DOWN/NORTH/EAST/SOUTH/WEST)
  22. local bufferInterfaceDirection = "UP"
  23.  
  24. -- Wrap interface of main network
  25. local interface = peripheral.wrap("tileinterface_6")
  26.  
  27. -- Cardinal direction from buffer network interface to main network interface
  28. local interfaceDirection = "DOWN"
  29.  
  30. -- The cardinal directions that the left and right sides of the drives are facing (look right/left while standing in front of the drives and hit F3)
  31. local drivesDirectionLeft = "SOUTH"
  32. local drivesDirectionRight = "NORTH"
  33.  
  34. -- Array of drives in main network
  35. -- Each drive must face another one to left or right
  36. -- Drive [11] must be defined, set to priority 1, be empty, have a drive in each row below/above it
  37. -- Every other drive must have their first slot empty
  38. -- You can replace drives with empty chests if you want to space them out
  39. -- The [key] is made up of x and y as of how the drives are setup where x is the row (beginning 0 in the left) and y is the column from up to down (beginning 0 at the top)
  40. local drives = {
  41. [11] = peripheral.wrap("bottom"),
  42. [12] = peripheral.wrap("tiledrive_1"),
  43. [13] = peripheral.wrap("tiledrive_2"),
  44. [20] = peripheral.wrap("tiledrive_6"),
  45. [21] = peripheral.wrap("tiledrive_5"),
  46. [22] = peripheral.wrap("tiledrive_4"),
  47. [23] = peripheral.wrap("tiledrive_3"),
  48. }
  49.  
  50. ------- End of Config ---------
  51.  
  52. local w, h = mon.getSize()
  53. local finishedItems = {}
  54. local finishedItemsCount = 0
  55. local cellOrigin = {}
  56. local totalItemsCount = 0
  57. local itemName = 0
  58. local inDrives = 0
  59. local inBuffer = 0
  60.  
  61. --display text text on monitor, "mon" peripheral
  62. function drawText(x, y, text, text_color, bg_color)
  63. mon.setBackgroundColor(bg_color)
  64. mon.setTextColor(text_color)
  65. mon.setCursorPos(x,y)
  66. mon.write(text)
  67. end
  68.  
  69. --draw line on monitor
  70. function drawLine(x, y, length, color)
  71. mon.setBackgroundColor(color)
  72. mon.setCursorPos(x,y)
  73. mon.write(string.rep(" ", length))
  74. end
  75.  
  76. --clear lines on monitor
  77. function clearLine(...)
  78. for _,y in ipairs(arg) do
  79. mon.setCursorPos(1,y)
  80. mon.clearLine()
  81. end
  82. end
  83.  
  84. function updateTask(msg, color, percent)
  85. percent = math.floor(percent)
  86. mon.setBackgroundColor(colors.black)
  87. clearLine(6,7,8,9,10)
  88.  
  89. drawText(2, 6, "Task", colors.white, colors.black)
  90.  
  91. drawText(math.floor(w - string.len(percent.."%")), 6, percent.."%", colors.white, colors.black)
  92.  
  93. drawText(2, 7, msg, color, colors.black)
  94.  
  95. if itemName ~= 0 then
  96. drawText(2, 9, itemName, colors.white, colors.black)
  97.  
  98. drawText(2, 10, ""..inDrives, colors.lightGray, colors.black)
  99. drawText(math.floor(w-string.len(""..inBuffer)), 10, ""..inBuffer, colors.lightGray, colors.black)
  100.  
  101. color = colors.orange
  102.  
  103. if percent >= 50 then
  104. color = colors.blue
  105. end
  106.  
  107. percent = math.floor(100/(inDrives+inBuffer)*inBuffer)
  108. local barLength = w-2
  109. local barBreak = math.ceil(barLength/100*percent)
  110. drawLine(2, 11, barBreak, color)
  111. drawLine(2+barBreak, 11, w-barBreak-2, colors.gray)
  112. end
  113. end
  114.  
  115. function updateProgress()
  116. mon.setBackgroundColor(colors.black)
  117. mon.clear()
  118. drawText(2, 2, "Progress ", colors.white, colors.black)
  119. local percent = math.floor(100/totalItemsCount*finishedItemsCount)
  120. local percentString = percent.."%"
  121. drawText(math.floor(w - string.len(percentString)), 2, percentString, colors.white, colors.black)
  122.  
  123. drawText(2, 3, finishedItemsCount.."/"..totalItemsCount, colors.lightGray, colors.black)
  124.  
  125. local barLength = w-2
  126. local barBreak = math.ceil(barLength/100*percent)
  127. drawLine(2, 4, barBreak, colors.green)
  128. drawLine(2+barBreak, 4, w-barBreak-2, colors.gray)
  129. end
  130.  
  131. function itemKey(item)
  132. local key = item.id .. "/" .. item.dmg
  133.  
  134. if item.nbt_hash ~= nil then
  135. key = key .. "/" .. item.nbt_hash
  136. end
  137.  
  138. return key
  139. end
  140.  
  141. function findItemToDefrag()
  142. local item
  143. local availableItems = interface.getAvailableItems()
  144. itemName = 0
  145. inDrives = 0
  146. inBuffer = 0
  147.  
  148. for _, item in pairs(interface.getAvailableItems()) do
  149. if not finishedItems[itemKey(item.fingerprint)] then
  150. if totalItemsCount == 0 then
  151. totalItemsCount = #availableItems
  152. updateProgress()
  153. end
  154. updateTask("Find next item", colors.lightGray, 0)
  155. if ambientSleeps then
  156. sleep(ambientSleeps)
  157. end
  158.  
  159. return exportItem(item)
  160. end
  161. end
  162. return false
  163. end
  164.  
  165. function exportItem(item)
  166. local details = interface.getItemDetail(item.fingerprint).basic();
  167. itemName = details.display_name
  168. if selector then
  169. selector.setSlot(1, item.fingerprint)
  170. end
  171. while details and details.qty > 0 do
  172. inDrives = details.qty
  173. updateTask("Export to buffer", colors.lightGray, 50/(inDrives+inBuffer)*inBuffer)
  174. local status = interface.exportItem(item.fingerprint, bufferInterfaceDirection)
  175. if details.qty < details.max_size then
  176. inBuffer = inBuffer + details.qty
  177. inDrives = 0
  178. details = nil
  179. else
  180. inBuffer = inBuffer + details.max_size
  181. details.qty = details.qty - details.max_size
  182. inDrives = details.qty
  183. sleep(0.001)
  184. end
  185. end
  186. return checkItem(item)
  187. end
  188.  
  189. function importItem(item)
  190. local details = bufferInterface.getItemDetail(item.fingerprint).basic();
  191. while details and details.qty > 0 do
  192. inBuffer = details.qty
  193. updateTask("Import to cell", colors.lightGray, 50+50/(inDrives+inBuffer)*inDrives)
  194. if bufferInterface.exportItem(item.fingerprint, interfaceDirection) then
  195. if details.qty < details.max_size then
  196. inDrives = inDrives + details.qty
  197. inBuffer = 0
  198. details = nil
  199. else
  200. inDrives = inDrives + details.max_size
  201. details.qty = details.qty - details.max_size
  202. if details.qty == 0 then
  203. inBuffer = 0
  204. end
  205. sleep(0.001)
  206. end
  207. else
  208. return false
  209. end
  210. end
  211. return true
  212. end
  213.  
  214. function checkItem(item)
  215. local details = bufferInterface.getItemDetail(item.fingerprint)
  216. while details do
  217. details = details.all()
  218. local requiredDrive
  219. local stacks = math.ceil(details.qty/64)
  220. updateTask("Find best Cell", colors.lightGray, 50)
  221.  
  222. if ambientSleeps then
  223. sleep(ambientSleeps)
  224. end
  225.  
  226. if stacks > 16 then
  227. requiredDrive = 65536
  228. elseif stacks > 4 then
  229. requiredDrive = 16384
  230. elseif stacks > 1 then
  231. requiredDrive = 4096
  232. else
  233. requiredDrive = 1024
  234. end
  235.  
  236. if findDrive(requiredDrive, details.qty) then
  237. if importItem(item) then
  238. finishedItems[itemKey(item.fingerprint)] = 1
  239. finishedItemsCount = finishedItemsCount + 1
  240.  
  241. updateProgress()
  242. updateTask("Finished", colors.lime, 100)
  243.  
  244. if ambientSleeps then
  245. os.sleep(ambientSleeps)
  246. end
  247.  
  248. details = nil
  249. return true
  250. else
  251. details = bufferInterface.getItemDetail(item.fingerprint)
  252. end
  253. else
  254. print("Please insert new "..requiredDrive.."Bytes drive and wait ~20 sec")
  255. updateTask("Insert new "..requiredDrive.."B drive", colors.red, 50)
  256. sleep(20)
  257. details = bufferInterface.getItemDetail(item.fingerprint)
  258. end
  259. end
  260. -- Wait for item to appear in buffer
  261. print("Wait for item to appear in buffer "..item.fingerprint.id)
  262. sleep(0.01)
  263.  
  264. return checkItem(item)
  265. end
  266.  
  267. function findDrive(requiredDrive, amount)
  268. local bytes = amount/8 + (requiredDrive/128)
  269. local name, drive, slot
  270. for name, drive in pairs(drives) do
  271. for slot = 1, 10, 1 do
  272. local cell = drive.getStackInSlot(slot)
  273. if cell then
  274. if cell.me_cell.totalBytes == requiredDrive and
  275. (cell.me_cell.freeBytes > bytes or cell.me_cell.freeBytes == cell.me_cell.totalBytes)
  276. and cell.me_cell.freeTypes > 0
  277. and not cell.me_cell.preformatted
  278. then
  279. if name == 11 and slot == 1 then
  280. -- best drive alreay in position
  281. return true
  282. elseif freeFirstSlot() then
  283. cellOrigin = {name, slot}
  284. updateTask("Get cell", colors.lightGray, 50)
  285. if ambientSleeps then
  286. sleep(ambientSleeps)
  287. end
  288.  
  289. return moveCell(""..name, slot, "11", 1)
  290. end
  291. end
  292. end
  293. end
  294. end
  295. return false
  296. end
  297.  
  298. function freeFirstSlot()
  299. if #cellOrigin > 0 then
  300. updateTask("Remove cell", colors.lightGray, 50)
  301. if ambientSleeps then
  302. sleep(ambientSleeps)
  303. end
  304.  
  305. if moveCell("11", 1, cellOrigin[1], cellOrigin[2], true) then
  306. cellOrigin = {}
  307. return true
  308. end
  309.  
  310. return false
  311. end
  312. return true
  313. end
  314.  
  315. function moveCell(from, fromSlot, to, toSlot, back)
  316. local move = true
  317. local moved = false
  318. local drive, fromY, fromX, toY, toX
  319.  
  320. while move do
  321. drive = drives[tonumber(from)]
  322. fromY = tonumber(string.sub(from, 1, 1))
  323. toY = tonumber(string.sub(to, 1, 1))
  324.  
  325. fromX = tonumber (string.sub(from, 2, 2))
  326. toX = tonumber( string.sub(to, 2, 2) )
  327.  
  328. -- directly insert in right slot if next drive will be destination as swapStack doesn't seem to work
  329. insertIntoSlot = 1
  330. if math.abs(fromX-toX) + math.abs(fromY-toY) == 1 then
  331. insertIntoSlot = toSlot
  332. end
  333. if fromX == toX or back then
  334. if fromY == toY then
  335. if back then
  336. back = false
  337. else
  338. if fromSlot == toSlot then
  339. moved = true
  340. move = false
  341. else
  342. -- go right to come back in correct slot as swapStack does not work; should not happen
  343. if drive.pushItemIntoSlot(drivesDirectionRight, fromSlot, 1, insertIntoSlot) == 1 then
  344. from = fromY..""..(fromX+1)
  345. fromSlot = insertIntoSlot
  346. end
  347. end
  348. end
  349. else
  350. if fromY > toY then
  351. if drive.pushItemIntoSlot("UP", fromSlot, 1, insertIntoSlot) == 1 then
  352. from = (fromY-1)..""..fromX
  353. fromSlot = insertIntoSlot
  354. end
  355. else
  356. if drive.pushItemIntoSlot("DOWN", fromSlot, 1, insertIntoSlot) == 1 then
  357. from = (fromY+1)..""..fromX
  358. fromSlot = insertIntoSlot
  359. end
  360. end
  361.  
  362. end
  363. else
  364. if fromX > toX then
  365. if drive.pushItemIntoSlot(drivesDirectionLeft, fromSlot, 1, insertIntoSlot) == 1 then
  366. from = fromY..""..(fromX-1)
  367. fromSlot = insertIntoSlot
  368. end
  369. else
  370. if drive.pushItemIntoSlot(drivesDirectionRight, fromSlot, 1, insertIntoSlot) == 1 then
  371. from = fromY..""..(fromX+1)
  372. fromSlot = insertIntoSlot
  373. end
  374. end
  375. end
  376. end
  377. return moved
  378. end
  379.  
  380. mon.setTextScale(1)
  381. mon.setBackgroundColor(colors.black)
  382. mon.clear()
  383.  
  384. while findItemToDefrag() do
  385.  
  386. end
  387.  
  388. freeFirstSlot()
  389. updateProgress()
  390. selector.setSlot(1, nil)
  391. updateTask("Defrag done", colors.lime, 100)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement