Files
Project-M/Docs/Vault/07_Sessions/2026/2026-07-20_Tuning_Bench_C.md
kronic aa5247aff4 Docs: commit basic-memory frontmatter backfill + resolved MCP lock hash
The 13 vault notes were left dirty by basic-memory back-filling
title/type/permalink frontmatter into files written with Write/Edit
(it also strips the trailing newline — restored here so future diffs
stay clean). Content is unchanged; verified frontmatter-only.

packages-lock.json is the com.coplaydev.unity-mcp #main branch ref
silently re-resolving. Pinning that dependency lands with the package
cleanup batch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 10:09:39 -07:00

3.4 KiB
Raw Permalink Blame History

title, type, permalink
title type permalink
2026-07-20_Tuning_Bench_C note gamevault/07-sessions/2026/2026-07-20-tuning-bench-c

2026-07-20 (C) — Data-driven tuning bench (profiles + audit + probe)

Operator: "the knobs are a lot & not very intuitive — is there any way for you to do data-driven tuning?" The answer: raw scalars are bad for both of us — the operator can't intuit ticks/radians, and I can't feel the game. What I CAN do precisely is derive and measure. Three tools:

1. Feel profiles — whole gestalts as data

Assets/_Project/Tuning/Profiles/*.json — one file = sim knobs (TuningKnob names) + FeelConfig fields, PARTIAL (only listed keys apply). FeelProfileService (Client/Debug, editor-only) applies via the existing authoritative SetTuning path + FeelConfig reflection; "Save current" captures a hand-dialed state back to a profile. DebugOverlay grew a Profiles section (one-click A/B) + the probe button. Starter set: baseline-0720 (the shipped defaults / reset), heavy-committed (MonHun-lean), snappier (Hades-lean) — all DPS-held (~60) via dmg = recover. Rule: code defaults stay the single shipped truth; profiles are experiments — a winner gets folded into TuningConfig.Defaults() / FeelConfig.ResetDefaults() and the profile archived.

2. TuningAuditTools — the derived truth (edit-time, no eyes needed)

ProjectM/Tuning/Audit Melee Timing + Reach: derives per-step contact from the ACTUAL clip WindUp takes ÷ wired state speeds and compares against MeleeTiming + the knob (drift detector — kills the hand-copied-constant class of bug); checks the un-clamped coupling invariants the design review flagged (contact < lock, ≤ CastFacingTicks); computes cadence/DPS; measures the reach-honesty ratio off the BAKED weapon mesh. First run: zero drift (16/10/20 == clip truth), DPS 60.0 flat, and reach ratio ×0.93 base / ×1.16 finisher — the "swings don't line up" complaint is now a measured number inside the ≤1.25 budget (was >2×).

3. CombatProbe — measured play numbers

CombatProbe.Run(n) (Client/Debug, editor-only; overlay button): spawns a 100k-HP dummy in the cone, mash-drives a real injected attack chain, samples the SERVER per frame → per-swing start/scheduled-contact/damage-tick/amount, measured cadence + DPS + buffer usage. Demo run at defaults: gaps 30/30/45 exactly, contacts +16/+10/+20 exactly, damage 36/36/54 (class seed × finisher). Then the full loop: applied snappier → measured 24/24/36 gaps and +12/+8/+15 contacts immediately. Tuning = author JSON → apply → measure → compare. Probe fix during the demo: wait for the FINAL swing's contact before finishing (first run cut off swing 6).

The workflow now

  • Me (precise): edit/author a profile → ApplyCombatProbe → read measured numbers vs targets → iterate.
  • Operator (intuitive): tap profile buttons in the overlay to A/B whole feels → nudge individual rows if desired → Save current → I fold the winner into code defaults.

Validation: console clean; audit + probe both demonstrated live; profile apply verified against measured sim output. No netcode surface (profiles ride the existing SetTuning RPC; probe is read-only diagnostics).

Next: operator A/Bs the three starter profiles in DevSandbox (DEV overlay → Feel Profiles); tell me which direction wins (or Save-current a custom) and I fold it into defaults + build the next profile iteration.