d2-stampede 0.1.4

Dota 2 replay parser written in Rust
Documentation
use crate::proto::{CMsgDotaCombatLogEntry, DotaCombatlogTypes};
use crate::string_table::StringTable;

/// Wrapper for [`CMsgDotaCombatLogEntry`]
#[derive(Clone)]
pub struct CombatLogEntry<'a> {
    pub(crate) names: &'a StringTable,
    pub(crate) log: CMsgDotaCombatLogEntry,
}

#[derive(thiserror::Error, Debug)]
pub enum CombatLogError {
    #[error("No {0} for {1}")]
    EmptyProperty(String, String),
    #[error("No {0} for {1}")]
    EmptyName(String, String),
}

macro_rules! define_combat_log_getters {
    ($($name:ident: $type:ty),*) => {
        $(
            pub fn $name(&self) -> Result<$type, CombatLogError> {
                self.log.$name.ok_or_else(|| {
                    CombatLogError::EmptyProperty(stringify!($name).into(), format!("{:?}", self.r#type()))
                })
            }
        )*
    };
}

macro_rules! define_name_getter {
    ($($fn_name:ident: $log_prop:ident),*) => {
        $(
            pub fn $fn_name(&self) -> Result<&str, CombatLogError> {
                self.log.$log_prop
                    .and_then(|id| self.names.items.get(id as usize).map(|name| name.key.as_ref()))
                    .ok_or_else(|| {
                        CombatLogError::EmptyName(stringify!($fn_name).into(), format!("{:?}", self.r#type()))
                    })
            }
        )*
    };
}

impl<'a> CombatLogEntry<'a> {
    pub fn r#type(&self) -> DotaCombatlogTypes {
        self.log.r#type()
    }

    pub fn assist_players(&self) -> &[i32] {
        self.log.assist_players.as_slice()
    }

    define_name_getter! {
        target_name: target_name,
        target_source_name: target_source_name,
        attacker_name: attacker_name,
        damage_source_name: damage_source_name,
        inflictor_name: inflictor_name,
        value_name: value
    }

    define_combat_log_getters! {
        value: u32,
        health: i32,
        timestamp: f32,
        stun_duration: f32,
        slow_duration: f32,
        ability_level: u32,
        location_x: f32,
        location_y: f32,
        gold_reason: u32,
        timestamp_raw: f32,
        modifier_duration: f32,
        xp_reason: u32,
        last_hits: u32,
        attacker_team: u32,
        target_team: u32,
        obs_wards_placed: u32,
        assist_player0: u32,
        assist_player1: u32,
        assist_player2: u32,
        assist_player3: u32,
        stack_count: u32,
        hidden_modifier: bool,
        neutral_camp_type: u32,
        rune_type: u32,
        attacker_hero_level: u32,
        target_hero_level: u32,
        xpm: u32,
        gpm: u32,
        event_location: u32,
        target_is_self: bool,
        damage_type: u32,
        invisibility_modifier: bool,
        damage_category: u32,
        networth: u32,
        building_type: u32,
        modifier_elapsed_duration: f32,
        silence_modifier: bool,
        heal_from_lifesteal: bool,
        modifier_purged: bool,
        spell_evaded: bool,
        motion_controller_modifier: bool,
        long_range_kill: bool,
        modifier_purge_ability: u32,
        modifier_purge_npc: u32,
        root_modifier: bool,
        total_unit_death_count: u32,
        aura_modifier: bool,
        armor_debuff_modifier: bool,
        no_physical_damage_modifier: bool,
        modifier_ability: u32,
        modifier_hidden: bool,
        inflictor_is_stolen_ability: bool,
        kill_eater_event: u32,
        unit_status_label: u32,
        spell_generated_attack: bool,
        is_attacker_illusion: bool,
        is_attacker_hero: bool,
        is_target_illusion: bool,
        is_target_hero: bool,
        is_visible_radiant: bool,
        is_visible_dire: bool,
        is_ability_toggle_on: bool,
        is_ability_toggle_off: bool,
        is_heal_save: bool,
        is_ultimate_ability: bool,
        uses_charges: bool,
        will_reincarnate: bool,
        regenerated_health: f32,
        neutral_camp_team: u32,
        at_night_time: bool,
        is_target_building: bool,
        attacker_has_scepter: bool
    }
}