From 1d65531ef8b03ddfdf051b276d221db6c39f2312 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 31 Aug 2026 19:50:50 +0700 Subject: [PATCH] knockback is a jump the server aims, and tabards wear their guild crest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - knockback is a jump whose seed came off the wire, not a server spline: SMSG_MOVE_KNOCK_BACK's four floats are exactly the MovementInfo jump tail in a different order (speedZ down-positive — a rising launch carries a negative value, the sign vmangos's own source marvels at), flown at the same take-off site as the keyboard jump and acked with the post-launch pose, which the server matches float-for-float within 0.01 before relaying to anyone; it is the one take-off that seeds BOTH axes, absolute in world XY, so it skips the arm that would hand the momentum back to a held key and reduce the whole knockback to a hop; root refuses it silently, a seated player stands up first, no MSG_MOVE_JUMP goes out — that packet is the keyboard's, and vmangos logs a jump at knockback speed as an overspeed cheat — and MSG_MOVE_KNOCK_BACK turns out not to be dead: an observed knockback replays as the arc it is - your guild crest reaches your tabard: the three GuildEmblems layers — background, border, emblem, on both torso tiles — belong to no equipment slot, so the body composite never wrote those cells and every guild wore the Guild Tabard's own default art; the install is gated on a display flag only seven of 29,604 rows set, of which exactly one is worn by any item — which is why every battleground and Argent Dawn tabard keeps its own art; the five wire indices are signed, because an undesigned guild carries −1 in all five and the client refuses to paint on the first −1 (unguarded, the commonest guild state on a young realm would have worn a blank tabard); the emblem keys the skin cache, so two guilds in the same tabard display cannot lend each other crests; and a guild tabard's background hides the bra where a plain tabard does not — it is a cutout, 79.5% opaque off the shipped art, and what shows at the sides is bare skin - a fly-by is framed by the world camera, not the M2 camera record's fov: a census of every reader shows the record's fov and clip planes reach only the portrait and Model-frame paths — nothing on the cinematic path reads any of the three — so fifteen of the sixteen shipped shots were rendering at HALF their intended vertical FOV, visibly over-zoomed on every race intro but the Undead; the fix is a deletion, and it dissolves a standing puzzle: the authored 0.22 and 27.8-yard "clips", which would render the dwarf intro's mountains as empty sky, are not clips at all on this path — two floats nobody consumes look exactly like that - 104 of Onyxia's lava traps stood on an interior floor classified as outdoors, taking the day/night sun inside a windowless lair: a GameObject's light node anchors at its model's AUTHORED bounding-box centre, and the trap's box reaches 98.42 yd past its bind pose — the anchor sits ~40 yd under the chamber floor, where a downward ray finds nothing above it to claim; the reference recovers with a 1000-yd upward retry at the claim itself, which benilla had only at the colour sample, so the verdict was decided before any colour was read; all 104 now classify interior, beside the 26 rocks and 119 eggs that always did — and the drowned-corpse pose came back from its cross-check confirmed at the bytes (a strict liquid-depth test at exactly two-thirds of a yard, Dead or Drowned), with the two reference-side notes it contradicted corrected over there Co-Authored-By: Claude Fable 5 --- crates/benilla-app/src/cinematic.rs | 60 +- crates/benilla-app/src/entities.rs | 4 + .../src/entities/attach/char_skin.rs | 13 + crates/benilla-app/src/entities/attach/mod.rs | 1 + .../src/entities/attach/preview.rs | 9 + .../src/entities/attach/redress.rs | 1 + crates/benilla-app/src/entities/corpse.rs | 64 +- .../benilla-app/src/entities/equipment/mod.rs | 9 + .../src/entities/equipment/resolve.rs | 22 +- crates/benilla-app/src/net.rs | 31 + crates/benilla-app/src/net/apply.rs | 18 +- crates/benilla-app/src/net/apply/session.rs | 32 +- crates/benilla-app/src/net/io.rs | 11 + crates/benilla-app/src/player.rs | 60 +- crates/benilla-app/src/player/move_trace.rs | 35 + crates/benilla-app/src/player/movement_net.rs | 201 ++++- crates/benilla-app/src/player/mover.rs | 163 +++- crates/benilla-app/src/player/state.rs | 44 +- crates/benilla-app/src/player/swim.rs | 1 + crates/benilla-app/src/player/wire_in.rs | 30 +- crates/benilla-app/src/portrait/dressup.rs | 4 + crates/benilla-app/src/ui_dressup.rs | 15 +- crates/benilla-app/src/ui_guild/mod.rs | 45 ++ .../src/bin/benilla-extract/charatlas.rs | 44 +- .../src/bin/benilla-extract/main.rs | 28 + crates/benilla-formats/src/characters/mod.rs | 4 +- .../src/characters/sections.rs | 734 +++++++++++++++++- crates/benilla-formats/src/cinematics.rs | 76 +- crates/benilla-formats/src/items.rs | 34 +- crates/benilla-formats/src/lib.rs | 6 +- crates/benilla-protocol/src/events.rs | 14 + crates/benilla-protocol/src/events/decode.rs | 9 + .../benilla-protocol/src/messages/client.rs | 16 + crates/benilla-protocol/src/messages/guild.rs | 41 +- crates/benilla-protocol/src/messages/mod.rs | 7 +- .../benilla-protocol/src/messages/opcode.rs | 37 + .../benilla-protocol/src/messages/packet.rs | 16 + crates/benilla-protocol/src/messages/parse.rs | 31 +- .../src/world/writer/self_movement.rs | 29 + crates/benilla-protocol/tests/movement.rs | 104 +++ .../benilla-world/src/wmo_portal/interior.rs | 87 ++- crates/benilla-world/src/wmo_portal/seed.rs | 105 ++- 42 files changed, 2082 insertions(+), 213 deletions(-) diff --git a/crates/benilla-app/src/cinematic.rs b/crates/benilla-app/src/cinematic.rs index 2fc1c572..f0c0567b 100644 --- a/crates/benilla-app/src/cinematic.rs +++ b/crates/benilla-app/src/cinematic.rs @@ -48,10 +48,11 @@ //! //! # What playback takes over //! -//! Three things, all released on the way out. The **camera** (this module writes the -//! [`WorldCamera`] pose and FOV after `control` has seated it, the same slot -//! `apply_camera_shake` uses); the **streaming focus**, which has to follow the camera rather than -//! the body, because a Tauren's shot opens 1741 yards from where the body stands and would +//! Three things, all released on the way out. The **camera** — its *pose* only; the projection is +//! left alone, because a fly-by is framed by the world camera's own optics and the M2 record's +//! `fov` reaches nothing on this path (decision 1711). Written after `control` has seated it, the +//! same slot `apply_camera_shake` uses. The **streaming focus**, which has to follow the camera +//! rather than the body, because a Tauren's shot opens 1741 yards from where the body stands and would //! otherwise fly over unstreamed terrain; and the **UI's cinematic flag**, which drives //! `CinematicFrame`'s letterbox and makes `InCinematic()` answer truthfully so `StaticPopup` //! suppresses dialogs the way the reference's does. @@ -62,7 +63,7 @@ use benilla_assets::{AssetSet, LockRecover, WorldAssets}; use benilla_formats::{CinematicCatalog, CinematicPath}; use benilla_ui::script::UiScript; use benilla_world::schedule::WorldStage; -use benilla_world::view::{WorldCamera, CAM_FOVY}; +use benilla_world::view::WorldCamera; use bevy::prelude::*; use crate::char_select::ClientState; @@ -399,38 +400,24 @@ fn start_pending( /// nothing accumulates and the *pose* needs no restore — the next frame's `control` simply seats /// it again. /// -/// The **FOV does** need one, and it is taken here rather than left to a neighbour. `scoped_view` -/// happens to rewrite the projection unconditionally every frame ahead of `control`, so today the -/// narrow cinematic FOV would be undone anyway — but that is its ordering, not our release, and a -/// reorder would leave the world permanently telephoto with nothing pointing at why. Ending a -/// cinematic puts [`CAM_FOVY`] back itself; the spyglass re-asserts its own value next frame if -/// one is up. +/// **The FOV is not touched at all**, and that is the correction decision 1711 landed. A fly-by is +/// rendered through the world camera's own optics, re-stamped every frame — the M2 camera record's +/// `fov` is written at model load and read by nothing on this path (wow-re +/// `ui/scratch/cinematic-camera-law.md`, a 24-site census; its one raw reader is reachable only +/// from the portrait and `` frames). Feeding the authored 45 degrees through the reference's +/// own `theta_v = F / sqrt(aspect^2 + 1)` builder — which is otherwise right, and angle-space +/// division really is what `0x5c3cc0` does — rendered fifteen of the sixteen shipped shots at +/// **half** the intended vertical FOV, i.e. visibly over-zoomed. Nothing to write means nothing to +/// release. fn drive( mut cine: ResMut, time: Res