Add itzg-based docker-compose for live-testing the mod against real MC servers
Three services (mc-1_12_2 default, mc-1_7_10/mc-neoforge-26_1 opt-in via Compose profiles) using itzg/docker-minecraft-server, with mods/config bind- mounted per loader/version (mods/<loader>/<version>/) so jars can be dropped in and swapped without touching the compose file. Verified against real containers: fixed a WSL docker credential-helper misconfig blocking pulls, and pinned legacy Forge services to the java8 image tag after itzg's :latest (Java 25) crashed LaunchWrapper with a ClassCastException — mc-1_12_2 now boots cleanly to "Done" on java8.
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
# Copy to .env (untracked) and adjust if the defaults in docker-compose.yml don't fit — none of
|
||||||
|
# these need to be set for the default `mc-1_12_2` service to work as-is.
|
||||||
|
|
||||||
|
# MC_1_12_2_PORT=25565
|
||||||
|
# MC_1_12_2_MEMORY=3G
|
||||||
|
# MC_1_12_2_ONLINE_MODE=FALSE
|
||||||
|
|
||||||
|
# MC_1_7_10_PORT=25566
|
||||||
|
# MC_1_7_10_MEMORY=2G
|
||||||
|
# MC_1_7_10_ONLINE_MODE=FALSE
|
||||||
|
|
||||||
|
# MC_NEOFORGE_26_1_PORT=25567
|
||||||
|
# MC_NEOFORGE_26_1_MEMORY=3G
|
||||||
|
# MC_NEOFORGE_26_1_ONLINE_MODE=FALSE
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Real jars/configs/world data dropped in here for local live-testing — never committed. The
|
||||||
|
# per-loader-per-version directories themselves are tracked via .gitkeep so `docker compose up`
|
||||||
|
# has somewhere to bind-mount without a manual `mkdir` first.
|
||||||
|
mods/*/*/*
|
||||||
|
config/*/*/*
|
||||||
|
!mods/*/*/.gitkeep
|
||||||
|
!config/*/*/.gitkeep
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
# Live test servers
|
||||||
|
|
||||||
|
Real Minecraft servers (via [itzg/docker-minecraft-server](https://github.com/itzg/docker-minecraft-server),
|
||||||
|
MIT — handles EULA acceptance, Forge/NeoForge installation, memory flags, etc. so this compose
|
||||||
|
file doesn't reimplement any of that) for exercising the mod end-to-end against a running
|
||||||
|
MCMapper-Backend stack — the thing the plan's own per-phase verification steps keep asking for
|
||||||
|
("place/break blocks, confirm they appear on the map") but that no session has actually done yet.
|
||||||
|
|
||||||
|
Only `mc-1_12_2` runs by default — it's the actual driving use case (Enigmatica 2, see the plan's
|
||||||
|
version priority). `mc-1_7_10` and `mc-neoforge-26_1` are opt-in via Compose profiles:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker compose up # 1.12.2 only (default)
|
||||||
|
docker compose --profile legacy-1_7_10 up # + 1.7.10
|
||||||
|
docker compose --profile neoforge-26_1 up # + 26.1.2 NeoForge (least tested, lowest priority)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Start a backend stack
|
||||||
|
|
||||||
|
From `MCMapper-Backend`, either:
|
||||||
|
- `docker compose up` (full stack — api/frontend/worker/postgres/redis/caddy; Caddy publishes
|
||||||
|
`:80` on the host, routing `/ws*` to `api` per the Caddyfile), or
|
||||||
|
- run `api` directly (`cd api && bun run dev`) for a lighter loop — it listens on `:3000` with no
|
||||||
|
proxy in front.
|
||||||
|
|
||||||
|
Either way, register a server row so the mod has a token to authenticate with:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd MCMapper-Backend/api
|
||||||
|
MCMAPPER_SEED_SERVER_NAME=test-1_12_2 MCMAPPER_SEED_SERVER_TOKEN=<pick-any-string> \
|
||||||
|
MCMAPPER_SEED_SERVER_AUTH_MODE=offline \
|
||||||
|
DATABASE_URL=postgres://mcmapper:mcmapper@localhost:<pg-port>/mcmapper bun run seed
|
||||||
|
```
|
||||||
|
|
||||||
|
(`authMode=offline` matches this compose's default `ONLINE_MODE=FALSE` — see docker-compose.yml's
|
||||||
|
comment on that variable. Use `online` + `ONLINE_MODE=TRUE` instead to test the real UUID-merge
|
||||||
|
identity path.) The admin panel (`/admin` on the frontend, Phase 6) is the other way to register a
|
||||||
|
server, if the backend is already up with `MCMAPPER_ADMIN_TOKEN` set.
|
||||||
|
|
||||||
|
## 2. Build the mod and drop the jar in
|
||||||
|
|
||||||
|
```
|
||||||
|
cd MCMapper-Mod
|
||||||
|
./gradlew :forge-1_12_2:build
|
||||||
|
cp forge-1_12_2/build/libs/forge-1_12_2-*.jar test/mods/forge/1.12.2/
|
||||||
|
```
|
||||||
|
|
||||||
|
(Swap the leaf/version for `forge-1_7_10`/`mods/forge/1.7.10` or `neoforge-26_1`/`mods/neoforge/26.1.2`
|
||||||
|
— note `neoforge-26_1` has its own standalone Gradle wrapper, see the root README's "Building". Mods
|
||||||
|
are split by loader first, then version — Forge and NeoForge mod jars aren't interchangeable even
|
||||||
|
for adjacent MC versions. Each `mods/<loader>/<version>/` directory maps straight to that server's
|
||||||
|
`/data/mods` — drop other mod jars in there too to test alongside MCMapper, and remove/swap them any
|
||||||
|
time, then `docker compose restart` to pick up the change; nothing in `mods/`/`config/` is ever
|
||||||
|
committed, see .gitignore.)
|
||||||
|
|
||||||
|
## 3. First boot, then configure
|
||||||
|
|
||||||
|
```
|
||||||
|
cd test
|
||||||
|
docker compose up -d
|
||||||
|
docker compose logs -f mc-1_12_2 # wait for "Done" / world generation to finish
|
||||||
|
```
|
||||||
|
|
||||||
|
The mod writes `config/mcmapper.cfg` with empty defaults on this first boot (it needs a
|
||||||
|
`backendUrl`/`serverToken` before it'll actually connect — see the root README's "Configuration"
|
||||||
|
section). Edit `test/config/forge/1.12.2/mcmapper.cfg`:
|
||||||
|
|
||||||
|
```
|
||||||
|
backendUrl=ws://host.docker.internal:80/ws
|
||||||
|
serverToken=<the token you seeded above>
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `ws://host.docker.internal:80/ws` if the backend is running via its own `docker compose up`
|
||||||
|
(Caddy on host `:80`), or `ws://host.docker.internal:3000/ws` if you ran `bun run dev` for `api`
|
||||||
|
directly instead (no Caddy in front). `extra_hosts: host.docker.internal:host-gateway` in
|
||||||
|
docker-compose.yml is what makes that hostname resolve to the host machine from inside the MC
|
||||||
|
container — works the same whether the host's Docker is Docker Desktop or a bare Linux daemon
|
||||||
|
(Engine ≥20.10, which this project's own WSL2 dockerd is).
|
||||||
|
|
||||||
|
Then:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker compose restart mc-1_12_2
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Verify
|
||||||
|
|
||||||
|
Connect a real Minecraft 1.12.2 client to `localhost:${MC_1_12_2_PORT:-25565}` (offline/cracked
|
||||||
|
login works fine with the default `ONLINE_MODE=FALSE`), walk around to load some chunks, place/
|
||||||
|
break a few blocks, then check the map frontend (`http://localhost` if using the backend's own
|
||||||
|
`docker compose`, or `http://localhost:3001` if running `frontend` directly) — this is the actual
|
||||||
|
Phase 1 verification step from the plan, finally exercised against a real server rather than only
|
||||||
|
unit/integration tests. Also useful for later phases' own live-test callouts that were flagged but
|
||||||
|
never actually run: the atlas shader's `invertY` assumption (Phase 12) and real non-cube block
|
||||||
|
rendering (Phase 13, place/find a vanilla non-cube block like a torch or stairs — or attach a mod
|
||||||
|
that ships one, e.g. Thaumcraft, by dropping its jar in the same `mods/forge/1.12.2/` directory).
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- World/server data persists in named Docker volumes (`mc-1_12_2-data` etc.) across
|
||||||
|
`docker compose restart`/`down` — use `docker compose down -v` to fully wipe a server and start
|
||||||
|
over (e.g. after bumping the mod jar in a way that needs a clean world).
|
||||||
|
- `mods/<loader>/<version>/` and `config/<loader>/<version>/` contents are gitignored (except the
|
||||||
|
`.gitkeep` placeholders that keep the mount points present in a fresh checkout) — nothing dropped
|
||||||
|
in them is committed.
|
||||||
|
- To add other mods for stress-testing (Thaumcraft was the plan's named non-cube-model stress
|
||||||
|
test for Phase 13) drop their jars in the same `mods/forge/1.12.2/` directory itzg's image reads
|
||||||
|
from — no compose changes needed. itzg's image also supports `CURSEFORGE_FILES`/`MODRINTH_PROJECTS`
|
||||||
|
for auto-downloading specific mods (CurseForge's downloads generally need a `CF_API_KEY` now);
|
||||||
|
not wired up here since that needs per-mod IDs/an API key only you can supply — see itzg's own
|
||||||
|
docs (https://docker-minecraft-server.readthedocs.io/) if you want that instead of manual jars.
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
# Real Minecraft servers for live-testing the mod against a running MCMapper-Backend stack —
|
||||||
|
# see README.md in this directory for the full walkthrough (build the mod, seed a backend server
|
||||||
|
# token, drop the jar in mods/<loader>/<version>/, docker compose up). Mods are split by loader
|
||||||
|
# first, then version — Forge and NeoForge mod jars aren't interchangeable even for adjacent MC
|
||||||
|
# versions, and a future Fabric leaf (Phase 14) would add its own mods/fabric/<version> alongside
|
||||||
|
# these rather than needing a reshuffle.
|
||||||
|
#
|
||||||
|
# Uses itzg/docker-minecraft-server (https://github.com/itzg/docker-minecraft-server, MIT) — the
|
||||||
|
# de facto standard MC server image, handles EULA/Forge/NeoForge installation, memory flags, etc.
|
||||||
|
# so this compose file doesn't have to reimplement any of that.
|
||||||
|
#
|
||||||
|
# Only `mc-1_12_2` (the actual driving use case — Enigmatica 2, see the plan's version priority)
|
||||||
|
# runs by default. The other two leaves are opt-in via Compose profiles, since running all three
|
||||||
|
# at once is a lot of RAM for a local dev box:
|
||||||
|
# docker compose up # 1.12.2 only (default)
|
||||||
|
# docker compose --profile legacy-1_7_10 up # + 1.7.10
|
||||||
|
# docker compose --profile neoforge-26_1 up # + 26.1.2 (NeoForge) — least tested, lowest MVP priority
|
||||||
|
|
||||||
|
services:
|
||||||
|
mc-1_12_2:
|
||||||
|
# itzg's `:latest` tag now defaults to a Java 25 base — legacy Forge's LaunchWrapper hard-
|
||||||
|
# crashes on anything past Java 8 (`ClassCastException: AppClassLoader cannot be cast to
|
||||||
|
# URLClassLoader`, confirmed by actually booting this service against `:latest` first). Same
|
||||||
|
# JDK 8 constraint as this repo's own build toolchain (see ../gradle.properties), just for the
|
||||||
|
# server *runtime* instead of the compiler this time.
|
||||||
|
image: itzg/minecraft-server:java8
|
||||||
|
tty: true
|
||||||
|
stdin_open: true
|
||||||
|
ports:
|
||||||
|
- "${MC_1_12_2_PORT:-25565}:25565"
|
||||||
|
environment:
|
||||||
|
EULA: "TRUE"
|
||||||
|
TYPE: "FORGE"
|
||||||
|
VERSION: "1.12.2"
|
||||||
|
# Same build pinned in ../gradle.properties (forge_1_12_2_version) — keep these in sync.
|
||||||
|
FORGE_VERSION: "14.23.5.2847"
|
||||||
|
MEMORY: "${MC_1_12_2_MEMORY:-3G}"
|
||||||
|
# Offline/cracked mode by default so any MC client can connect with no Microsoft account
|
||||||
|
# needed for a quick local smoke test — matches the plan's authMode="offline" identity
|
||||||
|
# scoping (see MCMapper-Backend's README). Flip to TRUE (and register the backend server
|
||||||
|
# row with authMode=online) to test the real online-mode UUID-merge path instead.
|
||||||
|
ONLINE_MODE: "${MC_1_12_2_ONLINE_MODE:-FALSE}"
|
||||||
|
volumes:
|
||||||
|
- mc-1_12_2-data:/data
|
||||||
|
# Drop the built forge-1_12_2 jar (see README.md — `./gradlew :forge-1_12_2:build`,
|
||||||
|
# output in ../forge-1_12_2/build/libs/) — and any other mod jars to stress-test against
|
||||||
|
# (e.g. Thaumcraft, the plan's named Phase 13 non-cube-model target) — straight into this
|
||||||
|
# directory; itzg's image loads anything here as-is, no repackaging needed. Add/remove jars
|
||||||
|
# any time and `docker compose restart mc-1_12_2` to pick up changes.
|
||||||
|
- ./mods/forge/1.12.2:/data/mods
|
||||||
|
# The mod writes config/mcmapper.cfg here on first boot (see the mod repo README's
|
||||||
|
# "Configuration" section) — edit backendUrl/serverToken in this mounted file, then
|
||||||
|
# `docker compose restart mc-1_12_2`.
|
||||||
|
- ./config/forge/1.12.2:/data/config
|
||||||
|
# Lets `backendUrl=ws://host.docker.internal:<port>/ws` in the mounted config reach a backend
|
||||||
|
# stack running on the host (either MCMapper-Backend's own `docker compose up`, published on
|
||||||
|
# host port 80 via its Caddy, or a bare `bun run dev` api on host port 3000) — see README.md.
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
mc-1_7_10:
|
||||||
|
# Same Java-8 requirement as mc-1_12_2 above — 1.7.10's Forge/LaunchWrapper generation is
|
||||||
|
# even older, so it needs this at least as much.
|
||||||
|
image: itzg/minecraft-server:java8
|
||||||
|
profiles: ["legacy-1_7_10"]
|
||||||
|
tty: true
|
||||||
|
stdin_open: true
|
||||||
|
ports:
|
||||||
|
- "${MC_1_7_10_PORT:-25566}:25565"
|
||||||
|
environment:
|
||||||
|
EULA: "TRUE"
|
||||||
|
TYPE: "FORGE"
|
||||||
|
VERSION: "1.7.10"
|
||||||
|
# Same build pinned in ../gradle.properties (forge_1_7_10_version).
|
||||||
|
FORGE_VERSION: "10.13.4.1614-1.7.10"
|
||||||
|
MEMORY: "${MC_1_7_10_MEMORY:-2G}"
|
||||||
|
ONLINE_MODE: "${MC_1_7_10_ONLINE_MODE:-FALSE}"
|
||||||
|
volumes:
|
||||||
|
- mc-1_7_10-data:/data
|
||||||
|
- ./mods/forge/1.7.10:/data/mods
|
||||||
|
- ./config/forge/1.7.10:/data/config
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
mc-neoforge-26_1:
|
||||||
|
# Unlike the two legacy leaves above, this one actually *wants* a modern JRE (Minecraft
|
||||||
|
# itself requires Java 25 as of the 26.x cycle, see ../neoforge-26_1/settings.gradle) — plain
|
||||||
|
# `:latest` already resolves to a java25 base as of this writing (confirmed by actually
|
||||||
|
# pulling it), so no separate tag pin needed here.
|
||||||
|
image: itzg/minecraft-server:latest
|
||||||
|
profiles: ["neoforge-26_1"]
|
||||||
|
tty: true
|
||||||
|
stdin_open: true
|
||||||
|
ports:
|
||||||
|
- "${MC_NEOFORGE_26_1_PORT:-25567}:25565"
|
||||||
|
environment:
|
||||||
|
EULA: "TRUE"
|
||||||
|
TYPE: "NEOFORGE"
|
||||||
|
VERSION: "26.1.2"
|
||||||
|
# Same build pinned in ../gradle.properties (neoforge_26_1_version). This is the least
|
||||||
|
# exercised leaf (lowest MVP priority, see the plan) — if itzg's installer doesn't yet
|
||||||
|
# recognize this exact MC/NeoForge version pairing, check for an itzg image update first.
|
||||||
|
NEOFORGE_VERSION: "26.1.2.94"
|
||||||
|
MEMORY: "${MC_NEOFORGE_26_1_MEMORY:-3G}"
|
||||||
|
ONLINE_MODE: "${MC_NEOFORGE_26_1_ONLINE_MODE:-FALSE}"
|
||||||
|
volumes:
|
||||||
|
- mc-neoforge-26_1-data:/data
|
||||||
|
- ./mods/neoforge/26.1.2:/data/mods
|
||||||
|
# NeoForge writes config/mcmapper-server.toml (TOML, not the legacy leaves' .cfg) — see
|
||||||
|
# the mod repo README's "Configuration" section.
|
||||||
|
- ./config/neoforge/26.1.2:/data/config
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mc-1_12_2-data:
|
||||||
|
mc-1_7_10-data:
|
||||||
|
mc-neoforge-26_1-data:
|
||||||
Reference in New Issue
Block a user