Further Tests & Progress
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
---
|
||||
date: 2026-06-04
|
||||
type: session
|
||||
tags: [session, polish, backlog, testing, hygiene, netcode, audio]
|
||||
---
|
||||
|
||||
# Session 2026-06-04 — Polish & Backlog-Clear Pass (Stages A–G)
|
||||
|
||||
## Goal
|
||||
|
||||
Operator asked to **clear the open backlog and do a comprehensive polish pass on everything**, executed **sequentially** at full scope. A critical read (3 explore audits + direct verification) found the game systems-complete through M6, single-client runtime-validated, console clean, netcode well-built and convention-compliant. The plan (`~/.claude/plans/melodic-yawning-hearth.md`) sequences the work into 9 dependency-ordered stages **A→I**, each landing cleanly (compile → console → tests → runtime spot-check).
|
||||
|
||||
This log covers **Stages A, B, C, D, and E(audio)**. Stages A–C were done on the unfocused editor; the operator then focused Unity, enabling the Burst-edit + ghost-re-bake + Play-mode validation for **D** (one new netcode surface, validated server==client in Play) and **E(audio)** (validated running in Play). The remaining Stage E *feel* tweaks + Stages F–I continue next.
|
||||
|
||||
## Done
|
||||
|
||||
### Stage A — Hygiene, reconcile, const-centralization
|
||||
- **Backlog reconciled** (`06_Roadmap/Backlog.md`): M1-revalidation → moot/subsumed (M1–M6 validated on stable 6.4.7); duplicate "template cleanup" checked off; M5 subscene-split/streaming → **superseded by [[DR-013_M6_Aether_Cycle_Region_Split]]** (region + GhostRelevancy; do not build streaming).
|
||||
- **Milestones**: added the **2026-06-04 Polish & backlog-clear pass** row.
|
||||
- **Home MOC** un-stale'd: latest session pointer + decisions range DR-001…DR-015.
|
||||
- **`Tuning.cs`** created (`Simulation/Tuning.cs`) — central, Burst-safe home for the previously-buried balance consts.
|
||||
- Verified **no stale "74" test-count claim** in CLAUDE.md (audit misattribution; the "74/74" is the historical M5.5 Milestones row, left as-is).
|
||||
|
||||
### Stage B — System-level EditMode tests for M6 systems
|
||||
**+31 cases / 9 files** (86 → **117** green): `StorageOpReceiveSystemTests`, `TurretFireSystemTests`, `ExpeditionGateSystemTests`, `CyclePhaseSystemTests`, `PlayerRespawnSystemTests`, `ResourceHarvestSystemTests` (incl. N-projectile at-most-once destroy), `WaveSystemTests`, `BuildPlaceSystemTests` (incl. **co-op same-cell atomicity**), `RegionTransitSystemTests`. Plain-Entities pattern; immediate-ECB-playback so no separate ECB system.
|
||||
|
||||
### Stage C — wire systems to `Tuning` (code)
|
||||
- `ResourceHarvestSystem.k_ProjectileRadius` and `AbilityUpgradeSystem` `UpgradeSourceId`/`TierStep`/`CostAmount` now derive from `Tuning.*` (value-identical const-from-const; comments preserved; not a query-set change → no Burst-binary hazard). 117/117 green.
|
||||
|
||||
### Stage D — replicated wave number (the ONE new netcode surface) ✅ Play-validated
|
||||
- Added `[GhostField] int WaveNumber` to `CycleState`; `CyclePhaseSystem` is the single writer (syncs it each tick from the server-only `WaveState`); `HudSystem` shows "WAVE N — M HUSKS" during Defend.
|
||||
- +1 EditMode test (118 green). **Play-mode validated server==client**: both worlds reported identical `CycleState` (Wave 0 at rest, and **Wave 7 after seeding the server `WaveState`** → synced + replicated). **No "not a known Burst entry point" spam** after the forced CycleDirector re-bake (focused editor) and **no errors** — only the pre-existing in-editor "Server Tick Batching" warnings (a known backlog item, not a regression).
|
||||
- **TMP HUD migration deferred** — would add a TMP font-asset dependency, against the project's asset-free HUD convention. Kept legacy `Text`; documented as optional future polish.
|
||||
|
||||
### Stage E(audio) — procedural ambient + phase stingers ✅ Play-validated
|
||||
- New **`AmbientAudioSystem`** (`Client/Presentation`, client-only `SystemBase` in `PresentationSystemGroup`, observer-only): a low (vol 0.10) **seamless-looping procedural drone** (frequencies snapped to integer cycles/buffer so the loop has no click) + short procedural **phase-change stingers** (Expedition/Defend/Build, with a tenser "wave incoming" cue + a Defend volume swell). Asset-free (`AudioClip.Create`, mirrors `CombatFeedbackSystem.MakeClip`); never mutates the sim.
|
||||
- **Play-validated**: `~AmbientAudio` AudioSource `isPlaying=true, loop=true, vol=0.10, clip=176400 samples (4s)`, no runtime/job-safety errors.
|
||||
|
||||
### Stage E(feel) — combat juice (4 client-only features) ✅ operator-approved
|
||||
- New **`FeelConfig`** static (`Client/Presentation/FeelConfig.cs`) — ~22 live-pokeable knobs, reset on play-enter via `[RuntimeInitializeOnLoadMethod(SubsystemRegistration)]` (the `AimPresentation` precedent). Client-presentation only; never read from Burst.
|
||||
- **Implemented (observer-only, validated in Play):** (1) hit camera-punch routed through `FeelConfig` + a netcode-safe FOV "hit-stop" kick (`PrototypeCameraRig.PunchFov` — NEVER `Time.timeScale`); (2) kill-shot fanfare (amplified Husk-death-on-prune burst/shake/SFX); (3) respawn shimmer (local Health 0→positive edge in `CombatFeedbackSystem`); (4) reticle lock-on tether in `AimReticleSystem` (client computes nearest living Husk itself — no replicated target exists — gamepad-gated `LineRenderer`).
|
||||
- Defaults **adversarially reviewed** (3-critic + synthesis Workflow) and **operator-approved live** ("feels good") in a forced Defend wave (10 Husks, server==client). Console clean.
|
||||
|
||||
### Stage F — ghost-prop reskin + post-processing ✅ (values verified)
|
||||
- **Prop reskin** — distinct material *assets* (persist into Play, no shared-material bleed; assigned via `PrefabUtility.SaveAsPrefabAsset`, the CLAUDE.md-safe prefab-asset edit) so props stop reading as identical "batteries": Storage → new **`M_Storage`** (dark steel + cool-blue emissive), Turret → new **`M_Turret`** (green ally-tech, distinct from orange Husks), ResourceNode → new **`M_ResourceNode`** (amber/gold), UpgradePickup keeps its glow. Found `M_Env_Storage` was a blank auto-stub (internal name "Universal Render Pipeline/Lit", white base) — replaced. Verified each prop's material/shader/base+emission **values** (not just a render).
|
||||
- **Post-processing verified already complete:** SSAO renderer feature present + `isActive` on the active `PC_Renderer`; URP `colorGradingMode=HighDynamicRange` (correct for ACES); `PostFX_DarkSciFi` = Bloom + Tonemapping(ACES) + ColorAdjustments + Vignette, all active. Backlog "add SSAO" satisfied.
|
||||
- **Deferred (diminishing returns, plan-noted):** reflection probe, ORM-repack / deeper material fidelity, a proper turret MESH (battery mesh kept — distinct material is the 80/20; a real turret mesh needs a Synty asset + Entities-Graphics verification). Materials are assets → instantly re-tintable on operator request.
|
||||
|
||||
### Stage G — new gameplay (in progress; design-reviewed) ✅ timed modifiers · knockback · telegraph
|
||||
- **Adversarial design review** (4-agent Workflow: netcode/determinism · reuse · test-plan → synthesis) gave per-feature specs (re-bake?/determinism/files/tests). No-re-bake: timed modifiers, knockback, debug-RPC, storage-gate, pickup, multi-prefab. Re-bake: Spitter (new ghost types) + telegraph (one `[GhostField]` on the Husk).
|
||||
- **Timed/removable modifiers ✅** — server-only `TimedModifier{SourceId,UntilTick}` buffer (StatModifier layout untouched → provably no re-bake) + `TimedModifierExpirySystem` (removes the matching StatModifier when due; replicates via the existing buffer; `StatRecomputeSystem` unchanged) + `TimedModifierUtil.RemoveBySourceId` (clear-by-type). +4 tests.
|
||||
- **Enemy knockback ✅** — server-only `KnockbackState{Dir,Speed,UntilTick}` (no re-bake; Husk position already replicates), stamped by `ProjectileDamageSystem` on hit (backward-compatible via `TryGetSingleton<NetworkTime>` so existing tests pass), applied by `EnemyAISystem` as the SOLE position writer (recoil replaces seek + suppresses the strike). Tunable `Tuning.KnockbackSpeed`(8, 0=off) / `KnockbackDurationTicks`(8). +3 tests.
|
||||
- **Husk attack telegraph ✅ (re-bake)** — replicated `[GhostField] AttackWindup.WindUpUntilTick` on the Husk; `EnemyAISystem` restructured to a 2-phase strike (commit wind-up when in-range + cooldown-ready → strike at expiry; cancel on leave-range; a knocked Husk doesn't wind up); client cue in `CombatFeedbackSystem` (observer, warns on the wind-up-start edge). Tunable `Tuning.AttackWindupTicks`(18 ≈ 0.3s, 0/1 = instant). +2 tests. **Re-bake Play-validated: server==client (4 Husks, 2 winding up, identical maxWindTick), no Burst-cache spam, no errors. 127 EditMode green.**
|
||||
|
||||
### Aim-drift fix (operator request, end of session) ✅
|
||||
- **Symptom:** holding the cursor near the player, the aim/reticle swims without mouse movement when the character turns / the camera pans — feels inaccurate. **Cause:** the camera look-ahead led toward `PlayerFacing` (aim) → turning to face a near-cursor panned the camera → the live cursor screen-ray re-projected onto a different ground point → aim drifted (worst near the player, short lever arm). **Fix:** `PrototypeCameraRig` now leads toward **MOVEMENT** (`PlayerInput.Move`), not aim — a stationary aim no longer pans the camera; the cam still anticipates where you're going. Researched (gamedeveloper.com dual-stick; Relic Hunters Zero "ignore the crosshair unless not moving"). EditMode **127/127**, console clean; "feels accurate now" = operator feel-test (tunable: `AimLeadDistance` 0 = no lead). Recorded in [[DR-012_Aim_Controls_Cursor_Gamepad]] Refinement 2.
|
||||
|
||||
## Decisions
|
||||
|
||||
- **Created [[DR-016_Stage_G_Combat_Gameplay]]** (timed-modifier / knockback / telegraph architecture + the deferred Spitter / multi-prefab) and **amended [[DR-012_Aim_Controls_Cursor_Gamepad]]** (Refinement 2: movement-based camera look-ahead supersedes the facing-based look-ahead).
|
||||
|
||||
- **Debug systems kept `#if UNITY_EDITOR`-gated in place** (not moved to a new Editor asmdef). Already build-stripped; tightly coupled to their Client/Server worlds; a separate Editor asmdef risks DOTS system-discovery surprises for no functional gain. `execute_code` statics preserved.
|
||||
- **RegionRelevancySystem is integration/operator-validated, not unit-tested.** `Unity.NetCode.GhostRelevancy` has an **internal** constructor + `readonly` `GhostRelevancySet` → the singleton genuinely cannot be constructed from the test assembly. Relies on existing runtime validation ([[DR-013_M6_Aether_Cycle_Region_Split]]) + the Stage-I multi-client checklist. (Verified type shapes via `unity_reflect`.)
|
||||
|
||||
## Open / deferred
|
||||
|
||||
- **Enemy knockback + Husk attack-telegraph → re-homed to Stage G** (server/netcode, not client presentation): the 3-critic review proved both inherently touch the sim/netcode surface — knockback fights `EnemyAISystem`'s per-tick `LocalTransform` write on the interpolated ghost (needs a server knockback-state component + EditMode test); telegraph needs a NEW replicated wind-up signal (`[GhostEnabledBit]`/`[GhostField]` on the Husk → re-bake) because `EnemyAttackCooldown`/`EnemyStats`/`AttackRange` are server-only. Each behind an adversarial review + test.
|
||||
- **Stage C decor-LOD client-only split** — verify deferred (wants the gameplay subscene open; tick-budget optimization, not correctness).
|
||||
- **Stages F–I**: ghost-prop reskin + post-processing (F); new content — Spitter/boss/timed-modifiers/multi-prefab-abilities/storage-proximity/standalone-debug-RPC (G); controls — rebind + ability slots + ability UI (H); validation harness + operator-required live runs — two-build LAN co-op, live fire, standalone server perf (I).
|
||||
|
||||
## Next
|
||||
|
||||
- **Polish stages A–F are DONE + validated** (118 EditMode green; the one new netcode surface — `CycleState.WaveNumber` — proven server==client in Play; feel operator-approved; props reskinned + post verified).
|
||||
- **Stage G done so far:** timed modifiers, knockback, attack telegraph (all validated). **Remaining:** the ranged **Spitter** (the large one — new `EnemySpitter` + new interpolated `EnemyProjectile` ghost prefabs + spit-fire/move/damage-vs-players systems; re-bake = new ghost TYPES, not an existing-ghost serializer change) and **multi-prefab abilities** (generalize the non-Burst `ProjectileClassificationSystem` to a ghost-type SET; core correctness — no owner-client double-spawn — is Play-only). Small fold-ins still open: standalone-server debug RPC, storage proximity-gate, pickup auto-grant (confirm intent).
|
||||
- **Stage H** (rebindable controls + ability slots + ability icon/UI) and **Stage I** (thin-client/MPPM harness + operator-required live runs: two-build LAN co-op, live fire, standalone server perf — the standing ~1.25–1.75 ticks/frame question).
|
||||
Reference in New Issue
Block a user