1
0
Fork 0
mirror of https://codeberg.org/demostf/parser.git synced 2026-06-03 18:24:05 +02:00
This commit is contained in:
Robin Appelman 2019-03-02 22:33:22 +01:00
commit f2650dc32f
19 changed files with 3614 additions and 2210 deletions

View file

@ -1,5 +1,4 @@
#[allow(unused_variables)] #[allow(unused_variables)]
use std::error::Error; use std::error::Error;
use std::fs; use std::fs;

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
use bitstream_reader::BitRead;
use std::collections::HashMap; use std::collections::HashMap;
use bitstream_reader::{BitRead};
use crate::{ParseError, Result}; use crate::{ParseError, Result};
@ -53,7 +53,7 @@ impl FromGameEventValue for String {
_ => Err(ParseError::InvalidGameEvent { _ => Err(ParseError::InvalidGameEvent {
name: name.to_string(), name: name.to_string(),
value, value,
}) }),
} }
} }
} }
@ -65,7 +65,7 @@ impl FromGameEventValue for f32 {
_ => Err(ParseError::InvalidGameEvent { _ => Err(ParseError::InvalidGameEvent {
name: name.to_string(), name: name.to_string(),
value, value,
}) }),
} }
} }
} }
@ -77,7 +77,7 @@ impl FromGameEventValue for u32 {
_ => Err(ParseError::InvalidGameEvent { _ => Err(ParseError::InvalidGameEvent {
name: name.to_string(), name: name.to_string(),
value, value,
}) }),
} }
} }
} }
@ -89,7 +89,7 @@ impl FromGameEventValue for u16 {
_ => Err(ParseError::InvalidGameEvent { _ => Err(ParseError::InvalidGameEvent {
name: name.to_string(), name: name.to_string(),
value, value,
}) }),
} }
} }
} }
@ -101,7 +101,7 @@ impl FromGameEventValue for u8 {
_ => Err(ParseError::InvalidGameEvent { _ => Err(ParseError::InvalidGameEvent {
name: name.to_string(), name: name.to_string(),
value, value,
}) }),
} }
} }
} }
@ -113,7 +113,7 @@ impl FromGameEventValue for bool {
_ => Err(ParseError::InvalidGameEvent { _ => Err(ParseError::InvalidGameEvent {
name: name.to_string(), name: name.to_string(),
value, value,
}) }),
} }
} }
} }
@ -125,7 +125,7 @@ impl FromGameEventValue for () {
_ => Err(ParseError::InvalidGameEvent { _ => Err(ParseError::InvalidGameEvent {
name: name.to_string(), name: name.to_string(),
value, value,
}) }),
} }
} }
} }
@ -138,4 +138,4 @@ pub struct RawGameEvent {
pub trait FromRawGameEvent: Sized { pub trait FromRawGameEvent: Sized {
fn from_raw_event(values: Vec<GameEventValue>) -> Result<Self>; fn from_raw_event(values: Vec<GameEventValue>) -> Result<Self>;
} }

View file

@ -1,8 +1,8 @@
use bitstream_reader::{BitRead, BitReadSized, LittleEndian}; use bitstream_reader::{BitRead, BitReadSized, LittleEndian};
use crate::{ReadResult, Stream};
use crate::demo::sendprop::read_bit_coord; use crate::demo::sendprop::read_bit_coord;
use crate::demo::vector::Vector; use crate::demo::vector::Vector;
use crate::{ReadResult, Stream};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct BSPDecalMessage { pub struct BSPDecalMessage {
@ -44,4 +44,3 @@ impl BitRead<LittleEndian> for BSPDecalMessage {
}) })
} }
} }

View file

@ -1,7 +1,7 @@
use bitstream_reader::{BitRead, BitReadSized, LittleEndian}; use bitstream_reader::{BitRead, BitReadSized, LittleEndian};
use crate::{ReadResult, Stream};
use crate::demo::message::stringtable::log_base2; use crate::demo::message::stringtable::log_base2;
use crate::{ReadResult, Stream};
#[derive(BitReadSized, Debug)] #[derive(BitReadSized, Debug)]
pub struct ClassInfoEntry { pub struct ClassInfoEntry {

View file

@ -3,9 +3,12 @@ use std::iter::FromIterator;
use bitstream_reader::{BitRead, BitReadSized, LittleEndian}; use bitstream_reader::{BitRead, BitReadSized, LittleEndian};
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::demo::gameevent_gen::GameEventType; use crate::demo::gameevent_gen::GameEventType;
use crate::demo::gamevent::{GameEvent, GameEventDefinition, GameEventEntry, GameEventValue, GameEventValueType, RawGameEvent}; use crate::demo::gamevent::{
GameEvent, GameEventDefinition, GameEventEntry, GameEventValue, GameEventValueType,
RawGameEvent,
};
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
fn read_event_value(stream: &mut Stream, definition: &GameEventEntry) -> Result<GameEventValue> { fn read_event_value(stream: &mut Stream, definition: &GameEventEntry) -> Result<GameEventValue> {
Ok(match definition.kind { Ok(match definition.kind {
@ -16,13 +19,13 @@ fn read_event_value(stream: &mut Stream, definition: &GameEventEntry) -> Result<
GameEventValueType::Byte => GameEventValue::Byte(stream.read()?), GameEventValueType::Byte => GameEventValue::Byte(stream.read()?),
GameEventValueType::Boolean => GameEventValue::Boolean(stream.read()?), GameEventValueType::Boolean => GameEventValue::Boolean(stream.read()?),
GameEventValueType::Local => GameEventValue::Local, GameEventValueType::Local => GameEventValue::Local,
GameEventValueType::None => unreachable!() GameEventValueType::None => unreachable!(),
}) })
} }
#[derive(Debug)] #[derive(Debug)]
pub struct GameEventMessage { pub struct GameEventMessage {
pub event: GameEvent pub event: GameEvent,
} }
impl Parse for GameEventMessage { impl Parse for GameEventMessage {
@ -37,17 +40,12 @@ impl Parse for GameEventMessage {
values.push(read_event_value(&mut data, &entry)?); values.push(read_event_value(&mut data, &entry)?);
} }
RawGameEvent { RawGameEvent { event_type, values }
event_type,
values,
}
} }
None => unreachable!() None => unreachable!(),
}; };
let event = GameEvent::from_raw_event(raw_event)?; let event = GameEvent::from_raw_event(raw_event)?;
Ok(GameEventMessage { Ok(GameEventMessage { event })
event
})
} }
} }
@ -86,12 +84,8 @@ impl BitRead<LittleEndian> for GameEventListMessage {
let length: u32 = stream.read_sized(20)?; let length: u32 = stream.read_sized(20)?;
let mut data = stream.read_bits(length as usize)?; let mut data = stream.read_bits(length as usize)?;
let event_list_vec: Vec<GameEventDefinition> = data.read_sized(count as usize)?; let event_list_vec: Vec<GameEventDefinition> = data.read_sized(count as usize)?;
let event_list = HashMap::from_iter( let event_list = HashMap::from_iter(event_list_vec.into_iter().map(|def| (def.id, def)));
event_list_vec.into_iter().map(|def| (def.id, def))
);
Ok(GameEventListMessage { Ok(GameEventListMessage { event_list })
event_list
})
} }
} }

View file

@ -1,7 +1,7 @@
use crate::Stream;
/// Messages that consists only of primitives and string and can be derived /// Messages that consists only of primitives and string and can be derived
use bitstream_reader::{BitRead, BitStream, LittleEndian}; use bitstream_reader::{BitRead, BitStream, LittleEndian};
use std::collections::HashMap; use std::collections::HashMap;
use crate::Stream;
#[derive(BitRead, Debug)] #[derive(BitRead, Debug)]
pub struct FileMessage { pub struct FileMessage {
@ -77,11 +77,11 @@ pub struct FixAngleMessage {
#[endianness = "LittleEndian"] #[endianness = "LittleEndian"]
pub struct EntityMessage { pub struct EntityMessage {
#[size = 11] #[size = 11]
pub index: u16, pub index: u16,
#[size = 9] #[size = 9]
pub class_id: u16, pub class_id: u16,
#[size = 11] #[size = 11]
pub length: u16, pub length: u16,
#[size = "length * 8"] #[size = "length * 8"]
pub data: Stream, pub data: Stream,
} }

View file

@ -3,7 +3,6 @@ use num_traits::FromPrimitive;
pub use generated::*; pub use generated::*;
use crate::{Parse, ParseError, ParserState, Result, Stream, ReadResult};
use crate::demo::message::bspdecal::*; use crate::demo::message::bspdecal::*;
use crate::demo::message::classinfo::*; use crate::demo::message::classinfo::*;
use crate::demo::message::gameevent::*; use crate::demo::message::gameevent::*;
@ -13,17 +12,18 @@ use crate::demo::message::stringtable::*;
use crate::demo::message::tempentities::*; use crate::demo::message::tempentities::*;
use crate::demo::message::usermessage::*; use crate::demo::message::usermessage::*;
use crate::demo::message::voice::*; use crate::demo::message::voice::*;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use bitstream_reader::{BitRead, LittleEndian}; use bitstream_reader::{BitRead, LittleEndian};
pub mod classinfo;
pub mod generated;
pub mod stringtable;
pub mod voice;
pub mod bspdecal; pub mod bspdecal;
pub mod usermessage; pub mod classinfo;
pub mod gameevent; pub mod gameevent;
pub mod generated;
pub mod packetentities; pub mod packetentities;
pub mod stringtable;
pub mod tempentities; pub mod tempentities;
pub mod usermessage;
pub mod voice;
#[derive(Primitive, Debug, Clone, Copy)] #[derive(Primitive, Debug, Clone, Copy)]
pub enum MessageType { pub enum MessageType {
@ -106,29 +106,51 @@ impl Parse for Message {
MessageType::NetTick => Message::NetTick(NetTickMessage::parse(stream, state)?), MessageType::NetTick => Message::NetTick(NetTickMessage::parse(stream, state)?),
MessageType::StringCmd => Message::StringCmd(StringCmdMessage::parse(stream, state)?), MessageType::StringCmd => Message::StringCmd(StringCmdMessage::parse(stream, state)?),
MessageType::SetConVar => Message::SetConVar(SetConVarMessage::parse(stream, state)?), MessageType::SetConVar => Message::SetConVar(SetConVarMessage::parse(stream, state)?),
MessageType::SigOnState => Message::SigOnState(SigOnStateMessage::parse(stream, state)?), MessageType::SigOnState => {
Message::SigOnState(SigOnStateMessage::parse(stream, state)?)
}
MessageType::Print => Message::Print(PrintMessage::parse(stream, state)?), MessageType::Print => Message::Print(PrintMessage::parse(stream, state)?),
MessageType::ServerInfo => Message::ServerInfo(ServerInfoMessage::parse(stream, state)?), MessageType::ServerInfo => {
Message::ServerInfo(ServerInfoMessage::parse(stream, state)?)
}
MessageType::ClassInfo => Message::ClassInfo(ClassInfoMessage::parse(stream, state)?), MessageType::ClassInfo => Message::ClassInfo(ClassInfoMessage::parse(stream, state)?),
MessageType::SetPause => Message::SetPause(SetPauseMessage::parse(stream, state)?), MessageType::SetPause => Message::SetPause(SetPauseMessage::parse(stream, state)?),
MessageType::CreateStringTable => Message::CreateStringTable(CreateStringTableMessage::parse(stream, state)?), MessageType::CreateStringTable => {
MessageType::UpdateStringTable => Message::UpdateStringTable(UpdateStringTableMessage::parse(stream, state)?), Message::CreateStringTable(CreateStringTableMessage::parse(stream, state)?)
}
MessageType::UpdateStringTable => {
Message::UpdateStringTable(UpdateStringTableMessage::parse(stream, state)?)
}
MessageType::VoiceInit => Message::VoiceInit(VoiceInitMessage::parse(stream, state)?), MessageType::VoiceInit => Message::VoiceInit(VoiceInitMessage::parse(stream, state)?),
MessageType::VoiceData => Message::VoiceData(VoiceDataMessage::parse(stream, state)?), MessageType::VoiceData => Message::VoiceData(VoiceDataMessage::parse(stream, state)?),
MessageType::ParseSounds => Message::ParseSounds(ParseSoundsMessage::parse(stream, state)?), MessageType::ParseSounds => {
Message::ParseSounds(ParseSoundsMessage::parse(stream, state)?)
}
MessageType::SetView => Message::SetView(SetViewMessage::parse(stream, state)?), MessageType::SetView => Message::SetView(SetViewMessage::parse(stream, state)?),
MessageType::FixAngle => Message::FixAngle(FixAngleMessage::parse(stream, state)?), MessageType::FixAngle => Message::FixAngle(FixAngleMessage::parse(stream, state)?),
MessageType::BspDecal => Message::BspDecal(BSPDecalMessage::parse(stream, state)?), MessageType::BspDecal => Message::BspDecal(BSPDecalMessage::parse(stream, state)?),
MessageType::UserMessage => Message::UserMessage(UserMessage::parse(stream, state)?), MessageType::UserMessage => Message::UserMessage(UserMessage::parse(stream, state)?),
MessageType::EntityMessage => Message::EntityMessage(EntityMessage::parse(stream, state)?), MessageType::EntityMessage => {
Message::EntityMessage(EntityMessage::parse(stream, state)?)
}
MessageType::GameEvent => Message::GameEvent(GameEventMessage::parse(stream, state)?), MessageType::GameEvent => Message::GameEvent(GameEventMessage::parse(stream, state)?),
MessageType::PacketEntities => Message::PacketEntities(PacketEntitiesMessage::parse(stream, state)?), MessageType::PacketEntities => {
MessageType::TempEntities => Message::TempEntities(TempEntitiesMessage::parse(stream, state)?), Message::PacketEntities(PacketEntitiesMessage::parse(stream, state)?)
}
MessageType::TempEntities => {
Message::TempEntities(TempEntitiesMessage::parse(stream, state)?)
}
MessageType::PreFetch => Message::PreFetch(PreFetchMessage::parse(stream, state)?), MessageType::PreFetch => Message::PreFetch(PreFetchMessage::parse(stream, state)?),
MessageType::Menu => Message::Menu(MenuMessage::parse(stream, state)?), MessageType::Menu => Message::Menu(MenuMessage::parse(stream, state)?),
MessageType::GameEventList => Message::GameEventList(GameEventListMessage::parse(stream, state)?), MessageType::GameEventList => {
MessageType::GetCvarValue => Message::GetCvarValue(GetCvarValueMessage::parse(stream, state)?), Message::GameEventList(GameEventListMessage::parse(stream, state)?)
MessageType::CmdKeyValues => Message::CmdKeyValues(CmdKeyValuesMessage::parse(stream, state)?), }
MessageType::GetCvarValue => {
Message::GetCvarValue(GetCvarValueMessage::parse(stream, state)?)
}
MessageType::CmdKeyValues => {
Message::CmdKeyValues(CmdKeyValuesMessage::parse(stream, state)?)
}
}) })
} }
} }

View file

@ -1,8 +1,8 @@
use bitstream_reader::{BitRead, BitReadSized, LittleEndian}; use bitstream_reader::{BitRead, BitReadSized, LittleEndian};
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::demo::packet::datatable::ServerClass; use crate::demo::packet::datatable::ServerClass;
use crate::demo::sendprop::SendProp; use crate::demo::sendprop::SendProp;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct EntityId(u32); pub struct EntityId(u32);
@ -58,4 +58,4 @@ impl Parse for PacketEntitiesMessage {
updated_base_line, updated_base_line,
}) })
} }
} }

View file

@ -1,11 +1,13 @@
use std::collections::HashMap; use std::collections::HashMap;
use arraydeque::{ArrayDeque, Wrapping}; use arraydeque::{ArrayDeque, Wrapping};
use bitstream_reader::{BitRead, BitReadSized, BitStream, LittleEndian, BitBuffer}; use bitstream_reader::{BitBuffer, BitRead, BitReadSized, BitStream, LittleEndian};
use snap::Decoder; use snap::Decoder;
use crate::demo::packet::stringtable::{
ExtraData, FixedUserdataSize, StringTable, StringTableEntry,
};
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream}; use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::demo::packet::stringtable::{ExtraData, FixedUserdataSize, StringTable, StringTableEntry};
use num_traits::{PrimInt, Unsigned}; use num_traits::{PrimInt, Unsigned};
#[derive(Debug)] #[derive(Debug)]
@ -55,12 +57,14 @@ impl Parse for CreateStringTableMessage {
let compressed_data = table_data.read_bytes(compressed_size as usize - 4)?; let compressed_data = table_data.read_bytes(compressed_size as usize - 4)?;
let mut decoder = Decoder::new(); let mut decoder = Decoder::new();
let decompressed_data = decoder.decompress_vec(&compressed_data).map_err(ParseError::from)?; let decompressed_data = decoder
.decompress_vec(&compressed_data)
.map_err(ParseError::from)?;
if decompressed_data.len() != decompressed_size as usize { if decompressed_data.len() != decompressed_size as usize {
return Err(ParseError::UnexpectedDecompressedSize { return Err(ParseError::UnexpectedDecompressedSize {
expected: decompressed_size, expected: decompressed_size,
size: decompressed_data.len() as u32 size: decompressed_data.len() as u32,
}); });
} }
@ -73,7 +77,8 @@ impl Parse for CreateStringTableMessage {
fixed_userdata_size, fixed_userdata_size,
}; };
let entries = parse_string_table_entries(&mut table_data, &table_meta, entity_count, &Vec::new())?; let entries =
parse_string_table_entries(&mut table_data, &table_meta, entity_count, &Vec::new())?;
let mut entries: Vec<(u16, StringTableEntry)> = entries.into_iter().collect(); let mut entries: Vec<(u16, StringTableEntry)> = entries.into_iter().collect();
// verify that there are no holes in our indexes // verify that there are no holes in our indexes
@ -93,9 +98,7 @@ impl Parse for CreateStringTableMessage {
compressed, compressed,
name, name,
}; };
Ok(CreateStringTableMessage { Ok(CreateStringTableMessage { table })
table
})
} }
} }
@ -115,14 +118,16 @@ impl Parse for UpdateStringTableMessage {
let mut data = stream.read_bits(len)?; let mut data = stream.read_bits(len)?;
let entries = match state.string_tables.get(table_id as usize) { let entries = match state.string_tables.get(table_id as usize) {
Some(table) => parse_string_table_entries(&mut data, &table.get_table_meta(), changed, &table.entries), Some(table) => parse_string_table_entries(
None => return Err(ParseError::StringTableNotFound(table_id)) &mut data,
&table.get_table_meta(),
changed,
&table.entries,
),
None => return Err(ParseError::StringTableNotFound(table_id)),
}?; }?;
Ok(UpdateStringTableMessage { Ok(UpdateStringTableMessage { table_id, entries })
table_id,
entries,
})
} }
} }
@ -147,17 +152,22 @@ fn parse_string_table_entries(
last_entry = index as i16; last_entry = index as i16;
let value = if stream.read()? { // set value let value = if stream.read()? {
if stream.read()? { // reuse from history // set value
if stream.read()? {
// reuse from history
let index: u16 = stream.read_sized(5)?; let index: u16 = stream.read_sized(5)?;
let bytes_to_copy: u32 = stream.read_sized(5)?; let bytes_to_copy: u32 = stream.read_sized(5)?;
let rest_of_string: String = stream.read()?; let rest_of_string: String = stream.read()?;
Some(match history.get(index as usize) { Some(match history.get(index as usize) {
Some(text) => String::from_utf8({ Some(text) => String::from_utf8({
text.bytes().take(bytes_to_copy as usize).chain(rest_of_string.bytes()).collect() text.bytes()
.take(bytes_to_copy as usize)
.chain(rest_of_string.bytes())
.collect()
})?, })?,
None => rest_of_string // best guess, happens in some pov demos but only for unimportant tables it seems None => rest_of_string, // best guess, happens in some pov demos but only for unimportant tables it seems
}) })
} else { } else {
Some(stream.read()?) Some(stream.read()?)
@ -176,7 +186,8 @@ fn parse_string_table_entries(
}) })
} else { } else {
None None
}.map(|stream| ExtraData { }
.map(|stream| ExtraData {
len: stream.bit_len() as u16 / 8, len: stream.bit_len() as u16 / 8,
data: stream, data: stream,
}); });
@ -193,7 +204,7 @@ fn parse_string_table_entries(
None => StringTableEntry { None => StringTableEntry {
text: value.unwrap_or_default(), text: value.unwrap_or_default(),
extra_data: user_data, extra_data: user_data,
} },
}; };
// optimize: any way to get rid of the clone here? // optimize: any way to get rid of the clone here?
// `entries` always outlives `history` without reallocation // `entries` always outlives `history` without reallocation
@ -225,4 +236,4 @@ pub fn read_var_int(stream: &mut Stream) -> ReadResult<u32> {
pub fn log_base2<T: PrimInt + Unsigned>(num: T) -> u32 { pub fn log_base2<T: PrimInt + Unsigned>(num: T) -> u32 {
(std::mem::size_of::<T>() as u32 * 8 - 1) - num.leading_zeros() (std::mem::size_of::<T>() as u32 * 8 - 1) - num.leading_zeros()
} }

View file

@ -7,7 +7,7 @@ use super::stringtable::read_var_int;
#[derive(Debug)] #[derive(Debug)]
pub struct TempEntitiesMessage { pub struct TempEntitiesMessage {
pub entities: Vec<PacketEntity> pub entities: Vec<PacketEntity>,
} }
impl Parse for TempEntitiesMessage { impl Parse for TempEntitiesMessage {
@ -17,7 +17,7 @@ impl Parse for TempEntitiesMessage {
let data = stream.read_bits(length as usize)?; let data = stream.read_bits(length as usize)?;
Ok(TempEntitiesMessage { Ok(TempEntitiesMessage {
entities: Vec::new() entities: Vec::new(),
}) })
} }
} }

View file

@ -2,8 +2,8 @@ use bitstream_reader::{BitRead, BitReadSized, LittleEndian};
use enum_primitive_derive::Primitive; use enum_primitive_derive::Primitive;
use num_traits::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive, ToPrimitive};
use crate::{ReadResult, Stream};
use crate::demo::message::usermessage::UserMessage::SayText2; use crate::demo::message::usermessage::UserMessage::SayText2;
use crate::{ReadResult, Stream};
#[derive(Primitive, Clone, Copy, Debug)] #[derive(Primitive, Clone, Copy, Debug)]
pub enum UserMessageType { pub enum UserMessageType {
@ -81,8 +81,8 @@ pub enum UserMessage {
impl BitRead<LittleEndian> for UserMessage { impl BitRead<LittleEndian> for UserMessage {
fn read(stream: &mut Stream) -> ReadResult<Self> { fn read(stream: &mut Stream) -> ReadResult<Self> {
let message_type = UserMessageType::from_u8(stream.read()?) let message_type =
.unwrap_or(UserMessageType::Unknown); UserMessageType::from_u8(stream.read()?).unwrap_or(UserMessageType::Unknown);
let length = stream.read_int(11)?; let length = stream.read_int(11)?;
let mut data = stream.read_bits(length)?; let mut data = stream.read_bits(length)?;
let message = match message_type { let message = match message_type {
@ -113,7 +113,7 @@ impl BitRead<LittleEndian> for SayText2Kind {
"TF_Chat_Team" => SayText2Kind::ChatTeam, "TF_Chat_Team" => SayText2Kind::ChatTeam,
"TF_Chat_AllDead" => SayText2Kind::ChatAllDead, "TF_Chat_AllDead" => SayText2Kind::ChatAllDead,
"#TF_Name_Change" => SayText2Kind::NameChange, "#TF_Name_Change" => SayText2Kind::NameChange,
_ => SayText2Kind::ChatAll _ => SayText2Kind::ChatAll,
}) })
} }
} }
@ -144,7 +144,9 @@ impl BitRead<LittleEndian> for SayText2Message {
// grave talk is in the format '*DEAD* \u0003$from\u0001: $text'b // grave talk is in the format '*DEAD* \u0003$from\u0001: $text'b
let start = text.find(char::from(3)).unwrap_or(0); let start = text.find(char::from(3)).unwrap_or(0);
let end = text.find(char::from(1)).unwrap_or(0); let end = text.find(char::from(1)).unwrap_or(0);
let from: String = String::from_utf8(text.bytes().skip(start + 1).take(end - start - 1).collect())?; let from: String = String::from_utf8(
text.bytes().skip(start + 1).take(end - start - 1).collect(),
)?;
let text: String = String::from_utf8(text.bytes().skip(end + 5).collect())?; let text: String = String::from_utf8(text.bytes().skip(end + 5).collect())?;
let kind = SayText2Kind::ChatAllDead; let kind = SayText2Kind::ChatAllDead;
(kind, from, text) (kind, from, text)
@ -162,11 +164,14 @@ impl BitRead<LittleEndian> for SayText2Message {
}; };
// cleanup color codes // cleanup color codes
let mut text = text let mut text = text.replace(char::from(1), "").replace(char::from(3), "");
.replace(char::from(1), "")
.replace(char::from(3), "");
while let Some(pos) = text.find(char::from(7)) { while let Some(pos) = text.find(char::from(7)) {
text = String::from_utf8(text.bytes().take(pos).chain(text.bytes().skip(pos + 7)).collect())?; text = String::from_utf8(
text.bytes()
.take(pos)
.chain(text.bytes().skip(pos + 7))
.collect(),
)?;
} }
Ok(SayText2Message { Ok(SayText2Message {
@ -198,12 +203,12 @@ pub struct TextMessage {
#[derive(BitRead, Debug, Clone)] #[derive(BitRead, Debug, Clone)]
pub struct ResetHudMessage { pub struct ResetHudMessage {
pub data: u8 pub data: u8,
} }
#[derive(BitRead, Debug, Clone)] #[derive(BitRead, Debug, Clone)]
pub struct TrainMessage { pub struct TrainMessage {
pub data: u8 pub data: u8,
} }
#[derive(BitRead, Debug, Clone)] #[derive(BitRead, Debug, Clone)]
@ -223,13 +228,13 @@ pub struct ShakeMessage {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct UnknownUserMessage { pub struct UnknownUserMessage {
data: Stream data: Stream,
} }
impl BitRead<LittleEndian> for UnknownUserMessage { impl BitRead<LittleEndian> for UnknownUserMessage {
fn read(stream: &mut Stream) -> ReadResult<Self> { fn read(stream: &mut Stream) -> ReadResult<Self> {
Ok(UnknownUserMessage { Ok(UnknownUserMessage {
data: stream.read_bits(stream.bits_left())? data: stream.read_bits(stream.bits_left())?,
}) })
} }
} }

View file

@ -52,7 +52,11 @@ impl BitRead<LittleEndian> for ParseSoundsMessage {
fn read(stream: &mut Stream) -> ReadResult<Self> { fn read(stream: &mut Stream) -> ReadResult<Self> {
let reliable = stream.read()?; let reliable = stream.read()?;
let num = if reliable { 1u8 } else { stream.read()? }; let num = if reliable { 1u8 } else { stream.read()? };
let length = if reliable { stream.read_sized::<u16>(8)? } else { stream.read()? }; let length = if reliable {
stream.read_sized::<u16>(8)?
} else {
stream.read()?
};
let data = stream.read_sized(length as usize)?; let data = stream.read_sized(length as usize)?;
Ok(ParseSoundsMessage { Ok(ParseSoundsMessage {
@ -62,4 +66,4 @@ impl BitRead<LittleEndian> for ParseSoundsMessage {
data, data,
}) })
} }
} }

View file

@ -1,7 +1,7 @@
use bitstream_reader::{BitBuffer, BitStream, LittleEndian}; use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
pub mod gamevent;
pub mod gameevent_gen; pub mod gameevent_gen;
pub mod gamevent;
pub mod header; pub mod header;
pub mod message; pub mod message;
pub mod packet; pub mod packet;

View file

@ -1,6 +1,6 @@
use crate::{Parse, ParseError, ParserState, Result, Stream};
use crate::demo::message::Message; use crate::demo::message::Message;
use crate::demo::vector::Vector; use crate::demo::vector::Vector;
use crate::{Parse, ParseError, ParserState, Result, Stream};
#[derive(Debug)] #[derive(Debug)]
pub struct MessagePacket { pub struct MessagePacket {
@ -36,7 +36,7 @@ impl Parse for MessagePacket {
let message = Message::parse(&mut packet_data, state)?; let message = Message::parse(&mut packet_data, state)?;
match message { match message {
Message::Empty => {} Message::Empty => {}
_ => messages.push(message) _ => messages.push(message),
} }
} }

View file

@ -2,9 +2,9 @@ use std::fmt;
use bitstream_reader::{BitRead, LittleEndian}; use bitstream_reader::{BitRead, LittleEndian};
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use crate::demo::message::stringtable::StringTableMeta; use crate::demo::message::stringtable::StringTableMeta;
use crate::demo::sendprop::SendPropFlag::Exclude; use crate::demo::sendprop::SendPropFlag::Exclude;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
#[derive(BitRead, Clone, Copy, Debug)] #[derive(BitRead, Clone, Copy, Debug)]
pub struct FixedUserdataSize { pub struct FixedUserdataSize {

View file

@ -30,10 +30,7 @@ pub enum ParseError {
/// A unknown game event type was read /// A unknown game event type was read
UnknownGameEvent(String), UnknownGameEvent(String),
/// A read game event doesn't contain the expected values /// A read game event doesn't contain the expected values
InvalidGameEvent { InvalidGameEvent { name: String, value: GameEventValue },
name: String,
value: GameEventValue,
},
/// Unexpected type of compressed data /// Unexpected type of compressed data
UnexpectedCompressionType(String), UnexpectedCompressionType(String),
/// Error while decompressing SNAP compressed string table /// Error while decompressing SNAP compressed string table
@ -43,8 +40,8 @@ pub enum ParseError {
/// Expected decompressed size /// Expected decompressed size
expected: u32, expected: u32,
/// Actual decompressed size /// Actual decompressed size
size: u32 size: u32,
} },
} }
impl From<ReadError> for ParseError { impl From<ReadError> for ParseError {

View file

@ -2,11 +2,11 @@ use std::collections::HashMap;
use crate::demo::gameevent_gen::GameEventType; use crate::demo::gameevent_gen::GameEventType;
use crate::demo::gamevent::GameEventDefinition; use crate::demo::gamevent::GameEventDefinition;
use crate::demo::message::Message;
use crate::demo::message::packetentities::EntityId; use crate::demo::message::packetentities::EntityId;
use crate::demo::message::Message;
use crate::demo::packet::datatable::{SendTable, ServerClass}; use crate::demo::packet::datatable::{SendTable, ServerClass};
use crate::demo::packet::Packet;
use crate::demo::packet::stringtable::{StringTable, StringTableEntry}; use crate::demo::packet::stringtable::{StringTable, StringTableEntry};
use crate::demo::packet::Packet;
use crate::demo::sendprop::SendProp; use crate::demo::sendprop::SendProp;
use crate::Stream; use crate::Stream;

View file

@ -206,11 +206,15 @@ pub fn read_bit_coord(stream: &mut Stream) -> ReadResult<f32> {
Ok(if has_int || has_frac { Ok(if has_int || has_frac {
let sign = if stream.read()? { -1f32 } else { 1f32 }; let sign = if stream.read()? { -1f32 } else { 1f32 };
let int_val: u16 = if has_int { stream.read_sized::<u16>(14)? + 1 } else { 0 }; let int_val: u16 = if has_int {
stream.read_sized::<u16>(14)? + 1
} else {
0
};
let frac_val: u8 = if has_frac { stream.read_sized(5)? } else { 0 }; let frac_val: u8 = if has_frac { stream.read_sized(5)? } else { 0 };
let value = int_val as f32 + (frac_val as f32 * (1f32 / 32f32)); let value = int_val as f32 + (frac_val as f32 * (1f32 / 32f32));
value * sign value * sign
} else { } else {
0f32 0f32
}) })
} }