Fix (clippy) warnings
This commit is contained in:
@@ -45,7 +45,7 @@ impl<'a> Bitreader<'a> {
|
|||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn bits_remaining(&mut self) -> Option<usize> {
|
pub fn bits_remaining(&mut self) -> Option<usize> {
|
||||||
Some(self.reader.bits_remaining()?)
|
self.reader.bits_remaining()
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn read_nbits(&mut self, n: u32) -> Result<u32, BitReadError> {
|
pub fn read_nbits(&mut self, n: u32) -> Result<u32, BitReadError> {
|
||||||
@@ -54,16 +54,16 @@ impl<'a> Bitreader<'a> {
|
|||||||
}
|
}
|
||||||
let b = self.peek(n);
|
let b = self.peek(n);
|
||||||
self.consume(n);
|
self.consume(n);
|
||||||
return Ok(b as u32);
|
Ok(b as u32)
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn read_u_bit_var(&mut self) -> Result<u32, BitReadError> {
|
pub fn read_u_bit_var(&mut self) -> Result<u32, BitReadError> {
|
||||||
let bits = self.read_nbits(6)?;
|
let bits = self.read_nbits(6)?;
|
||||||
match bits & 0b110000 {
|
match bits & 0b110000 {
|
||||||
0b10000 => return Ok((bits & 0b1111) | (self.read_nbits(4)? << 4)),
|
0b10000 => Ok((bits & 0b1111) | (self.read_nbits(4)? << 4)),
|
||||||
0b100000 => return Ok((bits & 0b1111) | (self.read_nbits(8)? << 4)),
|
0b100000 => Ok((bits & 0b1111) | (self.read_nbits(8)? << 4)),
|
||||||
0b110000 => return Ok((bits & 0b1111) | (self.read_nbits(28)? << 4)),
|
0b110000 => Ok((bits & 0b1111) | (self.read_nbits(28)? << 4)),
|
||||||
_ => return Ok(bits),
|
_ => Ok(bits),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -73,7 +73,7 @@ impl<'a> Bitreader<'a> {
|
|||||||
if x & 1 != 0 {
|
if x & 1 != 0 {
|
||||||
y = !y;
|
y = !y;
|
||||||
}
|
}
|
||||||
Ok(y as i32)
|
Ok(y)
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn read_varint(&mut self) -> Result<u32, BitReadError> {
|
pub fn read_varint(&mut self) -> Result<u32, BitReadError> {
|
||||||
@@ -160,18 +160,18 @@ impl<'a> Bitreader<'a> {
|
|||||||
}
|
}
|
||||||
pub fn read_ubit_var_fp(&mut self) -> Result<u32, BitReadError> {
|
pub fn read_ubit_var_fp(&mut self) -> Result<u32, BitReadError> {
|
||||||
if self.read_boolean()? {
|
if self.read_boolean()? {
|
||||||
return Ok(self.read_nbits(2)?);
|
return self.read_nbits(2);
|
||||||
}
|
}
|
||||||
if self.read_boolean()? {
|
if self.read_boolean()? {
|
||||||
return Ok(self.read_nbits(4)?);
|
return self.read_nbits(4);
|
||||||
}
|
}
|
||||||
if self.read_boolean()? {
|
if self.read_boolean()? {
|
||||||
return Ok(self.read_nbits(10)?);
|
return self.read_nbits(10);
|
||||||
}
|
}
|
||||||
if self.read_boolean()? {
|
if self.read_boolean()? {
|
||||||
return Ok(self.read_nbits(17)?);
|
return self.read_nbits(17);
|
||||||
}
|
}
|
||||||
return Ok(self.read_nbits(31)?);
|
self.read_nbits(31)
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn read_bit_coord(&mut self) -> Result<f32, BitReadError> {
|
pub fn read_bit_coord(&mut self) -> Result<f32, BitReadError> {
|
||||||
@@ -190,7 +190,7 @@ impl<'a> Bitreader<'a> {
|
|||||||
frac_val = self.read_nbits(5)?;
|
frac_val = self.read_nbits(5)?;
|
||||||
}
|
}
|
||||||
let resol: f64 = 1.0 / (1 << 5) as f64;
|
let resol: f64 = 1.0 / (1 << 5) as f64;
|
||||||
let result: f32 = (int_val as f64 + (frac_val as f64 * resol) as f64) as f32;
|
let result: f32 = (int_val as f64 + (frac_val as f64 * resol)) as f32;
|
||||||
if sign {
|
if sign {
|
||||||
Ok(-result)
|
Ok(-result)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ pub enum ParseContainerError {
|
|||||||
Other(&'static str),
|
Other(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A Container models the outer layer of a CS2 demo, which starts with a specific magic string and
|
||||||
|
/// some other values. Then it just stores the raw bytes afterwards, that contain the actual demo
|
||||||
|
/// data
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Container<'b> {
|
pub struct Container<'b> {
|
||||||
pub magic: &'b str,
|
pub magic: &'b str,
|
||||||
@@ -16,6 +19,7 @@ pub struct Container<'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> Container<'b> {
|
impl<'b> Container<'b> {
|
||||||
|
/// Attempts to parse the given bytes into a valid cs2 demo container
|
||||||
pub fn parse<'ib>(input: &'ib [u8]) -> Result<Self, ParseContainerError>
|
pub fn parse<'ib>(input: &'ib [u8]) -> Result<Self, ParseContainerError>
|
||||||
where
|
where
|
||||||
'ib: 'b,
|
'ib: 'b,
|
||||||
@@ -25,7 +29,7 @@ impl<'b> Container<'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let magic =
|
let magic =
|
||||||
core::str::from_utf8(&input[..8]).map_err(|e| ParseContainerError::InvalidMagic(e))?;
|
core::str::from_utf8(&input[..8]).map_err(ParseContainerError::InvalidMagic)?;
|
||||||
let raw_len: [u8; 4] = input[8..12]
|
let raw_len: [u8; 4] = input[8..12]
|
||||||
.try_into()
|
.try_into()
|
||||||
.expect("We know that the input buffer is at least 16 bytes large");
|
.expect("We know that the input buffer is at least 16 bytes large");
|
||||||
|
|||||||
39
src/frame.rs
39
src/frame.rs
@@ -5,20 +5,33 @@ pub struct Frame<'b> {
|
|||||||
pub inner: std::borrow::Cow<'b, [u8]>,
|
pub inner: std::borrow::Cow<'b, [u8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum FrameParseError {
|
||||||
|
ParseVarint(()),
|
||||||
|
NotEnoughBytes,
|
||||||
|
ParseDemoCommand(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum FrameDecompressError {
|
||||||
|
GettingDecompressedLength(snap::Error),
|
||||||
|
Decompressing(snap::Error),
|
||||||
|
}
|
||||||
|
|
||||||
impl<'b> Frame<'b> {
|
impl<'b> Frame<'b> {
|
||||||
pub fn parse<'ib>(input: &'ib [u8]) -> Result<(&'ib [u8], Self), ()>
|
pub fn parse<'ib>(input: &'ib [u8]) -> Result<(&'ib [u8], Self), FrameParseError>
|
||||||
where
|
where
|
||||||
'ib: 'b,
|
'ib: 'b,
|
||||||
{
|
{
|
||||||
let (input, raw_cmd) = crate::varint::parse_varint(input)?;
|
let (input, raw_cmd) = crate::varint::parse_varint(input).map_err(FrameParseError::ParseVarint)?;
|
||||||
let (input, tick) = crate::varint::parse_varint(input)?;
|
let (input, tick) = crate::varint::parse_varint(input).map_err(FrameParseError::ParseVarint)?;
|
||||||
let (input, size) = crate::varint::parse_varint(input)?;
|
let (input, size) = crate::varint::parse_varint(input).map_err(FrameParseError::ParseVarint)?;
|
||||||
|
|
||||||
if input.len() < size as usize {
|
if input.len() < size as usize {
|
||||||
return Err(());
|
return Err(FrameParseError::NotEnoughBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
let demo_cmd = crate::DemoCommand::try_from((raw_cmd & !64) as i32).map_err(|e| ())?;
|
let demo_cmd = crate::DemoCommand::try_from((raw_cmd & !64) as i32).map_err(FrameParseError::ParseDemoCommand)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
&input[size as usize..],
|
&input[size as usize..],
|
||||||
@@ -39,7 +52,7 @@ impl<'b> Frame<'b> {
|
|||||||
Some(self.inner.as_ref())
|
Some(self.inner.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decompress_with_buf<'s, 'buf>(&'s self, buf: &'b mut Vec<u8>) -> Result<&'buf [u8], ()>
|
pub fn decompress_with_buf<'s, 'buf>(&'s self, buf: &'b mut Vec<u8>) -> Result<&'buf [u8], FrameDecompressError>
|
||||||
where
|
where
|
||||||
's: 'buf,
|
's: 'buf,
|
||||||
{
|
{
|
||||||
@@ -48,29 +61,27 @@ impl<'b> Frame<'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let uncompressed_len = snap::raw::decompress_len(&self.inner).map_err(|e| {
|
let uncompressed_len = snap::raw::decompress_len(&self.inner).map_err(|e| {
|
||||||
println!("Getting decompress len");
|
FrameDecompressError::GettingDecompressedLength(e)
|
||||||
()
|
|
||||||
})?;
|
})?;
|
||||||
buf.resize(uncompressed_len, 0);
|
buf.resize(uncompressed_len, 0);
|
||||||
|
|
||||||
snap::raw::Decoder::new()
|
snap::raw::Decoder::new()
|
||||||
.decompress(&self.inner, buf.as_mut_slice())
|
.decompress(&self.inner, buf.as_mut_slice())
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
println!("Decompressing");
|
FrameDecompressError::Decompressing(e)
|
||||||
()
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(buf.as_slice())
|
Ok(buf.as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decompress(&mut self) -> Result<(), ()> {
|
pub fn decompress(&mut self) -> Result<(), FrameDecompressError> {
|
||||||
if !self.compressed {
|
if !self.compressed {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let decompressed = snap::raw::Decoder::new()
|
let decompressed = snap::raw::Decoder::new()
|
||||||
.decompress_vec(&self.inner.as_ref())
|
.decompress_vec(self.inner.as_ref())
|
||||||
.map_err(|e| ())?;
|
.map_err(FrameDecompressError::Decompressing)?;
|
||||||
|
|
||||||
self.compressed = false;
|
self.compressed = false;
|
||||||
self.inner = std::borrow::Cow::Owned(decompressed);
|
self.inner = std::borrow::Cow::Owned(decompressed);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ mod container;
|
|||||||
pub use container::{Container, ParseContainerError};
|
pub use container::{Container, ParseContainerError};
|
||||||
|
|
||||||
mod frame;
|
mod frame;
|
||||||
pub use frame::{Frame, FrameIterator};
|
pub use frame::{Frame, FrameIterator, FrameDecompressError, FrameParseError};
|
||||||
|
|
||||||
mod democmd;
|
mod democmd;
|
||||||
pub use democmd::DemoCommand;
|
pub use democmd::DemoCommand;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{packet::DemoEvent, DemoCommand, Frame, UserId};
|
use crate::{packet::DemoEvent, DemoCommand, Frame, UserId, FrameDecompressError};
|
||||||
|
|
||||||
mod fieldpath;
|
mod fieldpath;
|
||||||
pub use fieldpath::{FieldPath, Paths};
|
pub use fieldpath::{FieldPath, Paths};
|
||||||
@@ -13,7 +13,7 @@ pub use entities::EntityFilter;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FirstPassError {
|
pub enum FirstPassError {
|
||||||
DecompressFrame,
|
DecompressFrame(FrameDecompressError),
|
||||||
NoDataFrame,
|
NoDataFrame,
|
||||||
DecodeProtobuf(prost::DecodeError),
|
DecodeProtobuf(prost::DecodeError),
|
||||||
MissingFileHeader,
|
MissingFileHeader,
|
||||||
@@ -73,7 +73,6 @@ struct GameEventMapping {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Class {
|
pub struct Class {
|
||||||
class_id: i32,
|
|
||||||
name: String,
|
name: String,
|
||||||
serializer: sendtables::Serializer,
|
serializer: sendtables::Serializer,
|
||||||
}
|
}
|
||||||
@@ -111,7 +110,7 @@ where
|
|||||||
for frame in frames.into_iter() {
|
for frame in frames.into_iter() {
|
||||||
let data = frame
|
let data = frame
|
||||||
.decompress_with_buf(&mut buffer)
|
.decompress_with_buf(&mut buffer)
|
||||||
.map_err(|e| FirstPassError::DecompressFrame)?;
|
.map_err(FirstPassError::DecompressFrame)?;
|
||||||
|
|
||||||
match frame.cmd {
|
match frame.cmd {
|
||||||
DemoCommand::FileHeader => {
|
DemoCommand::FileHeader => {
|
||||||
@@ -205,7 +204,6 @@ where
|
|||||||
cls_id as u32,
|
cls_id as u32,
|
||||||
Class {
|
Class {
|
||||||
name: network_name.to_owned(),
|
name: network_name.to_owned(),
|
||||||
class_id: cls_id,
|
|
||||||
serializer: ser,
|
serializer: ser,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -235,7 +233,7 @@ fn parse_fullpacket(data: &[u8]) -> Result<Option<crate::csgo_proto::CDemoPacket
|
|||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// Handle string table stuff
|
// Handle string table stuff
|
||||||
for item in raw.string_table.iter().flat_map(|st| st.tables.iter()) {
|
for _item in raw.string_table.iter().flat_map(|st| st.tables.iter()) {
|
||||||
// dbg!(&item.table_name);
|
// dbg!(&item.table_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,8 +322,11 @@ fn inner_parse_packet(
|
|||||||
let cls = entity_ctx.create_entity(entity_id, &mut bitreader)?;
|
let cls = entity_ctx.create_entity(entity_id, &mut bitreader)?;
|
||||||
|
|
||||||
if let Some(baseline_bytes) = baselines.get(&cls) {
|
if let Some(baseline_bytes) = baselines.get(&cls) {
|
||||||
let mut br = crate::bitreader::Bitreader::new(&baseline_bytes);
|
let mut br = crate::bitreader::Bitreader::new(baseline_bytes);
|
||||||
let state = update_entity(
|
|
||||||
|
// TODO
|
||||||
|
// How should we handle is this?
|
||||||
|
let _state = update_entity(
|
||||||
entity_id,
|
entity_id,
|
||||||
&mut br,
|
&mut br,
|
||||||
entity_ctx,
|
entity_ctx,
|
||||||
@@ -348,10 +349,8 @@ fn inner_parse_packet(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
0b00 => {
|
0b00 => {
|
||||||
if raw.has_pvs_vis_bits() > 0 {
|
if raw.has_pvs_vis_bits() > 0 && bitreader.read_nbits(2)? & 0x01 == 1 {
|
||||||
if bitreader.read_nbits(2)? & 0x01 == 1 {
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = update_entity(
|
let state = update_entity(
|
||||||
@@ -385,7 +384,7 @@ fn inner_parse_packet(
|
|||||||
|
|
||||||
match event_mapper.mapping.get(&raw.eventid()) {
|
match event_mapper.mapping.get(&raw.eventid()) {
|
||||||
Some((name, keys)) => {
|
Some((name, keys)) => {
|
||||||
match crate::game_event::EVENT_PARSERS.get(&name) {
|
match crate::game_event::EVENT_PARSERS.get(name) {
|
||||||
Some(parser) => {
|
Some(parser) => {
|
||||||
let parsed = parser.parse(keys.as_slice(), raw.clone())?;
|
let parsed = parser.parse(keys.as_slice(), raw.clone())?;
|
||||||
|
|
||||||
@@ -419,11 +418,6 @@ fn inner_parse_packet(
|
|||||||
crate::netmessagetypes::NetmessageType::CS_UM_RadioText => {}
|
crate::netmessagetypes::NetmessageType::CS_UM_RadioText => {}
|
||||||
crate::netmessagetypes::NetmessageType::TE_WorldDecal => {}
|
crate::netmessagetypes::NetmessageType::TE_WorldDecal => {}
|
||||||
crate::netmessagetypes::NetmessageType::TE_EffectDispatch => {}
|
crate::netmessagetypes::NetmessageType::TE_EffectDispatch => {}
|
||||||
crate::netmessagetypes::NetmessageType::CS_UM_PlayerStatsUpdate => {
|
|
||||||
let raw: crate::csgo_proto::CcsUsrMsgPlayerStatsUpdate =
|
|
||||||
prost::Message::decode(msg_bytes.as_slice())?;
|
|
||||||
// dbg!(&raw);
|
|
||||||
}
|
|
||||||
crate::netmessagetypes::NetmessageType::CS_UM_EndOfMatchAllPlayersData => {
|
crate::netmessagetypes::NetmessageType::CS_UM_EndOfMatchAllPlayersData => {
|
||||||
let raw: crate::csgo_proto::CcsUsrMsgEndOfMatchAllPlayersData =
|
let raw: crate::csgo_proto::CcsUsrMsgEndOfMatchAllPlayersData =
|
||||||
prost::Message::decode(msg_bytes.as_slice())?;
|
prost::Message::decode(msg_bytes.as_slice())?;
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ pub fn find_decoder(field: &super::sendtables::ConstructorField, qf_map: &mut Qf
|
|||||||
}
|
}
|
||||||
|
|
||||||
match BASETYPE_DECODERS.get(field.field_type.base_type.as_str()) {
|
match BASETYPE_DECODERS.get(field.field_type.base_type.as_str()) {
|
||||||
Some(d) => d.clone(),
|
Some(d) => *d,
|
||||||
None => match field.field_type.base_type.as_str() {
|
None => match field.field_type.base_type.as_str() {
|
||||||
"float32" => float_decoder(field, qf_map),
|
"float32" => float_decoder(field, qf_map),
|
||||||
"Vector" => find_vector_type(3, field, qf_map),
|
"Vector" => find_vector_type(3, field, qf_map),
|
||||||
@@ -138,7 +138,7 @@ fn float_decoder(field: &super::sendtables::ConstructorField, qf_map: &mut QfMap
|
|||||||
"m_flSimulationTime" => Decoder::FloatSimulationTimeDecoder,
|
"m_flSimulationTime" => Decoder::FloatSimulationTimeDecoder,
|
||||||
_ => {
|
_ => {
|
||||||
if field.bitcount <= 0 || field.bitcount >= 32 {
|
if field.bitcount <= 0 || field.bitcount >= 32 {
|
||||||
return Decoder::NoscaleDecoder;
|
Decoder::NoscaleDecoder
|
||||||
} else {
|
} else {
|
||||||
let qf = QuantalizedFloat::new(
|
let qf = QuantalizedFloat::new(
|
||||||
field.bitcount as u32,
|
field.bitcount as u32,
|
||||||
@@ -213,7 +213,7 @@ impl Decoder {
|
|||||||
|
|
||||||
impl<'b> crate::bitreader::Bitreader<'b> {
|
impl<'b> crate::bitreader::Bitreader<'b> {
|
||||||
pub fn read_bit_coord_pres(&mut self) -> Result<f32, super::FirstPassError> {
|
pub fn read_bit_coord_pres(&mut self) -> Result<f32, super::FirstPassError> {
|
||||||
return Ok(self.read_nbits(20)? as f32 * 360.0 / (1 << 20) as f32 - 180.0);
|
Ok(self.read_nbits(20)? as f32 * 360.0 / (1 << 20) as f32 - 180.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_qfloat(
|
pub fn decode_qfloat(
|
||||||
@@ -232,7 +232,7 @@ impl<'b> crate::bitreader::Bitreader<'b> {
|
|||||||
if ammo > 0 {
|
if ammo > 0 {
|
||||||
return Ok(ammo - 1);
|
return Ok(ammo - 1);
|
||||||
}
|
}
|
||||||
return Ok(ammo);
|
Ok(ammo)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_uint64(&mut self) -> Result<u64, super::FirstPassError> {
|
pub fn decode_uint64(&mut self) -> Result<u64, super::FirstPassError> {
|
||||||
@@ -306,7 +306,7 @@ impl<'b> crate::bitreader::Bitreader<'b> {
|
|||||||
Ok(v)
|
Ok(v)
|
||||||
}
|
}
|
||||||
pub fn read_angle(&mut self, n: usize) -> Result<f32, super::FirstPassError> {
|
pub fn read_angle(&mut self, n: usize) -> Result<f32, super::FirstPassError> {
|
||||||
return Ok(self.decode_noscale()? / ((1 << n) as f32));
|
Ok(self.decode_noscale()? / ((1 << n) as f32))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_normal(&mut self) -> Result<f32, super::FirstPassError> {
|
pub fn decode_normal(&mut self) -> Result<f32, super::FirstPassError> {
|
||||||
@@ -331,7 +331,7 @@ impl<'b> crate::bitreader::Bitreader<'b> {
|
|||||||
let neg_z = self.read_boolean()?;
|
let neg_z = self.read_boolean()?;
|
||||||
let prod_sum = v[0] * v[0] + v[1] * v[1];
|
let prod_sum = v[0] * v[0] + v[1] * v[1];
|
||||||
if prod_sum < 1.0 {
|
if prod_sum < 1.0 {
|
||||||
v[2] = (1.0 - prod_sum).sqrt() as f32;
|
v[2] = (1.0 - prod_sum).sqrt();
|
||||||
} else {
|
} else {
|
||||||
v[2] = 0.0;
|
v[2] = 0.0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,25 +182,19 @@ impl QuantalizedFloat {
|
|||||||
steps = 1 << qf.bit_count;
|
steps = 1 << qf.bit_count;
|
||||||
}
|
}
|
||||||
qf.offset = range_2 as f32 / steps as f32;
|
qf.offset = range_2 as f32 / steps as f32;
|
||||||
qf.high = qf.low + ((range_2 as f32 - qf.offset) as f32);
|
qf.high = qf.low + (range_2 as f32 - qf.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
qf.assign_multipliers(steps);
|
qf.assign_multipliers(steps);
|
||||||
|
|
||||||
if (qf.flags & QFF_ROUNDDOWN) != 0 {
|
if (qf.flags & QFF_ROUNDDOWN) != 0 && qf.quantize(qf.low) == qf.low {
|
||||||
if qf.quantize(qf.low) == qf.low {
|
qf.flags &= !QFF_ROUNDDOWN;
|
||||||
qf.flags &= !QFF_ROUNDDOWN;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (qf.flags & QFF_ROUNDUP) != 0 {
|
if (qf.flags & QFF_ROUNDUP) != 0 && qf.quantize(qf.high) == qf.high {
|
||||||
if qf.quantize(qf.high) == qf.high {
|
qf.flags &= !QFF_ROUNDUP
|
||||||
qf.flags &= !QFF_ROUNDUP
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (qf.flags & QFF_ENCODE_ZERO) != 0 {
|
if (qf.flags & QFF_ENCODE_ZERO) != 0 && qf.quantize(0.0) == 0.0 {
|
||||||
if qf.quantize(0.0) == 0.0 {
|
qf.flags &= !QFF_ENCODE_ZERO;
|
||||||
qf.flags &= !QFF_ENCODE_ZERO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qf
|
qf
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ pub struct FieldPath {
|
|||||||
pub last: usize,
|
pub last: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Paths {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Paths {
|
impl Paths {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self(Vec::new())
|
Self(Vec::new())
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
pub const PLAYER_ENTITY_HANDLE_MISSING: i32 = 2047;
|
pub const PLAYER_ENTITY_HANDLE_MISSING: i32 = 2047;
|
||||||
pub const SPECTATOR_TEAM_NUM: u32 = 1;
|
pub const SPECTATOR_TEAM_NUM: u32 = 1;
|
||||||
pub const BUTTONS_BASEID: u32 = 100000;
|
pub const BUTTONS_BASEID: u32 = 100000;
|
||||||
@@ -136,11 +138,8 @@ impl PropController {
|
|||||||
path.clone(),
|
path.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Field::Array(ser) => match &mut ser.field_enum.as_mut() {
|
Field::Array(ser) => if let Field::Value(v) = &mut ser.field_enum.as_mut() {
|
||||||
Field::Value(v) => {
|
self.handle_prop(&(ser_name.clone() + "." + &v.name), v, path);
|
||||||
self.handle_prop(&(ser_name.clone() + "." + &v.name), v, path);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
},
|
||||||
Field::Vector(_x) => {
|
Field::Vector(_x) => {
|
||||||
let vec_path = path.clone();
|
let vec_path = path.clone();
|
||||||
@@ -150,17 +149,14 @@ impl PropController {
|
|||||||
for (inner_idx, f) in
|
for (inner_idx, f) in
|
||||||
&mut s.serializer.fields.iter_mut().enumerate()
|
&mut s.serializer.fields.iter_mut().enumerate()
|
||||||
{
|
{
|
||||||
match f {
|
if let Field::Value(v) = f {
|
||||||
Field::Value(v) => {
|
let mut myp = vec_path.clone();
|
||||||
let mut myp = vec_path.clone();
|
myp.push(inner_idx as i32);
|
||||||
myp.push(inner_idx as i32);
|
self.handle_prop(
|
||||||
self.handle_prop(
|
&(ser_name.clone() + "." + &v.name),
|
||||||
&(ser_name.clone() + "." + &v.name),
|
v,
|
||||||
v,
|
myp,
|
||||||
myp,
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.traverse_fields(
|
self.traverse_fields(
|
||||||
@@ -219,53 +215,50 @@ impl PropController {
|
|||||||
self.path_to_name.insert(a, prop_name.to_string());
|
self.path_to_name.insert(a, prop_name.to_string());
|
||||||
|
|
||||||
let prop_already_exists = self.name_to_id.contains_key(&(prop_name).to_string());
|
let prop_already_exists = self.name_to_id.contains_key(&(prop_name).to_string());
|
||||||
self.set_id(&prop_name, f, is_grenade_or_weapon);
|
self.set_id(&prop_name, f);
|
||||||
if !prop_already_exists {
|
if !prop_already_exists {
|
||||||
self.insert_propinfo(&prop_name, f);
|
self.insert_propinfo(&prop_name, f);
|
||||||
}
|
}
|
||||||
f.should_parse = true;
|
f.should_parse = true;
|
||||||
if full_name == "CCSPlayerPawn.CCSPlayer_WeaponServices.m_hMyWeapons" {
|
if full_name == "CCSPlayerPawn.CCSPlayer_WeaponServices.m_hMyWeapons" {
|
||||||
f.prop_id = MY_WEAPONS_OFFSET as u32;
|
f.prop_id = MY_WEAPONS_OFFSET;
|
||||||
}
|
}
|
||||||
if full_name
|
if full_name
|
||||||
== "CCSPlayerPawn.CCSPlayer_ActionTrackingServices.WeaponPurchaseCount_t.m_nCount"
|
== "CCSPlayerPawn.CCSPlayer_ActionTrackingServices.WeaponPurchaseCount_t.m_nCount"
|
||||||
{
|
{
|
||||||
f.prop_id = ITEM_PURCHASE_COUNT as u32;
|
f.prop_id = ITEM_PURCHASE_COUNT;
|
||||||
}
|
}
|
||||||
if full_name == "CCSPlayerPawn.CCSPlayer_BuyServices.SellbackPurchaseEntry_t.m_unDefIdx" {
|
if full_name == "CCSPlayerPawn.CCSPlayer_BuyServices.SellbackPurchaseEntry_t.m_unDefIdx" {
|
||||||
f.prop_id = ITEM_PURCHASE_DEF_IDX as u32;
|
f.prop_id = ITEM_PURCHASE_DEF_IDX;
|
||||||
}
|
}
|
||||||
if full_name == "CCSPlayerPawn.CCSPlayer_BuyServices.SellbackPurchaseEntry_t.m_nCost" {
|
if full_name == "CCSPlayerPawn.CCSPlayer_BuyServices.SellbackPurchaseEntry_t.m_nCost" {
|
||||||
f.prop_id = ITEM_PURCHASE_COST as u32;
|
f.prop_id = ITEM_PURCHASE_COST;
|
||||||
}
|
}
|
||||||
if full_name == "CCSPlayerPawn.CCSPlayer_ActionTrackingServices.WeaponPurchaseCount_t.m_nItemDefIndex" {
|
if full_name == "CCSPlayerPawn.CCSPlayer_ActionTrackingServices.WeaponPurchaseCount_t.m_nItemDefIndex" {
|
||||||
f.prop_id = ITEM_PURCHASE_NEW_DEF_IDX as u32;
|
f.prop_id = ITEM_PURCHASE_NEW_DEF_IDX;
|
||||||
}
|
}
|
||||||
if full_name == "CCSPlayerPawn.CCSPlayer_BuyServices.SellbackPurchaseEntry_t.m_hItem" {
|
if full_name == "CCSPlayerPawn.CCSPlayer_BuyServices.SellbackPurchaseEntry_t.m_hItem" {
|
||||||
f.prop_id = ITEM_PURCHASE_HANDLE as u32;
|
f.prop_id = ITEM_PURCHASE_HANDLE;
|
||||||
}
|
}
|
||||||
if prop_name.contains("CEconItemAttribute.m_iRawValue32") {
|
if prop_name.contains("CEconItemAttribute.m_iRawValue32") {
|
||||||
f.prop_id = WEAPON_SKIN_ID as u32;
|
f.prop_id = WEAPON_SKIN_ID;
|
||||||
}
|
}
|
||||||
self.id += 1;
|
self.id += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_id(&mut self, weap_prop: &str, f: &mut ValueField, is_grenade_or_weapon: bool) {
|
fn set_id(&mut self, weap_prop: &str, f: &mut ValueField) {
|
||||||
match self.name_to_id.get(weap_prop) {
|
match self.name_to_id.get(weap_prop) {
|
||||||
// If we already have an id for prop of same name then use that id.
|
// If we already have an id for prop of same name then use that id.
|
||||||
// Mainly for weapon props. For example CAK47.m_iClip1 and CWeaponSCAR20.m_iClip1
|
// Mainly for weapon props. For example CAK47.m_iClip1 and CWeaponSCAR20.m_iClip1
|
||||||
// are the "same" prop. (they have same path and we want to refer to it with one id not ~20)
|
// are the "same" prop. (they have same path and we want to refer to it with one id not ~20)
|
||||||
Some(id) => {
|
Some(id) => {
|
||||||
f.prop_id = *id as u32;
|
f.prop_id = *id;
|
||||||
self.id_to_name.insert(*id, weap_prop.to_string());
|
self.id_to_name.insert(*id, weap_prop.to_string());
|
||||||
self.set_special_ids(&weap_prop, is_grenade_or_weapon, *id);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.name_to_id.insert(weap_prop.to_string(), self.id);
|
self.name_to_id.insert(weap_prop.to_string(), self.id);
|
||||||
self.id_to_name.insert(self.id, weap_prop.to_string());
|
self.id_to_name.insert(self.id, weap_prop.to_string());
|
||||||
f.prop_id = self.id as u32;
|
f.prop_id = self.id;
|
||||||
self.set_special_ids(&weap_prop, is_grenade_or_weapon, self.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,24 +267,11 @@ impl PropController {
|
|||||||
self.prop_infos.insert(
|
self.prop_infos.insert(
|
||||||
f.prop_id,
|
f.prop_id,
|
||||||
PropInfo {
|
PropInfo {
|
||||||
id: f.prop_id as u32,
|
id: f.prop_id,
|
||||||
prop_name: prop_name.into(),
|
prop_name: prop_name.into(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_special_ids(&mut self, weap_prop: &str, is_grenade_or_weapon: bool, id: u32) {
|
|
||||||
// TODO
|
|
||||||
if is_grenade_or_weapon {
|
|
||||||
match weap_prop {
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
match weap_prop {
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpecialIDs {
|
impl SpecialIDs {
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
use super::decoder;
|
use super::decoder;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ParseSendTables {}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Serializer {
|
pub struct Serializer {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -138,7 +135,7 @@ fn generate_field_data(
|
|||||||
) -> Result<ConstructorField, super::FirstPassError> {
|
) -> Result<ConstructorField, super::FirstPassError> {
|
||||||
let name = msg.symbols.get(field.var_type_sym() as usize).unwrap();
|
let name = msg.symbols.get(field.var_type_sym() as usize).unwrap();
|
||||||
|
|
||||||
let ft = find_field_type(&name, field_type_map)?;
|
let ft = find_field_type(name, field_type_map)?;
|
||||||
let mut field = field_from_msg(field, msg, ft.clone())?;
|
let mut field = field_from_msg(field, msg, ft.clone())?;
|
||||||
|
|
||||||
field.category = find_category(&field);
|
field.category = find_category(&field);
|
||||||
@@ -166,7 +163,7 @@ fn generate_field_data(
|
|||||||
|
|
||||||
fn generate_serializer(
|
fn generate_serializer(
|
||||||
serializer: &crate::csgo_proto::ProtoFlattenedSerializerT,
|
serializer: &crate::csgo_proto::ProtoFlattenedSerializerT,
|
||||||
field_data: &mut Vec<Option<ConstructorField>>,
|
field_data: &mut [Option<ConstructorField>],
|
||||||
msg: &crate::csgo_proto::CsvcMsgFlattenedSerializer,
|
msg: &crate::csgo_proto::CsvcMsgFlattenedSerializer,
|
||||||
serializers: &mut std::collections::HashMap<String, Serializer>,
|
serializers: &mut std::collections::HashMap<String, Serializer>,
|
||||||
) -> Result<Serializer, super::FirstPassError> {
|
) -> Result<Serializer, super::FirstPassError> {
|
||||||
@@ -188,7 +185,7 @@ fn generate_serializer(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if f.field_enum_type.is_none() {
|
if f.field_enum_type.is_none() {
|
||||||
f.field_enum_type = Some(create_field(&symbol, f, serializers)?);
|
f.field_enum_type = Some(create_field(f, serializers)?);
|
||||||
}
|
}
|
||||||
if let Some(Some(f)) = &field_data.get(fi) {
|
if let Some(Some(f)) = &field_data.get(fi) {
|
||||||
if let Some(field) = &f.field_enum_type {
|
if let Some(field) = &f.field_enum_type {
|
||||||
@@ -221,6 +218,7 @@ pub enum FieldCategory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct ConstructorField {
|
pub struct ConstructorField {
|
||||||
pub var_name: String,
|
pub var_name: String,
|
||||||
pub var_type: String,
|
pub var_type: String,
|
||||||
@@ -245,7 +243,7 @@ static RE: std::sync::LazyLock<regex::Regex> = std::sync::LazyLock::new(|| {
|
|||||||
regex::Regex::new(r"([^<\[\*]+)(<\s(.*)\s>)?(\*)?(\[(.*)\])?").unwrap()
|
regex::Regex::new(r"([^<\[\*]+)(<\s(.*)\s>)?(\*)?(\[(.*)\])?").unwrap()
|
||||||
});
|
});
|
||||||
|
|
||||||
const POINTER_TYPES: &'static [&'static str] = &[
|
const POINTER_TYPES: &[&str] = &[
|
||||||
"CBodyComponent",
|
"CBodyComponent",
|
||||||
"CLightComponent",
|
"CLightComponent",
|
||||||
"CPhysicsComponent",
|
"CPhysicsComponent",
|
||||||
@@ -417,7 +415,7 @@ impl FieldType {
|
|||||||
|
|
||||||
if let Some(gt) = self.generic_type.as_ref() {
|
if let Some(gt) = self.generic_type.as_ref() {
|
||||||
s += "< ";
|
s += "< ";
|
||||||
s += &FieldType::to_string(>, true);
|
s += &FieldType::to_string(gt, true);
|
||||||
s += "< ";
|
s += "< ";
|
||||||
}
|
}
|
||||||
if self.pointer {
|
if self.pointer {
|
||||||
@@ -450,7 +448,6 @@ fn for_string(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_field(
|
fn create_field(
|
||||||
symbol: &String,
|
|
||||||
fd: &mut ConstructorField,
|
fd: &mut ConstructorField,
|
||||||
serializers: &mut std::collections::HashMap<String, Serializer>,
|
serializers: &mut std::collections::HashMap<String, Serializer>,
|
||||||
) -> Result<Field, super::FirstPassError> {
|
) -> Result<Field, super::FirstPassError> {
|
||||||
@@ -578,7 +575,8 @@ impl Field {
|
|||||||
fi.prop_id = ITEM_PURCHASE_NEW_DEF_IDX + path.path[2] as u32;
|
fi.prop_id = ITEM_PURCHASE_NEW_DEF_IDX + path.path[2] as u32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Some(fi);
|
|
||||||
|
Some(fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_decoder(&self) -> Result<decoder::Decoder, super::FirstPassError> {
|
pub fn get_decoder(&self) -> Result<decoder::Decoder, super::FirstPassError> {
|
||||||
|
|||||||
@@ -17,12 +17,12 @@ impl TryFrom<crate::csgo_proto::c_msg_source1_legacy_game_event::KeyT> for RawVa
|
|||||||
1 if value.val_string.is_some() => Ok(Self::String(value.val_string.unwrap())),
|
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())),
|
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())),
|
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)),
|
4 if value.val_short.is_some() => Ok(Self::I32(value.val_short.unwrap())),
|
||||||
5 if value.val_byte.is_some() => Ok(Self::I32(value.val_byte.unwrap() as i32)),
|
5 if value.val_byte.is_some() => Ok(Self::I32(value.val_byte.unwrap())),
|
||||||
6 if value.val_bool.is_some() => Ok(Self::Bool(value.val_bool.unwrap())),
|
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())),
|
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())),
|
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)),
|
9 if value.val_short.is_some() => Ok(Self::I32(value.val_short.unwrap())),
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,25 +18,19 @@ fn mirage_1() {
|
|||||||
assert_eq!("de_mirage", output.header.map_name());
|
assert_eq!("de_mirage", output.header.map_name());
|
||||||
|
|
||||||
for event in output.events.iter() {
|
for event in output.events.iter() {
|
||||||
match event {
|
if let DemoEvent::GameEvent(gevent) = event { if let GameEvent::PlayerDeath(death) = gevent {
|
||||||
DemoEvent::GameEvent(gevent) => match gevent {
|
assert!(
|
||||||
GameEvent::PlayerDeath(death) => {
|
death.remaining.is_empty(),
|
||||||
assert!(
|
"Remaining for PlayerDeath: {:?}",
|
||||||
death.remaining.is_empty(),
|
death.remaining
|
||||||
"Remaining for PlayerDeath: {:?}",
|
);
|
||||||
death.remaining
|
|
||||||
);
|
|
||||||
|
|
||||||
let died_user = output
|
let died_user = output
|
||||||
.player_info
|
.player_info
|
||||||
.get(death.userid.as_ref().unwrap())
|
.get(death.userid.as_ref().unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
// dbg!(died_user);
|
// dbg!(died_user);
|
||||||
}
|
} };
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
todo!()
|
todo!()
|
||||||
|
|||||||
Reference in New Issue
Block a user