saltar al contenido principal
paste
bin
.ca
type · paste · share
⌘
K
Familia
La familia bin
pastebin.ca
centro
Share text and code with expiry and privacy controls.
imagebin.ca
Upload and share images with direct links.
filebin.ca
Drop a file and get a shareable link.
notebin.ca
Write Markdown notes with durable links.
turl.ca
Short, reputation-checked links.
attn.ca
Notifications and alerts for your services.
voicebin.ca
Record and share short voice clips.
dnsbin.ca
Inspect DNS and debug records.
Docs
Iniciar sesión
?
← volver a la publicación
›
Editar / bifurcar
Publicación sin título
#4c45AdjCXW
public / public
nueva versión
anónimo
creado 1 day ago
Caduca en 6 days
12.1 KB
sintaxis:
text
Tus cambios crean una nueva publicación enlazada a esta — la original no se toca.
nueva versión
Tus cambios crean una nueva publicación enlazada a esta — la original no se toca.
Título (opcional)
Nombre de archivo
Sintaxis
text
text
bash
c
cpp
css
diff
dockerfile
go
html
ini
java
javascript
json
kotlin
lua
makefile
markdown
nginx
php
python
ruby
rust
shellscript
sql
swift
toml
typescript
xml
yaml
Visibilidad
Feed público
Acceso
public
Caduca
7 días
10 min
1 hora
1 día
7 días
30 días
90 días
personalizada…
Caducidad personalizada
Nota de cambio
(opcional)
Esta publicación aparecerá en el feed público. Cambia Visibilidad si solo quieres compartirla por enlace.
Crear nueva versión
Cancelar
Pegar o escribir…
-- ============================================================================ -- Online Player Viewer -- Requires: monitor + playerDetector peripherals -- Dependencies: CC:Tweaked + Advanced Peripherals -- ============================================================================ -- ============================================================================ -- Configuration -- ============================================================================ local REFRESH_INTERVAL = 1 -- Refresh interval in seconds local TEXT_SCALE = 0.5 -- Text scale (0.5 = smallest / most room) -- ============================================================================ -- Color Theme -- ============================================================================ local CLR = { bg = colors.black, title = colors.yellow, header = colors.cyan, text = colors.white, white = colors.white, dim = colors.lightGray, online = colors.lime, offline = colors.red, warn = colors.orange, highlight = colors.green, accent = colors.pink, border = colors.gray, } -- Dimension short names local DIM_NAMES = { ["minecraft:overworld"] = "Overworld", ["minecraft:the_nether"] = "Nether", ["minecraft:the_end"] = "End", } -- ============================================================================ -- Utility Functions -- ============================================================================ --- Format dimension name local function formatDimension(dim) return DIM_NAMES[dim] or dim or "???" end --- Format coordinates local function formatPos(x, y, z) if not x then return "---, ---, ---" end return string.format("%d, %d, %d", math.floor(x), math.floor(y), math.floor(z)) end --- Format health local function formatHealth(health, maxHealth) if not health then return "?/?" end return string.format("%.0f/%.0f", health, maxHealth) end --- Draw centered text local function drawCentered(mon, y, text, color) local w = mon.getSize() mon.setTextColor(color or CLR.text) local x = math.floor((w - #text) / 2) + 1 if x < 1 then x = 1 end mon.setCursorPos(x, y) mon.write(text) end --- Draw horizontal separator local function drawSeparator(mon, y, char, color) local w = mon.getSize() char = char or "-" mon.setTextColor(color or CLR.border) mon.setCursorPos(1, y) mon.write(string.rep(char, w)) end --- Truncate text to fit width local function truncate(text, maxLen) if #text <= maxLen then return text end return text:sub(1, maxLen - 1) .. "." end -- ============================================================================ -- Peripheral Setup -- ============================================================================ local function findPeripherals() local monitor = nil local detector = nil local names = peripheral.getNames() for _, name in ipairs(names) do local ptype = peripheral.getType(name) if ptype == "monitor" and not monitor then monitor = peripheral.wrap(name) elseif ptype == "player_detector" and not detector then detector = peripheral.wrap(name) end end return monitor, detector end -- ============================================================================ -- Data Fetching -- ============================================================================ local function getPlayerData(detector) local players = {} local ok, onlineList = pcall(detector.getOnlinePlayers, detector) if not ok then return nil, "Failed to get player list: " .. tostring(onlineList) end if not onlineList or #onlineList == 0 then return {}, nil end for _, name in ipairs(onlineList) do local info = detector.getPlayer(name) if info then table.insert(players, { name = name, x = info.x, y = info.y, z = info.z, dimension = info.dimension, health = info.health, maxHealth = info.maxHealth, }) else -- Still show player even if detail fetch fails table.insert(players, { name = name, x = nil, y = nil, z = nil, dimension = nil, health = nil, maxHealth = nil, }) end end -- Sort alphabetically table.sort(players, function(a, b) return a.name:lower() < b.name:lower() end) return players, nil end -- ============================================================================ -- Rendering -- ============================================================================ -- Fixed row layout (the static frame is drawn once; only dynamic rows update) local ROW_STATS = 4 -- player count / refresh rate / timestamp local ROW_HEADER = 6 -- column headers local ROW_FIRST = 8 -- first player row --- Blank a vertical region with the background color. Used instead of --- clearing the whole monitor so a refresh never flashes the entire screen. local function clearRows(mon, y1, y2) local w = mon.getSize() for y = y1, y2 do mon.setBackgroundColor(CLR.bg) mon.setCursorPos(1, y) mon.write(string.rep(" ", w)) end end --- Draw the static frame (title bar, separators, column header) once. --- It stays on screen; only the dynamic rows are rewritten afterwards. local function drawStaticFrame(mon) local w = mon.getSize() mon.setBackgroundColor(CLR.bg) mon.clear() -- Title bar mon.setTextColor(CLR.title) drawSeparator(mon, 1, "=", CLR.title) drawCentered(mon, 2, "** Online Player Viewer **", CLR.title) drawSeparator(mon, 3, "=", CLR.title) -- Column header local nameW = math.min(18, math.floor(w * 0.22)) local dimW = math.min(10, math.floor(w * 0.12)) local posW = math.min(24, math.floor(w * 0.35)) local hpW = math.min(10, math.floor(w * 0.12)) mon.setTextColor(CLR.header) mon.setCursorPos(2, ROW_HEADER) local headerFmt = "%-" .. nameW .. "s %-" .. dimW .. "s %-" .. posW .. "s %" .. hpW .. "s" mon.write(string.format(headerFmt, "Name", "Dimension", "Position (X, Y, Z)", "Health")) drawSeparator(mon, ROW_HEADER + 1, "-", CLR.border) end --- Redraw only the stats row (no full clear, so no flicker) local function renderStats(mon, playerCount, timestamp) local w = mon.getSize() mon.setBackgroundColor(CLR.bg) mon.setCursorPos(1, ROW_STATS) mon.write(string.rep(" ", w)) mon.setTextColor(CLR.text) mon.setCursorPos(2, ROW_STATS) mon.write("Online: ") mon.setTextColor(CLR.online) mon.write(tostring(playerCount)) mon.setTextColor(CLR.dim) mon.setCursorPos(math.floor(w / 2) + 1, ROW_STATS) mon.write("Refresh: " .. REFRESH_INTERVAL .. "s") -- Timestamp on the right local timeStr = "Updated: " .. timestamp mon.setCursorPos(w - #timeStr, ROW_STATS) mon.write(timeStr) end local function renderPlayerTable(mon, players) local w, h = mon.getSize() local lastRow = h - 2 if #players == 0 then clearRows(mon, ROW_FIRST, lastRow) drawCentered(mon, ROW_FIRST, "(No players online)", CLR.dim) return end -- Column widths local nameW = math.min(18, math.floor(w * 0.22)) local dimW = math.min(10, math.floor(w * 0.12)) local posW = math.min(24, math.floor(w * 0.35)) local hpW = math.min(10, math.floor(w * 0.12)) local row = ROW_FIRST for i, p in ipairs(players) do if row > lastRow then mon.setTextColor(CLR.dim) mon.setCursorPos(2, lastRow) mon.write("... +" .. (#players - i + 1) .. " more players") break end -- Alternating row colors if i % 2 == 0 then mon.setTextColor(CLR.text) else mon.setTextColor(CLR.white) end mon.setCursorPos(2, row) -- Name local name = truncate(p.name, nameW) mon.write(string.format("%-" .. nameW .. "s", name)) mon.setCursorPos(2 + nameW + 2, row) -- Dimension local dim = truncate(formatDimension(p.dimension), dimW) if p.dimension == "minecraft:the_nether" then mon.setTextColor(CLR.warn) elseif p.dimension == "minecraft:the_end" then mon.setTextColor(CLR.accent) end mon.write(string.format("%-" .. dimW .. "s", dim)) -- Position if i % 2 == 0 then mon.setTextColor(CLR.text) else mon.setTextColor(CLR.white) end mon.setCursorPos(2 + nameW + 2 + dimW + 2, row) local pos = formatPos(p.x, p.y, p.z) mon.write(string.format("%-" .. posW .. "s", pos)) -- Health mon.setCursorPos(2 + nameW + 2 + dimW + 2 + posW + 2, row) local hp = formatHealth(p.health, p.maxHealth) if p.health and p.maxHealth then local ratio = p.health / p.maxHealth if ratio < 0.25 then mon.setTextColor(CLR.offline) elseif ratio < 0.5 then mon.setTextColor(CLR.warn) else mon.setTextColor(CLR.highlight) end end mon.write(string.format("%" .. hpW .. "s", hp)) row = row + 1 end -- Blank the rows left over when the new list is shorter clearRows(mon, row, lastRow) end local function renderFooter(mon, errorMsg) local w, h = mon.getSize() mon.setBackgroundColor(CLR.bg) mon.setCursorPos(1, h - 1) mon.write(string.rep(" ", w)) mon.setCursorPos(1, h) mon.write(string.rep(" ", w)) if errorMsg then drawSeparator(mon, h - 1, "-", CLR.warn) mon.setTextColor(CLR.warn) mon.setCursorPos(2, h) mon.write("! " .. truncate(errorMsg, w - 4)) else drawSeparator(mon, h - 1, "-", CLR.border) mon.setTextColor(CLR.dim) mon.setCursorPos(2, h) mon.write("CC:Tweaked + Advanced Peripherals") end end -- ============================================================================ -- Main Loop -- ============================================================================ local function main() local monitor, detector = findPeripherals() if not monitor then print("Error: Monitor peripheral not found!") print("Available: " .. table.concat(peripheral.getNames(), ", ")) return end if not detector then print("Error: Player detector peripheral not found!") print("Available: " .. table.concat(peripheral.getNames(), ", ")) -- Show error on monitor too monitor.setTextScale(TEXT_SCALE) monitor.setBackgroundColor(CLR.bg) monitor.clear() monitor.setTextColor(CLR.warn) drawCentered(monitor, math.floor(monitor.getSize() / 2), "! Player detector not found !", CLR.warn) return end -- Init monitor monitor.setTextScale(TEXT_SCALE) print("Online Player Viewer started!") print("Monitor size: " .. monitor.getSize()) print("Press Ctrl+T to stop") -- Draw the static frame once; only dynamic rows are redrawn each tick drawStaticFrame(monitor) -- Main loop while true do local timestamp = os.date("%H:%M:%S") local players, err = getPlayerData(detector) renderStats(monitor, players and #players or 0, timestamp) if players then renderPlayerTable(monitor, players) else local _, h = monitor.getSize() clearRows(monitor, ROW_FIRST, h - 2) end renderFooter(monitor, err) sleep(REFRESH_INTERVAL) end end -- ============================================================================ -- Entry Point -- ============================================================================ local ok, err = pcall(main) if not ok then local monitor = peripheral.find("monitor") if monitor then monitor.setTextScale(TEXT_SCALE) monitor.setBackgroundColor(colors.black) monitor.clear() monitor.setTextColor(colors.red) monitor.setCursorPos(1, 1) monitor.write("Crash:\n" .. tostring(err)) end print("Error: " .. tostring(err)) end