Files
CC-StationBroadcast/test_blockreader_display.lua
T
Henry_Du 0de59531f9 test(br): diagnose block_reader instead of bailing
When no block_reader is found by exact type name, list all connected
peripherals (getType/getMethods/getName) into the output txt so the real
peripheral name can be identified on the target machine.
2026-08-16 14:07:13 +08:00

371 lines
14 KiB
Lua

-- 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)