Files
mapsyncer-paper/README.md
T
janhouse 7fb3a82482 mapsyncer-paper: server side of MapSyncer for Xaero's World Map, discovery-limited
Paper 26.2 plugin speaking the stock MapSyncer client mod's protocol.
Renders Xaero region zips from the world's region files, but only for chunks
players have actually been sent (PlayerChunkLoadEvent), seeded once from
InhabitedTime. Shared or per-player visibility, background render cycle,
per-player streaming with hash/timestamp skipping, Gitea Actions release
workflow.

Vendors the MCA parser and Xaero writer from upstream MapSyncer (GPL-3.0),
see NOTICE.md.

Claude-Session: https://claude.ai/code/session_011FePLXwBsCGLTzaSkk1Z6V
2026-09-07 00:04:43 +03:00

98 lines
4.0 KiB
Markdown

# mapsyncer-paper
The server half of [MapSyncer for Xaero's World Map](https://github.com/RuoChennn/MapSyncer-for-XaeroWorldmap),
as a Paper plugin — with one twist: the map players receive is built from
**what players have actually discovered**, not from every chunk the server has
ever generated.
Players run the stock MapSyncer client mod (Fabric or NeoForge, same Minecraft
version as the server) next to Xaero's World Map. The plugin speaks the mod's
wire protocol byte for byte, so nothing on the client needs patching.
## What it does
1. **Tracks discovery.** Every chunk the server sends to a player is recorded
for that player (`PlayerChunkLoadEvent`). That is exactly the set Xaero's
client maps on its own, so the server's picture of a region is always a
superset of the player's — which matters, because the client mod overwrites
region files wholesale.
2. **Seeds history once.** On first start the plugin scans each world's region
files and marks chunks with `InhabitedTime > 0` as discovered. Pre-generated
terrain (Chunky, distant-terrain LOD generation) has `InhabitedTime = 0` and
stays hidden until somebody walks there.
3. **Renders on demand.** A region is converted from its `.mca` file into a
Xaero region zip only for the discovered chunks; everything else becomes a
"no data" tile. Re-rendering happens when the region file changes or the
discovery mask grows.
4. **Streams to the mod.** On join the client gets a hello, polls
periodically, and receives whatever changed since it last asked, hash- and
timestamp-checked per region layer.
Two visibility modes (`config.yml`):
| `visibility` | Player receives |
| --- | --- |
| `shared` (default) | the union of everyone's discoveries |
| `own` | only what they discovered themselves, plus the seeded history |
## Requirements
- Paper 26.2 on Java 25 (the build compiles against Paper's Mojang-mapped
internals via paperweight; other versions need a rebuild).
- Clients: Xaero's World Map 1.40.11+ and the MapSyncer client mod for the
same Minecraft version.
- Xaero's **Multiplayer world map** setting should be *Single*. The client mod
writes into the newest `mw$…` folder; Xaero's "world spawn" mode uses folders
without the `$` and would never see the synced files.
## Install
Drop the jar from the latest release into `plugins/`, start the server, read
the generated `plugins/MapSyncer/config.yml`. The first start scans every
tracked world once (a few minutes for a multi-gigabyte world, in the
background); nothing is served until the first render cycle after that.
Dimension folders on the client follow Xaero's own naming: vanilla keys map to
`null`, `DIM-1`, `DIM1`; anything else, including Multiverse worlds, to
`namespace$path` (e.g. `minecraft$survival`).
## Commands
```
/mapsync status counters: discovery, cache, syncs, clients with the mod
/mapsync worlds per-world mapping, layers, region directory
/mapsync render [force] run a render cycle now; force drops the cache first
/mapsync seed <world|all> re-run the InhabitedTime scan
/mapsync player <name> what one player has discovered
/mapsync reload re-read config.yml
```
Permission `mapsyncer.admin` (default: op).
## Data
Everything lives under `plugins/MapSyncer/`:
```
discovery/<world>.bin discovery bitmaps (per region: union, seeded, per player)
cache/<scope>/<dim>/[caves/<L>/]<x>_<z>.zip rendered regions; scope = shared or a player UUID
cache/<scope>/index.tsv timestamps, CRC32s, content stamps
```
Deleting `cache/` is always safe (it is rebuilt). Deleting `discovery/` loses
who-discovered-what; the next start re-seeds from `InhabitedTime`.
## Building
```
./gradlew build # runs the unit tests; jar in build/libs/mapsyncer-paper-<version>.jar
```
CI (`.gitea/workflows/build.yml`) builds on every push and attaches the jar to
a release for every `v*` tag.
## Licence
GPL-3.0. The Xaero region writer and MCA parser are vendored from MapSyncer
(GPL-3.0); see `NOTICE.md` for the exact provenance and the local changes.