Change the way entity data is stored

This commit is contained in:
Lol3rrr
2024-09-22 23:19:18 +02:00
parent 8b41ad5108
commit ff8d05b79a
8 changed files with 73 additions and 30 deletions

View File

@@ -12,5 +12,5 @@ fn main() {
println!("Header: {:?}", output.header); println!("Header: {:?}", output.header);
println!("Players: {:?}", output.player_info); println!("Players: {:?}", output.player_info);
println!("Events: {:?}", output.events.len()); println!("Events: {:?}", output.events.len());
println!("Entities: {:?}", output.entity_states.len()); println!("Entity-Ticks: {:?}", output.entity_states.ticks.len());
} }

View File

@@ -12,5 +12,5 @@ fn main() {
println!("Header: {:?}", output.header); println!("Header: {:?}", output.header);
println!("Players: {:?}", output.player_info); println!("Players: {:?}", output.player_info);
println!("Events: {:?}", output.events.len()); println!("Events: {:?}", output.events.len());
println!("Entities: {:?}", output.entity_states.len()); println!("Entity-Ticks: {:?}", output.entity_states.ticks.len());
} }

View File

@@ -2,9 +2,9 @@ use crate::csgo_proto;
#[derive(Debug)] #[derive(Debug)]
pub enum DemoEvent { pub enum DemoEvent {
GameEvent(crate::game_event::GameEvent), GameEvent(Box<crate::game_event::GameEvent>),
ServerInfo(csgo_proto::CsvcMsgServerInfo), ServerInfo(Box<csgo_proto::CsvcMsgServerInfo>),
Tick(csgo_proto::CnetMsgTick), Tick(Box<csgo_proto::CnetMsgTick>),
RankUpdate(csgo_proto::CcsUsrMsgServerRankUpdate), RankUpdate(Box<csgo_proto::CcsUsrMsgServerRankUpdate>),
RankReveal(csgo_proto::CcsUsrMsgServerRankRevealAll), RankReveal(Box<csgo_proto::CcsUsrMsgServerRankRevealAll>),
} }

View File

@@ -51,13 +51,46 @@ pub struct Entity {
pub cls: u32, pub cls: u32,
} }
#[derive(Debug)]
pub struct EntityTickList {
pub ticks: Vec<EntityTickStates>,
}
impl EntityTickList {
pub fn new() -> Self {
Self {
ticks: vec![EntityTickStates {
tick: 0,
states: Vec::new()
}],
}
}
fn new_tick(&mut self, n_tick: u32) {
self.ticks.push(EntityTickStates {
tick: n_tick,
states: Vec::new(),
});
}
fn add_state(&mut self, state: entities::EntityState) {
self.ticks.last_mut().expect("We start with at least 1 tick entry and never remove any, so we can always get the last element").states.push(state);
}
}
#[derive(Debug)]
pub struct EntityTickStates {
pub tick: u32,
pub states: Vec<entities::EntityState>,
}
#[derive(Debug)] #[derive(Debug)]
pub struct FirstPassOutput { pub struct FirstPassOutput {
pub header: crate::csgo_proto::CDemoFileHeader, pub header: crate::csgo_proto::CDemoFileHeader,
pub info: crate::csgo_proto::CDemoFileInfo, pub info: crate::csgo_proto::CDemoFileInfo,
pub events: Vec<DemoEvent>, pub events: Vec<DemoEvent>,
pub player_info: std::collections::HashMap<UserId, Player>, pub player_info: std::collections::HashMap<UserId, Player>,
pub entity_states: Vec<entities::EntityState>, pub entity_states: EntityTickList,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -104,7 +137,9 @@ where
let mut baselines = std::collections::HashMap::new(); let mut baselines = std::collections::HashMap::new();
let mut entity_states = Vec::new(); let mut entity_states = EntityTickList::new();
let mut current_tick = 0;
let mut buffer = Vec::new(); let mut buffer = Vec::new();
for frame in frames.into_iter() { for frame in frames.into_iter() {
@@ -135,6 +170,7 @@ where
&mut baselines, &mut baselines,
&prop_controller, &prop_controller,
&mut entity_states, &mut entity_states,
&mut current_tick,
)?; )?;
} }
DemoCommand::FullPacket => { DemoCommand::FullPacket => {
@@ -152,6 +188,7 @@ where
&mut baselines, &mut baselines,
&prop_controller, &prop_controller,
&mut entity_states, &mut entity_states,
&mut current_tick,
)?; )?;
} }
} }
@@ -250,7 +287,8 @@ fn inner_parse_packet(
qf_mapper: &mut decoder::QfMapper, qf_mapper: &mut decoder::QfMapper,
baselines: &mut std::collections::HashMap<u32, Vec<u8>>, baselines: &mut std::collections::HashMap<u32, Vec<u8>>,
prop_controller: &propcontroller::PropController, prop_controller: &propcontroller::PropController,
entity_states: &mut Vec<entities::EntityState>, entity_states: &mut EntityTickList,
current_tick: &mut u32,
) -> Result<(), FirstPassError> { ) -> Result<(), FirstPassError> {
let mut bitreader = crate::bitreader::Bitreader::new(raw.data()); let mut bitreader = crate::bitreader::Bitreader::new(raw.data());
@@ -288,7 +326,7 @@ fn inner_parse_packet(
let raw: crate::csgo_proto::CsvcMsgServerInfo = let raw: crate::csgo_proto::CsvcMsgServerInfo =
prost::Message::decode(msg_bytes.as_slice())?; prost::Message::decode(msg_bytes.as_slice())?;
events.push(DemoEvent::ServerInfo(raw)); events.push(DemoEvent::ServerInfo(Box::new(raw)));
} }
crate::netmessagetypes::NetmessageType::net_SignonState => { crate::netmessagetypes::NetmessageType::net_SignonState => {
let raw: crate::csgo_proto::CnetMsgSignonState = let raw: crate::csgo_proto::CnetMsgSignonState =
@@ -299,7 +337,13 @@ fn inner_parse_packet(
let raw: crate::csgo_proto::CnetMsgTick = let raw: crate::csgo_proto::CnetMsgTick =
prost::Message::decode(msg_bytes.as_slice())?; prost::Message::decode(msg_bytes.as_slice())?;
events.push(DemoEvent::Tick(raw)); assert!(*current_tick <= raw.tick(), "Current Tick {} <= Tick Packet {}", *current_tick, raw.tick());
if raw.tick() > *current_tick {
*current_tick = raw.tick();
entity_states.new_tick(*current_tick);
}
events.push(DemoEvent::Tick(Box::new(raw)));
} }
crate::netmessagetypes::NetmessageType::net_SetConVar => {} crate::netmessagetypes::NetmessageType::net_SetConVar => {}
crate::netmessagetypes::NetmessageType::svc_ClassInfo => {} crate::netmessagetypes::NetmessageType::svc_ClassInfo => {}
@@ -345,7 +389,7 @@ fn inner_parse_packet(
prop_controller, prop_controller,
)?; )?;
if let Some(state) = state { if let Some(state) = state {
entity_states.push(state); entity_states.add_state(state);
} }
} }
0b00 => { 0b00 => {
@@ -362,7 +406,7 @@ fn inner_parse_packet(
prop_controller, prop_controller,
)?; )?;
if let Some(state) = state { if let Some(state) = state {
entity_states.push(state); entity_states.add_state(state);
} }
} }
unknown => { unknown => {
@@ -388,7 +432,7 @@ fn inner_parse_packet(
Some(parser) => { Some(parser) => {
let parsed = parser.parse(keys.as_slice(), raw.clone())?; let parsed = parser.parse(keys.as_slice(), raw.clone())?;
events.push(DemoEvent::GameEvent(parsed)); events.push(DemoEvent::GameEvent(Box::new(parsed)));
} }
None => { None => {
println!("No parser for {:?}", name); println!("No parser for {:?}", name);
@@ -406,13 +450,13 @@ fn inner_parse_packet(
let raw: crate::csgo_proto::CcsUsrMsgServerRankUpdate = let raw: crate::csgo_proto::CcsUsrMsgServerRankUpdate =
prost::Message::decode(msg_bytes.as_slice())?; prost::Message::decode(msg_bytes.as_slice())?;
events.push(DemoEvent::RankUpdate(raw)); events.push(DemoEvent::RankUpdate(Box::new(raw)));
} }
crate::netmessagetypes::NetmessageType::CS_UM_ServerRankRevealAll => { crate::netmessagetypes::NetmessageType::CS_UM_ServerRankRevealAll => {
let raw: crate::csgo_proto::CcsUsrMsgServerRankRevealAll = let raw: crate::csgo_proto::CcsUsrMsgServerRankRevealAll =
prost::Message::decode(msg_bytes.as_slice())?; prost::Message::decode(msg_bytes.as_slice())?;
events.push(DemoEvent::RankReveal(raw)); events.push(DemoEvent::RankReveal(Box::new(raw)));
} }
crate::netmessagetypes::NetmessageType::CS_UM_WeaponSound => {} crate::netmessagetypes::NetmessageType::CS_UM_WeaponSound => {}
crate::netmessagetypes::NetmessageType::CS_UM_RadioText => {} crate::netmessagetypes::NetmessageType::CS_UM_RadioText => {}
@@ -440,8 +484,8 @@ fn inner_parse_packet(
crate::netmessagetypes::NetmessageType::net_SpawnGroup_Load => {} crate::netmessagetypes::NetmessageType::net_SpawnGroup_Load => {}
crate::netmessagetypes::NetmessageType::CS_UM_MatchEndConditions => {} crate::netmessagetypes::NetmessageType::CS_UM_MatchEndConditions => {}
crate::netmessagetypes::NetmessageType::TE_Explosion => {} crate::netmessagetypes::NetmessageType::TE_Explosion => {}
unknown => { _unknown => {
dbg!(unknown); // dbg!(unknown);
} }
}; };
} }

View File

@@ -268,8 +268,8 @@ impl<'b> crate::bitreader::Bitreader<'b> {
pub fn decode_vector_noscale(&mut self) -> Result<[f32; 3], super::FirstPassError> { pub fn decode_vector_noscale(&mut self) -> Result<[f32; 3], super::FirstPassError> {
let mut v = [0.0; 3]; let mut v = [0.0; 3];
for idx in 0..3 { for item in v.iter_mut() {
v[idx] = self.decode_noscale()?; *item = self.decode_noscale()?;
} }
Ok(v) Ok(v)
} }
@@ -343,8 +343,8 @@ impl<'b> crate::bitreader::Bitreader<'b> {
pub fn decode_vector_float_coord(&mut self) -> Result<[f32; 3], super::FirstPassError> { pub fn decode_vector_float_coord(&mut self) -> Result<[f32; 3], super::FirstPassError> {
let mut v = [0.0; 3]; let mut v = [0.0; 3];
for idx in 0..3 { for item in v.iter_mut() {
v[idx] = self.decode_float_coord()?; *item = self.decode_float_coord()?;
} }
Ok(v) Ok(v)
} }

View File

@@ -54,12 +54,11 @@ impl QuantalizedFloat {
self.high_low_mul = 0.0; self.high_low_mul = 0.0;
let range = self.high - self.low; let range = self.high - self.low;
let high: u32; let high: u32 = if self.bit_count == 32 {
if self.bit_count == 32 { 0xFFFFFFFE
high = 0xFFFFFFFE;
} else { } else {
high = (1 << self.bit_count) - 1; (1 << self.bit_count) - 1
} };
let mut high_mul: f32; let mut high_mul: f32;
// Xd? // Xd?

View File

@@ -114,7 +114,7 @@ impl PropController {
self.traverse_fields(&mut serializer.fields, serializer.name.clone(), Vec::new()) self.traverse_fields(&mut serializer.fields, serializer.name.clone(), Vec::new())
} }
fn traverse_fields(&mut self, fields: &mut Vec<Field>, ser_name: String, path_og: Vec<i32>) { fn traverse_fields(&mut self, fields: &mut [Field], ser_name: String, path_og: Vec<i32>) {
for (idx, f) in fields.iter_mut().enumerate() { for (idx, f) in fields.iter_mut().enumerate() {
let mut path = path_og.clone(); let mut path = path_og.clone();
path.push(idx as i32); path.push(idx as i32);

View File

@@ -18,7 +18,7 @@ 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() {
if let DemoEvent::GameEvent(gevent) = event { if let GameEvent::PlayerDeath(death) = gevent { if let DemoEvent::GameEvent(gevent) = event { if let GameEvent::PlayerDeath(death) = gevent.as_ref() {
assert!( assert!(
death.remaining.is_empty(), death.remaining.is_empty(),
"Remaining for PlayerDeath: {:?}", "Remaining for PlayerDeath: {:?}",