Blackhome

Main Storage Management

May 2nd, 2025 (edited)
318
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 38.08 KB | Gaming | 0 0
  1. -- pastebin get wngsBEP2 StorageManager
  2.  
  3. -- === CONFIG ===
  4. local DISK_NAMES = {
  5.     incoming = "Incoming Task",
  6.     user = "User Task",
  7.     outgoing = "Outgoing Task",
  8.     finished = "Finished Task",
  9.     settings = "Settings",
  10.     storage = "Data Storage",
  11.     init = "Turtle Initializing"
  12. }
  13.  
  14. local TASK_DATA = {
  15.     currentTasks = {},
  16.     emptyChests = {},
  17.     storedItems = {},
  18.     completedTasks = {},
  19.     totalChestCount = 0,
  20.     outgoingTask = nil
  21. }
  22.  
  23. local SYSTEM_STATE = {
  24.     chestInitialized = false,
  25.     waitingForChestPlacement = false,
  26.     orientation = nil,
  27.     orientationDirection = 1,
  28.     startCoords = nil,
  29.     endCoords = nil,
  30.     finishBlockCoords = nil,
  31.     outputChestCoords = nil,
  32.     refuelChestCoords = nil,
  33.     modulo = nil,
  34.     yModulo = nil,
  35.     maxEntriesPerDiskFile = 100
  36. }
  37.  
  38. local TASK_TYPES = {
  39.     createChests = "create_chests",
  40.     storeItems = "store_items",
  41.     getItems = "get_items",
  42.     checkInventory = "check_inventory",
  43.     initializeChests = "initialize_chests"
  44. }
  45.  
  46. local MULTI_DISK_FILES = {
  47.     currentTasks = true,
  48.     emptyChests = true,
  49.     storedItems = true,
  50.     completedTasks = true
  51. }
  52.  
  53.  
  54. local taskIdCounter = 1
  55. local currentTaskSourceIndex = 1
  56. local TASK_SOURCES = {"incoming", "user", "settings"}  -- disk name keys
  57.  
  58. local DEFAULT_MAX_ENTRIES_PER_FILE = 100
  59. local DEFAULT_COMPLETED_TASKS_LIMIT = 50
  60.  
  61. SYSTEM_STATE = SYSTEM_STATE or {}
  62. SYSTEM_STATE.maxEntriesPerDiskFile = SYSTEM_STATE.maxEntriesPerDiskFile or DEFAULT_MAX_ENTRIES_PER_FILE
  63.  
  64. local STORAGE_LABEL_BASE = DISK_NAMES.storage
  65.  
  66.  
  67.  
  68. -- === UTILITIES ===
  69. -- compare two coords
  70. local function equalCoords(coord1, coord2)
  71.     return coord1.x == coord2.x and coord1.y == coord2.y and coord1.z == coord2.z
  72. end
  73.  
  74. -- copy a table
  75. function deepCopy(orig)
  76.     local copy
  77.     if type(orig) == 'table' then
  78.         copy = {}
  79.         for k, v in pairs(orig) do
  80.             copy[k] = deepCopy(v)
  81.         end
  82.     else
  83.         copy = orig
  84.     end
  85.     return copy
  86. end
  87.  
  88. local function coordToString(coord)
  89.     return "(" .. tostring(coord.x) .. ", " .. tostring(coord.y) .. ", "  .. tostring(coord.z) .. ")"
  90. end
  91.  
  92. -- === DISK MANAGEMENT ===
  93. local function getDiskByLabel(label)
  94.     for _, side in ipairs(peripheral.getNames()) do
  95.         if peripheral.getType(side) == "drive" then
  96.             local disk = peripheral.wrap(side)
  97.             if disk.getDiskLabel() == label then
  98.                 return disk, disk.getMountPath()
  99.             end
  100.         end
  101.     end
  102.     return nil, nil
  103. end
  104.  
  105. local function getStorageDisks()
  106.     local disks = {}
  107.     local index = 1
  108.     while true do
  109.         local label = STORAGE_LABEL_BASE .. (index > 1 and (" " .. tostring(index)) or "")
  110.         local _, path = getDiskByLabel(label)
  111.         if not path then break end
  112.         table.insert(disks, {label = label, path = path})
  113.         index = index + 1
  114.     end
  115.     return disks
  116. end
  117.  
  118. local function splitTable(tbl, chunkSize)
  119.     local chunks = {}
  120.     for i = 1, #tbl, chunkSize do
  121.         table.insert(chunks, {unpack(tbl, i, math.min(i + chunkSize - 1, #tbl))})
  122.     end
  123.     return chunks
  124. end
  125.  
  126. local function saveTableToDisk(tableData, baseFilename)
  127.     local maxEntries = SYSTEM_STATE.maxEntriesPerDiskFile or DEFAULT_MAX_ENTRIES_PER_FILE
  128.     local parts = splitTable(tableData, maxEntries)
  129.     local disks = getStorageDisks()
  130.  
  131.     if #parts > #disks then
  132.         print("[WARN] Speichergrenze erreicht: Füge eine weitere Data Storage Disk hinzu.")
  133.         repeat
  134.             sleep(1)
  135.             disks = getStorageDisks()
  136.         until #disks >= #parts
  137.     end
  138.  
  139.     for i, part in ipairs(parts) do
  140.         local fullPath = fs.combine(disks[i].path, baseFilename .. "_" .. tostring(i))
  141.         local file = fs.open(fullPath, "w")
  142.         file.write(textutils.serialize(part))
  143.         file.close()
  144.     end
  145.  
  146.     for i = #parts + 1, #disks do
  147.         local path = fs.combine(disks[i].path, baseFilename .. "_" .. tostring(i))
  148.         if fs.exists(path) then fs.delete(path) end
  149.     end
  150. end
  151.  
  152. local function loadTableFromDisk(baseFilename)
  153.     local result = {}
  154.     local index = 1
  155.     while true do
  156.         local label = STORAGE_LABEL_BASE .. (index > 1 and (" " .. tostring(index)) or "")
  157.         local _, path = getDiskByLabel(label)
  158.         if not path then break end
  159.  
  160.         local filePath = fs.combine(path, baseFilename .. "_" .. tostring(index))
  161.         if not fs.exists(filePath) then break end
  162.  
  163.         local file = fs.open(filePath, "r")
  164.         local chunk = textutils.unserialize(file.readAll())
  165.         file.close()
  166.  
  167.         if type(chunk) == "table" then
  168.             for _, entry in ipairs(chunk) do
  169.                 table.insert(result, entry)
  170.             end
  171.         end
  172.         index = index + 1
  173.     end
  174.     return result
  175. end
  176.  
  177. -- == Individual Save and Loading ==
  178. local function saveTotalChestCount(count)
  179.     local disk, path = getDiskByLabel("Data Storage")
  180.     if not path then error("Data Storage disk not found") end
  181.     local fullPath = fs.combine(path, "totalChestCount.txt")
  182.     local file = fs.open(fullPath, "w")
  183.     file.write(textutils.serialize({ count = count }))
  184.     file.close()
  185. end
  186.  
  187. local function loadTotalChestCount()
  188.     local disk, path = getDiskByLabel("Data Storage")
  189.     local fullPath = fs.combine(path, "totalChestCount.txt")
  190.     if not path or not fs.exists(fullPath) then return nil end
  191.     local file = fs.open(fullPath, "r")
  192.     local data = textutils.unserialize(file.readAll())
  193.     file.close()
  194.     return data
  195. end
  196.  
  197. local function saveSystemState()
  198.     for _, field in ipairs({"orientation", "startCoords", "endCoords", "finishBlockCoords", "outputChestCoords", "modulo", "yModulo"}) do
  199.         if SYSTEM_STATE[field] == nil then
  200.             print("[WARNUNG] SYSTEM_STATE-Feld fehlt: " .. field)
  201.         end
  202.     end
  203.  
  204.     local disk, path = getDiskByLabel("Data Storage")
  205.     if not path then error("Data Storage disk not found") end
  206.     local fullPath = fs.combine(path, "systemState.txt")
  207.     local file = fs.open(fullPath, "w")
  208.     file.write(textutils.serialize(SYSTEM_STATE))
  209.     file.close()
  210. end
  211. local function loadSystemState()
  212.     local disk, path = getDiskByLabel("Data Storage")
  213.     if not path then return {} end
  214.     local fullPath = fs.combine(path, "systemState.txt")
  215.     if not fs.exists(fullPath) then return {} end
  216.     local file = fs.open(fullPath, "r")
  217.     local data = textutils.unserialize(file.readAll())
  218.     file.close()
  219.     return data or {}
  220. end
  221.  
  222.  
  223. -- == save general IdCounter on storage ==
  224. local function loadTaskIdCounter()
  225.     local disk, path = getDiskByLabel(DISK_NAMES.storage)
  226.     if not path then return 1 end
  227.     local fullPath = fs.combine(path, "taskIdCounter")
  228.     if fs.exists(fullPath) then
  229.         local file = fs.open(fullPath, "r")
  230.         local id = tonumber(file.readLine())
  231.         file.close()
  232.         return id or 1
  233.     end
  234.     return 1
  235. end
  236.  
  237. local function saveTaskIdCounter()
  238.     local disk, path = getDiskByLabel(DISK_NAMES.storage)
  239.     if not path then error("Data Storage disk not found for saving taskIdCounter") end
  240.     local fullPath = fs.combine(path, "taskIdCounter")
  241.     local file = fs.open(fullPath, "w")
  242.     file.writeLine(tostring(taskIdCounter))
  243.     file.close()
  244. end
  245.  
  246. -- == save general coords ==
  247. local function getCoordsList(path)
  248.     if not fs.exists(path) then return {} end
  249.     local file = fs.open(path, "r")
  250.     local data = textutils.unserialize(file.readAll())
  251.     file.close()
  252.     return data or {}
  253. end
  254.  
  255. local function saveCoordList(path, coordList)
  256.     local file = fs.open(path, "w")
  257.     file.write(textutils.serialize(coordList))
  258.     file.close()
  259. end
  260.  
  261. local function addCoordToList(path, coord)
  262.     local coords = getCoordsList(path)
  263.     table.insert(coords, coord)
  264.     saveCoordList(path, coords)
  265. end
  266.  
  267. -- == save general tasks ==
  268. function getTaskList(path)
  269.     local filename = path:match(".-([^/]+)$")
  270.     local baseName = filename:gsub("%.txt", "")
  271.     if MULTI_DISK_FILES[baseName] then
  272.         return loadTableFromDisk(baseName)
  273.     end
  274.     if not fs.exists(path) then return {} end
  275.     local file = fs.open(path, "r")
  276.     local data = textutils.unserialize(file.readAll())
  277.     file.close()
  278.     return data or {}
  279. end
  280.  
  281. function saveTaskList(path, taskList)
  282.     local filename = path:match(".-([^/]+)$")
  283.     local baseName = filename:gsub("%.txt", "")
  284.     if MULTI_DISK_FILES[baseName] then
  285.         return saveTableToDisk(taskList, baseName)
  286.     end
  287.     local file = fs.open(path, "w")
  288.     file.write(textutils.serialize(taskList))
  289.     file.close()
  290. end
  291.  
  292. local function addTaskToList(path, task)
  293.     local tasks = getTaskList(path)
  294.     table.insert(tasks, task)
  295.     saveTaskList(path, tasks)
  296. end
  297.  
  298. -- save task on outgoing
  299. local function saveTaskToDisk(contentTable)
  300.     local taskCopy = deepCopy(contentTable) -- wichtig: Kopie erstellen
  301.     taskCopy.taskId = taskIdCounter
  302.     taskIdCounter = taskIdCounter + 1
  303.     saveTaskIdCounter()
  304.  
  305.     local outgoingDisk, outgoingPath = getDiskByLabel(DISK_NAMES.outgoing)
  306.     if not outgoingPath then error("Outgoing Task disk not found") end
  307.     local fullOutgoingPath = fs.combine(outgoingPath, "task_list.txt")
  308.  
  309.     addTaskToList(fullOutgoingPath, taskCopy)
  310.  
  311.     local storageDisk, storagePath = getDiskByLabel(DISK_NAMES.storage)
  312.     if not storagePath then error("Data Storage disk not found") end
  313.     local fullStoragePath = fs.combine(storagePath, "currentTasks")
  314.  
  315.     addTaskToList(fullStoragePath, taskCopy)
  316.     table.insert(TASK_DATA.currentTasks, taskCopy)
  317. end
  318.  
  319. local function trimCompletedTasks()
  320.     if TASK_DATA and TASK_DATA.completedTasks and #TASK_DATA.completedTasks > DEFAULT_COMPLETED_TASKS_LIMIT then
  321.         while #TASK_DATA.completedTasks > DEFAULT_COMPLETED_TASKS_LIMIT do
  322.             table.remove(TASK_DATA.completedTasks, 1)
  323.         end
  324.         saveTableToDisk(TASK_DATA.completedTasks, "completedTasks")
  325.     end
  326. end
  327.  
  328. local function checkStorageOverflow()
  329.     local tablesToCheck = {
  330.         currentTasks = TASK_DATA.currentTasks,
  331.         emptyChests = TASK_DATA.emptyChests,
  332.         storedItems = TASK_DATA.storedItems,
  333.         completedTasks = TASK_DATA.completedTasks
  334.     }
  335.  
  336.     local disks = getStorageDisks()
  337.     local maxEntries = SYSTEM_STATE.maxEntriesPerDiskFile or DEFAULT_MAX_ENTRIES_PER_FILE
  338.     local availableChunks = #disks
  339.  
  340.     for name, list in pairs(tablesToCheck) do
  341.         if math.ceil((#list + 5) / maxEntries) > availableChunks then
  342.             print("[INFO] Bitte weitere Data Storage Disk anschließen für " .. name)
  343.             repeat
  344.                 sleep(1)
  345.                 disks = getStorageDisks()
  346.                 availableChunks = #disks
  347.             until math.ceil((#list + 5) / maxEntries) <= availableChunks
  348.         end
  349.     end
  350. end
  351.  
  352. -- === MONITOR STORAGE SPACE ===
  353. function monitorStorageSpace()
  354.     local MIN_FREE_BYTES = 20000  -- Warnschwelle
  355.     local REDUCE_PERCENTAGE = 0.05
  356.  
  357.     local disks = getStorageDisks()
  358.     local lowSpaceDetected = false
  359.  
  360.     for _, disk in ipairs(disks) do
  361.         local free = fs.getFreeSpace(disk.path)
  362.         if free < MIN_FREE_BYTES then
  363.             print("[WARNUNG] Speicherplatz auf " .. disk.label .. " ist gering: " .. tostring(free) .. " Bytes frei.")
  364.             lowSpaceDetected = true
  365.         end
  366.     end
  367.  
  368.     if lowSpaceDetected then
  369.         print("[INFO] Speicherplatz wird knapp. Werte werden neu gespeichert und Chunkgröße ggf. angepasst.")
  370.         print("Bitte neue Disk bereithalten, falls nötig.")
  371.         print("Drücke Enter zum Fortfahren.")
  372.         io.read()
  373.         local oldMax = SYSTEM_STATE.maxEntriesPerDiskFile or DEFAULT_MAX_ENTRIES_PER_FILE
  374.         local reduceBy = math.max(1, math.floor(oldMax * REDUCE_PERCENTAGE))
  375.         local newMax = oldMax - reduceBy
  376.  
  377.         SYSTEM_STATE.maxEntriesPerDiskFile = newMax
  378.         saveSystemState()  
  379.  
  380.         -- Speicherbare Tabellen erneut sichern
  381.         saveTableToDisk(TASK_DATA.currentTasks, "currentTasks")
  382.         saveTableToDisk(TASK_DATA.emptyChests, "emptyChests")
  383.         saveTableToDisk(TASK_DATA.storedItems, "storedItems")
  384.         saveTableToDisk(TASK_DATA.completedTasks, "completedTasks")
  385.  
  386.         print("[INFO] Neue Chunkgröße gesetzt: " .. tostring(newMax) .. " Einträge pro Datei.")
  387.     end
  388. end
  389.  
  390.  
  391.  
  392. local function hasOutgoingTasks()
  393.     local _, path = getDiskByLabel(DISK_NAMES.outgoing)
  394.     if not path then return false end
  395.  
  396.     local tasks = getTaskList(fs.combine(path, "task_list.txt"))
  397.     return #tasks > 0
  398. end
  399.  
  400. local function registerNewChestCoord(newCoord)
  401.     local storageDisk, storagePath = getDiskByLabel(DISK_NAMES.storage)
  402.     local fullPath = fs.combine(storagePath, "usedCoords.txt")
  403.  
  404.     local chestCoords = getCoordsList(fullPath)
  405.     local bNewCoord = true
  406.  
  407.     for index, coord in ipairs(chestCoords) do
  408.         if equalCoords(coord, newCoord) then
  409.             bNewCoord = false
  410.             print("Coords " .. coordToString(newCoord) .. " already registered.\n")
  411.         end
  412.     end
  413.     if bNewCoord then
  414.         addCoordToList(fullPath, newCoord)
  415.     end
  416.  
  417.     return bNewCoord
  418. end
  419.  
  420. -- === INITIALIZATION ===
  421.  
  422. local function determineOrientation(startPos, endPos)
  423.     local finishPos = SYSTEM_STATE.finishBlockCoords
  424.     local outputPos = SYSTEM_STATE.outputChestCoords
  425.     local refuelPos = SYSTEM_STATE.refuelChestCoords
  426.  
  427.     if startPos.x ~= endPos.x then
  428.         SYSTEM_STATE.orientation = "x"
  429.         SYSTEM_STATE.orientationDirection = (endPos.x - startPos.x > 0) and 1 or -1
  430.         SYSTEM_STATE.modulo = (startPos.z - 2 * SYSTEM_STATE.orientationDirection) % 8
  431.     elseif startPos.z ~= endPos.z then
  432.         SYSTEM_STATE.orientation = "z"
  433.         SYSTEM_STATE.orientationDirection = (endPos.z - startPos.z > 0) and 1 or -1
  434.         SYSTEM_STATE.modulo = (startPos.x + 2 * SYSTEM_STATE.orientationDirection) % 8
  435.     else
  436.         SYSTEM_STATE.orientation = "unknown"
  437.         SYSTEM_STATE.orientationDirection = 1
  438.         SYSTEM_STATE.modulo = 0
  439.     end
  440.  
  441.     SYSTEM_STATE.yModulo = (startPos.y - 1) % 7
  442.  
  443.     local disk, path = getDiskByLabel(DISK_NAMES.init)
  444.     if path then
  445.         local file = fs.open(fs.combine(path, "init.txt"), "w")
  446.         file.writeLine("orientation=" .. SYSTEM_STATE.orientation)
  447.         file.writeLine("direction=" .. tostring(SYSTEM_STATE.orientationDirection))
  448.         file.writeLine("modulo=" .. tostring(SYSTEM_STATE.modulo))
  449.         file.writeLine("yModulo=" .. tostring(SYSTEM_STATE.yModulo))
  450.         file.writeLine("finish_x=" .. tostring(finishPos.x))
  451.         file.writeLine("finish_y=" .. tostring(finishPos.y))
  452.         file.writeLine("finish_z=" .. tostring(finishPos.z))
  453.         file.writeLine("output_x=" .. tostring(outputPos.x))
  454.         file.writeLine("output_y=" .. tostring(outputPos.y))
  455.         file.writeLine("output_z=" .. tostring(outputPos.z))
  456.         file.writeLine("refuel_x=" .. tostring(refuelPos.x))
  457.         file.writeLine("refuel_y=" .. tostring(refuelPos.y))
  458.         file.writeLine("refuel_z=" .. tostring(refuelPos.z))
  459.         file.close()
  460.     end
  461. end
  462.  
  463. local function waitForInitialSettings()
  464.     print("Waiting for settings...")
  465.     local _, path = getDiskByLabel(DISK_NAMES.settings)
  466.     while not path do sleep(1) path = select(2, getDiskByLabel(DISK_NAMES.settings)) end
  467.  
  468.  
  469.     local settingsPath = fs.combine(path, "initial_coords.txt")
  470.     while not fs.exists(settingsPath) do sleep(1) end
  471.     sleep(1)
  472.     local file = fs.open(settingsPath, "r")
  473.     local x1, y1, z1 = file.readLine():match("(-?%d+),(-?%d+),(-?%d+)")
  474.     local x2, y2, z2 = file.readLine():match("(-?%d+),(-?%d+),(-?%d+)")
  475.     local x3, y3, z3 = file.readLine():match("(-?%d+),(-?%d+),(-?%d+)")
  476.     local x4, y4, z4 = file.readLine():match("(-?%d+),(-?%d+),(-?%d+)")
  477.     local x5, y5, z5 = file.readLine():match("(-?%d+),(-?%d+),(-?%d+)")
  478.     file.close()
  479.  
  480.     SYSTEM_STATE.startCoords = {x=tonumber(x1), y=tonumber(y1), z=tonumber(z1)}
  481.     SYSTEM_STATE.endCoords = {x=tonumber(x2), y=tonumber(y2), z=tonumber(z2)}
  482.     SYSTEM_STATE.finishBlockCoords = {x=tonumber(x3), y=tonumber(y3), z=tonumber(z3)}
  483.     SYSTEM_STATE.outputChestCoords = {x=tonumber(x4), y=tonumber(y4), z=tonumber(z4)}
  484.     SYSTEM_STATE.refuelChestCoords = {x=tonumber(x5), y=tonumber(y5), z=tonumber(z5)}
  485.  
  486.     determineOrientation(SYSTEM_STATE.startCoords, SYSTEM_STATE.endCoords)
  487. end
  488.  
  489. local function initializeTotalChestCount()
  490.     -- Versuche, die Datei zu laden
  491.     local chestCountData = loadTotalChestCount()
  492.  
  493.     -- Prüfe, ob ein gültiger Wert vorhanden ist
  494.     if chestCountData and type(chestCountData.count) == "number" then
  495.         TASK_DATA.totalChestCount = chestCountData.count
  496.         return
  497.     end
  498.  
  499.     -- Wenn keine Datei vorhanden ist, aber relevante Daten existieren
  500.     local hasStoredItems = TASK_DATA.storedItems and #TASK_DATA.storedItems > 0
  501.     local hasEmptyChests = TASK_DATA.emptyChests and #TASK_DATA.emptyChests > 0
  502.  
  503.     if hasStoredItems or hasEmptyChests then
  504.         print("[WARNUNG] Kein gespeicherter Kistenzähler (totalChestCount) gefunden.")
  505.         print("Es wurden jedoch gespeicherte Kisteninformationen entdeckt.")
  506.         print("Bitte gib die gesamte Anzahl aller Kisten im System ein:")
  507.  
  508.         while true do
  509.             io.write("Kistenzahl: ")
  510.             local input = io.read()
  511.             local num = tonumber(input)
  512.             if num and num > 0 then
  513.                 TASK_DATA.totalChestCount = num
  514.                 saveTotalChestCount(num)
  515.                 print("[INFO] Gesamtanzahl an Kisten auf " .. num .. " gesetzt und gespeichert.")
  516.                 break
  517.             else
  518.                 print("Ungültige Eingabe. Bitte eine positive Zahl eingeben.")
  519.             end
  520.         end
  521.     end
  522. end
  523.  
  524. local function isSystemStateComplete()
  525.     for _, field in ipairs({
  526.         "orientation", "startCoords", "endCoords",
  527.         "finishBlockCoords", "outputChestCoords", "modulo", "yModulo"
  528.     }) do
  529.         if SYSTEM_STATE[field] == nil then
  530.             print("[WARNUNG] SYSTEM_STATE-Feld fehlt: " .. field)
  531.             return false
  532.         end
  533.     end
  534.     return true
  535. end
  536.  
  537.  
  538.  
  539.     -- == chest inventory ==
  540.  
  541. local function getChestFromEmptyForItem(item)
  542.     if #TASK_DATA.emptyChests == 0 then
  543.         error("Keine leeren Kisten mehr verfügbar!")
  544.     end
  545.     local newChest = table.remove(TASK_DATA.emptyChests, 1)
  546.  
  547.     saveTableToDisk(TASK_DATA.emptyChests, "emptyChests")
  548.  
  549.     newChest.amount = 0
  550.     newChest.incomingAmount = 0
  551.     newChest.outgoingAmount = 0
  552.     newChest.stackSize = item.stackSize
  553.     newChest.maxAmount = item.stackSize * 54
  554.    
  555.     return newChest
  556. end
  557.  
  558. local function addChestToEmpty(chestToAdd)
  559.     local chest = {id = chestToAdd.id, pos = chestToAdd.pos}
  560.  
  561.     local insertPos = nil
  562.     for i, emptyChest in ipairs(TASK_DATA.emptyChests) do
  563.         if emptyChest.id > chest.id then
  564.             insertPos = i
  565.             break
  566.         end
  567.     end
  568.  
  569.     if insertPos then
  570.         print("insert at " .. tostring(insertPos))
  571.         table.insert(TASK_DATA.emptyChests, insertPos, chest)
  572.     else
  573.         print("insert at end")
  574.         table.insert(TASK_DATA.emptyChests, chest)
  575.     end
  576.     saveTableToDisk(TASK_DATA.emptyChests, "emptyChests")
  577. end
  578.  
  579. local function getOpenAmount(chest)
  580.     local maxAmount = chest.maxAmount
  581.     local incomingAmount = chest.incomingAmount
  582.     local currentAmount = chest.amount
  583.  
  584.     return maxAmount - incomingAmount - currentAmount
  585. end
  586.  
  587. local function getOrderableAmount(chest)
  588.     local currentAmount = chest.amount
  589.     local outgoingAmount = chest.outgoingAmount
  590.  
  591.     return currentAmount - outgoingAmount
  592. end
  593.  
  594.     -- == last task steps ==
  595. local function initializeChestList(coords)
  596.     print("Initializing chest list...")
  597.     for row = 0, 4 do
  598.         for col = 0, 9 do
  599.             local offsetX = SYSTEM_STATE.orientation == "x" and col * SYSTEM_STATE.orientationDirection or 0
  600.             local offsetZ = SYSTEM_STATE.orientation == "z" and col * SYSTEM_STATE.orientationDirection or 0
  601.             local chestPos = {
  602.                 x = coords.x + offsetX,
  603.                 y = coords.y + row,
  604.                 z = coords.z + offsetZ
  605.             }
  606.             TASK_DATA.totalChestCount = TASK_DATA.totalChestCount + 1
  607.             table.insert(TASK_DATA.emptyChests, {id = TASK_DATA.totalChestCount, pos = chestPos})
  608.         end
  609.     end
  610.     SYSTEM_STATE.chestInitialized = true
  611.     SYSTEM_STATE.waitingForChestPlacement = false
  612.  
  613.     saveTableToDisk(TASK_DATA.emptyChests, "emptyChests")
  614.     saveTotalChestCount(TASK_DATA.totalChestCount)
  615.     saveSystemState()
  616. end
  617.  
  618. local function storageManagerTick()
  619.     checkStorageOverflow()
  620.     trimCompletedTasks()
  621.     monitorStorageSpace()
  622. end
  623.  
  624.  
  625.  
  626.  
  627. -- adds (+ or -) amount to chest and item. If Al amounts (including transits) are zero removes
  628. -- chest from item and if item amount is zero
  629. local function updateStoredItem(itemDisplayName, amount, chestId)
  630.     local itemIndex
  631.  
  632.     for index, item in ipairs(TASK_DATA.storedItems) do
  633.         if item.itemDisplayName == itemDisplayName then
  634.             local actualChest
  635.             local chestIndex
  636.             for i, chest in ipairs(item.storedChestsList) do
  637.                 print("chest.id = " .. tostring(chest.id))
  638.                 print("chestId = " .. tostring(chestId))
  639.                 if chest.id == chestId then
  640.                     print("Refresh Chest amount")
  641.  
  642.                     -- Aktualisiere gelagerten Amount
  643.                     chest.amount = chest.amount + amount
  644.  
  645.                     if amount > 0 then
  646.                         -- Items wurden geliefert
  647.                         chest.incomingAmount = chest.incomingAmount - amount
  648.                         item.itemIncomingAmount = item.itemIncomingAmount - amount
  649.                     elseif amount < 0 then
  650.                         -- Items wurden entnommen
  651.                         local delta = math.abs(amount)
  652.                         chest.outgoingAmount = chest.outgoingAmount - delta
  653.                         item.itemOutgoingAmount = item.itemOutgoingAmount - delta
  654.                     end
  655.  
  656.                     -- Item Count anpassen
  657.                     print("Refresh Item Count")
  658.                     item.itemCount = item.itemCount + amount
  659.  
  660.                     -- Leere Kiste wieder zurück in die leeren Kisten verschieben
  661.                     if chest.amount == 0 and chest.incomingAmount == 0 and chest.outgoingAmount == 0 then
  662.                         actualChest = chest
  663.                         chestIndex = i
  664.                     end
  665.                 end
  666.             end
  667.  
  668.             -- Kiste entfernen
  669.             if chestIndex then
  670.                 print("Add chest " .. tostring(actualChest.id) .. " to empty.")
  671.                 table.remove(item.storedChestsList, chestIndex)
  672.                 addChestToEmpty(actualChest)
  673.  
  674.                 -- Item komplett löschen, wenn leer
  675.                 if item.itemCount == 0 and item.itemIncomingAmount == 0 and item.itemOutgoingAmount == 0 then
  676.                     itemIndex = index
  677.                 end
  678.             end
  679.         end
  680.     end
  681.  
  682.     -- Item aus Liste löschen
  683.     if itemIndex then
  684.         table.remove(TASK_DATA.storedItems, itemIndex)
  685.     end
  686.    
  687.     saveTableToDisk(TASK_DATA.storedItems, "storedItems")
  688. end
  689.  
  690.  
  691.  
  692. local function checkForCompletedTasks()
  693.     local _, finishedPath = getDiskByLabel(DISK_NAMES.finished)
  694.     if not finishedPath then error("Finished disk not found") end
  695.     local finishedTasks = getTaskList(fs.combine(finishedPath, "task_list.txt"))
  696.  
  697.     for _, task in ipairs(finishedTasks) do
  698.         if task.taskId then
  699.             local handled = false
  700.  
  701.             if task.taskType == TASK_TYPES.createChests then
  702.                 print("Abgeschlossener Task: " .. tostring(task.taskType) .." --- Initialisiere Kistenliste")
  703.                 initializeChestList({x = task.x, y = task.y, z = task.z})
  704.                 handled = true
  705.  
  706.             elseif task.taskType == TASK_TYPES.storeItems then
  707.                 print("Abgeschlossener Task: " .. tostring(task.taskType) .. " --- Update stored Items")
  708.                 updateStoredItem(task.itemDisplayName, task.itemCount, task.chestId)
  709.                 handled = true
  710.  
  711.             elseif task.taskType == TASK_TYPES.getItems then
  712.                 print("Abgeschlossener Task: " .. tostring(task.taskType) .. " --- Update stored Items")
  713.                 updateStoredItem(task.itemDisplayName, -task.itemCount, task.chestId)
  714.                 handled = true
  715.            
  716.             elseif task.taskType == TASK_TYPES.checkInventory then
  717.                 print("Abgeschlossener Task: " .. tostring(task.taskType))
  718.  
  719.                 handled = true
  720.            
  721.             elseif task.taskType == TASK_TYPES.initializeChests then
  722.                 print("Abgeschlossener Task: " .. tostring(task.taskType) .." --- Initialisiere Kistenliste")
  723.                 initializeChestList({x = task.x, y = task.y, z = task.z})
  724.                 handled = true
  725.            
  726.             else
  727.                 print("Unbekannter Task-Typ: " .. tostring(task.taskType))
  728.             end
  729.  
  730.             if handled then
  731.                 -- Suche Task in den aktuellen Tasks
  732.                 local matchedIndex = nil
  733.                 for index, current in ipairs(TASK_DATA.currentTasks) do
  734.                     if current.taskId == task.taskId then
  735.                         matchedIndex = index
  736.                         break
  737.                     end
  738.                 end
  739.  
  740.                 if matchedIndex then
  741.                     local matchedTask = TASK_DATA.currentTasks[matchedIndex]
  742.                     table.insert(TASK_DATA.completedTasks, matchedTask)
  743.                     table.remove(TASK_DATA.currentTasks, matchedIndex)
  744.  
  745.                     local disk, storagePath = getDiskByLabel(DISK_NAMES.storage)
  746.                     if not storagePath then error("Data Storage disk not found") end
  747.  
  748.                     -- Aktuelle Tasks speichern
  749.                     local currentPath = fs.combine(storagePath, "currentTasks")
  750.                    
  751.                     saveTaskList(currentPath, TASK_DATA.currentTasks)
  752.                    
  753.  
  754.                     -- Abgeschlossene Tasks speichern
  755.                     local completedPath = fs.combine(storagePath, "completedTasks")
  756.  
  757.                     addTaskToList(completedPath, matchedTask)
  758.                 else
  759.                     print("Warnung: Task nicht in den aktuellen Tasks gefunden: " .. tostring(task.id))
  760.                 end
  761.             end
  762.         else
  763.             print("Warnung: Task ohne ID gefunden, wird übersprungen")
  764.             print(task.taskType)
  765.         end
  766.     end
  767.    
  768.     saveTaskList(fs.combine(finishedPath, "task_list.txt"), {})
  769. end
  770.  
  771.  
  772. local function processNextTaskFromDisk(diskLabelKey)
  773.     local disk, path = getDiskByLabel(DISK_NAMES[diskLabelKey])
  774.     if not path then return end
  775.  
  776.     local tasks = getTaskList(fs.combine(path, "task_list.txt"))
  777.     if #tasks == 0 then return end
  778.  
  779.     local task = table.remove(tasks, 1)
  780.  
  781.     -- Save remaining tasks back
  782.     local fullPath = fs.combine(path, "task_list.txt")
  783.     local file = fs.open(fullPath, "w")
  784.     print("process Next task from " .. diskLabelKey)
  785.     file.write(textutils.serialize(tasks))
  786.     file.close()
  787.     print("processed task from " .. diskLabelKey)
  788.     return task
  789.    
  790. end
  791.  
  792.  
  793.  
  794. local function handleIncomingTask()
  795.     local task = processNextTaskFromDisk("incoming")
  796.  
  797.     if not task then return end
  798.  
  799.     if task.taskType == TASK_TYPES.storeItems then
  800.         local displayName = task.itemDisplayName
  801.  
  802.         local bNewItem = true
  803.  
  804.         local taskItem = nil
  805.         local taskIndex = nil
  806.  
  807.         -- lookup item
  808.         for index, item in ipairs(TASK_DATA.storedItems) do
  809.             if displayName == item.itemDisplayName then
  810.                 bNewItem = false
  811.                 taskItem = item
  812.                 taskIndex = index
  813.             end
  814.         end
  815.  
  816.         -- create new item
  817.         if bNewItem then
  818.             taskItem = {
  819.                 itemName = task.itemName,
  820.                 itemDisplayName = displayName,
  821.                 stackSize = task.itemStackSize,
  822.                 itemCount = 0,
  823.                 itemIncomingAmount = 0,
  824.                 itemOutgoingAmount = 0,
  825.                 storedChestsList = {}
  826.             }
  827.         end
  828.  
  829.         local itemAmount = task.itemCount
  830.  
  831.         for i, chest in ipairs(taskItem.storedChestsList) do
  832.             local openAmount = getOpenAmount(chest)
  833.             if openAmount >= task.itemCount then
  834.                 chest.incomingAmount = chest.incomingAmount + task.itemCount
  835.                 taskItem.itemIncomingAmount = taskItem.itemIncomingAmount + task.itemCount
  836.  
  837.                 task.chestCoord = chest.pos
  838.                 task.chestId = chest.id
  839.                 saveTaskToDisk(task)
  840.  
  841.                 itemAmount = itemAmount - task.itemCount
  842.                 break
  843.             elseif openAmount < task.itemCount and openAmount > 0 then
  844.                 local task1 = deepCopy(task)
  845.  
  846.                 chest.incomingAmount = chest.incomingAmount + openAmount
  847.                 taskItem.itemIncomingAmount = taskItem.itemIncomingAmount + openAmount
  848.  
  849.                 task1.itemCount = openAmount
  850.                
  851.                 task.itemCount = task.itemCount - openAmount
  852.  
  853.                 task1.chestCoord = chest.pos
  854.                 task1.chestId = chest.id
  855.                 saveTaskToDisk(task1)
  856.  
  857.                 itemAmount = itemAmount - task1.itemCount
  858.             end
  859.         end
  860.  
  861.         if itemAmount > 0 then
  862.             local chest = getChestFromEmptyForItem(taskItem)
  863.             table.insert(taskItem.storedChestsList, chest)
  864.  
  865.             chest.incomingAmount = chest.incomingAmount + task.itemCount
  866.             taskItem.itemIncomingAmount = taskItem.itemIncomingAmount + task.itemCount
  867.            
  868.             task.chestCoord = chest.pos
  869.             task.chestId = chest.id
  870.             saveTaskToDisk(task)
  871.         end
  872.  
  873.         if taskIndex then
  874.             TASK_DATA.storedItems[taskIndex] = taskItem
  875.         else
  876.             table.insert(TASK_DATA.storedItems, taskItem)
  877.         end
  878.        
  879.         saveTableToDisk(TASK_DATA.storedItems, "storedItems")
  880.     end
  881.  
  882.     print("Processed incoming task ID: " .. tostring(taskIdCounter - 1))
  883. end
  884.  
  885. local function handleUserTask()
  886.     local task = processNextTaskFromDisk("user")
  887.  
  888.     if not task then return end
  889.  
  890.     if task.taskType == TASK_TYPES.getItems then
  891.         local displayName = task.itemDisplayName
  892.  
  893.         local taskItem = nil
  894.         local taskIndex = nil
  895.  
  896.         -- lookup item
  897.         for index, item in ipairs(TASK_DATA.storedItems) do
  898.             if displayName == item.itemDisplayName then
  899.                 taskItem = item
  900.                 taskIndex = index
  901.             end
  902.         end
  903.  
  904.         if not taskIndex then return end
  905.  
  906.         local itemAmount = task.itemCount
  907.  
  908.         for i, chest in ipairs(taskItem.storedChestsList) do
  909.             local orderableAmount = getOrderableAmount(chest)
  910.  
  911.             if orderableAmount >= task.itemCount then
  912.                 chest.outgoingAmount = chest.outgoingAmount + task.itemCount
  913.                 taskItem.itemOutgoingAmount = taskItem.itemOutgoingAmount + task.itemCount
  914.  
  915.                 while itemAmount > 0 do
  916.                     local taskAmount = math.min(taskItem.stackSize * 16, task.itemCount)
  917.  
  918.                     if taskAmount >= task.itemCount then
  919.                         task.chestCoord = chest.pos
  920.                         task.chestId = chest.id
  921.  
  922.                         saveTaskToDisk(task)
  923.  
  924.                         itemAmount = itemAmount - task.itemCount
  925.  
  926.                     elseif taskAmount < task.itemCount then
  927.                         local task1 = deepCopy(task)
  928.                         task1.chestCoord = chest.pos
  929.                         task1.chestId = chest.id
  930.                        
  931.                         task1.itemCount = taskAmount
  932.                         task.itemCount = task.itemCount - taskAmount
  933.  
  934.                         saveTaskToDisk(task1)
  935.  
  936.                         itemAmount = itemAmount - task1.itemCount
  937.                     end
  938.  
  939.                 end
  940.                 break
  941.             elseif orderableAmount < task.itemCount and orderableAmount > 0 then
  942.                
  943.  
  944.                 chest.outgoingAmount = chest.outgoingAmount + orderableAmount
  945.                 taskItem.itemOutgoingAmount = taskItem.itemOutgoingAmount + orderableAmount
  946.  
  947.                 local amountToOrder = orderableAmount
  948.  
  949.                 while amountToOrder > 0 do
  950.                     local taskAmount = math.min(taskItem.stackSize * 16, amountToOrder)
  951.                     local task1 = deepCopy(task)
  952.  
  953.                     task1.itemCount = taskAmount
  954.                     task.itemCount = task.itemCount - taskAmount
  955.  
  956.                     amountToOrder = amountToOrder - taskAmount
  957.  
  958.                     task1.chestCoord = chest.pos
  959.                     task1.chestId = chest.id
  960.  
  961.                     saveTaskToDisk(task1)
  962.  
  963.                     itemAmount = itemAmount - task1.itemCount
  964.                 end
  965.             end
  966.         end
  967.  
  968.         if itemAmount > 0 then
  969.             print("Error more items requested then available.")
  970.         end
  971.  
  972.         if taskIndex then
  973.             TASK_DATA.storedItems[taskIndex] = taskItem
  974.         end
  975.        
  976.         saveTableToDisk(TASK_DATA.storedItems, "storedItems")
  977.     end
  978.  
  979.     print("Processed user task ID: " .. tostring(taskIdCounter - 1))
  980. end
  981.  
  982. local function handleSettingsTask()
  983.     local task = processNextTaskFromDisk("settings")
  984.  
  985.     if not task then return end
  986.  
  987.     if task.taskType == TASK_TYPES.initializeChests then
  988.         local firstChestCoord = {x = task.x, y = task.y, z = task.z}
  989.         local bNewCoord = registerNewChestCoord(firstChestCoord)
  990.  
  991.         if bNewCoord then
  992.             task.taskId = taskIdCounter
  993.             taskIdCounter = taskIdCounter + 1
  994.             saveTaskIdCounter()
  995.  
  996.             local finishedDisk, finishedPath = getDiskByLabel(DISK_NAMES.finished)
  997.             if not finishedPath then error("Finished disk not found") end
  998.             local fullFinishedPath = fs.combine(finishedPath, "task_list.txt")
  999.  
  1000.             addTaskToList(fullFinishedPath, task)
  1001.  
  1002.             local storageDisk, storagePath = getDiskByLabel(DISK_NAMES.storage)
  1003.             if not storagePath then error("Data Storage disk not found") end
  1004.             local fullStoragePath = fs.combine(storagePath, "currentTasks")
  1005.  
  1006.             addTaskToList(fullStoragePath, task)
  1007.             table.insert(TASK_DATA.currentTasks, task)
  1008.         end
  1009.  
  1010.  
  1011.     elseif task.taskType == TASK_TYPES.createChests then
  1012.         local firstChestCoord = {x = task.x, y = task.y, z = task.z}
  1013.         local bNewCoord = registerNewChestCoord(firstChestCoord)
  1014.  
  1015.         if bNewCoord then
  1016.             -- Save to outgoing
  1017.             saveTaskToDisk(task)
  1018.         end
  1019.  
  1020.        
  1021.  
  1022.     elseif task.taskType == TASK_TYPES.checkInventory then
  1023.         print("Checking Inventory")
  1024.     end
  1025.    
  1026.     print("Processed settings task ID: " .. tostring(taskIdCounter - 1))
  1027.    
  1028. end
  1029.  
  1030.  
  1031. local handlerMap = {
  1032.     incoming = handleIncomingTask,
  1033.     user = handleUserTask,
  1034.     settings = handleSettingsTask
  1035. }
  1036.  
  1037. -- === START ===
  1038. local loadedSystemState = loadSystemState()
  1039. for k, v in pairs(loadedSystemState) do
  1040.     SYSTEM_STATE[k] = v
  1041. end
  1042.  
  1043. if not isSystemStateComplete() then
  1044.     print("[INFO] SYSTEM_STATE unvollständig. Initiale Einstellungen werden geladen...")
  1045.     waitForInitialSettings()
  1046. end
  1047.  
  1048. saveSystemState()
  1049.  
  1050. TASK_DATA.currentTasks = loadTableFromDisk("currentTasks")
  1051. TASK_DATA.emptyChests = loadTableFromDisk("emptyChests")
  1052. TASK_DATA.storedItems = loadTableFromDisk("storedItems")
  1053. TASK_DATA.completedTasks = loadTableFromDisk("completedTasks")
  1054. initializeTotalChestCount()
  1055. taskIdCounter = loadTaskIdCounter()
  1056.  
  1057.  
  1058.  
  1059. if #TASK_DATA.emptyChests == 0 and not SYSTEM_STATE.chestInitialized then
  1060.     waitForInitialSettings()
  1061.     local _, settingsPath = getDiskByLabel(DISK_NAMES.settings)
  1062.     if not settingsPath then error("Settings disk not found") end
  1063.     local taskList = getTaskList(fs.combine(settingsPath, "task_list.txt"))
  1064.     local hasCreateTask = false
  1065.     local createTaskIndex = nil
  1066.     local createTask = nil
  1067.  
  1068.     for index, task in ipairs(taskList) do
  1069.         if task.taskType == TASK_TYPES.createChests then
  1070.             local firstChestCoord = {x = task.x, y = task.y, z = task.z}
  1071.             local bNewCoord = registerNewChestCoord(firstChestCoord)
  1072.  
  1073.             if bNewCoord then
  1074.                 hasCreateTask = true
  1075.                 createTaskIndex = index
  1076.                 createTask = task
  1077.             end
  1078.             break
  1079.         end
  1080.     end
  1081.  
  1082.     if hasCreateTask then
  1083.         -- Task abspeichern auf Daten-Disk (als wäre er gerade ausgeführt worden)
  1084.         local disk, path = getDiskByLabel(DISK_NAMES.storage)
  1085.         if not path then error("Data Storage disk not found") end
  1086.         local currentPath = fs.combine(path, "currentTasks")
  1087.        
  1088.         addTaskToList(currentPath, createTask)
  1089.         saveTaskToDisk(createTask)
  1090.  
  1091.         -- Task aus taskList entfernen und aktualisieren
  1092.         table.remove(taskList, createTaskIndex)
  1093.        
  1094.         saveTaskList(fs.combine(settingsPath, "task_list.txt"), taskList)
  1095.        
  1096.     else
  1097.         local bNewCoord = registerNewChestCoord(SYSTEM_STATE.startCoords)
  1098.         if bNewCoord then
  1099.             initializeChestList(SYSTEM_STATE.startCoords)
  1100.         else
  1101.             print("Warning: System trying to initialize but Coords are already present")
  1102.         end
  1103.     end
  1104. end
  1105.  
  1106.  
  1107. -- === MAIN LOOP ===
  1108. while true do
  1109.     storageManagerTick()
  1110.  
  1111.     checkForCompletedTasks()
  1112.  
  1113.     if not hasOutgoingTasks() then
  1114.         if SYSTEM_STATE.waitingForChestPlacement then
  1115.             handlerMap.settings()
  1116.         elseif #TASK_DATA.emptyChests == 0 then
  1117.             SYSTEM_STATE.waitingForChestPlacement = true
  1118.             saveSystemState()
  1119.         else
  1120.             local sourceKey = TASK_SOURCES[currentTaskSourceIndex]
  1121.             handlerMap[sourceKey]()
  1122.  
  1123.             currentTaskSourceIndex = currentTaskSourceIndex + 1
  1124.             if currentTaskSourceIndex > #TASK_SOURCES then
  1125.                 currentTaskSourceIndex = 1
  1126.             end
  1127.         end
  1128.     end
  1129.  
  1130.     sleep(1)
  1131. end
  1132.  
Advertisement
Add Comment
Please, Sign In to add comment