diff --git a/create_factory_scheduler.lua b/create_factory_scheduler.lua index d8a097a..cbfd4cb 100644 --- a/create_factory_scheduler.lua +++ b/create_factory_scheduler.lua @@ -1,7 +1,7 @@ -- ATM10 Create factory scheduler V1 -- Persistent jobs, dependency planning, progress-aware retries and diagnostics. -local VERSION = "1.0.1" +local VERSION = "1.0.2" local REFRESH_SECONDS = 1 local CONFIRM_SECONDS = 6 local DRAIN_SECONDS = 60 @@ -61,7 +61,7 @@ if not monitorName then error("Kein Monitor gefunden", 0) end local monitor = peripheral.wrap(monitorName) monitor.setTextScale(0.5) -local stock, stockEntries = {}, {} +local stock, stockEntries, vaults = {}, {}, {} local stockPage, stockPageCount = 1, 1 local stockPageButtons, buttons, modeButtons, errorPageButtons = {}, {}, {}, {} local events = {} @@ -169,6 +169,37 @@ local function refreshStock() return true end +local function refreshVaults() + local nextVaults = {} + for _, name in ipairs(peripheral.getNames()) do + if peripheral.getType(name) == "create:item_vault" then + local okSize, slotCount = pcall(peripheral.call, name, "size") + local okList, contents = pcall(peripheral.call, name, "list") + if okSize and okList then + slotCount = tonumber(slotCount) or 0 + local okLimit, slotLimit = pcall(peripheral.call, name, "getItemLimit", 1) + slotLimit = okLimit and tonumber(slotLimit) or 64 + if not slotLimit or slotLimit <= 0 then slotLimit = 64 end + local used = 0 + for _, item in pairs(contents or {}) do + if type(item) == "table" then used = used + (tonumber(item.count) or 0) end + end + local capacity = slotCount * slotLimit + nextVaults[#nextVaults + 1] = { + name = name, + slots = slotCount, + used = used, + capacity = capacity, + free = math.max(0, capacity - used), + percent = capacity > 0 and (used * 100 / capacity) or 0, + } + end + end + end + table.sort(nextVaults, function(a, b) return a.name < b.name end) + vaults = nextVaults +end + local function terminal(job) return job.status == "DONE" or job.status == "FAILED" or job.status == "CANCELLED" end @@ -340,6 +371,18 @@ local function updateZinc(job) return end if job.status == "WAITING" then job.activeStation = nil dispatchZincWashing(job, remaining) return end + + -- Do not wait for the complete 60-second crushing drain when the material + -- which has already reached storage can satisfy the remaining parent job. + -- Late crushing returns remain valid surplus and are still counted. + if job.phase == "CRUSHING" and (stock["alltheores:zinc_clump"] or 0) * 9 >= remaining then + job.activeStation, job.status, job.phase = nil, "WAITING", "PLAN" + logEvent("#" .. job.id .. " genug Clumps angekommen - sofort weiter zum Washing", colors.lime) + saveState() + dispatchZincWashing(job, remaining) + return + end + local idle = epoch() - job.lastProgressAt if idle >= WARNING_SECONDS and not job.warned then job.warned = true logEvent("#" .. job.id .. " " .. tostring(job.phase) .. " wartet auf Output", colors.orange) @@ -500,6 +543,30 @@ local function drawLogs(width, height, top) end end +local function drawVaults(width, height) + local firstRow = height - 2 + writeAt(2, firstRow, "VAULTS", colors.cyan) + if #vaults == 0 then + writeAt(10, firstRow, "keine Vault-Peripherie", colors.gray) + return + end + + local x, y = 10, firstRow + for index, vault in ipairs(vaults) do + local percent = math.floor(vault.percent * 10 + 0.5) / 10 + local text = "V" .. index .. " " .. percent .. "% (frei " .. formatNumber(vault.free) .. ")" + if x + #text > width then + x, y = 10, y + 1 + end + if y >= height then break end + local color = colors.lime + if vault.percent >= 95 then color = colors.red + elseif vault.percent >= 80 then color = colors.orange end + writeAt(x, y, text, color) + x = x + #text + 2 + end +end + local function render() local width, height = monitor.getSize() monitor.setBackgroundColor(colors.black) monitor.setTextColor(colors.white) monitor.clear() buttons = {} @@ -513,6 +580,7 @@ local function render() (index % 2 == 1 and left or right) + buttonWidth - 1, top + math.floor((index - 1) / 2) * 2) end drawLogs(width, height, top + math.ceil(#ACTION_ORDER / 2) * 2) + drawVaults(width, height) writeAt(2, height, "Bestellen/Abbrechen/OFF: doppelt beruehren | Nachlauf: " .. DRAIN_SECONDS .. "s", colors.gray) end @@ -581,7 +649,7 @@ local function handleTouch(x, y) end end -loadState() refreshStock() +loadState() refreshStock() refreshVaults() logEvent("Scheduler V" .. VERSION .. " gestartet auf Computer " .. os.getComputerID(), colors.cyan) render() local refreshTimer = os.startTimer(REFRESH_SECONDS) @@ -593,6 +661,7 @@ while true do armed, armedUntil = nil, 0 statusText, statusColor = "Bestaetigung abgelaufen", colors.gray end if refreshStock() then updateJobs() end + refreshVaults() render() refreshTimer = os.startTimer(REFRESH_SECONDS) - elseif event == "peripheral" or event == "peripheral_detach" then refreshStock() render() end + elseif event == "peripheral" or event == "peripheral_detach" then refreshStock() refreshVaults() render() end end