- TypeScript 68.5%
- mcfunction 29.8%
- Shell 1.7%
|
|
||
|---|---|---|
| .forgejo/workflows | ||
| assets/markers | ||
| datapack | ||
| packaging/Archlinux | ||
| src | ||
| test | ||
| biome.json | ||
| bun.lock | ||
| LICENSE | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
bluemap-telemetry
Standalone Minecraft player telemetry daemon. It connects to a Minecraft server over RCON, polls online player positions on a fixed interval, and writes players.json into each configured map directory under a web root.
The daemon is not a BlueMap plugin or package dependency. It produces plain JSON files on disk that any web map (or other consumer) can read. BlueMap is one such consumer: when configured to load live/players.json from each map directory, BlueMap can display live player markers.
How it works
- Connect to the Minecraft server via RCON.
- Run
list uuidsand, for each online player, fetchPos,Rotation, andDimensionviadata get entity "<name>" …. - For each map in
MAPS, filter players by dimension and write the matching subset to{WEB_ROOT}/{map}/live/players.json. - Default map names (
overworld,nether,end) map to Minecraft dimensions automatically — noMAP_DIMENSIONSenv var required. UseMAP_DIMENSIONSonly for custom map names or to override those defaults. - On RCON failure, write an empty
playersarray so consumers clear stale player markers. - When the optional marker datapack is enabled, fetch
storage bluemap-telemetry:data markersand write per-maplive/markers.json. - Repeat every
INTERVALmilliseconds.
On startup the daemon ensures {WEB_ROOT}/{map}/live/ exists and seeds markers.json only when the file is missing.
Optional marker datapack
The repository includes an optional vanilla datapack under [datapack/](datapack/) for in-game map markers. Ops store POIs in command storage; the daemon reads that storage over RCON each poll and writes live/markers.json per map.
Enable it by copying the datapack into the world's datapacks folder. Since Minecraft 1.20+, symlinks inside a world are rejected unless explicitly whitelisted in allowed_symlinks.txt at the server root — copying avoids that.
# From a git checkout
cp -a datapack /path/to/world/datapacks/bluemap-telemetry
# Arch Linux package
cp -a /usr/share/bluemap-telemetry/datapack /path/to/world/datapacks/bluemap-telemetry
Re-run the copy after upgrading bluemap-telemetry to pick up datapack changes.
Optional: symlink with allowed_symlinks.txt
If you prefer a symlink (updates automatically on package upgrade), allow it in the server root (same directory as server.jar, not inside the world):
echo '[prefix]/usr/share/bluemap-telemetry' >> /srv/minecraft/allowed_symlinks.txt
ln -s /usr/share/bluemap-telemetry/datapack /srv/minecraft/world/datapacks/bluemap-telemetry
Without that file, the server fails at startup with ContentValidationException: Found forbidden symlinks.
Then run /reload in-game (op) or restart the server.
Open the marker menu (op, as a player):
/function bluemap-telemetry:marker
Or bind Quick Actions in Controls (menu is in #minecraft:quick_actions). Dialogs: Add / List / Update / Rename / Delete / Pin. CRUD also lives under bluemap-telemetry:marker/* with required macro args — see datapack/README.md.
Typed markers need icons served by the web server. Symlink them once into the BlueMap web root (next to index.html, not into BlueMap’s assets/):
ln -s /usr/share/bluemap-telemetry/assets/markers /srv/http/bluemap-telemetry
# from a git checkout: ln -s /path/to/repo/assets/markers /srv/http/bluemap-telemetry
Set MARKER_ICON_BASE=bluemap-telemetry in the daemon config (the default). The daemon does not copy icons at runtime; package upgrades update the share directory and the symlink keeps working. Empty type keeps BlueMap’s built-in assets/poi.svg.
Verify storage:
/data get storage bluemap-telemetry:data
After the next daemon poll, check {WEB_ROOT}/{map}/live/markers.json for the matching dimension. BlueMap refreshes live markers about every 10 seconds.
See [datapack/README.md](datapack/README.md) for layout and requirements (Minecraft Java 26.2+).
Requirements
- Bun 1.0+
- A Minecraft server with RCON enabled
- A writable map web root with one subdirectory per map (for example
/srv/http/maps/overworld)
Build from source
git clone https://git.macaw.me/blue/bluemap-telemetry
cd bluemap-telemetry
bun install
bun run start
For development with auto-reload:
bun run dev
Output format
Each map directory receives the same schema at {WEB_ROOT}/{map}/live/players.json:
{
"players": [
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Steve",
"foreign": false,
"position": { "x": 12.5, "y": 64.0, "z": -8.25 },
"rotation": { "pitch": 0, "yaw": 0, "roll": 0 }
}
]
}
| Field | Type | Description |
|---|---|---|
players |
array | Online players included for this map |
players[].uuid |
string | Player UUID from list uuids |
players[].name |
string | Player display name |
players[].foreign |
boolean | Always false for players on this server |
players[].position |
object | World coordinates (x, y, z) |
players[].rotation |
object | View angles (pitch, yaw, roll) from RCON; falls back to zero if parsing fails |
Each map's players.json contains only players whose current dimension matches that map. Default map names (overworld, nether, end) are filtered automatically; see MAP_DIMENSIONS below for custom names or overrides.
Environment variables
| Variable | Default | Description |
|---|---|---|
RCON_HOST |
127.0.0.1 |
Minecraft server RCON host |
RCON_PORT |
25575 |
RCON TCP port |
RCON_PASS |
(required) | RCON password |
WEB_ROOT |
/srv/http/maps |
Web root containing per-map subdirectories |
MAPS |
overworld,nether,end |
Comma-separated map directory names under WEB_ROOT |
INTERVAL |
5000 |
Poll interval in milliseconds (minimum 1000) |
MARKER_ICON_BASE |
bluemap-telemetry |
Web-relative path to marker icons (see below) |
MAP_DIMENSIONS |
(optional) | Override or extend per-map dimension filters; see below |
CONFIG_PATH |
(optional) | Path to a .env-style or JSON config file |
Example:
export RCON_HOST=127.0.0.1
export RCON_PORT=25575
export RCON_PASS=your-rcon-password
export WEB_ROOT=/srv/http/maps
export MAPS=overworld,nether,end
export INTERVAL=5000
export MARKER_ICON_BASE=bluemap-telemetry
bun run start
Marker icons
Typed markers reference {MARKER_ICON_BASE}/{type}.svg (for example bluemap-telemetry/home.svg).
Important:
- That URL is relative to the BlueMap web root (the directory that contains
index.html), notWEB_ROOT(map data folders). - Do not put them under BlueMap’s own
assets/directory — use a separate path so upgrades never collide. - The daemon never copies icon files; it only writes the URL into
markers.json.
Ship icons live in assets/markers/ (package: /usr/share/bluemap-telemetry/assets/markers/). Symlink them once:
# If BlueMap’s web UI is served from /srv/http (adjust to your web root)
ln -s /usr/share/bluemap-telemetry/assets/markers /srv/http/bluemap-telemetry
Then keep MARKER_ICON_BASE=bluemap-telemetry in config (default). If you use a different link name, set MARKER_ICON_BASE to match. Package upgrades refresh /usr/share/.../assets/markers; the symlink keeps working.
MAP_DIMENSIONS
Optional mapping from map name to Minecraft dimension identifier. Each map's players.json lists only players currently in that dimension.
The default map names in MAPS already map to dimensions without this variable:
| Map name | Default dimension |
|---|---|
overworld |
minecraft:overworld |
nether |
minecraft:the_nether |
end |
minecraft:the_end |
Set MAP_DIMENSIONS when you use custom map directory names, or when you need to override a default mapping (for example a non-standard nether map name).
Format: comma-separated map:dimension pairs.
Example (custom map name):
MAPS=overworld,nether_map,end
MAP_DIMENSIONS=nether_map:minecraft:the_nether
Map names must match entries in MAPS. Every map listed in MAPS must resolve to a dimension — either via a default name or an entry in MAP_DIMENSIONS.
Enabling RCON on Arch Linux Minecraft server
RCON is configured in server.properties. This file lives in the server data directory (where eula.txt and world saves are stored), not in the package install path. The exact path depends on how you installed and run the server, but the properties themselves are the same for vanilla, Paper, and Spigot.
Edit server.properties
After the server has been started at least once, open server.properties and set:
enable-rcon=true
rcon.port=25575
rcon.password=choose-a-strong-password
broadcast-rcon-to-ops=false
| Property | Value | Notes |
|---|---|---|
enable-rcon |
true |
Required; RCON does not start when false |
rcon.port |
25575 |
Default TCP port; change only if you need a non-default port |
rcon.password |
non-empty string | Required; blank password prevents RCON from starting |
broadcast-rcon-to-ops |
false |
Recommended; keeps RCON command output out of in-game op chat |
Common Arch installations
| Installation | Where to find server.properties |
|---|---|
| minecraft-server (AUR) | Server data directory configured for the package (commonly under /srv/minecraft or a path set in the unit/env file) |
Paper / Spigot (AUR, e.g. paper, spigot) |
The directory from which the server JAR is launched — the same folder that contains eula.txt after first run |
| Manual / custom install | Your chosen server working directory |
If unsure of the path, search from the service unit or launch script: systemctl cat <minecraft-service> often shows WorkingDirectory= or the data path.
Firewall and remote RCON
When the telemetry daemon runs on the same host as the Minecraft server, bind RCON to localhost and point RCON_HOST at 127.0.0.1. No firewall changes are needed.
When the daemon runs on a different host, allow inbound TCP to rcon.port only from the telemetry machine's IP (for example with ufw or iptables). RCON is not encrypted; avoid exposing it to the public internet.
Restart after changes
server.properties is read at server startup. After editing RCON settings, restart the Minecraft server.
For a systemd-managed service:
sudo systemctl restart <minecraft-service>
Replace <minecraft-service> with your unit name (for example minecraft-server, minecraft@survival, or a custom instance).
Scripts
| Script | Description |
|---|---|
bun run start |
Run the telemetry daemon |
bun run dev |
Run with file watch / reload (development) |
bun run typecheck |
Type-check with TypeScript |
bun run test |
Run parser and config unit tests |
bun run lint |
Lint and format check (Biome) |
Deployment
Arch Linux (AUR)
Install bluemap-telemetry from the AUR. The package depends on bun and installs the application to /usr/lib/bluemap-telemetry/.
# Edit RCON credentials, WEB_ROOT, and (if using typed markers) MARKER_ICON_BASE
sudo nano /etc/bluemap-telemetry/config.env
# Grant the minecraft user write access to your map web root
sudo usermod -aG http minecraft # example: add to the http group
# Optional: typed marker icons — once, next to BlueMap’s index.html (not assets/)
sudo ln -s /usr/share/bluemap-telemetry/assets/markers /srv/http/bluemap-telemetry
sudo systemctl enable --now bluemap-telemetry.service
journalctl -u bluemap-telemetry.service -f
Packaging files live in packaging/Archlinux/. The package installs the optional datapack to /usr/share/bluemap-telemetry/datapack/ and marker icons to /usr/share/bluemap-telemetry/assets/markers/. Publishing a Forgejo release triggers the AUR workflow (requires DEPLOY_TO_AUR_* repository secrets). Release tags may use a v prefix (for example v1.0.0); the AUR pkgver is published without it.
systemd
The unit runs as the minecraft system user (provided by your Minecraft server package, e.g. minecraftd), loads /etc/bluemap-telemetry/config.env, and runs bun run src/main.ts from /usr/lib/bluemap-telemetry. Logs go to stdout/stderr for the journal. All application output uses [info], [warn], and [error] prefixes.
License
MIT — see LICENSE.