#[rewriter]Expand description
Implements the DemoRewriter trait for your struct.
Apply this to an inherent impl block and mark methods with writer callback
attributes. The macro builds the RewriteInterests mask from those methods
so the writer only decodes the parts of the replay your rewrite needs.
§Callback Types
#[rewrite_demo_message]sees outerEDemoCommandspayloads before packet-level decoding.#[rewrite_packet_message]sees messages inside demo packets. It can take raw(msg_type, payload)arguments or a decoded protobuf message.#[rewrite_packet_messages]can mutate the final decoded packet message list after individual packet-message callbacks run.#[rewrite_demo_string_tables],#[rewrite_string_table_entry],#[rewrite_svc_create_string_table], and#[rewrite_svc_update_string_table]target string-table data at different levels of decoding.#[rewrite_field]and#[replace_entity_field]replace decoded entity field values, while#[should_rewrite_entity]filters which entities enter that path and#[should_track_entity]filters which entities retain state.
§Return Values
Message callbacks return Result<MessageRewrite, ParserError>.
Keep leaves the current payload alone, Drop removes it, Replace(bytes)
writes explicit bytes, and Rewrite re-encodes a mutable decoded protobuf
argument when that callback supports it. List, entry, and filter callbacks
use the return type of the matching DemoRewriter method.
§Examples
§Drop a decoded packet message
struct RemoveChat;
#[rewriter]
impl RemoveChat {
#[rewrite_packet_message]
fn remove_chat(
&mut self,
_msg: CDotaUserMsgChatMessage,
) -> Result<MessageRewrite, ParserError> {
Ok(MessageRewrite::Drop)
}
}§Mutate and re-encode a decoded packet message
struct RedactChat;
#[rewriter]
impl RedactChat {
#[rewrite_packet_message]
fn redact_chat(
&mut self,
message: &mut CDotaUserMsgChatMessage,
) -> Result<MessageRewrite, ParserError> {
message.message_text = Some("[redacted]".to_string());
Ok(MessageRewrite::Rewrite)
}
}§Rewrite a string table entry
struct AnonymizeUserInfo;
#[rewriter]
impl AnonymizeUserInfo {
#[rewrite_string_table_entry]
fn rewrite_userinfo(
&mut self,
table_name: &str,
entry: &mut StringTableEntryUpdate,
) -> Result<(), ParserError> {
if table_name == "userinfo" {
if let Some(value) = entry.value_mut() {
let mut player = CMsgPlayerInfo::decode(value.as_slice())?;
player.name = Some("Anonymous".to_string());
*value = player.encode_to_vec();
}
}
Ok(())
}
}§Rewrite decoded entity fields
struct RemoveSteamIds;
#[rewriter]
impl RemoveSteamIds {
#[rewrite_field(class = "CDOTA_PlayerResource", field = ends_with("m_iPlayerSteamID"))]
fn remove_steam_id(&mut self, _value: u64) -> u64 {
0
}
}