#[observer]Expand description
Implements the Observer trait for your struct.
This is the main macro that ties everything together. Apply it to an impl block
that contains event handler methods marked with #[on_*] attributes.
§What It Does
- Automatically implements the Observer trait
- Generates code to call all handler methods at appropriate times
- Sets up interest flags based on which handlers are defined
- Decodes protobuf messages and passes them to handlers
- Filters events based on optional string arguments
§Handler Attributes
Use these attributes inside the impl block to mark event handlers:
#[on_tick_start]- Called at the start of each tick#[on_tick_end]- Called at the end of each tick#[on_entity]- Called when entities change#[on_entity("ClassName")]- Only for specific entity classes#[on_message]- Called for protobuf messages (type inferred from param)#[on_game_event]- Called for all game events#[on_game_event("event_name")]- Only for specific events#[on_string_table]- Called when string tables update#[on_string_table("table_name")]- Only for specific tables#[on_stop]- Called when replay ends#[on_combat_log]- Called for combat log entries (Dota 2 only)
§Trait Attributes
Apply these to the impl block or individual methods to enable tracking:
#[uses_entities]- Enable entity tracking#[uses_string_tables]- Enable string table tracking#[uses_game_events]- Enable game event tracking#[uses_combat_log]- Enable combat log tracking (Dota 2 only)
§Parameter Guidelines
Handlers can have these parameters (all optional except &mut self):
ctx: &Context- Current replay state (always optional)- Specific parameters depending on the handler:
event: EntityEvents(on_entity)entity: &Entity(on_entity)ge: &GameEvent(on_game_event)table: &StringTable(on_string_table)modified: &[i32](on_string_table)cle: &CombatLogEntry(on_combat_log)- Protobuf message types (on_message)
§Examples
§Basic observer
#[derive(Default)]
struct BasicObserver;
#[observer]
impl BasicObserver {
#[on_tick_start]
fn on_tick_start(&mut self, ctx: &Context) -> ObserverResult {
println!("Tick: {}", ctx.tick());
Ok(())
}
}§With entity tracking
#[derive(Default)]
struct EntityTracker;
#[observer]
#[uses_entities]
impl EntityTracker {
#[on_entity]
fn on_hero_created(&mut self, event: EntityEvents, entity: &Entity) -> ObserverResult {
if event == EntityEvents::Created && entity.class().name().starts_with("CDOTA_Unit_Hero_") {
println!("Hero created: {}", entity.class().name());
}
Ok(())
}
}§With multiple handlers
#[derive(Default)]
struct ComplexObserver {
ticks: u32,
messages: u32,
}
#[observer]
impl ComplexObserver {
#[on_tick_start]
fn on_tick(&mut self, ctx: &Context) -> ObserverResult {
self.ticks += 1;
Ok(())
}
#[on_message]
fn on_chat(&mut self, msg: CDotaUserMsgChatMessage) -> ObserverResult {
self.messages += 1;
println!("Message: {}", msg.message_text());
Ok(())
}
#[on_stop]
fn on_replay_end(&mut self) -> ObserverResult {
println!("Total ticks: {}, messages: {}", self.ticks, self.messages);
Ok(())
}
}§With game event filtering
#[derive(Default)]
struct DeathTracker {
deaths: u32,
}
#[observer]
impl DeathTracker {
#[on_game_event("player_death")]
fn on_death(&mut self, ctx: &Context, ge: &GameEvent) -> ObserverResult {
self.deaths += 1;
Ok(())
}
}§Interest Flags
The macro automatically determines which interest flags to set based on which handlers are defined. For example:
- If you have
#[on_tick_start],Interests::TICK_STARTis added - If you have
#[on_entity], bothENABLE_ENTITYandTRACK_ENTITYare added - If you have
#[on_message]handlers, appropriate message interest flags are added
You can also use trait attributes like #[uses_entities] to manually ensure
certain interests are set.