Everything the next agent needs to run the Phase 2 optimisation loop on a machine that can launch the client: - analysis/client-perf/: LEVERS (ranked levers + corrections), BENCH-MATRIX (world, scenes, config IDs, blocks B0-B14 with decision rules), PLAYER-TUNING, SPAWN-TUNING, research briefs, the jar scanner and its output, observed default configs, and proposed-configs/ (build.py generates tiers and bench variants and fails on unknown keys; apply_variant.py applies a variant and merges options.txt). - analysis/client-perf/bench/onion-bench/: bench-world datapack (scene teleports, Create grid, mob pen, sound storm, 120 s teleport tour). - analysis/audit/: the static recipe/dependency audit, including gen_fixes.py, which generates the shipped Paxi datapack and was never tracked. - phase0/: per-machine measurement harness (Steam Deck, 7700K/1060, 6700K/1080 Ti). - .pi/journal.md: running work log; read it first. All of it is packwizignored, so nothing here ships to players.
64 lines
4.2 KiB
Markdown
64 lines
4.2 KiB
Markdown
# Spawn tuning (server-side lever 3)
|
||
|
||
**Owner brief (2026-10-14):** tune spawns, but not in a way that hurts gameplay much. All
|
||
three files ship **enforced** from `config/` (this repo is the server directory, and clients
|
||
get them too, which only matters in singleplayer). Each file is **partial**: the mod fills
|
||
every other key with its default. Research came from three subagent briefs (2026-10-14);
|
||
every load-bearing fact below was re-checked against the pinned jar or the source at the
|
||
matching version. **Unmeasured:** bench block B14 (below) checks it.
|
||
|
||
## What shipped
|
||
|
||
### Alex's Mobs 1.22.17: `config/alexsmobs-common.toml`
|
||
- Format: NeoForge `ModConfigSpec` **COMMON** (`AlexsMobs.class`: `registerConfig(COMMON, …)`;
|
||
no custom filename). Keys are flat under `[spawning]` (`CommonConfig`: `push("spawning")`;
|
||
`buildInt` ignores its category argument). A partial file gets corrected and re-saved by
|
||
NeoForge.
|
||
- Changed (weight, 0–1000; group sizes are hard-coded in `AMWorldRegistry`): gazelle 40→20
|
||
(herds of 7), capuchinMonkey 28→14 (groups of 9–16), elephant 30→15, straddler 70→35,
|
||
rockyRoller 60→30, underminer 50→25, blobfish 30→15, mudskipper 28→14, caiman 29→15.
|
||
Everything rare is untouched.
|
||
- Issue #62 on Raguto/AlexsMobs-1.21.1 ("tons of monsters" / inflated *vanilla* spawns) is
|
||
open, unexplained, and no config addresses it. If it shows up, A/B test a world without
|
||
Alex's Mobs.
|
||
|
||
### Fowl Play 1.2.3: `config/fowlplay.json5`
|
||
- Format: YACL v3 JSON5 (`YACLIntegration`: `fowlplay.json5`). YACL 3.8.2
|
||
(`GsonConfigSerializer.loadSafely`) keeps defaults for missing fields and re-saves; a bad
|
||
value is logged and left at its default, not a crash.
|
||
- Changed (default → new): duck weight 4→2, max group 6→4 · goose 4→2, 4→3 · gull 5→3, 8→5 ·
|
||
sparrow 20→12, 6→4. Songbirds and raptors are untouched.
|
||
- Context: #214 (~400 ducks on rivers) is open. 1.2.1 added a 200-tick spawn gate. The
|
||
category caps (`fowlplay_birds` 20, `fowlplay_ambient_birds` 15) scale with loaded chunks
|
||
like vanilla, and only became configurable *after* 1.2.3. If counts are still high, the
|
||
next lever is a Paxi datapack that narrows `#fowlplay:spawns_ducks` (currently includes
|
||
forest tags), added through `analysis/audit/gen_fixes.py`.
|
||
|
||
### Critters and Companions 2.7.0: `config/crittersandcompanions-common.json5`
|
||
- It *does* have a spawn config (contrary to LEVERS' "no config"): YACL JSON5, nested
|
||
`spawning` object, one `List<SpawnEntry>` per mob. `SpawnEntry` is a record
|
||
`{biomeSpec, weight, min, max}` with no custom type adapter, so it serialises as plain Gson
|
||
record JSON. The jar has no biome-modifier JSON, so a datapack *cannot* reduce these spawns.
|
||
- A listed mob's list **replaces** its defaults, so each changed mob lists all its default
|
||
biomes. `"configVersion": 2` is required, otherwise the v1→v2 migration runs.
|
||
- Changed: sea bunny (the worst: warm ocean 32 × groups ≤4 → 20 × ≤3; other oceans 16 → 10,
|
||
max 4 → 3), leaf insect jungle 14→8 / forest 6→4, dragonfly lush 10→6, and the
|
||
ladybug / stag beetle / roly poly / snail / stick bug / weevil rules about −40 %. Unchanged:
|
||
jumping spider, red panda, ferret, dumbo octopus, otter, koi, shima enaga.
|
||
|
||
## Verify on first boot (part of BENCH-MATRIX §0)
|
||
- `latest.log` has no YACL "Failed to deserialize" lines for `fowlplay` or `crittersandcompanions`.
|
||
- After the first launch, each file has been re-saved in full with our values intact.
|
||
(In the repo working tree that shows up as a diff: **don't commit the expanded files**
|
||
unless you mean to.)
|
||
|
||
## B14: measure it (P2, singleplayer, Creative, `doMobSpawning true`)
|
||
Fresh world `onionspawn`, at a river/forest edge (ducks), a jungle (capuchins, leaf
|
||
insects) and a warm ocean (sea bunnies). Stand still 10 minutes at each, then count with
|
||
`/execute if entity @e[type=<id>,distance=..128]` for `fowlplay:duck`, `fowlplay:gull`,
|
||
`alexsmobs:capuchin_monkey`, `crittersandcompanions:sea_bunny`, and in total
|
||
(`@e[type=!player,distance=..128]`). Compare against the same world with these three
|
||
config files removed (defaults). **Keep the tuning** if totals drop and every species still
|
||
appears; **back it off** if a species effectively disappears. Spot-check that vanilla
|
||
passives (cows, sheep) still spawn normally.
|