# MCMapper-Mod Thin, version-independent Forge/NeoForge client for [MCMapper-Backend](https://git.octoturge.com/octoturge/MCMapper-Backend). Streams delta block updates out to the backend instead of rendering the map on the MC server itself (the Bluemap/Dynmap resource problem this project exists to avoid). Full architecture and phased delivery plan lives in the backend repo's planning docs / was tracked during design in Claude Code's plan mode. ## Repo layout - `common/` — loader-agnostic Java: protocol types, config model, and the interfaces (`ChunkAdapter`, `ChatBridge`, `BackendConnection`) each leaf implements. Not a compiled dependency — pulled in as source per leaf (see `common/README.md`). - `forge-1_12_2/` — **primary leaf**, MC 1.12.2 Forge. First implemented; this is the actual driving use case (an Enigmatica 2 modpack server). Builds with legacy ForgeGradle 2.3 via anatawa12's Gradle-7-compatible fork (see `THIRD_PARTY_NOTICES.md`). - `forge-1_7_10/` — MC 1.7.10 Forge (Phase 9). Second priority, fully wired against the same `common` interfaces as `forge-1_12_2`. Builds with legacy ForgeGradle 1.2, same fork family, one Forge-tooling generation further back — pre-block-state (raw `Block` + metadata int, no `IBlockState`) and pre-FML-repackage (`cpw.mods.fml.*`, not `net.minecraftforge.fml.*`). - `neoforge-26_1/` — MC 26.1.2 (NeoForge, assumed). Lowest MVP priority. Structurally scaffolded, not yet wired into the default build (see `settings.gradle`). ## Version targets and priority 1. **MC 1.12.2 Forge** — highest priority (Enigmatica 2) 2. **MC 1.7.10 Forge** — also a priority 3. **MC 26.1.2** — lowest of the three MVP targets Fabric support is an explicit future phase, not part of the MVP. ## Building Both legacy leaves share one root build, on Gradle 7.6 / JDK 8 (pinned via `org.gradle.java.home` in `gradle.properties` — see `settings.gradle` for why): ``` ./gradlew :forge-1_12_2:build ./gradlew :forge-1_7_10:build ``` The first build downloads Minecraft/Forge artifacts and MCP mappings from Forge's Maven and can take a while / needs network access. `neoforge-26_1` is not yet buildable from the root — it needs Gradle 8+ and JDK 17+ (ModDevGradle), incompatible with the legacy leaves' toolchain within one Gradle invocation; see `settings.gradle`'s comment for the workaround until Phase 10 gives it a proper isolated build. ## Configuration (forge-1_12_2 and forge-1_7_10) On first server start the leaf writes `config/mcmapper.cfg` with defaults. Set: ``` backendUrl=ws://:3000/ws serverToken= ``` then restart. With those set, the mod connects to the backend, backfills already-loaded overworld chunks, and streams event-driven column deltas (block place/break) in batches every `deltaFlushIntervalTicks` (default 20 = 1s). A periodic reconciliation sweep (Phase 7) also walks a bounded number of currently-loaded chunks per tick (`reconciliationChunksPerSweep`, default 4) and re-sends any that drifted from what the backend last acknowledged, to catch mutations event hooks miss (world-gen, other mods, `/fill`). Only the overworld is tracked — other dimensions and `neoforge-26_1` land in a later phase. The WS client and JSON encoding are hand-rolled (no third-party dependency) — see `common/src/main/java/.../ws/SimpleWebSocketClient.java` and `.../json/MiniJson.java` for why. `forge-1_7_10` implements the identical config/flush/reconciliation/player-tracking behavior against 1.7.10's own API generation (see `Forge1710ChunkAdapter`'s javadoc for what differs) — it has no `MultiPlaceEvent` hook (that class doesn't reliably exist at this Forge version), so multi-block placements like doors/beds are only caught by the reconciliation sweep rather than immediately, unlike `forge-1_12_2`. ### Player position tracking (Phase 7b) When `playerTrackingEnabled` (default `true`), the leaf sends a throttled roster of online overworld players (`{"type":"player_positions",...}`, see `DefaultBackendConnection`'s class-level wire-protocol doc comment) every `playerPositionIntervalTicks` (default 40 = 2s) — always the *full current roster*, not a diff, so a logged-out player simply stops appearing in the next send. This is a mod-local toggle only: whether the backend actually relays positions on to web viewers is a separate, independent per-server admin setting on the backend side (see MCMapper-Backend's README) — a server operator can track positions server-side without exposing them publicly, or vice versa. ## Attribution See `THIRD_PARTY_NOTICES.md`.