Add some more types and improve typing for player events
This commit is contained in:
@@ -1,60 +1,4 @@
|
||||
use crate::csgo_proto;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RawValue {
|
||||
String(String),
|
||||
F32(f32),
|
||||
I32(i32),
|
||||
Bool(bool),
|
||||
U64(u64),
|
||||
}
|
||||
|
||||
impl TryFrom<crate::csgo_proto::c_msg_source1_legacy_game_event::KeyT> for RawValue {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: crate::csgo_proto::c_msg_source1_legacy_game_event::KeyT) -> Result<Self, Self::Error> {
|
||||
match value.r#type() {
|
||||
1 if value.val_string.is_some() => Ok(Self::String(value.val_string.unwrap())),
|
||||
2 if value.val_float.is_some() => Ok(Self::F32(value.val_float.unwrap())),
|
||||
3 if value.val_long.is_some() => Ok(Self::I32(value.val_long.unwrap())),
|
||||
4 if value.val_short.is_some() => Ok(Self::I32(value.val_short.unwrap() as i32)),
|
||||
5 if value.val_byte.is_some() => Ok(Self::I32(value.val_byte.unwrap() as i32)),
|
||||
6 if value.val_bool.is_some() => Ok(Self::Bool(value.val_bool.unwrap())),
|
||||
7 if value.val_uint64.is_some() => Ok(Self::U64(value.val_uint64.unwrap())),
|
||||
8 if value.val_long.is_some() => Ok(Self::I32(value.val_long.unwrap())),
|
||||
9 if value.val_short.is_some() => Ok(Self::I32(value.val_short.unwrap() as i32)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RawValue> for i32 {
|
||||
type Error = ();
|
||||
fn try_from(value: RawValue) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
RawValue::I32(v) => Ok(v),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<RawValue> for bool {
|
||||
type Error = ();
|
||||
fn try_from(value: RawValue) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
RawValue::Bool(v) => Ok(v),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<RawValue> for String {
|
||||
type Error = ();
|
||||
fn try_from(value: RawValue) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
RawValue::String(v) => Ok(v),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::{csgo_proto, RawValue, UserId};
|
||||
|
||||
macro_rules! define_event {
|
||||
($name:ident, $target:path $(, ($field:ident, $field_ty:ty))*) => {
|
||||
@@ -87,12 +31,48 @@ macro_rules! define_event {
|
||||
|
||||
define_event!(HltvVersionInfo, GameEvent::HltvVersionInfo);
|
||||
|
||||
define_event!(ItemEquip, GameEvent::ItemEquip, (userid, i32), (hassilencer, bool), (hastracers, bool), (item, String), (issilenced, bool), (canzoom, bool), (ispainted, bool), (weptype, i32), (defindex, i32));
|
||||
define_event!(ItemPickup, GameEvent::ItemPickup, (userid, RawValue), (item, RawValue), (silent, RawValue), (defindex, RawValue));
|
||||
define_event!(
|
||||
ItemEquip,
|
||||
GameEvent::ItemEquip,
|
||||
(userid, UserId),
|
||||
(hassilencer, bool),
|
||||
(hastracers, bool),
|
||||
(item, String),
|
||||
(issilenced, bool),
|
||||
(canzoom, bool),
|
||||
(ispainted, bool),
|
||||
(weptype, i32),
|
||||
(defindex, i32)
|
||||
);
|
||||
define_event!(
|
||||
ItemPickup,
|
||||
GameEvent::ItemPickup,
|
||||
(userid, UserId),
|
||||
(item, RawValue),
|
||||
(silent, RawValue),
|
||||
(defindex, RawValue)
|
||||
);
|
||||
|
||||
define_event!(WeaponReload, GameEvent::WeaponReload, (userid, RawValue), (userid_pawn, RawValue));
|
||||
define_event!(WeaponZoom, GameEvent::WeaponZoom, (userid, RawValue), (userid_pawn, RawValue));
|
||||
define_event!(WeaponFire, GameEvent::WeaponFire, (userid, RawValue), (weapon, RawValue), (silenced, RawValue), (userid_pawn, RawValue));
|
||||
define_event!(
|
||||
WeaponReload,
|
||||
GameEvent::WeaponReload,
|
||||
(userid, UserId),
|
||||
(userid_pawn, RawValue)
|
||||
);
|
||||
define_event!(
|
||||
WeaponZoom,
|
||||
GameEvent::WeaponZoom,
|
||||
(userid, UserId),
|
||||
(userid_pawn, RawValue)
|
||||
);
|
||||
define_event!(
|
||||
WeaponFire,
|
||||
GameEvent::WeaponFire,
|
||||
(userid, UserId),
|
||||
(weapon, RawValue),
|
||||
(silenced, RawValue),
|
||||
(userid_pawn, RawValue)
|
||||
);
|
||||
|
||||
define_event!(SmokeGrenadeDetonate, GameEvent::SmokeGrenadeDetonate);
|
||||
define_event!(SmokeGrenadeExpired, GameEvent::SmokeGrenadeExpired);
|
||||
@@ -103,16 +83,106 @@ define_event!(FlashbangDetonate, GameEvent::FlashbangDetonate);
|
||||
define_event!(DecoyStarted, GameEvent::DecoyStarted);
|
||||
define_event!(DecoyDetonate, GameEvent::DecoyDetonate);
|
||||
|
||||
define_event!(PlayerConnect, GameEvent::PlayerConnect, (address, RawValue), (bot, RawValue), (name, RawValue), (userid, RawValue), (networkid, RawValue), (xuid, RawValue));
|
||||
define_event!(PlayerConnectFull, GameEvent::PlayerConnectFull, (userid, RawValue));
|
||||
define_event!(PlayerDisconnect, GameEvent::PlayerDisconnect, (userid, RawValue), (reason, RawValue), (name, RawValue), (networkid, RawValue), (xuid, RawValue));
|
||||
define_event!(PlayerFootstep, GameEvent::PlayerFootstep);
|
||||
define_event!(PlayerJump, GameEvent::PlayerJump);
|
||||
define_event!(PlayerHurt, GameEvent::PlayerHurt);
|
||||
define_event!(PlayerDeath, GameEvent::PlayerDeath);
|
||||
define_event!(PlayerSpawn, GameEvent::PlayerSpawn);
|
||||
define_event!(PlayerBlind, GameEvent::PlayerBlind);
|
||||
define_event!(PlayerTeam, GameEvent::PlayerTeam, (userid, RawValue), (team, RawValue), (oldteam, RawValue), (disconnect, RawValue), (silent, RawValue), (isbot, RawValue), (userid_pawn, RawValue));
|
||||
define_event!(
|
||||
PlayerConnect,
|
||||
GameEvent::PlayerConnect,
|
||||
(address, RawValue),
|
||||
(bot, RawValue),
|
||||
(name, RawValue),
|
||||
(userid, i32),
|
||||
(networkid, RawValue),
|
||||
(xuid, RawValue)
|
||||
);
|
||||
define_event!(
|
||||
PlayerConnectFull,
|
||||
GameEvent::PlayerConnectFull,
|
||||
(userid, UserId)
|
||||
);
|
||||
define_event!(
|
||||
PlayerDisconnect,
|
||||
GameEvent::PlayerDisconnect,
|
||||
(userid, UserId),
|
||||
(reason, RawValue),
|
||||
(name, RawValue),
|
||||
(networkid, RawValue),
|
||||
(xuid, RawValue)
|
||||
);
|
||||
define_event!(
|
||||
PlayerFootstep,
|
||||
GameEvent::PlayerFootstep,
|
||||
(userid, UserId),
|
||||
(userid_pawn, RawValue)
|
||||
);
|
||||
define_event!(PlayerJump, GameEvent::PlayerJump, (userid, i32));
|
||||
define_event!(
|
||||
PlayerHurt,
|
||||
GameEvent::PlayerHurt,
|
||||
(userid, UserId),
|
||||
(attacker, UserId),
|
||||
(health, RawValue),
|
||||
(armor, RawValue),
|
||||
(weapon, String),
|
||||
(dmg_health, RawValue),
|
||||
(dmg_armor, RawValue),
|
||||
(hitgroup, RawValue),
|
||||
(userid_pawn, RawValue),
|
||||
(attacker_pawn, RawValue)
|
||||
);
|
||||
define_event!(
|
||||
PlayerDeath,
|
||||
GameEvent::PlayerDeath,
|
||||
(userid, UserId),
|
||||
(attacker, UserId),
|
||||
(assister, UserId),
|
||||
(assistedflash, bool),
|
||||
(weapon, String),
|
||||
(weapon_itemid, String),
|
||||
(weapon_fauxitemid, String),
|
||||
(weapon_originalowner_xuid, String),
|
||||
(headshot, bool),
|
||||
(dominated, RawValue),
|
||||
(revenge, RawValue),
|
||||
(wipe, RawValue),
|
||||
(penetrated, RawValue),
|
||||
(noreplay, bool),
|
||||
(noscope, bool),
|
||||
(thrusmoke, bool),
|
||||
(attackerblind, bool),
|
||||
(distance, RawValue),
|
||||
(userid_pawn, RawValue),
|
||||
(attacker_pawn, RawValue),
|
||||
(assister_pawn, RawValue),
|
||||
(dmg_health, RawValue),
|
||||
(dmg_armor, RawValue),
|
||||
(hitgroup, RawValue),
|
||||
(attackerinair, bool)
|
||||
);
|
||||
define_event!(
|
||||
PlayerSpawn,
|
||||
GameEvent::PlayerSpawn,
|
||||
(userid, UserId),
|
||||
(inrestart, RawValue),
|
||||
(userid_pawn, RawValue)
|
||||
);
|
||||
define_event!(
|
||||
PlayerBlind,
|
||||
GameEvent::PlayerBlind,
|
||||
(userid, UserId),
|
||||
(attacker, RawValue),
|
||||
(entityid, RawValue),
|
||||
(blind_duration, RawValue)
|
||||
);
|
||||
define_event!(
|
||||
PlayerTeam,
|
||||
GameEvent::PlayerTeam,
|
||||
(userid, UserId),
|
||||
(team, RawValue),
|
||||
(oldteam, RawValue),
|
||||
(disconnect, RawValue),
|
||||
(silent, RawValue),
|
||||
(isbot, RawValue),
|
||||
(userid_pawn, RawValue)
|
||||
);
|
||||
|
||||
define_event!(BulletDamage, GameEvent::BulletDamage);
|
||||
|
||||
@@ -138,12 +208,18 @@ define_event!(RoundPreRestart, GameEvent::RoundPreRestart);
|
||||
define_event!(RoundTimeWarning, GameEvent::RoundTimeWarning);
|
||||
define_event!(RoundFinalBeep, GameEvent::RoundFinalBeep);
|
||||
define_event!(BuyTimeEnded, GameEvent::BuyTimeEnded);
|
||||
define_event!(RoundAnnounceLastRoundHalf, GameEvent::RoundAnnounceLastRoundHalf);
|
||||
define_event!(
|
||||
RoundAnnounceLastRoundHalf,
|
||||
GameEvent::RoundAnnounceLastRoundHalf
|
||||
);
|
||||
define_event!(AnnouncePhaseEnd, GameEvent::AnnouncePhaseEnd);
|
||||
|
||||
define_event!(WinPanelMatch, GameEvent::WinPanelMatch);
|
||||
|
||||
type ParseFn = fn(keys: &[csgo_proto::csvc_msg_game_event_list::KeyT], event: csgo_proto::CMsgSource1LegacyGameEvent) -> Result<GameEvent, ParseGameEventError>;
|
||||
type ParseFn = fn(
|
||||
keys: &[csgo_proto::csvc_msg_game_event_list::KeyT],
|
||||
event: csgo_proto::CMsgSource1LegacyGameEvent,
|
||||
) -> Result<GameEvent, ParseGameEventError>;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
@@ -203,7 +279,7 @@ pub enum GameEvent {
|
||||
BuyTimeEnded(BuyTimeEnded),
|
||||
RoundAnnounceLastRoundHalf(RoundAnnounceLastRoundHalf),
|
||||
AnnouncePhaseEnd(AnnouncePhaseEnd),
|
||||
|
||||
|
||||
WinPanelMatch(WinPanelMatch),
|
||||
}
|
||||
|
||||
@@ -217,7 +293,7 @@ pub static EVENT_PARSERS: phf::Map<&'static str, GameEventParser> = phf::phf_map
|
||||
|
||||
"item_equip" => GameEventParser::new(ItemEquip::parse),
|
||||
"item_pickup" => GameEventParser::new(ItemPickup::parse),
|
||||
|
||||
|
||||
"weapon_reload" => GameEventParser::new(WeaponReload::parse),
|
||||
"weapon_zoom" => GameEventParser::new(WeaponZoom::parse),
|
||||
"weapon_fire" => GameEventParser::new(WeaponFire::parse),
|
||||
@@ -230,7 +306,7 @@ pub static EVENT_PARSERS: phf::Map<&'static str, GameEventParser> = phf::phf_map
|
||||
"flashbang_detonate" => GameEventParser::new(FlashbangDetonate::parse),
|
||||
"decoy_started" => GameEventParser::new(DecoyStarted::parse),
|
||||
"decoy_detonate" => GameEventParser::new(DecoyDetonate::parse),
|
||||
|
||||
|
||||
"player_connect" => GameEventParser::new(PlayerConnect::parse),
|
||||
"player_connect_full" => GameEventParser::new(PlayerConnectFull::parse),
|
||||
"player_disconnect" => GameEventParser::new(PlayerDisconnect::parse),
|
||||
@@ -241,7 +317,7 @@ pub static EVENT_PARSERS: phf::Map<&'static str, GameEventParser> = phf::phf_map
|
||||
"player_spawn" => GameEventParser::new(PlayerSpawn::parse),
|
||||
"player_blind" => GameEventParser::new(PlayerBlind::parse),
|
||||
"player_team" => GameEventParser::new(PlayerTeam::parse),
|
||||
|
||||
|
||||
"bullet_damage" => GameEventParser::new(BulletDamage::parse),
|
||||
|
||||
"other_death" => GameEventParser::new(OtherDeath::parse),
|
||||
@@ -273,17 +349,22 @@ pub static EVENT_PARSERS: phf::Map<&'static str, GameEventParser> = phf::phf_map
|
||||
};
|
||||
|
||||
pub struct GameEventParser {
|
||||
inner: fn(keys: &[csgo_proto::csvc_msg_game_event_list::KeyT], event: csgo_proto::CMsgSource1LegacyGameEvent) -> Result<GameEvent, ParseGameEventError>,
|
||||
inner: fn(
|
||||
keys: &[csgo_proto::csvc_msg_game_event_list::KeyT],
|
||||
event: csgo_proto::CMsgSource1LegacyGameEvent,
|
||||
) -> Result<GameEvent, ParseGameEventError>,
|
||||
}
|
||||
|
||||
impl GameEventParser {
|
||||
pub const fn new(func: ParseFn) -> Self {
|
||||
Self {
|
||||
inner: func,
|
||||
}
|
||||
Self { inner: func }
|
||||
}
|
||||
|
||||
pub fn parse(&self, keys: &[csgo_proto::csvc_msg_game_event_list::KeyT], event: csgo_proto::CMsgSource1LegacyGameEvent) -> Result<GameEvent, ParseGameEventError> {
|
||||
pub fn parse(
|
||||
&self,
|
||||
keys: &[csgo_proto::csvc_msg_game_event_list::KeyT],
|
||||
event: csgo_proto::CMsgSource1LegacyGameEvent,
|
||||
) -> Result<GameEvent, ParseGameEventError> {
|
||||
if keys.len() != event.keys.len() {
|
||||
return Err(ParseGameEventError::MismatchedKeysFields);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ mod packet;
|
||||
pub use packet::DemoEvent;
|
||||
pub mod game_event;
|
||||
|
||||
mod values;
|
||||
pub use values::*;
|
||||
|
||||
pub mod parser;
|
||||
|
||||
pub mod csgo_proto {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{packet::DemoEvent, DemoCommand, Frame};
|
||||
use crate::{packet::DemoEvent, DemoCommand, Frame, UserId};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FirstPassError {
|
||||
@@ -8,7 +8,7 @@ pub enum FirstPassError {
|
||||
MissingFileHeader,
|
||||
MissingFileInfo,
|
||||
Bitreader(crate::bitreader::BitReadError),
|
||||
ParseGameEventError(crate::game_event::ParseGameEventError)
|
||||
ParseGameEventError(crate::game_event::ParseGameEventError),
|
||||
}
|
||||
|
||||
impl From<prost::DecodeError> for FirstPassError {
|
||||
@@ -38,12 +38,18 @@ pub struct FirstPassOutput {
|
||||
pub header: crate::csgo_proto::CDemoFileHeader,
|
||||
pub info: crate::csgo_proto::CDemoFileInfo,
|
||||
pub events: Vec<DemoEvent>,
|
||||
pub player_info: std::collections::HashMap<i32, Player>,
|
||||
pub player_info: std::collections::HashMap<UserId, Player>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct GameEventMapping {
|
||||
mapping: std::collections::HashMap<i32, (String, Vec<crate::csgo_proto::csvc_msg_game_event_list::KeyT>)>,
|
||||
mapping: std::collections::HashMap<
|
||||
i32,
|
||||
(
|
||||
String,
|
||||
Vec<crate::csgo_proto::csvc_msg_game_event_list::KeyT>,
|
||||
),
|
||||
>,
|
||||
}
|
||||
|
||||
pub fn parse<'b, FI>(frames: FI) -> Result<FirstPassOutput, FirstPassError>
|
||||
@@ -87,14 +93,19 @@ where
|
||||
let header = header.ok_or(FirstPassError::MissingFileHeader)?;
|
||||
let info = file_info.ok_or(FirstPassError::MissingFileInfo)?;
|
||||
|
||||
Ok(FirstPassOutput { header, info, events, player_info })
|
||||
Ok(FirstPassOutput {
|
||||
header,
|
||||
info,
|
||||
events,
|
||||
player_info,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_fullpacket(
|
||||
data: &[u8],
|
||||
events: &mut Vec<DemoEvent>,
|
||||
event_mapper: &mut GameEventMapping,
|
||||
player_info: &mut std::collections::HashMap<i32, Player>,
|
||||
player_info: &mut std::collections::HashMap<UserId, Player>,
|
||||
) -> Result<(), FirstPassError> {
|
||||
let raw: crate::csgo_proto::CDemoFullPacket = prost::Message::decode(data)?;
|
||||
|
||||
@@ -115,7 +126,7 @@ fn parse_packet(
|
||||
data: &[u8],
|
||||
events: &mut Vec<DemoEvent>,
|
||||
event_mapper: &mut GameEventMapping,
|
||||
player_info: &mut std::collections::HashMap<i32, Player>,
|
||||
player_info: &mut std::collections::HashMap<UserId, Player>,
|
||||
) -> Result<(), FirstPassError> {
|
||||
let raw: crate::csgo_proto::CDemoPacket = prost::Message::decode(data)?;
|
||||
|
||||
@@ -128,7 +139,7 @@ fn inner_parse_packet(
|
||||
raw: &crate::csgo_proto::CDemoPacket,
|
||||
events: &mut Vec<DemoEvent>,
|
||||
event_mapper: &mut GameEventMapping,
|
||||
player_info: &mut std::collections::HashMap<i32, Player>,
|
||||
player_info: &mut std::collections::HashMap<UserId, Player>,
|
||||
) -> Result<(), FirstPassError> {
|
||||
let mut bitreader = crate::bitreader::Bitreader::new(raw.data());
|
||||
|
||||
@@ -167,7 +178,8 @@ fn inner_parse_packet(
|
||||
events.push(DemoEvent::ServerInfo(raw));
|
||||
}
|
||||
crate::netmessagetypes::NetmessageType::net_SignonState => {
|
||||
let raw: crate::csgo_proto::CnetMsgSignonState = prost::Message::decode(msg_bytes.as_slice())?;
|
||||
let raw: crate::csgo_proto::CnetMsgSignonState =
|
||||
prost::Message::decode(msg_bytes.as_slice())?;
|
||||
dbg!(raw);
|
||||
}
|
||||
crate::netmessagetypes::NetmessageType::net_Tick => {
|
||||
@@ -228,13 +240,17 @@ fn inner_parse_packet(
|
||||
crate::netmessagetypes::NetmessageType::TE_EffectDispatch => {}
|
||||
crate::netmessagetypes::NetmessageType::CS_UM_PlayerStatsUpdate => {}
|
||||
crate::netmessagetypes::NetmessageType::CS_UM_EndOfMatchAllPlayersData => {
|
||||
let raw: crate::csgo_proto::CcsUsrMsgEndOfMatchAllPlayersData = prost::Message::decode(msg_bytes.as_slice())?;
|
||||
let raw: crate::csgo_proto::CcsUsrMsgEndOfMatchAllPlayersData =
|
||||
prost::Message::decode(msg_bytes.as_slice())?;
|
||||
|
||||
for data in raw.allplayerdata {
|
||||
player_info.insert(data.slot(), Player {
|
||||
name: data.name.unwrap(),
|
||||
xuid: data.xuid.unwrap(),
|
||||
});
|
||||
player_info.insert(
|
||||
UserId(data.slot()),
|
||||
Player {
|
||||
name: data.name.unwrap(),
|
||||
xuid: data.xuid.unwrap(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
crate::netmessagetypes::NetmessageType::TE_PhysicsProp => {}
|
||||
|
||||
71
src/values.rs
Normal file
71
src/values.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
#[derive(Debug)]
|
||||
pub enum RawValue {
|
||||
String(String),
|
||||
F32(f32),
|
||||
I32(i32),
|
||||
Bool(bool),
|
||||
U64(u64),
|
||||
}
|
||||
|
||||
impl TryFrom<crate::csgo_proto::c_msg_source1_legacy_game_event::KeyT> for RawValue {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(
|
||||
value: crate::csgo_proto::c_msg_source1_legacy_game_event::KeyT,
|
||||
) -> Result<Self, Self::Error> {
|
||||
match value.r#type() {
|
||||
1 if value.val_string.is_some() => Ok(Self::String(value.val_string.unwrap())),
|
||||
2 if value.val_float.is_some() => Ok(Self::F32(value.val_float.unwrap())),
|
||||
3 if value.val_long.is_some() => Ok(Self::I32(value.val_long.unwrap())),
|
||||
4 if value.val_short.is_some() => Ok(Self::I32(value.val_short.unwrap() as i32)),
|
||||
5 if value.val_byte.is_some() => Ok(Self::I32(value.val_byte.unwrap() as i32)),
|
||||
6 if value.val_bool.is_some() => Ok(Self::Bool(value.val_bool.unwrap())),
|
||||
7 if value.val_uint64.is_some() => Ok(Self::U64(value.val_uint64.unwrap())),
|
||||
8 if value.val_long.is_some() => Ok(Self::I32(value.val_long.unwrap())),
|
||||
9 if value.val_short.is_some() => Ok(Self::I32(value.val_short.unwrap() as i32)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RawValue> for i32 {
|
||||
type Error = ();
|
||||
fn try_from(value: RawValue) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
RawValue::I32(v) => Ok(v),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<RawValue> for bool {
|
||||
type Error = ();
|
||||
fn try_from(value: RawValue) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
RawValue::Bool(v) => Ok(v),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TryFrom<RawValue> for String {
|
||||
type Error = ();
|
||||
fn try_from(value: RawValue) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
RawValue::String(v) => Ok(v),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct UserId(pub(crate) i32);
|
||||
|
||||
impl TryFrom<RawValue> for UserId {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: RawValue) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
RawValue::I32(v) => Ok(Self(v)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
use csdemo::{game_event::GameEvent, DemoEvent};
|
||||
|
||||
#[test]
|
||||
fn mirage_1() {
|
||||
let content = std::fs::read("testfiles/mirage.dem").unwrap();
|
||||
@@ -11,7 +13,27 @@ fn mirage_1() {
|
||||
|
||||
assert_eq!("de_mirage", output.header.map_name());
|
||||
|
||||
todo!()
|
||||
for event in output.events.iter() {
|
||||
match event {
|
||||
DemoEvent::GameEvent(gevent) => match gevent {
|
||||
GameEvent::PlayerDeath(death) => {
|
||||
assert!(
|
||||
death.remaining.is_empty(),
|
||||
"Remaining for PlayerDeath: {:?}",
|
||||
death.remaining
|
||||
);
|
||||
|
||||
let died_user = output
|
||||
.player_info
|
||||
.get(death.userid.as_ref().unwrap())
|
||||
.unwrap();
|
||||
dbg!(died_user);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user