use crate::error::S2ProtocolError;
use crate::game_events::{GameEvent, VersionedBalanceUnit};
use crate::versions::protocol75689::bit_packed::GameEEventId as Protocol75689GameEEventId;
use crate::versions::protocol87702::bit_packed::GameEEventId as Protocol87702GameEEventId;
use crate::{SC2EventType, SC2UserState};
use nom::*;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct GameEventIteratorState {
event_data: Vec<u8>,
event_loop: i64,
byte_index: usize,
bit_index: usize,
}
impl From<Vec<u8>> for GameEventIteratorState {
fn from(event_data: Vec<u8>) -> Self {
Self {
event_data,
event_loop: 0,
byte_index: 0,
bit_index: 0,
}
}
}
impl GameEventIteratorState {
#[tracing::instrument(level = "debug", skip(self), fields(event_loop = self.event_loop))]
pub fn read_versioned_game_event(
&mut self,
protocol_version: u32,
) -> Result<GameEvent, S2ProtocolError> {
let (delta, user_id, event) = match protocol_version {
0..=75689 => {
let ((tail_byte, tail_bit), (delta, user_id, event)) =
Protocol75689GameEEventId::parse_event_triplet((
&self.event_data[self.byte_index..],
self.bit_index,
))?;
self.byte_index += tail_byte.as_ptr() as usize
- self.event_data[self.byte_index..].as_ptr() as usize;
self.bit_index = tail_bit;
self.event_loop += delta;
(delta, user_id, event.try_into()?)
}
_ => {
let ((tail_byte, tail_bit), (delta, user_id, event)) =
Protocol87702GameEEventId::parse_event_triplet((
&self.event_data[self.byte_index..],
self.bit_index,
))?;
self.byte_index += tail_byte.as_ptr() as usize
- self.event_data[self.byte_index..].as_ptr() as usize;
self.bit_index = tail_bit;
self.event_loop += delta;
(delta, user_id, event.try_into()?)
}
};
Ok(GameEvent {
delta,
user_id,
event,
})
}
#[tracing::instrument(level = "debug", skip(self), fields(event_loop = self.event_loop))]
pub fn get_next_event(
&mut self,
protocol_version: u32,
user_state: &HashMap<i64, SC2UserState>,
abilities: &HashMap<String, VersionedBalanceUnit>,
) -> Option<SC2EventType> {
loop {
let current_slice: &[u8] = &self.event_data[self.byte_index..];
if current_slice.input_len() == 0 {
return None;
}
match self.read_versioned_game_event(protocol_version) {
Ok(val) => {
let GameEvent {
delta: _,
user_id,
event,
} = val;
let mut player_name: Option<String> = None;
if let Some(player_state) = user_state.get(&user_id) {
player_name = Some(
player_state
.player_lobby_details
.player_details
.name
.clone(),
);
}
let event = SC2EventType::Game {
game_loop: self.event_loop,
event: event.clone(),
user_id,
player_name,
};
return Some(event);
}
Err(S2ProtocolError::UnsupportedEventType) => {}
Err(err) => {
tracing::error!("Error reading game event: {:?}", err);
return None;
}
}
}
}
}