Ballistic FX: DAFC muzzle flash + autocannon fire replication (task #61)
The autocannon gains its authentic muzzle effect AND becomes visible when an enemy fires it -- the ballistic-FX gap behind "I only see the AC from my own view." MUZZLE FLASH (the genuine shipped effect, not the cut card): - MUZFLASH.BGF is an orphaned/cut asset (nothing references it) -- so it is NOT rendered. The shipped projectile-gun muzzle effect is DAFC.PFX, which BTDPL.INI documents as "the effect used on all projectile guns" (psfx 6 external / 14 internal): an orange fire-smoke blast (btfx:firesmoke1), maxIssue 25 over ~0.2s so the emitter auto-expires = one burst per shot. - BTFlashMuzzle (mech4.cpp) spawns it on the gun-port SEGMENT via the existing BTStartPfxAttached path; the segment frame sprays -Z out the barrel. Hooked at ProjectileWeapon::FireWeapon (the fire edge). Default ON (BT_MUZZLE=0 disables). AC only -- lasers show their beam, missiles their launch. ENEMY AC FIRE NOW REPLICATES (the real find): - ROOT CAUSE: the subsystem-record replication channel EXISTS and works (mech ticks subsystem->PerformAndWatch(update_stream); Entity::UpdateMessageHandler routes incoming records to GetSimulation(subsystemID-1)->ReadUpdateRecord). The emitter (beam) and MissileLauncher (salvo mirror) both call ForceUpdate() so their fire serializes -> enemy lasers + missiles ARE visible on the peer. The AUTOCANNON set only `simulationFlags |= 0x1` (the +0x28 instance flag, NOT the updateModel bit WriteSimulationUpdate walks) and had NO fire record, so its shot never crossed the wire -- the enemy's cannon was invisible. - FIX (the AC twin of the missile salvo mirror): ProjectileWeapon:: WriteUpdateRecord/ReadUpdateRecord (fire counter + aim) + ForceUpdate() in FireWeapon. The replicant edge-detects the counter and mirrors ONE visual round + DAFC muzzle flash from its own resolved muzzle; a null/untargeted aim streaks straight out the barrel (launchVelocity) instead of toward origin. - Verified live 2-node: the watching node logs REPLICANT AC shots + DAFC flashes at the enemy's gun-port (seg 7), aimed shots fly to the real target; no crashes. TRACER: all ACs author TracerInterval=1 (every round is a tracer); the existing amber streak is acceptable-authentic, so no tracer change was needed. KB: open-questions.md -- CORRECTED the (wrong) earlier note that claimed no subsystem-record channel exists; it does, the AC just wasn't using it. Logged the methodology lesson: the coverage audit finds UNWRITTEN functions, not "reconstructed but inert" ones (a function present but never called -- the AC record + the missile mirror both looked done); a LIVENESS audit would catch that class. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
267059ab88
commit
4c54f7ef0c
@@ -480,6 +480,25 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR
|
||||
- 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).
|
||||
- **✅ Subsystem-record replication IS wired — the AC just wasn't using it (task #61,
|
||||
2026-07-13) [T2, CORRECTED].** (An earlier draft of this note WRONGLY claimed "no
|
||||
subsystem-record channel" — that was concluded from an AC-only test before the AC's
|
||||
ForceUpdate gap was found. The channel exists and works.) MECHANISM: the mech's per-frame
|
||||
tick calls `subsystem->PerformAndWatch(till, update_stream)` for every subsystem
|
||||
(mech4.cpp:3893) → base `Simulation::WriteSimulationUpdate` walks the subsystem's `updateModel`
|
||||
and serializes any set record; `Entity::UpdateMessageHandler` (ENTITY.cpp:387) routes each
|
||||
incoming record to `GetSimulation(subsystemID-1)->ReadUpdateRecord` on the peer. A subsystem
|
||||
replicates its fire IFF its `FireWeapon` calls **`ForceUpdate()`** (sets the updateModel bit).
|
||||
The EMITTER (beam) and MISSILELAUNCHER (salvo mirror, mislanch.cpp:326) both do → enemy lasers
|
||||
+ missiles ARE visible on the peer. The AUTOCANNON set only `simulationFlags |= 0x1` (the
|
||||
+0x28 instance flag, NOT updateModel) and had no fire record → its shot never serialized → the
|
||||
enemy's cannon (tracer + DAFC muzzle flash) was invisible. FIX: added
|
||||
`ProjectileWeapon::WriteUpdateRecord/ReadUpdateRecord` (fire counter + aim, the AC twin of the
|
||||
salvo mirror) + `ForceUpdate()` in FireWeapon. Verified live: watching node now logs
|
||||
REPLICANT AC shots + muzzle flashes. **LESSON (methodology):** the binary-coverage audit is a
|
||||
function-PRESENCE census — it can't see "reconstructed but inert" code (a function that exists
|
||||
but is never CALLED, like the salvo mirror was thought to be, or a missing ForceUpdate). A
|
||||
LIVENESS audit (does a live call path reach each reconstructed fn?) would catch this class.
|
||||
|
||||
## Rendering follow-ups (non-blocking)
|
||||
- **.PFX effect-layer polish (deferred 2026-07-08; the layer itself is LIVE + verified).** The
|
||||
|
||||
Reference in New Issue
Block a user