Files
benilla-octo/crates/benilla-protocol/src/world/writer/pet.rs
T
SamandClaude Fable 5 77dc8f8ead pets get their action bar, macros arrive, and hunters draw the bow
- a hunter's or warlock's pet has its action bar now: attack, follow, stay, the pet's own spells with cooldowns and autocast sparkles
- the macro system lands: the macro window, the icon chooser, /cast and /macro, and macros dragged onto the action bar
- hunter shots look right at last: the bow draws and releases on the shot, and the arrow lays a spark trail its whole flight
- the options window re-dresses in 1.12's own art with the classic dialog look, and gets a working search box and clickable steppers

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 19:03:13 +07:00

55 lines
2.6 KiB
Rust

//! The pet bar's `WorldWriter` sends — mirroring [`crate::messages::pet`] (decisions 0982, 0988).
//!
//! Three verbs, and the thing to know about them is that **the server answers none of them**.
//! Every one is an intent the client has already applied to its own state before sending
//! (wow-re §10.1/§10.2: the reaction, command and autocast paths all write `[0xb71468]` or the
//! slot word and fire `PET_BAR_UPDATE` *before* the packet leaves). The bar's contents change only
//! when a fresh `SMSG_PET_SPELLS` arrives — a summon, a swap, a learned spell — never as a reply
//! to one of these.
//!
//! Every one carries the pet's guid: the server re-checks ownership on each
//! (`PetHandler.cpp`'s `GetCharmerOrOwnerGuid` gate) and silently drops anything naming a unit we
//! don't control.
use anyhow::Result;
use crate::messages::{self, opcode};
use super::WorldWriter;
impl WorldWriter {
/// Press one pet bar slot (`CMSG_PET_ACTION`, layout in [`messages::pet_action`]) — the one
/// verb behind all three slot classes, because the server dispatches on the **type byte inside
/// the word we echo**: a command token runs `HandlePetCommand`, a reaction token sets the react
/// state, a spell casts. `target` is the unit the action should aim at, or `0`.
pub fn pet_action(&mut self, pet_guid: u64, packed: u32, target_guid: u64) -> Result<()> {
self.send(
opcode::CMSG_PET_ACTION,
&messages::pet_action(pet_guid, packed, target_guid),
)
}
/// Call the pet off its target (`CMSG_PET_STOP_ATTACK`, layout in
/// [`messages::pet_stop_attack`]) — the Attack button's second press.
pub fn pet_stop_attack(&mut self, pet_guid: u64) -> Result<()> {
self.send(
opcode::CMSG_PET_STOP_ATTACK,
&messages::pet_stop_attack(pet_guid),
)
}
/// Write one or two pet bar slots (`CMSG_PET_SET_ACTION`, layout — and the reason this one
/// opcode carries two different verbs — in [`messages::pet_set_action`]).
///
/// **The autocast toggle is this send**, with one entry: the pressed slot and its word with
/// bit 30 flipped. The drag is the same send with one or two. Unlike the player bar's
/// [`WorldWriter::set_action_button`], a swap here IS atomic — the server tells the forms
/// apart by body size and applies both entries together.
pub fn pet_set_action(&mut self, pet_guid: u64, entries: &[(u32, u32)]) -> Result<()> {
self.send(
opcode::CMSG_PET_SET_ACTION,
&messages::pet_set_action(pet_guid, entries),
)
}
}