• 欢迎加入MineBBS QQ讨论群:点击查看所有的官方讨论群
  • 我们将于近期对服务器进行迁移,服务可能中断至多2日。请各位安排好自己的访问计划,造成不便敬请谅解!
  • MineBBS入站考试已经上线!想要成为【正式会员】解锁更多功能吗?快来参与吧!【点我去看】
资源图标

原生 Atlas-plus -- 真正的实时卫星地图 v1.0.1

完成注册/登录后下载
[MD] # Atlas-plus A **live**, top-down world map for a Minecraft **Bedrock Dedicated Server**, built as a [LeviLamina](https://github.com/LiteLDev/LeviLamina) Rust mod. [/MD]
[MD] Atlas-plus renders your world two ways and fuses them: - **Disk bootstrap** — on enable, it reads the world's LevelDB once (strictly read-only) and renders the whole explored world as the base map. - **Live layer** — it then reads blocks straight out of the running server's memory and keeps the map current where things change, with live player markers, **without waiting for a save**. The map is served by a tiny built-in web server. Nothing is fetched over plain HTTP: the browser opens a single WebSocket and the server streams the map manifest, player positions, and tile images down it as they change — so there's no polling and nothing for the browser to cache stale. Tiles are still written to disk in the same format as the disk-based [Atlas], so anything that reads Atlas tiles reads these too. > **TPS-friendly by design.** The live layer never scans more than a fixed budget of chunks per > cycle, and by default only touches the handful of chunks nearest each player plus whatever a > world-change event flags. A still scene produces no work at all. --- ## Features - 🗺️ **Full base map from disk** + **live updates** where players are. - ⚡ **Bounded cost** — one hard "chunks per cycle" budget across every update mode. - 🎛️ **Configurable update strategy**: nearest-to-player, world-change events, both, full radius sweep, or off. - 🖼️ **Minecraft-styled canvas viewer** — a self-contained world-map page, pushed pixels only, no blank frames. - 🧭 Pan / zoom / grid / dimension switch / spawn marker / live player markers. - 🔌 **Everything live over one WebSocket** — the map manifest, player positions, *and* tile images are all pushed down `/ws` as they change (tiles as binary PNG frames). There is no HTTP polling and the browser never fetches a tile over HTTP, so there's nothing for it to cache stale. The socket auto-reconnects and a reconnecting client is replayed the full current state. - 🛠️ **Operator command** — `/atlas url | status`. - 📦 Zero external services — hand-rolled HTTP + WebSocket server, vanilla-JS viewer, no build step for the front end. --- ## Requirements - A LeviLamina Bedrock server. - The LeviLamina **Rust loader** mod (`levilamina-rust-loader`), which loads Rust `.dll` mods. - To build from source: a Rust toolchain (stable) and network access for crates. --- ## Install **Option A — prebuilt.** Drop `atlas_plus.dll` and `manifest.json` into a folder under your server's `mods/` (or wherever your loader picks up Rust mods), alongside the Rust loader. Start the server. **Option B — build from source.** ```bash git https://github.com/Maskviva/Atlas-plus cd Atlas-plus cargo build --release # → target/release/atlas_plus.dll (Windows / the platform your BDS runs on) ``` Ship `target/release/atlas_plus.dll` together with `manifest.json`. `manifest.json` declares a dependency on `levilamina-rust-loader`, so the loader must be present. On first run Atlas-plus writes a fully-populated `plugins/Atlas-plus/config.json`. Edit that and restart the plugin (or the server) to apply changes. --- ## Quick start 1. Start the server with the mod installed. 2. Watch the console for `Atlas-plus live map: http://<host>:8899/`. 3. Open that URL. The page connects over WebSocket immediately; the base map streams in from disk in the background, and areas around players update live as you watch. 4. Check status in-game with `/atlas status`, or tune behaviour by editing `config.json` and restarting. --- ## The `/atlas` command `atlas` is the Atlas-plus operator command (any player can run it; it only reports state). | Command | Effect | | --- | --- | | `/atlas url` | Print the live map URL. | | `/atlas status` | Players online, dimensions, update mode, render version, and the map URL. | Config changes are picked up on the next plugin enable (reload the plugin or restart the server) — there's no runtime config-editing command. --- ## Configuration `plugins/Atlas-plus/config.json` — written with defaults on first run. Unknown keys are ignored. ### Web server | Field | Default | Notes | | --- | --- | --- | | `http_bind` | `"0.0.0.0"` | Interface the web server (and WebSocket) binds to. | | `http_port` | `8899` | Map is at `http://<host>:<port>/`; the live socket is at `ws://<host>:<port>/ws`. | | `http_workers` | `3` | Tiny HTTP worker threads; 2–4 is plenty. Each open WebSocket runs on its own thread outside this pool. | | `out_dir` | `"plugins/Atlas-plus/map"` | Where tiles / `map.json` / the viewer are written to disk (kept for Atlas-tile compatibility and as a fallback you can serve yourself; the bundled viewer doesn't read from here — it uses the WebSocket). | | `world_name` | `"Atlas-plus (live)"` | Shown in the viewer. | ### What to render | Field | Default | Notes | | --- | --- | --- | | `dimensions` | `[0]` | `0` overworld, `1` nether, `2` end. | | `render_radius_chunks` | `6` | Live square around each player — **`update_mode: "full"` only**. | | `pinned_areas` | `[]` | Always-refreshed areas, e.g. spawn: `[{ "dim":0, "x":0, "z":0, "radius_chunks":6 }]`. Keep them loaded with a `tickingarea`. | ### Disk bootstrap (once, on enable, in the background) | Field | Default | Notes | | --- | --- | --- | | `bootstrap` | `true` | Read the on-disk world and render the explored map. **Read-only** — never writes to the database. | | `world_dir` | `null` | World folder (contains `db/`, `level.dat`). `null` = auto-detect from `server.properties`. | | `bootstrap_radius_chunks` | `null` | Limit the bootstrap to this chunk radius around spawn + pinned areas. `null` = the whole world. Set on huge worlds to bound memory while decoding. | | `bootstrap_throttle_ms` | `10` | Pause between region batches so the bootstrap trickles in gently. | ### Live update strategy | `update_mode` | Behaviour | | --- | --- | | `"nearby+events"` *(default)* | The **4 chunks nearest each player** are kept fresh, plus any chunk touched by a world-change event. | | `"nearby"` | Only the 4 chunks nearest each player. | | `"events"` | Only event-touched chunks (near-zero idle cost). | | `"full"` | Continuously round-robin the whole `render_radius_chunks` square around every player (heaviest). | | `"off"` | No live scanning (bootstrap + player markers only). | **Events covered:** player block **place / destroy / interact**, and **fire spread** — the world-change events the loader exposes. TNT and other explosions, mob griefing, and redstone do **not** raise loader events; in practice those happen near players, where the `nearby` half of the default mode picks up the result. In every mode, leftover budget slowly round-robins the pinned areas. ### Scan pacing (server-thread cost) | Field | Default | Notes | | --- | --- | --- | | `chunks_per_cycle` | `6` | **Hard ceiling** on chunk scans per cycle, every mode. The main TPS knob. | | `cycle_interval_ms` | `250` | Delay between cycles. Raise if you see tick lag. | ### Scan depth / correctness | Field | Default | Notes | | --- | --- | --- | | `slab_height` | `16` | Vertical slice per `scan_region` call. | | `scan_top` / `scan_bottom` | `null` | Override the scanned Y range (all dims). Setting `scan_top` to your real build ceiling is the biggest single speed win — but anything above it won't appear. | | `use_height_cache` | `true` | Remember each chunk's surface height so repeat scans start near the top. Leave on. | | `rebuild_headroom` | `16` | Blocks to start above the cached top so small new builds show without a full rescan. | | `full_rescan_every` | `16` | Force a full-range rescan every Nth scan of a chunk (catches very tall new builds). | ### Renderer | Field | Default | Notes | | --- | --- | --- | | `flush_interval_ms` | `1000` | Minimum delay between tile flushes (debounce) — also how often changed tiles are pushed over the socket. Player markers update faster, independently. | | `max_regions` | `48` | Cap on retained 512×512 region buffers (LRU-evicted). ~2 MB each; bounds memory. Evicted tiles are flushed to disk and the socket before eviction. | --- ## How it works On enable, a background thread reads the on-disk LevelDB with a small pure-Rust, read-only reader (SST tables + WAL replay, Mojang's raw-deflate), computes each explored chunk's surface, and streams them to the renderer — region-grouped and throttled — as the base map. Every LeviLamina callback runs on the server thread, so the live scan loop uses `schedule_after` to pace itself there and calls `scan_region` directly (the only safe way to read live blocks). Each cycle it decides what to rescan from `update_mode`, scans at most `chunks_per_cycle` chunks, and hands surfaces to a **background renderer** thread. A chunk the live scanner has already drawn is never overwritten by (older) bootstrap data. A chunk that isn't loaded reads as air through the API; Atlas-plus detects an all-air full scan and leaves the existing pixels untouched rather than erasing them. The renderer owns the pixel buffers, and on a debounce it hillshades the regions that changed, writes their PNG tiles to disk (for Atlas-tile compatibility), and — this is the part that keeps the browser both flicker-free and cache-proof — **pushes exactly those changed tiles down the WebSocket as binary frames** (a small header with dimension/zoom/tile coordinates, followed by the raw PNG bytes). The updated map manifest and, whenever players move, their positions go down the same socket as JSON text frames. There is no HTTP request the browser could serve from a stale cache: the only way tile pixels reach the page is a fresh push over an open socket. A freshly connected (or reconnected) browser is immediately replayed the current manifest, player list, and every tile the server currently holds, so it catches up in one burst rather than waiting for the next change. **Tiles:** zoom 0 is one 512×512 image per 32×32-chunk region (tile coord == region coord, 1 px = 1 block); higher zooms are 2×2 downsamples. The on-disk copies under `out_dir` use the same `tiles/<dimension>/<zoom>/<rx>_<rz>.png` layout as disk Atlas, for compatibility with other tools — the bundled viewer itself never reads them back over HTTP. --- ## The viewer The viewer is a self-contained, Minecraft-styled world-map page served at your `out_dir` root (`index.html` + `map-viewer.js`). Open `http://<host>:<port>/` in any browser — no build step, no external assets. On load it opens `ws://<host>:<port>/ws` and receives the manifest, player positions, and every tile image over that one connection; it decodes tile frames with `createImageBitmap` and draws straight to a `<canvas>`. If the socket drops, it reconnects automatically (with a short backoff) and is replayed the full current state. It can also be embedded in another page via an `<iframe>` pointing at the served `index.html`. --- ## Performance tuning - **Server feels laggy?** Lower `chunks_per_cycle` and/or raise `cycle_interval_ms` (the ceiling applies in every mode). Set `scan_top` to your real build ceiling; keep `use_height_cache` on. The default `update_mode` is already light — `"events"` is near-free when idle, `"off"` stops live scans entirely. - **Changes appear too slowly?** Raise `chunks_per_cycle` and/or lower `cycle_interval_ms`. In `"full"` mode, also lower `render_radius_chunks`. You can also lower `flush_interval_ms` so changed tiles are pushed to the browser sooner. - **Big world, bootstrap eats RAM?** Set `bootstrap_radius_chunks` (e.g. `128`). - **Tall builds occasionally missing near the top?** Lower `full_rescan_every` or raise `rebuild_headroom` (or set an explicit `scan_top`). --- ## Notes & limitations - Written for the loader's safe `levilamina-rust-loader` API (v1.0.0 / ABI v4). On a different loader version, align the versions if it won't build or load. - `panic = "abort"` is intentionally **not** set — the loader wraps mod entry points in `catch_unwind`, and aborting would take the whole server down on a panic. - The disk bootstrap reads a database the server has open. That's safe for the database (reads only), but a save landing mid-read can make the load fail; that's logged and the map fills in live instead. - The WebSocket handshake and framing are a small hand-rolled RFC 6455 implementation (the loader has no WebSocket support to build on) — no external crate, no TLS. Put it behind a reverse proxy if you need `wss://`. - Not affiliated with Mojang or Microsoft. --- ## Building ```bash cargo build --release ``` Dependencies: `levilamina-rust-loader` (the Rust loader crate, via git), `image` (PNG only), `serde` / `serde_json`, and `flate2` (for the LevelDB reader). No `panic = "abort"`. --- ## License Choose a license before publishing (MIT or Apache-2.0 are common for this ecosystem) and add a `LICENSE` file. Update this section to match. [Atlas]: https://www.minebbs.com/resources/atlasmap.17092/ [/MD]
后退
顶部 底部