Docs: DR-052 SoD facing + underwater feel — build spec, session log, gotchas archive 07-16, skinned-kit cookbook recipe, CLAUDE.md facing contract (net-zero condensations)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: Facing & Underwater Feel — Build Spec (SoD facing + heavier movement + suit kit)
|
||||
date: 2026-07-15
|
||||
links: "[[DR-051_Lantern_Realignment_Purge]], [[Roadmap_Lantern_Slice]], [[Identity_Lantern]]"
|
||||
---
|
||||
|
||||
# Facing & Underwater Feel — Build Spec
|
||||
|
||||
Pre-code design review run `wf_a13d4395-1c7` (3 lenses, 25 findings → 21 confirmed / 3 refuted / 1 critic died on session-limit — its ordering claim was independently refuted by a sibling critic with full code evidence). This spec = the approved plan **as corrected by the review**. Operator forks locked 07-15: facing model (a) move-facing + cast-turn; suit = dome+tank+shoulder-lamp (no chest beacon); **keep cursor-dash** (Move→Aim→facing fallback); **dome + bare head** (sci-fi helmet removed).
|
||||
|
||||
## The review's blocking correction ★
|
||||
|
||||
**Fire directions do NOT read `PlayerInput.Aim` today — they read `PlayerFacing`** (AbilityFireSystem cFace :174 / aFace :209 / hFace :242 / rawAim :279 + auto-target seed :286; MeleeComboSystem face :163). Under move-facing every skillshot/cleave would fire along the travel direction. Fix (wire-neutral, both queries already carry `PlayerInput`): re-source all five sites to `FacingMath.ResolveAim(input.Aim, facing.Direction)` = normalize(Aim) if lengthsq>1e-6 else facing else (0,1). **`PlayerFacing` becomes body-yaw/presentation only.** Windup path keeps current-tick Aim (existing contract).
|
||||
|
||||
## Part B — facing rework (Simulation)
|
||||
|
||||
1. **`Simulation/Combat/TickWindowMath.cs`** (new): `SwingActive`/`FireActive`/`SocketFireAndCone` moved **verbatim** from PlayerAnimationDriveSystem (:118-162), window length stays a caller param. Add Movement-archetype skip (hoist the blob lookup, `continue` on `AbilityArchetype.Movement`) — used by BOTH the facing path and the anim path (kills the latent cooldown-tail phantom `IsFiring` from the blink socket; anim behavior change is a bug fix). Blink socket must never count as a cast (review: blink stamps its cooldown row → facing would yank toward cursor at the cooldown tail).
|
||||
2. **`Simulation/FacingMath.cs`** (new): `ResolveAim` (above) + `SelectTarget` + `RotateToward` (verbatim extraction of PlayerAimSystem :39-59). **One shared Aim→Move→hold cascade in BOTH branches** — castActive selects turn RATE + Aim-priority, never bypasses the cascade (gamepad Aim is zeroed at rest → a resting-stick cast must fall through to Move).
|
||||
3. **PlayerAimSystem**: target = castActive(melee swing window ∪ non-Movement socket windows) ? cascade-with-Aim-first : (Move | hold). Locomotion rate = `EffectiveCharacterStats.TurnRateRadiansPerSec` (knob-overridable), cast rate = const 1080°/s (knob-overridable). **No `IsFirstTimeFullyPredictingTick` gate — the rate-limited turn is an incremental integrator over the snapshot-restored [GhostField]; it must re-integrate on EVERY predicted pass** (document in header, DashSystem wording). Add `[UpdateAfter(typeof(MeleeComboSystem))]` — optional hygiene pin (cycle-free, verified against the full predicted-group edge set; sorter tie-break is deterministic and cross-world-identical, so this pins same-tick cast-window semantics, not a divergence fix). Socket windows open 1 tick late by construction (AbilityFire stamps after PlayerAim) — acceptable, cosmetic-only once fire directions are decoupled.
|
||||
4. **DashSystem :67 + BlinkSystem :101**: stationary fallback Move → **Aim** → facing (operator: keep cursor-dash). Update the :64-65 comment.
|
||||
5. **AimReticleSystem**: add `RefRO<PlayerInput>`; gamepad ring + tether axis from `ResolveAim(Aim, facing)` (tether stays consistent with the server assist cone because the assist seed also moves to Aim).
|
||||
6. **CombatFeedbackSystem**: LOCAL socket cue (:330-335) + melee arc (:409-413) direction from `FacingMath.ResolveAim(Aim, facing)` — the SAME resolver as the sim fire sites, so cue == damage direction in every case *(amended post-impl: the draft's literal Aim→Move→facing could diverge from damage on a moving resting-stick gamepad cast)*; remote arcs stay facing-based (Aim not replicated to non-owners; asymmetry documented at UpdateRemoteSwings).
|
||||
|
||||
## Part C — heavier movement (all coupled sites together ★)
|
||||
|
||||
- Sharpness 15→6: `CharacterComponent.DefaultGroundedSharpness` const AND `Player.prefab` serialized `GroundedMovementSharpness: 15`→6 AND DashSystemTests literal 15f assertions (:94/:113/:207/:230) → const reference. (DashSystem's non-dash branch restores to the const EVERY tick — a prefab-only edit is stomped within one tick.)
|
||||
- Turn rate 720→360: **`Character_Default.asset`** `TurnRateDegreesPerSec` (the asset — serialized wins) + `CharacterStatsDefinition.cs:18` initializer hygiene. Re-bake accepted (DependsOn; no ghost-hash change).
|
||||
- **Knobs** (full checklist in one pass): `TuningKnob.TurnRateDeg=26, CastTurnRateDeg=27, MoveSharpness=28, Count=29` (retired 20-23 untouched). Semantics: **0 = no override** (use stat/const/authored). Extend Defaults(0)/explicit ClampKnob case (`max(0f,v)` — must NOT fall into the default ≥1 branch)/Apply/Get/ToReport/FromReport/`DebugTuningReport` fields (unconditional, no #if)/TuningConfigTests pin/DebugOverlay rows. Consumption: PlayerAimSystem rates; sharpness override at the restore sites (DashSystem :97/:101, BlinkSystem :127, PlayerDeathStateSystem :51) so the knob is live within a tick. **Dev-protocol bump**: DebugTuningReport layout changes → a stale standalone dev build refuses the handshake vs a fresh peer; expected, rebuild both.
|
||||
|
||||
## Part D — footsteps + gait (client-only)
|
||||
|
||||
- Stride-distance footsteps (accumulate planar distance, step every `FootstepStrideMeters`≈1.5, + a 0.18s cadence floor so a dash can't machine-gun thuds — post-impl review), heavier clip (~100Hz, longer decay, noise), jitter *(shipped as 3 fixed pitch-variant clips 95/108/120Hz + ±12% volume jitter — `PlayClipAtPoint` has no pitch control)*, silt-puff particle per step. New FeelConfig fields.
|
||||
- Locomotion blend state speed ~0.85 + idle↔locomotion transitions ~0.25s via AnimatorController API (PlayerRigTools).
|
||||
|
||||
## Part A — suit kit (art)
|
||||
|
||||
Blender export was missing the armature (FBX had no skin — cause under diagnosis; re-export with verified selection). Kit = `SM_Suit_KitBrass` (940 tris, Head/Spine_03/Clavicle_L rigid-skinned) + `SM_Suit_KitGlow` (104 tris) → FBX → `AttachBathynautKit` re-binds SMRs by bone name onto Player.prefab. Brass = `M_Skinned_Palette`; glow = new `ProjectM/EmissiveGloamSkinned` (hand-written HLSL + Rukhanka `ComputeDeformedVertex`, DOTS-instanced `_DeformedMeshIndex`) on `M_EmissiveGloam_WarmSkinned` (steady warm). Plus: **remove `SM_Chr_Attach_SpaceSoldier_Male_Helmet_01`, graft the bare head** (Bathynaut material).
|
||||
|
||||
## Tests / validation
|
||||
|
||||
FacingMathTests (cascade incl. resting-stick cast; RotateToward step/snap), TickWindowMathTests (windows + Movement skip + wrap), DashSystemTests → const, SystemOrderingCycleTests + PlayerAimSystem (+PlayerControl/Blink) in the fixture, TuningConfigTests knob pins. L1 console clean · L2 suite green + Play smoke (server==client PlayerFacing under injected input) · L3 suit + steps screenshots. Post-impl diff review (same lenses).
|
||||
|
||||
## Deferred (surfaced, not silent)
|
||||
|
||||
- `Ability_Blink.asset` CooldownTicks 1 vs BlinkSystem's 150 stamp (HUD bar + window-math hygiene) — align later.
|
||||
- Skinned EG shader on non-DOTS/classic path renders undeformed (BRG-only by design, like all EG-skinned materials).
|
||||
- Bathynaut body still over hero tri budget (game-ready decimate pass parked since 07-14; kit adds ~1044).
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: 2026-07-16 — SoD facing, underwater feel, Bathynaut kit in-engine
|
||||
date: 2026-07-16
|
||||
links: "[[DR-052_SoD_Facing_Underwater_Feel]], [[Facing_Underwater_Feel_Build_Spec]], [[DR-051_Lantern_Realignment_Purge]], [[Art_Direction_Lantern]]"
|
||||
---
|
||||
|
||||
# 2026-07-16 — SoD facing, underwater feel, Bathynaut kit (movement/animation tuning session 1)
|
||||
|
||||
Operator brief (07-15, /art-dev + /dots-dev): get the lamp/helmet/etc. in-engine on the character; kill rotate-to-cursor — facing "exactly like Shape of Dreams"; heavier underwater movement; heavier animation + footstep sounds; gap-analyze the movement+animation combo.
|
||||
|
||||
Forks locked by operator: facing model (a) move-facing + cast-turn + idle-hold · suit = dome+tank+shoulder lamp, **no chest beacon** · **keep cursor-dash** (stationary dash/blink fallback Move→Aim→facing) · **dome + bare male head** (Synty sci-fi helmet removed).
|
||||
|
||||
## Shipped (working tree, uncommitted — 22 modified + new files)
|
||||
|
||||
### B — Shape-of-Dreams facing (the rework, as corrected by the pre-code review)
|
||||
- **Pre-code design review `wf_a13d4395-1c7`** (3 lenses → 25 findings → 21 confirmed / 3 refuted / 1 critic died on session-limit; the dead critic's ordering claim was independently refuted by a sibling with full code evidence). **Blocking catch: fire directions did NOT read raw Aim — every archetype + the melee cleave aimed from `PlayerFacing`**; under move-facing every skillshot would have fired along the travel direction. The Build Spec ([[Facing_Underwater_Feel_Build_Spec]]) records all verdicts.
|
||||
- `FacingMath` (new, Simulation): `ResolveAim` (THE fire-direction resolver: Aim→facing→+Z), `SelectTarget` (shared Aim→Move→hold cascade; castActive grants Aim *priority* only — a resting gamepad stick mid-cast falls to Move), `RotateToward` (verbatim extraction).
|
||||
- `TickWindowMath` (new, Simulation/Combat): `SwingActive`/`FireActive`/`SocketFireAndCone` moved verbatim from PlayerAnimationDriveSystem (window length stays a caller param) + **Movement-archetype skip** — a blink is a dodge, never a cast; also kills the latent cooldown-tail phantom `IsFiring` pulse. Anim path now shares the same code.
|
||||
- `PlayerAimSystem`: castActive = melee swing ∪ non-Movement socket windows; locomotion rate = stat (360°/s), cast rate = const 1080°/s, both knob-overridable; **no `IsFirstTimeFullyPredictingTick` gate** (incremental integrator over the snapshot-restored [GhostField] — documented in header); `[UpdateAfter(MeleeComboSystem)]` hygiene pin (cycle-free, verified; sorter tie-breaks are deterministic cross-world so this pins semantics, not a divergence fix).
|
||||
- **Fire-direction decoupling**: AbilityFireSystem (cone :174 / aoe :209 / hitscan :242 / projectile+assist-seed :279) + MeleeComboSystem cleave (:163) → `FacingMath.ResolveAim(input.Aim, facing)`. PlayerFacing = body yaw only. Windup keeps current-tick Aim (existing contract).
|
||||
- Presentation coupled to the damage source: AimReticleSystem gamepad ring + lock-on tether, CombatFeedbackSystem local socket cue + melee arc (remotes stay facing-based — Aim isn't replicated to non-owners, documented asymmetry).
|
||||
- DashSystem/BlinkSystem stationary fallback → Move→**Aim**→facing (cursor-dash kept).
|
||||
|
||||
### C — Heavier underwater movement
|
||||
- `DefaultGroundedSharpness` 15→6 — **all coupled sites together** (const + Player.prefab serialized value + 4 DashSystemTests assertions → const refs; the review confirmed DashSystem's every-tick restore stomps a prefab-only edit within one tick).
|
||||
- `Character_Default.asset` TurnRateDegreesPerSec 720→360 (the asset, not just the initializer).
|
||||
- TuningKnob 26/27/28 (`TurnRateDeg`/`CastTurnRateDeg`/`MoveSharpness`), Count=29, **0 = no-override sentinel** (explicit ClampKnob case ≥0 — the default ≥1 branch would force a 1-unit override); all six maps + `DebugTuningReport` fields extended (**dev-protocol bump**: a stale standalone dev build will refuse the handshake vs a fresh peer — expected, rebuild both) + DebugOverlay rows + TuningConfigTests pin. Sharpness knob honored at all 4 restore sites (dash tail/idle, blink, death).
|
||||
|
||||
### D — Heavier animation + footsteps
|
||||
- Stride-distance footsteps (`FootstepStrideMeters` 1.5m; accumulate planar travel → cadence tracks the drifting velocity), 3 deep-thud clip variants (95–120Hz noise sweeps, decay 7) + ±12% volume jitter + a dark silt puff at the feet (new `SiltPuff` pool emitter). Old fixed-interval timer + `FootstepIntervalSec` deleted.
|
||||
- `RetimeLocomotionGait` (PlayerRigTools): Locomotion blend-state speed 0.85, idle⇄locomotion blends 0.25s (AnimatorController API).
|
||||
|
||||
### A — Bathynaut kit in-engine (art track)
|
||||
- Blender: 33 kitbash pieces rigid-skinned to Head/Spine_03/Clavicle_L (vgroup w=1 + armature modifier, saved in the master), joined per shader role → `SM_Suit_KitBrass` (940 tris) + `SM_Suit_KitGlow` (104: porthole glass + lamp lens), FBX to `ArtSource/Blender/`. ChestLamp + LampRim excluded per fork.
|
||||
- Unity: `PlayerRigTools.AttachBathynautKit` — grafts the kit SMRs + the bare male head onto Player.prefab's flattened skeleton by bone name (in place, GUID preserved, ghost surface unchanged); removes the Synty sci-fi helmet. **GraftSmr REBASES**: verts baked to rest-world space, bindposes = inverse of **rigid (scale-stripped)** rest matrices, `RecalculateTangents()` — persisted as `Rebased_*.asset` meshes (GUID-stable Clear+refill).
|
||||
- New `ProjectM/EmissiveGloamSkinned` shader (hand-written HLSL + Rukhanka `ComputeDeformedVertex`, in-place skinning) on `M_EmissiveGloam_WarmSkinned` (steady warm gold — true light): porthole + lamp lens glow and DEFORM.
|
||||
- Player.prefab children now: Root skeleton · body · armour · KitBrass · KitGlow · bare head. Suit tris ~8.9k (body 7.9k + kit 1k) — still over the ≤6k hero budget; decimate pass stays parked (07-14).
|
||||
|
||||
## Validation
|
||||
|
||||
- L1: console clean (only known tick-batching noise from execute_code stalls).
|
||||
- L2: **409/409 EditMode green** (+19: FacingMathTests 11, TickWindowMathTests 7 incl. the Movement-skip + resting-stick-cast cases, TuningConfigTests sentinel pin; SystemOrderingCycleTests now co-registers PlayerAim/PlayerControl/Blink/PlayerDeathState).
|
||||
- Play smoke (DevSandbox, client+server): **server==client facing under injected input**; move-east → facing (1,0) both worlds; **idle + aim-north holds facing** (no passive cursor tracking); cast opens → facing swings fully north at cast rate and returns; blink socket does NOT open a cast window; **projectile fired while moving east flies (0.00, 1.00) = raw Aim** — the SoD manual-aim contract, live. World creation clean (ordering pin acyclic).
|
||||
- L3: screenshots (`Assets/Screenshots/suitkit_front_glow.png`, `suitkit_back_rigid.png`) — brass dome + glowing amber porthole behind the grille + shoulder lamp from the front; dome crown + tank pack silhouette from the back/game angle. Kit deforms with the rig.
|
||||
- Post-impl diff review `wf_9a8d6162-e72` (20/20 agents, no failures): **17 findings → 15 confirmed (0 blocking: 3 should-fix + 12 nits) / 2 refuted.** All triaged and closed same-session:
|
||||
- **Fixed in code**: blink no longer fires the muzzle/fire cue (the third SocketCooldown consumer got the Movement skip); footsteps got a 0.18s cadence floor (a dash could machine-gun 2–4 thuds); `GraftSmr` now validates the bone rebind BEFORE destroying the old child (a mismatch used to silently strip the piece) + a rigid-skinning guard (`weight0<0.999` aborts) + `rebase:false` for the meter-scale blend-skinned head (tool now reproduces the committed prefab); orphaned doc-blocks deleted from PlayerAnimationDriveSystem; `k_AttackAnimTicks` now structurally = `PlayerAimSystem.CastFacingTicks`; dead ResolveAim re-guard removed from AimReticleSystem; remote-arc asymmetry documented at UpdateRemoteSwings; wrap (0-sentinel) + no-blob tests added to TickWindowMathTests. **Suite 411/411 green after fixes.**
|
||||
- **Docs amended**: Build Spec B.6 (local FX = ResolveAim, deliberately better than the draft cascade — cue==damage in every case) + Part D (pitch jitter shipped as 3 clip variants + volume jitter).
|
||||
- **Accepted**: the Move→Aim→facing cascade is duplicated verbatim in DashSystem/BlinkSystem (byte-identical, commented; a `ResolveDashDir` helper is available cleanup if a third site ever appears).
|
||||
|
||||
## Gotchas learned (new, durable)
|
||||
|
||||
1. **Blender skinned-kit export: a HIDDEN armature can't be selected → `use_selection` FBX export silently drops the skeleton + all vgroups** (the mesh imports as static MeshRenderers). `hide_set(False)` before selecting; restore after.
|
||||
2. **Blender→Unity skinned roundtrip imports cm bones under a 0.01 armature** (regardless of FBX_SCALE_UNITS vs FBX_SCALE_ALL) while Synty-native skeletons are meter-scale. **Rebind by bindpose reuse EXPLODES (×100)**. The fix that works: rebase at graft time — bake verts to rest-world, bindposes = inverse of **rigid (scale-stripped)** rest matrices (`Matrix4x4.TRS(pos, m.rotation, one).inverse`).
|
||||
3. **A procedural skinned Mesh asset without TANGENTS fails Rukhanka/BRG registration** (`BatchMeshID not present` + assertion spam, whole rig vanishes) — `RecalculateTangents()` mandatory.
|
||||
4. **Hand-written Rukhanka deformation shaders**: the `UNITY_DOTS_INSTANCING_START` block with `_DeformedMeshIndex` must be declared **BEFORE** including `ComputeDeformedVertex.hlsl` (macro expands at include time → else "undeclared identifier ..._DOTSInstancingOverrideMode" only in the DOTS_INSTANCING_ON variant = magenta), AND `_DeformedMeshIndex` must ALSO be a Properties-block entry — Rukhanka's SkinnedMeshBaker validates `material.HasProperty`.
|
||||
5. Synty variant containers hold BOTH genders' heads — match grafts by exact name (`Contains("Head")` grabbed the female head first).
|
||||
6. `manage_asset rename` can half-fail (moved the asset to `Assets/` root, extensionless, while reporting an error) — verify on disk; a plain file copy + `refresh_unity force` is the reliable fallback.
|
||||
|
||||
## Follow-ups (surfaced, not silent)
|
||||
|
||||
- `Ability_Blink.asset` CooldownTicks=1 vs BlinkSystem's 150-tick stamp (HUD bar + window-math hygiene) — align to 150 later.
|
||||
- Bathynaut game-ready decimate pass (~8.9k tris vs ≤6k hero budget) — parked since 07-14.
|
||||
- EmissiveGloamSkinned is BRG-only by design (invisible in plain classic scenes — same class as all EG-skinned materials).
|
||||
- Operator eyes-on tuning pass: knobs live in the DevSandbox overlay (Turn rate deg / Cast turn deg / Move sharp + the melee/dash rows); FeelConfig footstep values compile-time for now.
|
||||
|
||||
## Part E — gap analysis (the operator deliverable)
|
||||
|
||||
What the movement+animation combo still lacks for the underwater-heavy feel, in recommended order:
|
||||
1. **Idle sway/breathing** — the suit stands statue-still; a subtle full-body idle drift (Blender clip on the humanoid pipeline) would sell suspension-in-water more than any tuning knob.
|
||||
2. **Start/stop weight reads** — sharpness 6 gives the velocity drift, but there's no lean-in/lean-back pose; a 2-frame lean overlay driven off acceleration (AnimParamMath already computes the basis) is the cheap version.
|
||||
3. **Bubble exhaust** — periodic bubble trickle from the dome (pool emitter, warm-neutral, rises) synced loosely to the footstep cadence; strongest cheap underwater cue after the silt puffs.
|
||||
4. **Turn lean/banking** — body roll proportional to the facing turn rate (client-only, presentation quaternion tweak).
|
||||
5. **Camera weight** — PrototypeCameraRig positional lag/damping scaled up slightly so the camera "drags" through water with the player.
|
||||
6. **Underwater ambience loop** — procedural low rumble + occasional distant groans; the soundscape is currently just SFX.
|
||||
7. **Walk-cycle authoring** — the retimed Synty walk still reads "land walk slowed down"; a Blender heavy-trudge clip (lead with the chest, delayed foot plants) is the real fix per the humanoid clip pipeline.
|
||||
|
||||
## Next session
|
||||
|
||||
Operator eyes-on feel pass with the live knobs (turn rates, sharpness, footstep values), then pick from the gap list (recommend 1+3 first). Post-impl review findings (wf_9a8d6162-e72) to triage if any confirmed.
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: DR-052 — Shape-of-Dreams facing model + underwater movement feel
|
||||
date: 2026-07-16
|
||||
status: locked
|
||||
links: "[[2026-07-16_Facing_Underwater_Feel_Suit_Kit]], [[Facing_Underwater_Feel_Build_Spec]], [[DR-048_Lantern_Adoption_Full_Pivot]], [[DR-051_Lantern_Realignment_Purge]]"
|
||||
---
|
||||
|
||||
# DR-052 — Shape-of-Dreams facing model + underwater movement feel
|
||||
|
||||
## Decisions (operator-locked 07-15/16)
|
||||
|
||||
1. **The facing model is SoD option (a)**: the body turns toward the MOVEMENT direction while moving; turns toward the AIM only during a cast window (melee swing / non-Movement socket fire, `CastFacingTicks`=13 ≈ the anim pulse); holds the last facing when idle. **The cursor is never passively tracked.** Twin-stick cursor-facing is dead.
|
||||
2. **`PlayerFacing` is body-yaw/presentation ONLY.** Every gameplay direction (all four AbilityFireSystem archetypes, the auto-target seed, the melee cleave) reads `FacingMath.ResolveAim(PlayerInput.Aim, facing)` — raw replicated Aim, facing fallback for a resting gamepad stick, +Z last. Aim-consuming presentation (reticle ring, tether axis, local slash/cone cues) reads the SAME resolver so sim and FX cannot diverge; remote players' cues stay facing-based (Aim isn't replicated to non-owners).
|
||||
3. **A Movement-archetype socket (blink) never counts as a cast** — `TickWindowMath.SocketFireAndCone` skips it outright (facing AND animation paths; this also killed the latent cooldown-tail phantom IsFiring).
|
||||
4. **Stationary dash/blink keep going toward the cursor** (fallback Move→Aim→facing) — cursor-dodge control kept deliberately over SoD purity.
|
||||
5. **Underwater weight defaults**: `GroundedMovementSharpness` 6 (was 15), locomotion turn 360°/s (was 720), cast turn 1080°/s const; MoveSpeed unchanged (6). Locomotion gait ×0.85, idle⇄locomotion blends 0.25s. Footsteps are stride-distance (1.5m) deep thuds + silt puffs.
|
||||
6. **Live tuning rides TuningKnob 26–28 with a 0 = NO-OVERRIDE sentinel** (0 falls back to stat/const/authored; explicit ClampKnob ≥0 case). Extending `DebugTuningReport` is an accepted **dev-protocol bump** (stale standalone dev build ⇒ handshake refusal ⇒ rebuild both).
|
||||
|
||||
## Determinism/netcode contract (from review wf_a13d4395-1c7, confirmed)
|
||||
|
||||
- Wire-neutral apart from the dev report bump: no `[GhostField]`/RPC/input-struct changes; PlayerFacing stays the only replicated facing state.
|
||||
- PlayerAimSystem stays **un-gated** (no `IsFirstTimeFullyPredictingTick`) — the rate-limited turn is an incremental integrator over the snapshot-restored ghost field and must re-integrate every predicted pass.
|
||||
- `[UpdateAfter(MeleeComboSystem)]` on PlayerAimSystem is a **hygiene pin**, not a divergence fix — the sorter's tie-break is deterministic and cross-world-identical (confirmed by critic evidence; the "cross-world sort divergence" claim was refuted). Socket windows open 1 tick late by construction — cosmetic-only since damage is Aim-sourced.
|
||||
|
||||
## Suit attachment pipeline (the reusable recipe)
|
||||
|
||||
Blender kitbash attachments → rigid-skin (vgroup w=1 + armature modifier) → join per shader role → FBX (UNHIDE the armature first — hidden = silently skinless) → `PlayerRigTools.AttachBathynautKit`: bone-name rebind + **rebase** (verts to rest-world; bindposes = inverse of RIGID scale-stripped rest matrices; `RecalculateTangents`) → `Rebased_*.asset` meshes. Glow pieces ride `ProjectM/EmissiveGloamSkinned` (Rukhanka ComputeDeformedVertex; DOTS-instanced block BEFORE the include; `_DeformedMeshIndex` in Properties for the baker's validation).
|
||||
@@ -482,3 +482,23 @@ The surviving invariants (ledger spend-in-place soft-fail; snapshot-above-early-
|
||||
- **Automation (server-only):** catch-up `ProductionMath.CyclesDue` **lower-bound 0**; `RuntimePlacedTag`=player-built. [[DR-020_M7_Automation_Production_Chains]].
|
||||
- (Persistence bullet, pre-v7 form): **born-correct load** — `CycleDirectorSpawnSystem` stages `PendingSave` AT SPAWN; `BaseRestoreSystem` replays structures charge-free + REMAINING-tick cooldowns + HP. `SaveService.Load` = additive floor `[MinLoadableVersion=2, Current]` (old saves load; missing field 0-defaults).
|
||||
- (Netcode bullet, pre-purge form): **Shared GLOBAL state (cycle phase, resource ledger, goal meter) rides an UNTAGGED ghost**, never a region-tagged one (`SetIsIrrelevant` would hide it cross-region). Resolve the ledger via its DISTINCT `ResourceLedger` tag (the multi-`StorageEntry` "multiple instances" rule — EB-2 line).
|
||||
|
||||
## 2026-07-16 — facing/underwater-feel session condensations (pays the SoD facing contract + the skinned-attachment recipe)
|
||||
|
||||
Condensed from CLAUDE.md 07-16; the inline bullets keep the operational core, verbose forms preserved here.
|
||||
|
||||
- **Old "Aim controls" bullet (pre-DR-052, superseded):** Client-derived aim on `PlayerInput.Aim`; scheme byte KBM=0/Gamepad=1; reticle re-raycasts inside `AimReticleSystem` → full detail: archive 2026-07-06 section + the source files. *(Superseded by the SoD facing model — [[DR-052_SoD_Facing_Underwater_Feel]]: PlayerFacing = body-yaw only; fire directions read `FacingMath.ResolveAim`.)*
|
||||
- **Dark-lit screenshot / material values (full form):** `shader.GetPropertyType(idx)`-guard before `GetColor`/`GetFloat`/`GetTexture` (`S_General`'s `_BaseColorMultiply` is a float → `GetColor` returns black). Gate emission on the `_Emissive` flag + a fixture name; keep converted env metallic low (0.1–0.2).
|
||||
- **EG per-instance tint (full form):** works only if the graph's `_BaseColor` is Hybrid-Per-Instance (ShaderGraph `overrideHLSLDeclaration:true`+`hlslDeclarationOverride:2`). `AnimatedLitShader` is DOTS-authored so enemies flash; a stock Synty prop graph (`Generic_Basic`) is Unity-Per-Material → the override renders but silently no-ops. Fallback = procedural decal quads (07-12 cover damage-cracks, Part P).
|
||||
- **Asset-free presentation (full form):** runtime `ParticleSystem` pool uses Sprites/Default + HDR start color; ACES tonemapping needs URP color grading mode = HDR (`m_ColorGradingMode=1`).
|
||||
- **New ghost prefab recipe (full form):** `manage_prefabs modify_contents` swaps the authoring MonoBehaviour (strip MeshFilter+MeshRenderer for an invisible state-holder); subscene wiring sequence `manage_scene load additive` → `set_active_scene Gameplay` → create+verify → `save` → `close_scene`.
|
||||
- **Old condensation-history parentheticals:** 07-07b paid the attribute-swallow gotcha · 07-07c = game-state narrative → invariants+DR pointers (~3 KB freed, operator-ordered) · 07-13 = co-op-Hades core-loop bullet → LANTERN direction pointer ([[DR-048_Lantern_Adoption_Full_Pivot]]) · 07-15 = siege-era/automation/GoalProgress bullets retired with the DR-051 purge · 07-16 = this heading.
|
||||
- **Stack-table trivia:** packages-lock reconcile 2026-06-17 pinned test-framework 1.7.0, ugui 2.5.0, multiplayer.center 1.0.1; `com.unity.ai.assistant` was removed 07-04 for console noise. serena MCP was removed 2026-07-07 (unused in practice + flaky on Unity).
|
||||
|
||||
### The 07-16 skinned-attachment session's full failure chain (for the record)
|
||||
1. Hidden Blender armature → `select_set` no-op → FBX exported skinless (meshes imported as static MeshRenderers, no vgroups). Fix: `hide_set(False)` before selection-export.
|
||||
2. Blender FBX roundtrip (both FBX_SCALE_UNITS and FBX_SCALE_ALL) imports cm bones under a 0.01-scale armature; Synty-native skeletons are meter-scale. Raw bindpose reuse on rebind → skin matrices ×100 (kit rendered 140 m in the air). Fix: rebase — verts baked to rest-world, bindposes = inverse of RIGID (scale-stripped) rest matrices.
|
||||
3. Procedural skinned Mesh asset without tangents → Rukhanka/BRG `BatchMeshID not present` + assertion spam, the whole rig invisible. Fix: `RecalculateTangents()`.
|
||||
4. Hand-written Rukhanka deformation shader: `UNITY_DOTS_INSTANCING_START` block with `_DeformedMeshIndex` must precede the `ComputeDeformedVertex.hlsl` include (macro expands at include time; else "undeclared identifier `_DeformedMeshIndex_DOTSInstancingOverrideMode`" in the DOTS_INSTANCING_ON variant = magenta), and `_DeformedMeshIndex` must also exist in the Properties block (SkinnedMeshBaker validates `material.HasProperty`).
|
||||
5. Synty variant containers hold both genders' heads — graft by exact name, purge wrong-variant children for idempotency.
|
||||
6. `manage_asset rename` half-failed (moved the asset to `Assets/` root, extensionless, while reporting an error) — verify on disk; plain file copy + `refresh_unity force` is the reliable fallback.
|
||||
|
||||
Reference in New Issue
Block a user