1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use super::bit_packed::*;
use crate::message_events::{MessageEvent, MessageEventError, ReplayMessageEvent};
use crate::*;
use nom::*;
use nom_mpq::MPQ;

impl GameEMessageId {
    /// Reads a delta, GameMessage set
    #[tracing::instrument(name="GameEMessageId::parse_events", level = "debug", skip(input), fields(peek = peek_bits(input)))]
    pub fn parse_event_triplet(
        input: (&[u8], usize),
    ) -> IResult<(&[u8], usize), (i64, i64, GameEMessageId)> {
        let (tail, delta) = SVarUint32::parse(input)?;
        tracing::debug!("Delta: {:?}", delta);
        let (tail, user_id) = ReplaySGameUserId::parse(tail)?;
        tracing::debug!("UserId: {:?}", user_id);
        let (tail, event) = GameEMessageId::parse(tail)?;
        tracing::debug!("Event: {:?}", event);
        let delta = match delta {
            SVarUint32::MUint6(val) => val.value,
            SVarUint32::MUint14(val) => val.value,
            SVarUint32::MUint22(val) => val.value,
            SVarUint32::MUint32(val) => val.value,
        };
        // The next event is byte aligned
        let (tail, _) = byte_align(tail)?;
        Ok((tail, (delta, user_id.m_user_id, event)))
    }

    /// Read the Message Events
    pub fn read_events(mpq: &MPQ, file_contents: &[u8]) -> Vec<MessageEvent> {
        // TODO: Make it return an Iterator, remove the unwrap.
        let (_event_tail, game_events) = mpq
            .read_mpq_file_sector("replay.message.events", false, file_contents)
            .unwrap();
        let mut res = vec![];
        let mut count = 1usize;
        let mut event_tail: (&[u8], usize) = (&game_events, 0usize);
        loop {
            tracing::debug!("-----------------------------------------------");
            tracing::debug!("Event number: {}", count);
            let (new_event_tail, (delta, user_id, event)) =
                Self::parse_event_triplet(event_tail).expect("Unable to parse GameEvents");
            count += 1;
            event_tail = new_event_tail;
            match event.try_into() {
                Ok(val) => res.push(MessageEvent {
                    delta,
                    user_id,
                    event: val,
                }),
                Err(err) => {
                    tracing::debug!("Skipping event: {:?}", err);
                }
            };
            if event_tail.0.input_len() == 0 {
                break;
            }
        }
        res
    }
}

impl TryFrom<GameEMessageId> for ReplayMessageEvent {
    type Error = MessageEventError;
    fn try_from(value: GameEMessageId) -> Result<Self, Self::Error> {
        match value {
            GameEMessageId::EChat(e) => Ok(e.try_into()?),
            _ => Err(MessageEventError::UnsupportedEventType),
        }
    }
}

impl TryFrom<GameSChatMessage> for ReplayMessageEvent {
    type Error = MessageEventError;
    fn try_from(source: GameSChatMessage) -> Result<Self, Self::Error> {
        Ok(message_events::ReplayMessageEvent::EChat(
            message_events::ChatMessage {
                m_recipient: source.m_recipient.into(),
                m_string: str::from_utf8(&source.m_string.value)?.to_string(),
            },
        ))
    }
}

impl From<GameEMessageRecipient> for message_events::GameEMessageRecipient {
    fn from(source: GameEMessageRecipient) -> message_events::GameEMessageRecipient {
        match source {
            GameEMessageRecipient::EAll => message_events::GameEMessageRecipient::EAll,
            GameEMessageRecipient::EAllies => message_events::GameEMessageRecipient::EAllies,
            GameEMessageRecipient::EIndividual => {
                message_events::GameEMessageRecipient::EIndividual
            }
            GameEMessageRecipient::EBattlenet => message_events::GameEMessageRecipient::EBattlenet,
            GameEMessageRecipient::EObservers => message_events::GameEMessageRecipient::EObservers,
        }
    }
}