-- BlockReader NBT Dumper for Advanced Display Block -- Reads block NBT via Advanced Peripherals block_reader and writes to txt local COLORS = { INFO = colors.white, WARN = colors.yellow, ERROR = colors.red, SUCCESS = colors.green } local OUTPUT_FILE = "blockreader_display_nbt.txt" local function log(level, message) local timestamp = os.date("%H:%M:%S") local logMessage = string.format("[%s][%s] %s", timestamp, level, message) local color = COLORS[level] or colors.white local oldColor = term.getTextColor() term.setTextColor(color) print(logMessage) term.setTextColor(oldColor) end local function serializeValue(value, indent) indent = indent or 0 local pad = string.rep(" ", indent) local t = type(value) if t == "nil" then return "nil" elseif t == "boolean" then return value and "true" or "false" elseif t == "number" then return tostring(value) elseif t == "string" then local escaped = value:gsub("\\", "\\\\"):gsub("\n", "\\n"):gsub("\r", "\\r"):gsub("\t", "\\t") return string.format("%q", escaped) elseif t == "table" then local lines = {} local isArray = true local maxIndex = 0 for k, v in pairs(value) do if type(k) ~= "number" or k < 1 or math.floor(k) ~= k then isArray = false break end if k > maxIndex then maxIndex = k end end if isArray then for i = 1, maxIndex do if value[i] ~= nil then table.insert(lines, pad .. " [" .. tostring(i) .. "] = " .. serializeValue(value[i], indent + 1)) end end else local keys = {} for k, _ in pairs(value) do table.insert(keys, k) end table.sort(keys, function(a, b) local ta, tb = type(a), type(b) if ta == tb then if ta == "number" then return a < b end return tostring(a) < tostring(b) end return ta < tb end) for _, k in ipairs(keys) do local keyStr if type(k) == "string" and k:match("^[%a_][%w_]*$") then keyStr = k else keyStr = "[" .. serializeValue(k, 0) .. "]" end local v = value[k] if type(v) == "table" and next(v) ~= nil then table.insert(lines, pad .. " " .. keyStr .. " = {") table.insert(lines, serializeValue(v, indent + 1)) table.insert(lines, pad .. " }") else table.insert(lines, pad .. " " .. keyStr .. " = " .. serializeValue(v, indent + 1)) end end end if #lines == 0 then return "{}" end if isArray then return table.concat(lines, "\n") end table.insert(lines, 1, pad .. "{") table.insert(lines, pad .. "}") return table.concat(lines, "\n") else return "<" .. t .. ">" end end local PERIPHERAL_TYPE_CANDIDATES = { "blockReader", "block_reader", "blockreader", "BlockReader", "advancedperipherals:block_reader", "advancedperipherals:blockReader" } local function enumeratePeripherals() local list = {} local names = peripheral.getNames() or {} for _, name in ipairs(names) do local entry = { name = name, getType = nil, methodsSorted = nil, getNameCall = nil } local ok, tp = pcall(function() return peripheral.getType(name) end) if ok then entry.getType = tp end if type(entry.getType) == "string" and entry.getType:lower():find("block") and entry.getType:lower():find("reader") then entry.matchHint = "type-name contains block+reader" end local ok2, methods = pcall(function() return peripheral.getMethods(name) end) if ok2 and type(methods) == "table" then local m = {} for _, v in ipairs(methods) do table.insert(m, tostring(v)) end table.sort(m) entry.methodsSorted = m local hasKey = false for _, v in ipairs(m) do if v == "getBlockName" or v == "getBlockState" or v == "getBlockData" or v == "isBlockPresent" then hasKey = true break end end if hasKey then entry.methodsHint = "contains block-reader methods" end end local ok3, p = pcall(function() return peripheral.wrap(name) end) if ok3 and type(p) == "table" and type(p.getName) == "function" then local ok4, res = pcall(function() return p.getName() end) if ok4 then entry.getNameCall = res end end table.insert(list, entry) end return list end local function findBlockReader() for _, candidateType in ipairs(PERIPHERAL_TYPE_CANDIDATES) do local ok, found = pcall(function() return { peripheral.find(candidateType) } end) if ok and type(found) == "table" and #found > 0 then for _, dev in ipairs(found) do local ok2, nm = pcall(function() return peripheral.getName(dev) end) if not ok2 then nm = candidateType end if type(dev) == "table" and (dev.getBlockData or dev.getBlockName or dev.getBlockState or dev.isBlockPresent) then return dev, nm end end return found[1], candidateType end end for _, side in ipairs(rs.getSides()) do if peripheral.isPresent(side) then local ok, tp = pcall(function() return peripheral.getType(side) end) local wrapped = nil local ok2, w = pcall(function() return peripheral.wrap(side) end) if ok2 then wrapped = w end local match = false if ok and type(tp) == "string" then local tpl = tp:lower() for _, cand in ipairs(PERIPHERAL_TYPE_CANDIDATES) do if tpl == cand:lower() then match = true; break end end if not match and tpl:find("block") and tpl:find("reader") then match = true end end if not match and type(wrapped) == "table" and (wrapped.getBlockData or wrapped.getBlockName or wrapped.getBlockState or wrapped.isBlockPresent) then match = true end if match then return wrapped, side end end end local names = peripheral.getNames() or {} for _, name in ipairs(names) do local ok, tp = pcall(function() return peripheral.getType(name) end) local ok2, wrapped = pcall(function() return peripheral.wrap(name) end) if not ok2 then wrapped = nil end local match = false if ok and type(tp) == "string" then local tpl = tp:lower() for _, cand in ipairs(PERIPHERAL_TYPE_CANDIDATES) do if tpl == cand:lower() then match = true; break end end if not match and tpl:find("block") and tpl:find("reader") then match = true end end if not match and type(wrapped) == "table" and (wrapped.getBlockData or wrapped.getBlockName or wrapped.getBlockState or wrapped.isBlockPresent) then match = true end if match then return wrapped, name end end return nil, nil end local function writeToFile(content) local handle = fs.open(OUTPUT_FILE, "w") if not handle then return false, "Cannot open output file" end handle.write(content) handle.close() return true, nil end local function main() term.clear() term.setCursorPos(1, 1) print("=== BlockReader Advanced Display NBT Dumper ===") print("Output file: " .. OUTPUT_FILE) print() local output = {} table.insert(output, "Advanced Display Block NBT Dump") table.insert(output, "Generated: " .. os.date("%Y-%m-%d %H:%M:%S")) table.insert(output, string.rep("=", 60)) table.insert(output, "") log("INFO", "Looking for block_reader peripheral...") local reader, readerName = findBlockReader() if not reader then log("WARN", "block_reader not found by exact type, dumping peripheral diagnostics...") local periList = enumeratePeripherals() table.insert(output, "[Peripheral Diagnostics]") table.insert(output, " Connected peripherals count: " .. tostring(#periList)) table.insert(output, "") if #periList == 0 then table.insert(output, " (no peripherals found via peripheral.getNames())") table.insert(output, " Ensure modems/cables connect the block_reader to this computer.") else for i, entry in ipairs(periList) do table.insert(output, string.format(" [%d] name = %s", i, tostring(entry.name))) table.insert(output, string.format(" getType = %s", tostring(entry.getType))) if entry.matchHint then table.insert(output, string.format(" [HINT] %s", tostring(entry.matchHint))) end if entry.getNameCall ~= nil then table.insert(output, string.format(" getName() = %s", tostring(entry.getNameCall))) end if entry.methodsSorted then table.insert(output, string.format(" getMethods() = [ %s ]", table.concat(entry.methodsSorted, ", "))) end if entry.methodsHint then table.insert(output, string.format(" [HINT] %s", tostring(entry.methodsHint))) end table.insert(output, "") end end table.insert(output, "[Troubleshooting Tips]") table.insert(output, " 1. Verify the block_reader is adjacent/connected via modem.") table.insert(output, " 2. In CC, run: lua -e \"p=peripheral.getNames(); for _,n in ipairs(p) do print(n, peripheral.getType(n)) end\"") local fullContent = table.concat(output, "\n") local ok, err = writeToFile(fullContent) if not ok then log("ERROR", "Failed to write file: " .. tostring(err)) return 3 end log("SUCCESS", "Peripheral diagnostics written to " .. OUTPUT_FILE) local size = fs.getSize(OUTPUT_FILE) log("INFO", "File size: " .. tostring(size) .. " bytes") print() print("Press any key to exit...") os.pullEvent("key") return 1 end log("SUCCESS", "block_reader found: " .. tostring(readerName)) table.insert(output, "BlockReader: " .. tostring(readerName)) table.insert(output, "") if type(reader.isBlockPresent) ~= "function" then log("WARN", "isBlockPresent() not available on this block_reader, trying direct read...") else local ok, present = pcall(function() return reader.isBlockPresent() end) if ok and not present then log("ERROR", "No block in front of block_reader. Place the Advanced Display block adjacent to the block_reader.") table.insert(output, "[Block Present Check]") table.insert(output, " isBlockPresent() = false") local fullContent = table.concat(output, "\n") local ok2, err = writeToFile(fullContent) if not ok2 then log("ERROR", "Failed to write file: " .. tostring(err)) return 3 end log("SUCCESS", "Result written to " .. OUTPUT_FILE) return 2 end end if type(reader.getBlockName) == "function" then local ok, name = pcall(function() return reader.getBlockName() end) if ok and name then table.insert(output, "[Block Registry Name]") table.insert(output, " " .. tostring(name)) table.insert(output, "") end end if type(reader.getBlockState) == "function" then local ok, state = pcall(function() return reader.getBlockState() end) if ok and state then table.insert(output, "[Block State]") if type(state) == "table" and next(state) == nil then table.insert(output, " (empty)") else table.insert(output, serializeValue(state, 0)) end table.insert(output, "") end end if type(reader.getBlockData) == "function" then local ok, data = pcall(function() return reader.getBlockData() end) if ok and data then table.insert(output, "[Block NBT Data]") if type(data) == "table" and next(data) == nil then table.insert(output, " (empty)") else table.insert(output, serializeValue(data, 0)) end table.insert(output, "") else log("WARN", "getBlockData() failed or returned nothing: " .. tostring(data)) end else log("WARN", "getBlockData() not found on this block_reader") end local fullContent = table.concat(output, "\n") local ok, err = writeToFile(fullContent) if not ok then log("ERROR", "Failed to write file: " .. tostring(err)) return 3 end log("SUCCESS", "NBT data written to " .. OUTPUT_FILE) local size = fs.getSize(OUTPUT_FILE) log("INFO", "File size: " .. tostring(size) .. " bytes") print() print("Press any key to exit...") os.pullEvent("key") return 0 end local exitCode = 0 local ok, err = pcall(main) if not ok then log("ERROR", "Program crashed: " .. tostring(err)) exitCode = 99 end if exitCode ~= 0 then print() print("Press any key to exit...") os.pullEvent("key") end error("", exitCode)