From 0574e74e18d25213773a4d49040760885ef0c08b Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Thu, 9 Jul 2026 13:48:32 -0700 Subject: [PATCH] Docs: collision-fidelity pass record + MeshCollider Read/Write gotcha + guardian harness pattern Session log Part C (execution + validation evidence), roadmap stabilize #2 ticked, CLAUDE.md gains the MeshCollider-bakes-only-if-Read/Write gotcha (38.4 KB, in budget), validation-harness.md gains the EditorApplication.update guardian + EditorPrefs handoff pattern. Co-Authored-By: Claude Fable 5 --- .../dots-dev/references/validation-harness.md | 6 +++ CLAUDE.md | 2 +- .../06_Roadmap/Iteration_2026-07_CoopHades.md | 14 +++--- ...2026-07-09_B4d_Tail_Collision_Grounding.md | 46 +++++++++++++++++-- 4 files changed, 58 insertions(+), 10 deletions(-) diff --git a/.claude/skills/dots-dev/references/validation-harness.md b/.claude/skills/dots-dev/references/validation-harness.md index 7c015370a..18266c042 100644 --- a/.claude/skills/dots-dev/references/validation-harness.md +++ b/.claude/skills/dots-dev/references/validation-harness.md @@ -63,6 +63,12 @@ DOES propagate into parented children's `LocalToWorld` (verified live on 6.5.0). and tears down the room. - Therefore: **capture evidence in the SAME `execute_code` call that first detects the condition** (e.g. `enemies>0`) — a separate "then screenshot" round-trip loses the window. +- **Multi-sample observations (movement deltas, before/after) that can't fit one call: install an + `EditorApplication.update` guardian delegate** (proven 2026-07-09, enemy-backstop smoke). The closure runs every + editor frame: it can out-race damage (`Health.Current = Max` per frame — beats the respawn-reset trap above), + park the player, take timed snapshots, and stash results in `EditorPrefs` (survives across `execute_code` + calls — statics do NOT). Always: wrap the body in try/catch that UNSUBSCRIBES on error, add a hard timeout + unsubscribe (~90 s), self-unsubscribe when done, and delete the `EditorPrefs` keys after reading them. - Prefer the server-inject harness above whenever the question doesn't actually require a live run. ## Visual/asset verification limits diff --git a/CLAUDE.md b/CLAUDE.md index a1065e253..d1e679c2e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -78,7 +78,7 @@ Long-form originals + the milestone each came from: `Docs/Vault/_Meta/CLAUDE_Bui - **Frontend world lifecycle (menu → on-demand worlds) ★:** use `CreateClientWorld`/`CreateServerWorld` (they register the `ServerWorld`/`ClientWorld` statics the UI reads; `CreateLocalWorld` was internal pre-6.5, PUBLIC on 6.5.0); menu world via `DefaultWorldInitialization.Initialize(name, false)`. **Never dispose/create worlds inside an ECS system** — do it on a frame-boundary coroutine (`SessionRunner`, `DontDestroyOnLoad`). The gameplay subscene streams in ONLY if a netcode world is the `DefaultGameObjectInjectionWorld` at `LoadScene` time. See [[DR-019_Frontend_Menu_Settings_Saves_Build]]. ### Physics & character controller -- **Unity Physics 1.x bakes built-in `UnityEngine` colliders + `Rigidbody`** (the Physics-0.x `PhysicsShapeAuthoring`/`PhysicsBodyAuthoring` are gone). Static collider (no Rigidbody) → baked into the subscene PhysicsWorld, deterministic, no replication. `Rigidbody.FreezeRotation` is **NOT** honored by the baker — zero angular velocity + write rotation each tick, or set `PhysicsMass.InverseInertia = float3.zero`. +- **Unity Physics 1.x bakes built-in `UnityEngine` colliders + `Rigidbody`** (the Physics-0.x `PhysicsShapeAuthoring`/`PhysicsBodyAuthoring` are gone). Static collider (no Rigidbody) → baked into the subscene PhysicsWorld, deterministic, no replication. `Rigidbody.FreezeRotation` is **NOT** honored by the baker — zero angular velocity + write rotation each tick, or set `PhysicsMass.InverseInertia = float3.zero`. **A `MeshCollider` bakes ONLY if the mesh has Read/Write enabled** — else `InvalidOperationException` per bake and NO baked shape (classic scene view still shows the collider; only a baked-`CollisionWorld` probe catches it); flip the ModelImporter `isReadable`. Env-collider fidelity is tool-driven: `ColliderFitTools` (audit/apply) refits subscene walls/cover/landmarks to the Game.unity visuals. - **The player is a Unity Character Controller kinematic character** (NOT a dynamic Rigidbody; M5's `PlayerMoveSystem`/`PlayerPlanarConstraintSystem` deleted, predicted-physics infra kept). `PlayerControlSystem` maps input → `CharacterControl`; `CharacterProcessor` collide-and-slides in the relocated `KinematicCharacterPhysicsUpdateGroup`. CC 1.4.2 API = `IKinematicCharacterProcessor` + `KinematicCharacterDataAccess` + static `KinematicCharacterUtilities.Update_*` (verify with `unity_reflect`). - **`KinematicCharacterUtilities.BakeCharacter` aborts with a `Rigidbody`** and needs uniform (1,1,1) scale. **`CharacterInterpolation` must be PredictedClient-only** (a `DefaultVariantSystemBase` strips it from server + interpolated prefabs) — else double-interp on remotes. **Do NOT copy the CC sample's global `LocalTransform → DontSerializeVariant`** (project-wide; breaks non-character ghosts that rely on stock `LocalTransform` replication). - **Top-down CC config:** `SnapToGround=false`, `InterpolateRotation=false` (rotation owned by `PlayerAimSystem`), `SimulateDynamicBody=false`; gravity handled by feeding `float3.zero` to `Update_GroundPushing`. diff --git a/Docs/Vault/06_Roadmap/Iteration_2026-07_CoopHades.md b/Docs/Vault/06_Roadmap/Iteration_2026-07_CoopHades.md index d741ba00e..395ee2e6c 100644 --- a/Docs/Vault/06_Roadmap/Iteration_2026-07_CoopHades.md +++ b/Docs/Vault/06_Roadmap/Iteration_2026-07_CoopHades.md @@ -117,12 +117,14 @@ attacks/animations/effects**. Art direction deliberately UNDECIDED — lighting `[RuntimeInitializeOnLoadMethod]` attribute** off `WorldFeelConfig.ResetDefaults` → `Enabled=false` → the WHOLE feedback slice (shrink/pop + chips + SFX + micro-punch) silently dead. One-line restore; verified on-screen + numerically on a live server-spawned node; 455/455. Operator still eyeballs a real harvest in the next playtest. -2. **Collision precision pass — SCOPED (2026-07-07 operator): environment collider FIDELITY.** Collision shapes - don't match the visual meshes (cover rocks etc.) — invisible walls / visual clipping. TODO: audit every - Environment-layer collider (boundary rim, landmark rocks, in-room cover props) and fit them to the render mesh - (tightened primitives or convex mesh colliders); verify against the baked subscene PhysicsWorld (that's where - they live — classic-GameObject views lie). Re-validate the enemy stuck-fix backstop after any shape change - (Depenetrate/tangent-slide was tuned on the old shapes). +2. ~~Collision precision pass~~ **DONE (2026-07-09, gate-approved incl. missing-collider adds).** + `ColliderFitTools` (Editor, audit/apply) refit everything to the Game.unity visuals: rings rebuilt + 16/24/24→54/82/82 fine segments fitted to torso-band cliff vertices; cover = convex MeshColliders of the + actual rock meshes (needed Read/Write on 2 PNB meshes — new CLAUDE.md gotcha); landmarks hint-matched OBB + fits; 11 solid-prop colliders added (tree/turbine/crates/dish/solar). Verified in the baked CollisionWorld + (ring closure, cover 8/8 solid, server==client parity) + enemy backstop re-validated live (embedded enemy + depenetrates out of a cover hull and keeps moving). Operator feel-lap still pending. See + [[2026-07-09_B4d_Tail_Collision_Grounding]]. ### Short-term wins (asset/scene/client layer) diff --git a/Docs/Vault/07_Sessions/2026/2026-07-09_B4d_Tail_Collision_Grounding.md b/Docs/Vault/07_Sessions/2026/2026-07-09_B4d_Tail_Collision_Grounding.md index d8ce16b8c..6f96724f5 100644 --- a/Docs/Vault/07_Sessions/2026/2026-07-09_B4d_Tail_Collision_Grounding.md +++ b/Docs/Vault/07_Sessions/2026/2026-07-09_B4d_Tail_Collision_Grounding.md @@ -64,11 +64,51 @@ RPC / ordering surface**). Validation ladder: baked `CollisionWorld` raycast sam enemy backstop re-validation (spawned Husks near refit cover keep moving — the Depenetrate/tangent-slide was tuned on the OLD shapes) · suite + operator feel pass. +## Part C — collision-fidelity pass EXECUTED (gate approved: full plan + large-solid-prop adds) + +**Built `Assets/_Project/Scripts/Editor/ColliderFitTools.cs`** (menu + programmatic Audit/Apply; idempotent — +regenerates ring segments + prop adds from the current visuals each run) and applied it to the subscene: + +- **Rings REBUILT at fine resolution**: 16/24/24 coarse segments → **54/82/82** (~3.5-4 u arcs), each segment's + inner face fitted to the innermost TORSO-band (y 0.9–2.5) cliff vertex in its arc. Two audit-driven corrections: + (1) the 0.2–3.0 walk band chased shin-high cliff *skirts* and pulled the base wall 30→24.75 flat, stranding + playable meadow; (2) at coarse arcs one jutting rock walled off a whole 12–14 u span — hence torso band + fine + arcs. Result: base wall tracks 22.1–29.7 (avg 25.1), expedition 44.5–51.2 (avg 47.6), zero clamps/no-samples. +- **Cover rocks**: 8 uniform boxes (4.2×4.2, axis-aligned) → **convex `MeshCollider`s of the actual + `CoverRock_*` render meshes** at the visuals' exact TRS. +- **Landmarks**: hint-matched claim-once OBB fits (first audit's nearest-largest heuristic double-claimed the + cabin for `LM_WaterWheel` and gave `LM_Sign` a tent). Cabin 6×6→5.8×8.1, Tent 4×4→4.5×4.5 (walk-into-building + fixed); Well 3×3→1.9×2.0, Sign 2×2→0.6×0.5, Artefact 3×3→2.4×1.5 (invisible walls removed); Warpgate + 8×2.5→8.3×6.8. +- **Adds (approved fork)**: 11 colliders on previously walk-through solid props gated by the LOCAL fitted wall + radius at each prop's angle — 1 meadow-tree trunk capsule + 2 sci-fi crates (base), wind-turbine poles ×2, + satellite dish, solar rig ×2 per survey camp (both expedition slots). 50 rim-decoration trees correctly + excluded (they stand in the cliff transition zone behind the fitted wall). +- **Spawn-safety pre-check**: player ring 2.5, wave ring 16, zone ring 14, room scatter ≤24, portal offset 5 — + all far inside every fitted wall; nothing gameplay-critical sits in the moved band. + +**New build gotcha (now in CLAUDE.md): a `MeshCollider` bakes ONLY if the mesh has Read/Write enabled** — the +first Play after Apply threw `InvalidOperationException` per bake and produced NO cover shapes (0/6 solid in the +baked `CollisionWorld`) while the classic scene view showed the colliders fine. Fixed by flipping `isReadable` +on `SM_Env_Rocks_Spikey_03.fbx` + `SM_Env_Rock_06.fbx` (PNB_Arid_Desert) → 8/8 solid. + +**Validation (all passed):** +- Baked-`CollisionWorld` probe (server): ring closure 32/32 rays per region inside the fitted band (expedition + 44.1–50.6; base ≤28.5, short hits = Core/crate structures); cabin solid at its true footprint; well + 1.7 u off-center FREE (old invisible wall gone); cover hulls 8/8 solid; **server==client static-body parity + (249 each)**. +- **Enemy stuck-fix backstop re-validated live**: an `EditorApplication.update` guardian delegate (new + harness pattern → validation-harness.md) kept the AFK player alive + parked across the room, embedded enemy + E5041 at the exact center of a cover hull, and took timed snapshots: E5041 was **depenetrated out of the hull + and moving** (993.00,6.00 → 991.26,5.80 in ~4 s), the other 4 enemies converged normally around cover to the + parked player. No freezes. +- EditMode suite green + console clean post-fix (bake exceptions gone). + ## Next-session intent -Execute the collision-fidelity pass per the gate answer → lighting/atmosphere pass → art-look decision -gate (pixel filter ON/OFF side-by-sides). The B5 split-panels focused Play VISUAL smoke is still pending -operator eyes (unfocused editor can't drive it). +Phase 1.5 continues: lighting/atmosphere pass → art-look decision gate (pixel filter ON/OFF side-by-sides). +Operator: eyeball the refit walls + cover rocks + new prop colliders in a real lap (fidelity is numeric-verified, +feel is not), plus the still-pending B5 split-panels visual smoke. Related: [[Iteration_2026-07_CoopHades]] · [[2026-07-07_Workflow_Consolidation]] · [[2026-07-07_Expedition_Enemy_Stuck_Harvest_Feedback]]