diff --git a/test/.env.example b/test/.env.example new file mode 100644 index 0000000..9996da7 --- /dev/null +++ b/test/.env.example @@ -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 diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..ab1af0b --- /dev/null +++ b/test/.gitignore @@ -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 diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..45d79de --- /dev/null +++ b/test/README.md @@ -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= \ +MCMAPPER_SEED_SERVER_AUTH_MODE=offline \ +DATABASE_URL=postgres://mcmapper:mcmapper@localhost:/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///` 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= +``` + +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///` and `config///` 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. diff --git a/test/config/forge/1.12.2/.gitkeep b/test/config/forge/1.12.2/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/config/forge/1.7.10/.gitkeep b/test/config/forge/1.7.10/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/config/neoforge/26.1.2/.gitkeep b/test/config/neoforge/26.1.2/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/docker-compose.yml b/test/docker-compose.yml new file mode 100644 index 0000000..eead3ec --- /dev/null +++ b/test/docker-compose.yml @@ -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///, 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/ 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:/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: diff --git a/test/mods/forge/1.12.2/.gitkeep b/test/mods/forge/1.12.2/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/mods/forge/1.7.10/.gitkeep b/test/mods/forge/1.7.10/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/mods/neoforge/26.1.2/.gitkeep b/test/mods/neoforge/26.1.2/.gitkeep new file mode 100644 index 0000000..e69de29