KB: task #1 landings -- update-record channel DONE, movementMode=simulationState identification swept
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
c9f0c2a7f1
commit
e8b9f71025
@@ -284,6 +284,13 @@ Full decomp map of the death path. Two tiers:
|
||||
kill → full chain (blhdead → wreck swap → smoke → sink → burial → INERT). [T2]
|
||||
- `Mech::IsDestroyed()` (`FUN_0049fb54`) = `movementMode==2||9` (reconstructed as `IsDisabled`, btstubs.cpp);
|
||||
`FUN_004ab1c8` freezes locomotion (zeros mech+0x298) when destroyed.
|
||||
**IDENTIFICATION (task #1, 2026-07-11): `movementMode` (mech+0x40) IS
|
||||
`Simulation::simulationState.currentState`** -- the StateIndicator @0x2c (+0x10 oldState,
|
||||
+0x14 currentState); every binary "movementMode write" is a `SetLevel(this+0x2c, n)` call.
|
||||
The port's parallel `int movementMode` member is gone: `MovementMode()/SetMovementMode()`
|
||||
accessors ride the engine StateIndicator, which is why the death state (9) now REPLICATES --
|
||||
it travels in every update record's header (+0xC) and the observer's replicant runs its own
|
||||
wreck sink off it (see [[multiplayer]] "Mech-level update records"). [T1]
|
||||
- **`MechDeathHandler`** (ctor `FUN_0042a984` + Performance `FUN_0042aa2c`, cached mech+0x850 / `mech[0x214]`) —
|
||||
the **per-subsystem destroyed-skin + explosion engine**. Each tick walks the damage subsystems
|
||||
(mech+0x120[mech+0x11c]); as a subsystem's damage crosses a descriptor-table threshold (`FUN_0042a5f4`
|
||||
|
||||
+52
-6
@@ -6,7 +6,7 @@ source_sections: "PROGRESS_LOG.md §7 (Phase 7), §8 (P6); docs/HARD_PROBLEMS.md
|
||||
related_topics: [wintesla-port, combat-damage, locomotion, decomp-reference]
|
||||
key_terms: [master, replicant, EGG, dead-reckon]
|
||||
open_questions:
|
||||
- "pod-LAN config (real IPs); update-record velocity from the body-channel projection; peer SimulationState/DropZoneLocation replication (authentic peer warp spheres); Mech-level update records @0x4a0c2c (in progress)"
|
||||
- "pod-LAN config (real IPs); update-record velocity from the body-channel projection; peer SimulationState/DropZoneLocation replication (authentic peer warp spheres); stream the model deadband constants (UpdatePositionDiffrence et al) to the update-record senders"
|
||||
---
|
||||
|
||||
# Multiplayer
|
||||
@@ -188,6 +188,55 @@ from the leg channel); the binary publishes the BODY channel's smoothed projecti
|
||||
disasm +0x2a0). Swapping the source is a fidelity refinement DEFERRED — it risks a verified working feed
|
||||
for a smoothing nuance. [T3 on that nuance]
|
||||
|
||||
## Mech-level update records (task #1, 2026-07-11) — DONE [T1 transcription / T2 live]
|
||||
|
||||
The 9-type Mech record channel is LIVE end-to-end: **writer @004a0c2c** transcribed
|
||||
instruction-for-instruction from `reference/decomp/mech_writeupdate_004a0c2c.disasm.txt`, **reader
|
||||
@004a1232** rewritten from part_012.c:9576-9692 with every Wword absorber promoted to the NAMED
|
||||
engine/port member. Wire sizes verified live (0x14/0x20/0x2c/0x78). Key mechanics:
|
||||
|
||||
- **Record type == the `updateModel` BIT INDEX** (`Simulation::WriteSimulationUpdate` walks the
|
||||
mask, SIMULATE.cpp:302-328; binary twin FUN_0041bd98). Request = `Mech::ForceUpdate(1<<N)`
|
||||
(@0x4a4c54: `updateModel |= mask`, `&= 0xfe03` filter when disabled). THREE prior mislabels of
|
||||
the same binary fns are retired: `SetInstanceFlags` and `RequestActionFlags` (both @0x4a4c54 —
|
||||
+0x18 is `Simulation::updateModel`, NOT entity flags) and `IsNetworkCopy` (@0x49fb54 =
|
||||
`IsDisabled`, simulationState 2||9).
|
||||
- **`movementMode` == `Simulation::simulationState.currentState`** (binary mech+0x40 =
|
||||
StateIndicator@0x2c +0x14; oldState @+0x3c). The port's parallel `int movementMode` member is
|
||||
GONE — `MovementMode()/SetMovementMode()` accessors ride the engine StateIndicator, so the state
|
||||
(death 9 / limbo 2 / airborne 3,4) replicates in EVERY record header (+0xC) and the replicant
|
||||
tracks the master automatically.
|
||||
- **Every record tail = the mapper's `speedDemand`** (subsystemArray[0]+0x128) mirrored into
|
||||
`bodyTargetSpeed@0x6b4` on both sides — the authentic replicant-gait feed (it was misread as a
|
||||
"sequence number"; the type-2 record exists solely to ship it on change). Task #50's
|
||||
velocity-derived gait stays as the leg-channel driver meanwhile.
|
||||
- **Types**: 0 pose (Mover record + tail; orientation SAVED/RESTORED around the base call — it
|
||||
rides ONLY type 4), 1 damage zones (engine), 2 speedDemand, 3 leg-state+stability (write-through
|
||||
body dispatch both sides), 4 orientation+angular-velocity resync (euler-encoded, quat
|
||||
normalized), 5 knockdown (SetBodyAnimation 0x20 both sides), 6 death, 7 impact (fields only),
|
||||
8 airborne/reverse selector. 5/6/7 share the 0x2c heat/throttle/fall-basis payload.
|
||||
- **Senders wired byte-exact** (the perf-loop + event map recovered from 27 binary call sites):
|
||||
gait transitions `Force(8)` (mech2 — already transcribed under the RequestActionFlags mislabel,
|
||||
masks matched the binary exactly), knockdown `Force(1|0x20)` (mech4), death `Force(1|0x40)`
|
||||
BEFORE `SetMovementMode(9)` (the disabled filter would mask it after), `Reset` `Force(0x1f)` +
|
||||
the binary zero-set (state 0, cycle/target speeds, poseSyncLatch), perf-loop deadbands: position
|
||||
→ type 0, orientation deviation → type 4, speedDemand change → type 2, heat-level change → type
|
||||
7 (snapshot @0x780). [T3 deadband thresholds — the model record's `UpdatePositionDiffrence` /
|
||||
`UpdateTurnVelocityDiffrence` / `UpdateTurnDegreeDiffrence` fields (+0x26..0x28) are the
|
||||
authentic constants, not yet streamed to the runtime members +0x768/+0x76c/+0x770.]
|
||||
- **VERIFIED 2-node**: types 2/3/4 flow while driving; kill → B emits ONE type-6 (simState=9 in
|
||||
the header) → A's replicant flips to MovementMode 9 and its own `UpdateDeathState` runs the
|
||||
wreck-sink loop on the OBSERVER's screen (smoke re-arm logged on A; NO double death transition,
|
||||
NO replicant VehicleDead) — the death SINK/burial gap (old item 3) is CLOSED. Respawn:
|
||||
`Force(0x1f)` burst snaps the replicant to the drop zone + un-wrecks it. Walking replicant
|
||||
un-regressed (run states 10→12, legCycle tracking, with type-3 records flowing). Solo clean.
|
||||
- Telemetry: `[mrec-tx]/[mrec-rx]` per non-pose record (BT_REPL_LOG). Note the type-1 rx line
|
||||
prints a bogus simState (the damage record's own layout at +0xC) — cosmetic.
|
||||
- New by-name members: `poseSyncLatch@0x77c` (dead-reckon re-base latch, consumed by
|
||||
FUN_004ab1c8), `fallDirection@0x4a8` + `fallScalar@0x4b4` [T4 names], `heatLevelSnapshot@0x780`.
|
||||
A TU-local stub type forced the `BTMapperSpeedDemandRaw(void*)` bridge (mech.cpp carries a local
|
||||
`struct MechControlsMapper` recon stub — typed cross-TU signatures mangle differently).
|
||||
|
||||
## Remaining (P6 phase 4 / Phase 7)
|
||||
The pod-LAN config (real IPs, bare-IP pilot entries); update-record velocity sourced from the body-channel
|
||||
projection (above). See [[open-questions]]. [T3]
|
||||
@@ -310,11 +359,8 @@ transition, HUD all landed since P6): console egg → mesh → RunningMission on
|
||||
(base ran, nothing serialized); and `recordLength` must be each level's sizeof or the stream
|
||||
framing misparses. VERIFIED 2-node: A fires 57 volleys → 225 records → B applies 225 → draws 414
|
||||
replicant beams (PPC blue / laser red from A's replicant's gun ports). Solo un-regressed.
|
||||
REMAINING (deferred): the MECH-level writer @0x4a0c2c (recovered + preserved:
|
||||
`reference/decomp/mech_writeupdate_004a0c2c.disasm.txt`; 9 record types decoded — 0/1/4 pose
|
||||
variants, 2 alarm, 3 leg-state+heat with body-channel write-through re-sync, 5 knockdown
|
||||
(SetBodyAnimation(0x20) write-through), 6 death, 7 impact, 8 movementMode) — transcribing it
|
||||
would replicate remote KNOCKDOWN/death/heat states; beams did not need it.
|
||||
✅ **The MECH-level records LANDED (task #1, 2026-07-11)** — see the section below; this
|
||||
REMAINING note is closed.
|
||||
5. ✅ **2-window driving — RESOLVED (tasks #48/#51).** Keyboard MP turning was restored at the root
|
||||
(the `pilotArray[1]` shrunk-span overrun fix, task #51); `BT_KEY_NOFOCUS` exists for automated
|
||||
harnesses. DEATHS scoring lights via the existing BTPostKillScore MP branch. Respawn is
|
||||
|
||||
@@ -195,11 +195,12 @@ authentic path scoped.
|
||||
master, full cross-pod kill verified). ✅ Replicant GAIT animation — DONE (task #50: replicant
|
||||
derives speedDemand from the replicated velocity, full stand→walk→run lifecycle verified).
|
||||
See [[multiplayer]] — the entries here were stale (swept 2026-07-11).
|
||||
- **Mech-level update records (@0x4a0c2c) untranscribed — the biggest remaining MP fidelity gap:**
|
||||
only the base Mover record replicates, so a peer's death SINK/burial, knockdown, heat, alarm and
|
||||
movementMode states don't reach the other pod (the wreck SWAP does appear). The writer's disasm is
|
||||
recovered + 9 record types decoded (`reference/decomp/mech_writeupdate_004a0c2c.disasm.txt`);
|
||||
the read-side leg-state branches at mech.cpp:1511/:1613 are the dead Wword comparisons.
|
||||
- ✅ **Mech-level update records (@0x4a0c2c) — DONE (task #1, 2026-07-11):** all 9 types
|
||||
transcribed + 2-node verified; the peer's death SINK/burial, knockdown, heat and state now
|
||||
replicate (the observer's replicant runs its own wreck loop off the replicated
|
||||
simulationState). Full mechanics in [[multiplayer]] "Mech-level update records". Residue
|
||||
[T3]: stream the model's UpdatePositionDiffrence/TurnVelocity/TurnDegree deadband constants
|
||||
to the senders (stand-in thresholds meanwhile).
|
||||
- The WinSock2 stack (L4NET.CPP) is 2-node verified end-to-end (cross-pod kills, beams,
|
||||
replicant gait — tasks #46-#51); remaining = the real pod-LAN config (real IPs, bare-IP
|
||||
pilot entries).
|
||||
|
||||
@@ -53,9 +53,10 @@ and `BTVal` is the recon **absorber** type: `operator=` stores NOTHING, every re
|
||||
check `mech.hpp`'s offset map first (the slot may already exist under a best-effort
|
||||
mislabel; 0x111 was mislabeled `ammoExpended`).
|
||||
- `if (Wword(a) != Wword(b))` and `if (Wword(a) == 2)` are BOTH always-false → the guarded
|
||||
branch is dead code. Known dead sites: `mech.cpp:1673` + `mech.cpp:1775` (replicant
|
||||
state sync in ReadUpdateRecord — MP is live; these are being revived by the in-progress
|
||||
Mech Write/ReadUpdateRecord reconstruction, task #1).
|
||||
branch is dead code. (The archetype sites — the replicant state sync in Mech::
|
||||
ReadUpdateRecord — were REVIVED by the task #1 update-record reconstruction, 2026-07-11:
|
||||
every Wword in that path is now a named engine/port member; the `Wword(0xf)/(0x10)`
|
||||
comparisons were `simulationState.oldState/currentState`.)
|
||||
- Any `Wword(N)` used for OBJECT access reads a shared global, not `this+i*4`; e.g.
|
||||
`(Mech*)Wword(3)` for a zone's owner → garbage; use `GetOwningSimulation()`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user