diff --git a/README.md b/README.md index 5364d34..b4fc0b9 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,26 @@ stehen alle verbundenen Peripherien, Methoden, Frogport-Adressen sowie abrufbare Paket-, Inventar- und Stock-Ticker-Daten. Das Programm versendet keine Pakete und veraendert keine Redstone-Ausgaenge. +## Greenhouse-Inventar erfassen + +`greenhouse_inventory_debug.lua` erkennt einen per Wired Modem verbundenen +Drawer-/Storage-Controller und schreibt dessen Inhalt rein lesend nach +`greenhouse_inventory_debug.txt`. Essenzen, Seeds und die vollstaendige +Itemliste werden mit Registry-ID, Menge und Slot ausgegeben. + +```lua +delete greenhouse_inventory_debug.lua +wget https://git.peli-server.de/Dystroyer8/ATM10_CC_Codes/raw/branch/main/greenhouse_inventory_debug.lua greenhouse_inventory_debug.lua +greenhouse_inventory_debug +``` + +Falls mehrere Controller verbunden sind, kann der im Dump angezeigte +Peripheral-Name gezielt uebergeben werden: + +```lua +greenhouse_inventory_debug +``` + ### Erster Logistik-Funktionstest Nach erfolgreicher Erkennung kann der Monitor-Testcontroller installiert werden: diff --git a/greenhouse_inventory_debug.lua b/greenhouse_inventory_debug.lua new file mode 100644 index 0000000..455db90 --- /dev/null +++ b/greenhouse_inventory_debug.lua @@ -0,0 +1,184 @@ +-- ATM10 Greenhouse inventory diagnostic +-- Read-only: detects a connected drawer/storage controller and writes its contents. + +local OUTPUT_FILE = "greenhouse_inventory_debug.txt" +local requestedName = ({ ... })[1] + +local function containsMethod(methods, wanted) + for _, method in ipairs(methods or {}) do + if method == wanted then return true end + end + return false +end + +local function allTypes(name) + local types = { peripheral.getType(name) } + local result = {} + for _, value in ipairs(types) do + if type(value) == "string" then result[#result + 1] = value end + end + return result +end + +local function joinedTypes(name) + return table.concat(allTypes(name), ", ") +end + +local function isInventory(name) + if peripheral.hasType and peripheral.hasType(name, "inventory") then return true end + local methods = peripheral.getMethods(name) or {} + return containsMethod(methods, "list") and containsMethod(methods, "size") +end + +local function safeCall(name, method, ...) + local result = table.pack(pcall(peripheral.call, name, method, ...)) + if not result[1] then return false, tostring(result[2]) end + return true, table.unpack(result, 2, result.n) +end + +local function itemCount(contents) + local total, occupied = 0, 0 + for _, item in pairs(contents or {}) do + if type(item) == "table" and item.name then + total = total + (tonumber(item.count) or 0) + occupied = occupied + 1 + end + end + return total, occupied +end + +local function scoreCandidate(candidate) + local text = (candidate.name .. " " .. candidate.types):lower() + local score = candidate.occupied + if text:find("functionalstorage", 1, true) then score = score + 10000 end + if text:find("storage_controller", 1, true) then score = score + 5000 end + if text:find("controller", 1, true) then score = score + 2000 end + if text:find("drawer", 1, true) then score = score + 1000 end + return score +end + +local candidates = {} +for _, name in ipairs(peripheral.getNames()) do + if isInventory(name) then + local okList, contents = safeCall(name, "list") + if okList and type(contents) == "table" then + local total, occupied = itemCount(contents) + local okSize, size = safeCall(name, "size") + candidates[#candidates + 1] = { + name = name, + types = joinedTypes(name), + contents = contents, + total = total, + occupied = occupied, + size = okSize and tonumber(size) or 0, + } + end + end +end + +table.sort(candidates, function(left, right) + local leftScore, rightScore = scoreCandidate(left), scoreCandidate(right) + if leftScore == rightScore then return left.name < right.name end + return leftScore > rightScore +end) + +local selected +if requestedName then + for _, candidate in ipairs(candidates) do + if candidate.name == requestedName then selected = candidate break end + end + if not selected then error("Inventar-Peripheral nicht gefunden: " .. requestedName, 0) end +else + selected = candidates[1] +end + +if not selected then + error("Kein verbundenes Inventar gefunden. Wired Modem am Drawer Controller pruefen.", 0) +end + +local aggregate = {} +for slot, item in pairs(selected.contents) do + if type(item) == "table" and item.name then + local entry = aggregate[item.name] + if not entry then + entry = { name = item.name, displayName = item.displayName, count = 0, slots = {} } + aggregate[item.name] = entry + end + entry.count = entry.count + (tonumber(item.count) or 0) + entry.slots[#entry.slots + 1] = tonumber(slot) or slot + end +end + +local items = {} +for _, item in pairs(aggregate) do items[#items + 1] = item end +table.sort(items, function(left, right) return left.name < right.name end) + +local function isEssence(item) + return item.name:find("_essence", 1, true) ~= nil +end + +local function isSeed(item) + return item.name:find("_seeds", 1, true) ~= nil or item.name:find("_seed", 1, true) ~= nil +end + +local file = fs.open(OUTPUT_FILE, "w") +if not file then error("Kann " .. OUTPUT_FILE .. " nicht schreiben", 0) end + +local function line(text) + file.writeLine(tostring(text or "")) +end + +line("ATM10 GREENHOUSE INVENTORY DEBUG") +line("Computer ID: " .. os.getComputerID()) +line("Selected peripheral: " .. selected.name) +line("Types: " .. selected.types) +line("Slots reported: " .. tostring(selected.size)) +line("Occupied entries: " .. selected.occupied) +line("Total items: " .. selected.total) +line("") +line("INVENTORY CANDIDATES") +for index, candidate in ipairs(candidates) do + line(string.format("%d. %s | %s | slots=%d occupied=%d items=%d%s", + index, candidate.name, candidate.types, candidate.size, candidate.occupied, + candidate.total, candidate == selected and " | SELECTED" or "")) +end + +line("") +line("ESSENCES") +local essenceCount = 0 +for _, item in ipairs(items) do + if isEssence(item) then + essenceCount = essenceCount + 1 + line(string.format("%s | count=%d | slots=%s", + item.name, item.count, table.concat(item.slots, ","))) + end +end +line("Essence types: " .. essenceCount) + +line("") +line("SEEDS") +local seedCount = 0 +for _, item in ipairs(items) do + if isSeed(item) then + seedCount = seedCount + 1 + line(string.format("%s | count=%d | slots=%s", + item.name, item.count, table.concat(item.slots, ","))) + end +end +line("Seed types: " .. seedCount) + +line("") +line("ALL ITEMS") +for _, item in ipairs(items) do + line(string.format("%s | count=%d | slots=%s", + item.name, item.count, table.concat(item.slots, ","))) +end +line("Unique item types: " .. #items) +file.close() + +print("Greenhouse-Dump erstellt:") +print(OUTPUT_FILE) +print("Controller: " .. selected.name) +print("Items: " .. #items .. " | Essenzen: " .. essenceCount .. " | Seeds: " .. seedCount) +print("Falls der falsche Controller gewaehlt wurde:") +print("greenhouse_inventory_debug ")