the action bars' empty slots go ghost, and a rooted creature stays put
- picking a spell up off the bar no longer blacks out every empty slot: `UI-Quickslot` is a FILLED 60%-black plate, not a hollow ring (decoded off the shipped BLPs — Quickslot2's interior is RGBA 0,0,0,0, Quickslot's 0,0,0,153), and the reference dims it to half alpha in `ActionButton_ShowGrid`, so an empty well now ghosts at 30% black where it read as a hole; the wow-re cross-check then found the reference never UN-dims it (a 3-argument `SetVertexColor` preserves the current alpha at `0x79abd0`, and `SetNormalTexture` reuses the region), so in the real client the first drag leaves every button's border at half alpha for the rest of the session — benilla ends the dim on purpose and records it as the divergence it is (1782) - the bag bar is the reference's own `MainMenuBarBagButtons.xml` (window 3 of the stock-first migration), and the swap found a real bug rather than a move: the reference's `ItemAnim_OnEvent` matches a push against the button's inventory-slot id (20..23) and benilla emitted its own container numbering (1..4), so all four bag-push cards would have silently never played against the stock body — `push_container` now emits the reference's selector (`bag + 1`), which is what an addon expects anyway; beside it, a readiness probe that asks the LOADER, not a grep, which of the 85 stock windows load off the player's chain today (58 do; the 27 that don't name their own blocker) - a rooted, hovering, water-walking or walking creature reached benilla as an unhandled opcode: the twelve `SMSG_SPLINE_MOVE_*` (the observer twin of the ack'd force family — bare packed guid, no ack, any unit) now decode into one MOVEMENTFLAGS word per unit, which benilla kept for our mover and for a relayed player and not at all for a creature, the one body this family is ever addressed to; ROOT wipes the direction bits so the dead-reckon stops walking a rooted body on for its next heartbeat (`0x7c7340`), HOVER clears a yard off the floor without climbing a body already inside that yard (`0x636e81`), WATERWALK elects the liquid surface against the terrain, SAFE_FALL's terminal is 7.0 not 60.148 (`0x7c5d23`), and SET_RUN_MODE's bool is inverted against the bit, folded at the parse; the inspect card names a unit's granted modes in words (`granted rooted+hover`) so a creature resting a yard off the floor reads as intended rather than broken Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -1119,6 +1119,21 @@ pub enum SessionEvent {
|
||||
mode: crate::messages::MoveMode,
|
||||
apply: bool,
|
||||
},
|
||||
/// **Some unit's movement mode changed** — the `SMSG_SPLINE_MOVE_*` twelve (decision 1780),
|
||||
/// the observer half of [`Self::MoveMode`]'s family. Nothing to ack; `guid` is any unit, and on
|
||||
/// vmangos it is one the server is driving itself (a creature), which is precisely the case the
|
||||
/// ack'd family structurally cannot reach. `apply` is always the direction of the mode's
|
||||
/// `MOVEMENTFLAGS` bit ([`crate::messages::SplineMode::flag`]).
|
||||
///
|
||||
/// The app folds it into that unit's granted-mode word, which the animation selector, the
|
||||
/// creature ground clamp and the remote dead-reckon all read — the reference does the same and
|
||||
/// then re-runs the unit's gait selector on the spot (`0x6014ec`), which is what makes the
|
||||
/// family *visual* rather than bookkeeping.
|
||||
SplineMoveMode {
|
||||
guid: u64,
|
||||
mode: crate::messages::SplineMode,
|
||||
apply: bool,
|
||||
},
|
||||
/// **A knockback aimed at our own mover** (`SMSG_MOVE_KNOCK_BACK`, decision 1702) — the server
|
||||
/// hands the controlling client a ballistic launch and lets it fly the arc itself; nothing about
|
||||
/// it is a spline or a teleport. `launch` is the packet's quad as the jump tail it becomes:
|
||||
|
||||
@@ -501,6 +501,9 @@ pub fn decode(packet: ServerPacket) -> Vec<SessionEvent> {
|
||||
mode,
|
||||
apply,
|
||||
}],
|
||||
ServerPacket::SplineMoveMode { guid, mode, apply } => {
|
||||
vec![SessionEvent::SplineMoveMode { guid, mode, apply }]
|
||||
}
|
||||
ServerPacket::KnockBack {
|
||||
guid,
|
||||
counter,
|
||||
|
||||
@@ -19,7 +19,7 @@ pub use events::{
|
||||
};
|
||||
pub use messages::{
|
||||
CharCreateReq, CharEnumItem, Character, CorpseLook, CreateSpline, ItemInfo, JumpInfo,
|
||||
MonsterMoveFacing, MoveMode, ObjectFields, OwnerFallback, ServerPacket, SpeedKind,
|
||||
MonsterMoveFacing, MoveMode, ObjectFields, OwnerFallback, ServerPacket, SpeedKind, SplineMode,
|
||||
TransportPose, CHARACTER_FLAG_GHOST, CHARACTER_FLAG_HIDE_CLOAK, CHARACTER_FLAG_HIDE_HELM,
|
||||
CHARACTER_FLAG_RENAME,
|
||||
};
|
||||
|
||||
@@ -168,7 +168,7 @@ pub use mirror_timer::{
|
||||
read_pause_mirror_timer, read_start_mirror_timer, read_stop_mirror_timer, MirrorTimerKind,
|
||||
MirrorTimerStart,
|
||||
};
|
||||
pub use movement::{JumpInfo, MoveMode, MovementInfo, SpeedKind, TransportPose};
|
||||
pub use movement::{JumpInfo, MoveMode, MovementInfo, SpeedKind, SplineMode, TransportPose};
|
||||
pub use opcode_names::opcode_name;
|
||||
pub use packet::{CreatureQueryInfo, MonsterMoveFacing, ServerPacket};
|
||||
pub use page_text::page_text_query;
|
||||
|
||||
@@ -168,6 +168,57 @@ impl MoveMode {
|
||||
}
|
||||
}
|
||||
|
||||
/// **A movement mode granted on a unit we do not control** — the `SMSG_SPLINE_MOVE_*` twelve
|
||||
/// (decision 1780), the observer half of [`MoveMode`]'s family.
|
||||
///
|
||||
/// Same bits, and for the four they share the same reference setters — but it is a *different
|
||||
/// message*, and the three differences are what the type exists to keep straight:
|
||||
///
|
||||
/// 1. **No counter and no ack.** The controller's family is a handshake (`packed guid + u32
|
||||
/// counter`, ack or the server never applies it); this one is a bare `packed guid` broadcast.
|
||||
/// The client's handler `0x603c80` replies to nothing.
|
||||
/// 2. **Any unit.** `0x603c80` resolves the guid with `TYPEMASK_UNIT` and applies to whatever it
|
||||
/// finds — normally a creature, since vmangos only takes this leg for a unit *not* being moved
|
||||
/// by a player (`Unit::SetRooted`/`SetWaterWalking`/`SetFeatherFall`/`SetHover`'s `else` arm,
|
||||
/// and `SendToggleRunWalkToAll` unconditionally).
|
||||
/// 3. **Two extra modes.** [`WalkMode`](Self::WalkMode) and [`Swimming`](Self::Swimming) have no
|
||||
/// ack'd counterpart at all.
|
||||
///
|
||||
/// [`Swimming`](Self::Swimming) is modelled but vmangos never sends it — nothing in the tree
|
||||
/// constructs `SMSG_SPLINE_MOVE_START_SWIM`/`_STOP_SWIM`, and `Opcodes.cpp:888` marks both
|
||||
/// `SendByServer`-only. The client handles them (`0x61a130`/`0x61a160`), so we decode them; on this
|
||||
/// server they are dead wire.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SplineMode {
|
||||
Root,
|
||||
WaterWalk,
|
||||
FeatherFall,
|
||||
Hover,
|
||||
/// `MOVEFLAG_WALK_MODE` (`0x100`) — the gait selector. **`apply` here is the flag's direction,
|
||||
/// not the opcode's noun**: `SMSG_SPLINE_MOVE_SET_WALK_MODE` is `apply: true` and
|
||||
/// `..._SET_RUN_MODE` is `apply: false`, because the reference's `0x617e80` passes the opcode's
|
||||
/// bool to `SetRunMode 0x7c71c0`, whose argument is *run*. The inversion is folded at the parse
|
||||
/// so every variant of this enum means the same thing by "apply".
|
||||
WalkMode,
|
||||
/// `MOVEFLAG_SWIMMING` (`0x20_0000`) — `SMSG_SPLINE_MOVE_START_SWIM`/`_STOP_SWIM`. Never sent by
|
||||
/// vmangos (see the type docs).
|
||||
Swimming,
|
||||
}
|
||||
|
||||
impl SplineMode {
|
||||
/// This mode's `MOVEMENTFLAGS` bit — the same word [`MoveMode::flag`] writes into.
|
||||
pub fn flag(self) -> u32 {
|
||||
match self {
|
||||
SplineMode::Root => 0x0000_1000,
|
||||
SplineMode::WaterWalk => 0x1000_0000,
|
||||
SplineMode::FeatherFall => 0x2000_0000,
|
||||
SplineMode::Hover => 0x4000_0000,
|
||||
SplineMode::WalkMode => 0x0000_0100,
|
||||
SplineMode::Swimming => 0x0020_0000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// One jump's ballistic launch parameters — the conditional `MovementInfo` tail present iff the
|
||||
/// `MOVEFLAG_JUMPING` (0x2000) flag is set. VERIFIED byte-for-byte against vmangos `MovementInfo::Read`
|
||||
/// (build 1.12.1): wire order is `zspeed, cosAngle, sinAngle, xyspeed` (note cos *before* sin). The
|
||||
|
||||
@@ -616,6 +616,57 @@ pub const SMSG_SPLINE_SET_SWIM_SPEED: u16 = 0x0300; // 768
|
||||
pub const SMSG_SPLINE_SET_WALK_SPEED: u16 = 0x0301; // 769
|
||||
pub const SMSG_SPLINE_SET_SWIM_BACK_SPEED: u16 = 0x0302; // 770
|
||||
pub const SMSG_SPLINE_SET_TURN_RATE: u16 = 0x0303; // 771
|
||||
|
||||
// **The OBSERVER movement-mode family** (decision 1780) — the spline-move twelve. Where the
|
||||
// `SMSG_FORCE_*`/`SMSG_MOVE_*` family above hands the *controlling client* a mode to ack, this one
|
||||
// tells everyone else that some unit's mode changed, and it is a different wire in three ways:
|
||||
// the body is a **bare packed guid** (no counter, no `MovementInfo`), there is **no ack**, and the
|
||||
// target is **any unit**, not our mover.
|
||||
//
|
||||
// VERIFIED both ends. Server: vmangos `MovementPacketSender::SendMovementFlagChangeToAll` /
|
||||
// `SendToggleRunWalkToAll` (`MovementPacketSender.cpp:399-462`) write `data << unit->GetPackGUID()`
|
||||
// and stop — the `+ 4` / `9` in the `WorldPacket` ctor is a capacity hint, not content. Client:
|
||||
// all twelve register the single handler `0x603c80`, which reads one packed guid (`0x642ed0`),
|
||||
// resolves it with `ClntObjMgrObjectPtr(TYPEMASK_UNIT)` and calls the dispatcher `0x601420`
|
||||
// (`lea eax,[edi-0x304]; cmp eax,0x16; ja` — so `0x304..=0x31A`, and `SMSG_SPLINE_MOVE_ROOT`'s
|
||||
// out-of-band `0x31A` is deliberately the range's top). An unresolvable guid is dropped silently.
|
||||
//
|
||||
// The dispatcher's twelve arms, in registration order (`0x603775`-`0x603830`), are a 1:1 map onto
|
||||
// the twelve opcodes; six of the arms are independently VERIFIED in wow-re's collision ledger:
|
||||
//
|
||||
// | opcode | arm | effect on `CMovement+0x40` |
|
||||
// |---|---|---|
|
||||
// | `0x31A` ROOT | `0x619a10` | `SetRoot 0x7c7340` — sets `0x1000`, and **wipes `0xffe07f00`'s complement once at apply** |
|
||||
// | `0x304` UNROOT | `0x619a40` | `ClearRoot 0x7c7370(1)` — clears `0x1000` |
|
||||
// | `0x305`/`0x306` | `0x61a4e0` | `SetFeatherFall 0x7c72e0` — `0x20000000` |
|
||||
// | `0x307`/`0x308` | `0x61a620` | `SetHover 0x7c7310` — `0x40000000` |
|
||||
// | `0x309`/`0x30A` | `0x61a3d0` | `SetWaterWalk 0x7c7280` — `0x10000000` |
|
||||
// | `0x30B`/`0x30C` | `0x61a130`/`0x61a160` | `SetSwim 0x7c6e50`/`0x7c6e80` — `0x200000` |
|
||||
// | `0x30D`/`0x30E` | `0x617e80` | `SetRunMode 0x7c71c0` — `0x100`, **inverted** (see below) |
|
||||
//
|
||||
// After any arm the dispatcher re-runs the unit's animation selector (`0x6014ec push edi; call
|
||||
// 0x60e480` then `push -1; call 0x5fd9e0`), which is why this family is *visual*: the mode change
|
||||
// re-picks the gait on the spot rather than waiting for the next pose.
|
||||
//
|
||||
// (wow-re `collision/scratch/moveflag-family.md` §§2-5, `collision/scratch/walk-mode-law.md` §5,
|
||||
// `collision/scratch/remote-swim-decision.md` §1.4, `collision/ledger.tsv` rows for each arm.)
|
||||
pub const SMSG_SPLINE_MOVE_UNROOT: u16 = 0x0304; // 772
|
||||
pub const SMSG_SPLINE_MOVE_FEATHER_FALL: u16 = 0x0305; // 773
|
||||
pub const SMSG_SPLINE_MOVE_NORMAL_FALL: u16 = 0x0306; // 774
|
||||
pub const SMSG_SPLINE_MOVE_SET_HOVER: u16 = 0x0307; // 775
|
||||
pub const SMSG_SPLINE_MOVE_UNSET_HOVER: u16 = 0x0308; // 776
|
||||
pub const SMSG_SPLINE_MOVE_WATER_WALK: u16 = 0x0309; // 777
|
||||
pub const SMSG_SPLINE_MOVE_LAND_WALK: u16 = 0x030A; // 778
|
||||
pub const SMSG_SPLINE_MOVE_START_SWIM: u16 = 0x030B; // 779
|
||||
pub const SMSG_SPLINE_MOVE_STOP_SWIM: u16 = 0x030C; // 780
|
||||
// **The run/walk pair is inverted against the flag bit, and that is the reference's own sign.**
|
||||
// `0x617e80` passes the opcode's bool straight to `CMovement::SetRunMode 0x7c71c0`, whose argument
|
||||
// is *run* — so `SET_RUN_MODE` CLEARS `MOVEFLAG_WALK_MODE` (`0x100`) and `SET_WALK_MODE` sets it.
|
||||
// Modelled as one [`super::movement::SplineMode::WalkMode`] whose `apply` is the flag's direction,
|
||||
// so every arm of the family means the same thing by "apply": set this bit.
|
||||
pub const SMSG_SPLINE_MOVE_SET_RUN_MODE: u16 = 0x030D; // 781
|
||||
pub const SMSG_SPLINE_MOVE_SET_WALK_MODE: u16 = 0x030E; // 782
|
||||
pub const SMSG_SPLINE_MOVE_ROOT: u16 = 0x031A; // 794
|
||||
pub const MSG_MOVE_SET_RUN_SPEED: u16 = 0x00CD; // 205
|
||||
pub const MSG_MOVE_SET_RUN_BACK_SPEED: u16 = 0x00CF; // 207
|
||||
pub const MSG_MOVE_SET_WALK_SPEED: u16 = 0x00D1; // 209
|
||||
|
||||
@@ -18,9 +18,9 @@ use super::{
|
||||
QuestDetails, QuestGiverList, QuestOfferReward, QuestOption, QuestPushResult,
|
||||
QuestRequestItems, QuestTemplate, ResurrectRequestBody, SpeedKind, SpellChainTargets,
|
||||
SpellCooldown, SpellDamageLog, SpellDispelLog, SpellEnergizeLog, SpellGo, SpellHealLog,
|
||||
SpellInstaKillLog, SpellLogExecute, SpellLogMiss, SpellOutcomeLog, SpellStart, StabledPet,
|
||||
TaxiMask, TradeStatus, TradeStatusExtended, TrainerSpell, TransportPose, VendorItem,
|
||||
WhoResults, XpGain,
|
||||
SpellInstaKillLog, SpellLogExecute, SpellLogMiss, SpellOutcomeLog, SpellStart, SplineMode,
|
||||
StabledPet, TaxiMask, TradeStatus, TradeStatusExtended, TrainerSpell, TransportPose,
|
||||
VendorItem, WhoResults, XpGain,
|
||||
};
|
||||
|
||||
/// The **final facing** a `SMSG_MONSTER_MOVE` dictates (its `moveType`): the unit snaps to face this
|
||||
@@ -1018,6 +1018,16 @@ pub enum ServerPacket {
|
||||
mode: MoveMode,
|
||||
apply: bool,
|
||||
},
|
||||
/// **Some unit's movement mode changed** — the `SMSG_SPLINE_MOVE_*` twelve (decision 1780), the
|
||||
/// observer half of [`Self::MoveMode`]'s family. A bare packed guid: no counter, **no ack**, and
|
||||
/// `guid` is any unit — normally a creature, which is exactly the case the ack'd family cannot
|
||||
/// reach. `apply` is always the direction of [`SplineMode::flag`]'s bit (the run/walk pair's
|
||||
/// inversion is folded at the parse).
|
||||
SplineMoveMode {
|
||||
guid: u64,
|
||||
mode: SplineMode,
|
||||
apply: bool,
|
||||
},
|
||||
/// **The server aimed a knockback at our mover** (`SMSG_MOVE_KNOCK_BACK`, decision 1702) —
|
||||
/// a ballistic launch it hands the controlling client to fly. `launch` is the packet's four
|
||||
/// floats read into the launch quad they *are*: `cos_angle`/`sin_angle` the world-XY direction,
|
||||
@@ -1639,6 +1649,21 @@ impl ServerPacket {
|
||||
(MoveMode::Hover, true) => "SMSG_MOVE_SET_HOVER".into(),
|
||||
(MoveMode::Hover, false) => "SMSG_MOVE_UNSET_HOVER".into(),
|
||||
},
|
||||
ServerPacket::SplineMoveMode { mode, apply, .. } => match (mode, apply) {
|
||||
(SplineMode::Root, true) => "SMSG_SPLINE_MOVE_ROOT".into(),
|
||||
(SplineMode::Root, false) => "SMSG_SPLINE_MOVE_UNROOT".into(),
|
||||
(SplineMode::WaterWalk, true) => "SMSG_SPLINE_MOVE_WATER_WALK".into(),
|
||||
(SplineMode::WaterWalk, false) => "SMSG_SPLINE_MOVE_LAND_WALK".into(),
|
||||
(SplineMode::FeatherFall, true) => "SMSG_SPLINE_MOVE_FEATHER_FALL".into(),
|
||||
(SplineMode::FeatherFall, false) => "SMSG_SPLINE_MOVE_NORMAL_FALL".into(),
|
||||
(SplineMode::Hover, true) => "SMSG_SPLINE_MOVE_SET_HOVER".into(),
|
||||
(SplineMode::Hover, false) => "SMSG_SPLINE_MOVE_UNSET_HOVER".into(),
|
||||
(SplineMode::Swimming, true) => "SMSG_SPLINE_MOVE_START_SWIM".into(),
|
||||
(SplineMode::Swimming, false) => "SMSG_SPLINE_MOVE_STOP_SWIM".into(),
|
||||
// Inverted on purpose — see [`SplineMode::WalkMode`].
|
||||
(SplineMode::WalkMode, true) => "SMSG_SPLINE_MOVE_SET_WALK_MODE".into(),
|
||||
(SplineMode::WalkMode, false) => "SMSG_SPLINE_MOVE_SET_RUN_MODE".into(),
|
||||
},
|
||||
ServerPacket::KnockBack { .. } => "SMSG_MOVE_KNOCK_BACK".into(),
|
||||
ServerPacket::LogoutComplete => "SMSG_LOGOUT_COMPLETE".into(),
|
||||
ServerPacket::LogoutResponse { .. } => "SMSG_LOGOUT_RESPONSE".into(),
|
||||
|
||||
@@ -16,6 +16,7 @@ use super::{
|
||||
mirror_timer, monster_move, movement, opcode, page_text, pet, petition, progression, pvp,
|
||||
quest, social, spellbook, spells, stable, summon, taxi, trade, trainer, update_object, vendor,
|
||||
world_state, Character, CreatureQueryInfo, JumpInfo, MoveMode, ServerPacket, SpeedKind,
|
||||
SplineMode,
|
||||
};
|
||||
|
||||
/// Read one `SMSG_FORCE_*_SPEED_CHANGE` body — `[packed mover guid][u32 counter][f32 speed]`,
|
||||
@@ -891,6 +892,45 @@ pub fn parse_server(opcode: u16, body: &[u8]) -> io::Result<ServerPacket> {
|
||||
apply,
|
||||
}
|
||||
}
|
||||
// **The observer movement-mode family** (decision 1780) — the spline-move twelve. Body is a
|
||||
// BARE packed guid: no counter, no `MovementInfo`, and nothing to ack (VERIFIED vmangos
|
||||
// `MovementPacketSender::SendMovementFlagChangeToAll`/`SendToggleRunWalkToAll`, and the
|
||||
// reference's single handler `0x603c80`, which reads one packed guid and dispatches).
|
||||
// `guid` is any unit, not our mover — the constants block in `opcode` carries the arm map.
|
||||
opcode::SMSG_SPLINE_MOVE_ROOT
|
||||
| opcode::SMSG_SPLINE_MOVE_UNROOT
|
||||
| opcode::SMSG_SPLINE_MOVE_WATER_WALK
|
||||
| opcode::SMSG_SPLINE_MOVE_LAND_WALK
|
||||
| opcode::SMSG_SPLINE_MOVE_FEATHER_FALL
|
||||
| opcode::SMSG_SPLINE_MOVE_NORMAL_FALL
|
||||
| opcode::SMSG_SPLINE_MOVE_SET_HOVER
|
||||
| opcode::SMSG_SPLINE_MOVE_UNSET_HOVER
|
||||
| opcode::SMSG_SPLINE_MOVE_START_SWIM
|
||||
| opcode::SMSG_SPLINE_MOVE_STOP_SWIM
|
||||
| opcode::SMSG_SPLINE_MOVE_SET_RUN_MODE
|
||||
| opcode::SMSG_SPLINE_MOVE_SET_WALK_MODE => {
|
||||
let (mode, apply) = match opcode {
|
||||
opcode::SMSG_SPLINE_MOVE_ROOT => (SplineMode::Root, true),
|
||||
opcode::SMSG_SPLINE_MOVE_UNROOT => (SplineMode::Root, false),
|
||||
opcode::SMSG_SPLINE_MOVE_WATER_WALK => (SplineMode::WaterWalk, true),
|
||||
opcode::SMSG_SPLINE_MOVE_LAND_WALK => (SplineMode::WaterWalk, false),
|
||||
opcode::SMSG_SPLINE_MOVE_FEATHER_FALL => (SplineMode::FeatherFall, true),
|
||||
opcode::SMSG_SPLINE_MOVE_NORMAL_FALL => (SplineMode::FeatherFall, false),
|
||||
opcode::SMSG_SPLINE_MOVE_SET_HOVER => (SplineMode::Hover, true),
|
||||
opcode::SMSG_SPLINE_MOVE_UNSET_HOVER => (SplineMode::Hover, false),
|
||||
opcode::SMSG_SPLINE_MOVE_START_SWIM => (SplineMode::Swimming, true),
|
||||
opcode::SMSG_SPLINE_MOVE_STOP_SWIM => (SplineMode::Swimming, false),
|
||||
// The one inverted pair: RUN_MODE *clears* `MOVEFLAG_WALK_MODE`, because the
|
||||
// reference's `0x617e80` feeds the opcode's bool to `SetRunMode 0x7c71c0`.
|
||||
opcode::SMSG_SPLINE_MOVE_SET_WALK_MODE => (SplineMode::WalkMode, true),
|
||||
_ => (SplineMode::WalkMode, false),
|
||||
};
|
||||
ServerPacket::SplineMoveMode {
|
||||
guid: read_packed_guid(&mut r)?,
|
||||
mode,
|
||||
apply,
|
||||
}
|
||||
}
|
||||
// **The knockback the server aims at our mover** (decision 1702): `packed guid + u32
|
||||
// counter`, then the launch quad `vcos, vsin, speedXY, speedZ` (VERIFIED vmangos
|
||||
// `MovementPacketSender.cpp:261-277`, the `> CLIENT_BUILD_1_9_4` branch). The quad reads
|
||||
|
||||
Reference in New Issue
Block a user