mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 18:24:05 +02:00
dont stop prop and table name in sendprop
This commit is contained in:
parent
df9a6a138e
commit
35519d5fce
7 changed files with 215 additions and 216 deletions
|
|
@ -69,15 +69,13 @@ impl fmt::Display for PacketEntity {
|
|||
}
|
||||
|
||||
impl PacketEntity {
|
||||
fn get_prop_by_identifier(&mut self, identifier: &SendPropIdentifier) -> Option<&mut SendProp> {
|
||||
self.props
|
||||
.iter_mut()
|
||||
.find(|prop| prop.identifier.index == identifier.index)
|
||||
fn get_prop_by_identifier(&mut self, index: &SendPropIdentifier) -> Option<&mut SendProp> {
|
||||
self.props.iter_mut().find(|prop| prop.index == *index)
|
||||
}
|
||||
|
||||
pub fn apply_update(&mut self, props: Vec<SendProp>) {
|
||||
for prop in props {
|
||||
match self.get_prop_by_identifier(&prop.identifier) {
|
||||
match self.get_prop_by_identifier(&prop.index) {
|
||||
Some(existing_prop) => existing_prop.value = prop.value,
|
||||
None => self.props.push(prop),
|
||||
}
|
||||
|
|
@ -85,10 +83,8 @@ impl PacketEntity {
|
|||
}
|
||||
|
||||
pub fn get_prop_by_name(&self, table_name: &str, name: &str) -> Option<&SendProp> {
|
||||
self.props.iter().find(|prop| {
|
||||
prop.identifier.owner_table.as_str() == table_name
|
||||
&& prop.identifier.name.as_str() == name
|
||||
})
|
||||
let identifier = SendPropIdentifier::new(table_name, name);
|
||||
self.props.iter().find(|prop| prop.index == identifier)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -249,9 +245,9 @@ impl PacketEntitiesMessage {
|
|||
|
||||
match send_table.flattened_props.get(index as usize) {
|
||||
Some(definition) => {
|
||||
let value = SendPropValue::parse(stream, definition)?;
|
||||
let value = SendPropValue::parse(stream, &definition.parse_definition)?;
|
||||
props.push(SendProp {
|
||||
identifier: definition.identifier(),
|
||||
index: definition.identifier,
|
||||
value,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ use bitbuffer::BitRead;
|
|||
|
||||
use crate::demo::parser::MalformedSendPropDefinitionError;
|
||||
use crate::demo::sendprop::{
|
||||
RawSendPropDefinition, SendPropDefinition, SendPropDefinitionIndex, SendPropFlag, SendPropName,
|
||||
SendPropType,
|
||||
RawSendPropDefinition, SendPropDefinition, SendPropFlag, SendPropIdentifier, SendPropType,
|
||||
};
|
||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||
use parse_display::{Display, FromStr};
|
||||
|
|
@ -81,12 +80,12 @@ impl From<String> for SendTableName {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct ParseSendTable {
|
||||
pub name: SendTableName,
|
||||
pub props: Vec<Rc<RawSendPropDefinition>>,
|
||||
pub props: Vec<RawSendPropDefinition>,
|
||||
pub needs_decoder: bool,
|
||||
}
|
||||
|
||||
impl ParseSendTable {
|
||||
fn parse(stream: &mut Stream, _state: &ParserState, table_index: usize) -> Result<Self> {
|
||||
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||
let needs_decoder = stream.read()?;
|
||||
let raw_name: String = stream.read()?;
|
||||
let name: SendTableName = raw_name.into();
|
||||
|
|
@ -95,10 +94,8 @@ impl ParseSendTable {
|
|||
let mut array_element_prop = None;
|
||||
let mut props = Vec::with_capacity(min(prop_count, 128));
|
||||
|
||||
for prop_index in 0..prop_count {
|
||||
let definition_index = SendPropDefinitionIndex::new(table_index, prop_index);
|
||||
let prop: RawSendPropDefinition =
|
||||
RawSendPropDefinition::read(stream, name.clone(), definition_index)?;
|
||||
for _ in 0..prop_count {
|
||||
let prop: RawSendPropDefinition = RawSendPropDefinition::read(stream, name.clone())?;
|
||||
if prop.flags.contains(SendPropFlag::InsideArray) {
|
||||
if array_element_prop.is_some() || prop.flags.contains(SendPropFlag::ChangesOften) {
|
||||
return Err(MalformedSendPropDefinitionError::ArrayChangesOften.into());
|
||||
|
|
@ -109,9 +106,9 @@ impl ParseSendTable {
|
|||
return Err(MalformedSendPropDefinitionError::UntypedArray.into());
|
||||
}
|
||||
array_element_prop = None;
|
||||
props.push(Rc::new(prop.with_array_property(array_element)));
|
||||
props.push(prop.with_array_property(array_element));
|
||||
} else {
|
||||
props.push(Rc::new(prop));
|
||||
props.push(prop);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -124,7 +121,7 @@ impl ParseSendTable {
|
|||
}
|
||||
|
||||
impl ParseSendTable {
|
||||
pub fn flatten_props(&self, tables: &[ParseSendTable]) -> Vec<Rc<RawSendPropDefinition>> {
|
||||
pub fn flatten_props(&self, tables: &[ParseSendTable]) -> Vec<RawSendPropDefinition> {
|
||||
let mut flat = Vec::with_capacity(32);
|
||||
self.get_all_props(tables, &self.get_excludes(tables), &mut flat);
|
||||
|
||||
|
|
@ -139,18 +136,18 @@ impl ParseSendTable {
|
|||
}
|
||||
}
|
||||
|
||||
flat.into_iter().map(|prop| Rc::clone(&prop)).collect()
|
||||
flat
|
||||
}
|
||||
|
||||
fn get_excludes<'a>(&'a self, tables: &'a [ParseSendTable]) -> Vec<Exclude<'a>> {
|
||||
fn get_excludes<'a>(&'a self, tables: &'a [ParseSendTable]) -> Vec<SendPropIdentifier> {
|
||||
let mut excludes = Vec::with_capacity(8);
|
||||
|
||||
for prop in self.props.iter() {
|
||||
if let Some(exclude_table) = prop.get_exclude_table() {
|
||||
excludes.push(Exclude {
|
||||
table: exclude_table,
|
||||
prop: &prop.identifier.name,
|
||||
})
|
||||
excludes.push(SendPropIdentifier::new(
|
||||
exclude_table.as_str(),
|
||||
prop.name.as_str(),
|
||||
))
|
||||
} else if let Some(table) = prop.get_data_table(tables) {
|
||||
excludes.extend_from_slice(&table.get_excludes(tables));
|
||||
}
|
||||
|
|
@ -163,8 +160,8 @@ impl ParseSendTable {
|
|||
fn get_all_props(
|
||||
&self,
|
||||
tables: &[ParseSendTable],
|
||||
excludes: &[Exclude],
|
||||
props: &mut Vec<Rc<RawSendPropDefinition>>,
|
||||
excludes: &[SendPropIdentifier],
|
||||
props: &mut Vec<RawSendPropDefinition>,
|
||||
) {
|
||||
let mut local_props = Vec::new();
|
||||
|
||||
|
|
@ -175,14 +172,14 @@ impl ParseSendTable {
|
|||
fn get_all_props_iterator_props(
|
||||
&self,
|
||||
tables: &[ParseSendTable],
|
||||
excludes: &[Exclude],
|
||||
local_props: &mut Vec<Rc<RawSendPropDefinition>>,
|
||||
props: &mut Vec<Rc<RawSendPropDefinition>>,
|
||||
excludes: &[SendPropIdentifier],
|
||||
local_props: &mut Vec<RawSendPropDefinition>,
|
||||
props: &mut Vec<RawSendPropDefinition>,
|
||||
) {
|
||||
self.props
|
||||
.iter()
|
||||
.filter(|prop| !prop.is_exclude())
|
||||
.filter(|prop| !excludes.iter().any(|exclude| exclude.matches(prop)))
|
||||
.filter(|prop| !excludes.iter().any(|exclude| *exclude == prop.identifier()))
|
||||
.for_each(|prop| {
|
||||
if let Some(table) = prop.get_data_table(tables) {
|
||||
if prop.flags.contains(SendPropFlag::Collapsible) {
|
||||
|
|
@ -191,24 +188,12 @@ impl ParseSendTable {
|
|||
table.get_all_props(tables, excludes, props);
|
||||
}
|
||||
} else {
|
||||
local_props.push(Rc::clone(prop));
|
||||
local_props.push(prop.clone());
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Exclude<'a> {
|
||||
table: &'a SendTableName,
|
||||
prop: &'a SendPropName,
|
||||
}
|
||||
|
||||
impl<'a> Exclude<'a> {
|
||||
pub fn matches(&self, prop: &RawSendPropDefinition) -> bool {
|
||||
self.table == &prop.identifier.owner_table && *self.prop == prop.identifier.name
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SendTable {
|
||||
pub name: SendTableName,
|
||||
|
|
@ -230,10 +215,8 @@ impl Parse<'_> for DataTablePacket {
|
|||
let mut packet_data = stream.read_bits(len * 8)?;
|
||||
|
||||
let mut tables = Vec::new();
|
||||
let mut table_index = 0;
|
||||
while packet_data.read_bool()? {
|
||||
let table = ParseSendTable::parse(&mut packet_data, state, table_index)?;
|
||||
table_index += 1;
|
||||
let table = ParseSendTable::parse(&mut packet_data, state)?;
|
||||
tables.push(table);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use crate::demo::message::packetentities::{EntityId, PacketEntity};
|
||||
use crate::demo::message::Message;
|
||||
use crate::demo::packet::datatable::{ParseSendTable, ServerClass, ServerClassName};
|
||||
use crate::demo::packet::datatable::{ParseSendTable, SendTableName, ServerClass, ServerClassName};
|
||||
pub use crate::demo::parser::analyser::{Class, Team, UserId};
|
||||
use crate::demo::parser::handler::BorrowMessageHandler;
|
||||
use crate::demo::parser::MessageHandler;
|
||||
use crate::demo::sendprop::{SendProp, SendPropValue};
|
||||
use crate::demo::sendprop::{SendProp, SendPropIdentifier, SendPropName, SendPropValue};
|
||||
use crate::demo::vector::{Vector, VectorXY};
|
||||
use crate::{MessageType, ParserState};
|
||||
use fnv::FnvHashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
use std::str::FromStr;
|
||||
|
|
@ -142,6 +143,7 @@ impl GameState {
|
|||
#[derive(Default, Debug)]
|
||||
pub struct GameStateAnalyser {
|
||||
pub state: GameState,
|
||||
prop_names: FnvHashMap<SendPropIdentifier, (SendTableName, SendPropName)>,
|
||||
class_names: Vec<ServerClassName>, // indexed by ClassId
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +168,20 @@ impl MessageHandler for GameStateAnalyser {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_data_tables(&mut self, _tables: &[ParseSendTable], server_classes: &[ServerClass]) {
|
||||
fn handle_data_tables(
|
||||
&mut self,
|
||||
parse_tables: &[ParseSendTable],
|
||||
server_classes: &[ServerClass],
|
||||
) {
|
||||
for table in parse_tables {
|
||||
for prop_def in &table.props {
|
||||
self.prop_names.insert(
|
||||
prop_def.identifier(),
|
||||
(prop_def.owner_table.clone(), prop_def.name.clone()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.class_names = server_classes
|
||||
.iter()
|
||||
.map(|class| &class.name)
|
||||
|
|
@ -206,7 +221,8 @@ impl GameStateAnalyser {
|
|||
|
||||
pub fn handle_player_resource(&mut self, entity: &PacketEntity) {
|
||||
for prop in &entity.props {
|
||||
if let Ok(player_id) = u32::from_str(prop.identifier.name.as_str()) {
|
||||
if let Some((table_name, prop_name)) = self.prop_names.get(&prop.index) {
|
||||
if let Ok(player_id) = u32::from_str(prop_name.as_str()) {
|
||||
let entity_id = EntityId::from(player_id);
|
||||
if let Some(player) = self
|
||||
.state
|
||||
|
|
@ -214,9 +230,10 @@ impl GameStateAnalyser {
|
|||
.iter_mut()
|
||||
.find(|player| player.entity == entity_id)
|
||||
{
|
||||
match prop.identifier.owner_table.as_str() {
|
||||
match table_name.as_str() {
|
||||
"m_iTeam" => {
|
||||
player.team = Team::new(i64::try_from(&prop.value).unwrap_or_default())
|
||||
player.team =
|
||||
Team::new(i64::try_from(&prop.value).unwrap_or_default())
|
||||
}
|
||||
"m_iMaxHealth" => {
|
||||
player.max_health =
|
||||
|
|
@ -232,18 +249,21 @@ impl GameStateAnalyser {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_player_entity(&mut self, entity: &PacketEntity) {
|
||||
let player = self.state.get_or_create_player(entity.entity_index);
|
||||
|
||||
for prop in &entity.props {
|
||||
match prop.identifier.owner_table.as_str() {
|
||||
"DT_BasePlayer" => match prop.identifier.name.as_str() {
|
||||
if let Some((table_name, prop_name)) = self.prop_names.get(&prop.index) {
|
||||
match table_name.as_str() {
|
||||
"DT_BasePlayer" => match prop_name.as_str() {
|
||||
"m_iHealth" => {
|
||||
player.health = i64::try_from(&prop.value).unwrap_or_default() as u16
|
||||
}
|
||||
"m_iMaxHealth" => {
|
||||
player.max_health = i64::try_from(&prop.value).unwrap_or_default() as u16
|
||||
player.max_health =
|
||||
i64::try_from(&prop.value).unwrap_or_default() as u16
|
||||
}
|
||||
"m_lifeState" => {
|
||||
player.state =
|
||||
|
|
@ -252,7 +272,7 @@ impl GameStateAnalyser {
|
|||
_ => {}
|
||||
},
|
||||
"DT_TFLocalPlayerExclusive" | "DT_TFNonLocalPlayerExclusive" => {
|
||||
match prop.identifier.name.as_str() {
|
||||
match prop_name.as_str() {
|
||||
"m_vecOrigin" => {
|
||||
let pos_xy = VectorXY::try_from(&prop.value).unwrap_or_default();
|
||||
player.position.x = pos_xy.x;
|
||||
|
|
@ -271,6 +291,7 @@ impl GameStateAnalyser {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_world_entity(&mut self, entity: &PacketEntity) {
|
||||
if let (
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ impl<'a> ParserState {
|
|||
needs_decoder: parse_table.needs_decoder,
|
||||
flattened_props: flat
|
||||
.into_iter()
|
||||
.map(|raw| SendPropDefinition::try_from(raw.as_ref()))
|
||||
.map(|raw| SendPropDefinition::try_from(raw))
|
||||
.collect::<std::result::Result<Vec<_>, _>>()?,
|
||||
},
|
||||
))
|
||||
|
|
|
|||
|
|
@ -11,9 +11,11 @@ use crate::demo::packet::datatable::SendTableName;
|
|||
use crate::demo::parser::MalformedSendPropDefinitionError;
|
||||
use parse_display::Display;
|
||||
use std::cmp::min;
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
use fnv::FnvHasher;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(
|
||||
|
|
@ -42,7 +44,8 @@ impl From<String> for SendPropName {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct RawSendPropDefinition {
|
||||
pub prop_type: SendPropType,
|
||||
pub identifier: Rc<SendPropIdentifier>,
|
||||
pub name: SendPropName,
|
||||
pub owner_table: SendTableName,
|
||||
pub flags: SendPropFlags,
|
||||
pub table_name: Option<SendTableName>,
|
||||
pub low_value: Option<f32>,
|
||||
|
|
@ -54,7 +57,7 @@ pub struct RawSendPropDefinition {
|
|||
|
||||
impl PartialEq for RawSendPropDefinition {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.identifier.index == other.identifier.index
|
||||
self.identifier() == other.identifier()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -64,8 +67,8 @@ impl fmt::Display for RawSendPropDefinition {
|
|||
SendPropType::Vector | SendPropType::VectorXY => write!(
|
||||
f,
|
||||
"{}::{}({})(flags: {}, low: {}, high: {}, bits: {})",
|
||||
self.identifier.owner_table,
|
||||
self.identifier.name,
|
||||
self.owner_table,
|
||||
self.name,
|
||||
self.prop_type,
|
||||
self.flags,
|
||||
self.low_value.unwrap_or_default(),
|
||||
|
|
@ -75,8 +78,8 @@ impl fmt::Display for RawSendPropDefinition {
|
|||
SendPropType::Float => write!(
|
||||
f,
|
||||
"{}::{}({})(flags: {}, low: {}, high: {}, bits: {})",
|
||||
self.identifier.owner_table,
|
||||
self.identifier.name,
|
||||
self.owner_table,
|
||||
self.name,
|
||||
self.prop_type,
|
||||
self.flags,
|
||||
self.low_value.unwrap_or_default(),
|
||||
|
|
@ -86,55 +89,52 @@ impl fmt::Display for RawSendPropDefinition {
|
|||
SendPropType::Int => write!(
|
||||
f,
|
||||
"{}::{}({})(flags: {}, bits: {})",
|
||||
self.identifier.owner_table,
|
||||
self.identifier.name,
|
||||
self.owner_table,
|
||||
self.name,
|
||||
self.prop_type,
|
||||
self.flags,
|
||||
self.bit_count.unwrap_or(32)
|
||||
),
|
||||
SendPropType::String => {
|
||||
write!(
|
||||
f,
|
||||
"{}::{}({})",
|
||||
self.identifier.owner_table, self.identifier.name, self.prop_type
|
||||
)
|
||||
write!(f, "{}::{}({})", self.owner_table, self.name, self.prop_type)
|
||||
}
|
||||
SendPropType::Array => match &self.array_property {
|
||||
Some(array_prop) => write!(
|
||||
f,
|
||||
"{}::{}([{}({})] * {})",
|
||||
self.identifier.owner_table,
|
||||
self.identifier.name,
|
||||
self.owner_table,
|
||||
self.name,
|
||||
array_prop.prop_type,
|
||||
array_prop.flags,
|
||||
self.element_count.unwrap_or_default(),
|
||||
),
|
||||
None => write!(f, "{}(Malformed array)", self.identifier.name),
|
||||
None => write!(f, "{}(Malformed array)", self.name),
|
||||
},
|
||||
SendPropType::DataTable => match &self.table_name {
|
||||
Some(sub_table) => write!(
|
||||
f,
|
||||
"{}::{}(DataTable = {})",
|
||||
self.identifier.owner_table, self.identifier.name, sub_table
|
||||
self.owner_table, self.name, sub_table
|
||||
),
|
||||
None => write!(f, "{}(Malformed DataTable)", self.identifier.name),
|
||||
None => write!(f, "{}(Malformed DataTable)", self.name),
|
||||
},
|
||||
SendPropType::NumSendPropTypes => {
|
||||
write!(
|
||||
f,
|
||||
"{}::{}(NumSendPropTypes)",
|
||||
self.identifier.owner_table, self.identifier.name
|
||||
)
|
||||
write!(f, "{}::{}(NumSendPropTypes)", self.owner_table, self.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RawSendPropDefinition {
|
||||
pub fn identifier(&self) -> SendPropIdentifier {
|
||||
SendPropIdentifier::new(self.owner_table.as_str(), self.name.as_str())
|
||||
}
|
||||
|
||||
pub fn with_array_property(self, array_property: Self) -> Self {
|
||||
RawSendPropDefinition {
|
||||
prop_type: self.prop_type,
|
||||
identifier: self.identifier,
|
||||
owner_table: self.owner_table,
|
||||
name: self.name,
|
||||
flags: self.flags,
|
||||
table_name: self.table_name,
|
||||
low_value: self.low_value,
|
||||
|
|
@ -158,11 +158,7 @@ impl RawSendPropDefinition {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn read(
|
||||
stream: &mut Stream,
|
||||
owner_table: SendTableName,
|
||||
index: SendPropDefinitionIndex,
|
||||
) -> ReadResult<Self> {
|
||||
pub fn read(stream: &mut Stream, owner_table: SendTableName) -> ReadResult<Self> {
|
||||
let prop_type = SendPropType::read(stream)?;
|
||||
let name = stream.read_string(None)?.to_string().into();
|
||||
let flags = SendPropFlags::read(stream)?;
|
||||
|
|
@ -193,11 +189,8 @@ impl RawSendPropDefinition {
|
|||
|
||||
Ok(RawSendPropDefinition {
|
||||
prop_type,
|
||||
identifier: Rc::new(SendPropIdentifier {
|
||||
index,
|
||||
name,
|
||||
owner_table,
|
||||
}),
|
||||
flags,
|
||||
table_name,
|
||||
low_value,
|
||||
|
|
@ -353,82 +346,71 @@ impl FloatDefinition {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SendPropDefinition {
|
||||
pub struct SendPropDefinition {
|
||||
pub identifier: SendPropIdentifier,
|
||||
pub parse_definition: SendPropParseDefinition,
|
||||
}
|
||||
|
||||
impl TryFrom<RawSendPropDefinition> for SendPropDefinition {
|
||||
type Error = MalformedSendPropDefinitionError;
|
||||
|
||||
fn try_from(definition: RawSendPropDefinition) -> std::result::Result<Self, Self::Error> {
|
||||
let parse_definition = (&definition).try_into()?;
|
||||
Ok(SendPropDefinition {
|
||||
parse_definition,
|
||||
identifier: definition.identifier(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SendPropParseDefinition {
|
||||
NormalVarInt {
|
||||
identifier: Rc<SendPropIdentifier>,
|
||||
unsigned: bool,
|
||||
},
|
||||
UnsignedInt {
|
||||
identifier: Rc<SendPropIdentifier>,
|
||||
bit_count: u8,
|
||||
},
|
||||
Int {
|
||||
identifier: Rc<SendPropIdentifier>,
|
||||
bit_count: u8,
|
||||
},
|
||||
Float {
|
||||
identifier: Rc<SendPropIdentifier>,
|
||||
definition: FloatDefinition,
|
||||
},
|
||||
String {
|
||||
identifier: Rc<SendPropIdentifier>,
|
||||
},
|
||||
String,
|
||||
Vector {
|
||||
identifier: Rc<SendPropIdentifier>,
|
||||
definition: FloatDefinition,
|
||||
},
|
||||
VectorXY {
|
||||
identifier: Rc<SendPropIdentifier>,
|
||||
definition: FloatDefinition,
|
||||
},
|
||||
Array {
|
||||
identifier: Rc<SendPropIdentifier>,
|
||||
inner_definition: Box<SendPropDefinition>,
|
||||
inner_definition: Box<SendPropParseDefinition>,
|
||||
count_bit_count: u16,
|
||||
},
|
||||
}
|
||||
|
||||
impl SendPropDefinition {
|
||||
pub fn identifier(&self) -> Rc<SendPropIdentifier> {
|
||||
match self {
|
||||
SendPropDefinition::NormalVarInt { identifier, .. } => identifier.clone(),
|
||||
SendPropDefinition::UnsignedInt { identifier, .. } => identifier.clone(),
|
||||
SendPropDefinition::Int { identifier, .. } => identifier.clone(),
|
||||
SendPropDefinition::Float { identifier, .. } => identifier.clone(),
|
||||
SendPropDefinition::String { identifier, .. } => identifier.clone(),
|
||||
SendPropDefinition::Vector { identifier, .. } => identifier.clone(),
|
||||
SendPropDefinition::VectorXY { identifier, .. } => identifier.clone(),
|
||||
SendPropDefinition::Array { identifier, .. } => identifier.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&RawSendPropDefinition> for SendPropDefinition {
|
||||
impl TryFrom<&RawSendPropDefinition> for SendPropParseDefinition {
|
||||
type Error = MalformedSendPropDefinitionError;
|
||||
|
||||
fn try_from(definition: &RawSendPropDefinition) -> std::result::Result<Self, Self::Error> {
|
||||
let identifier = definition.identifier.clone();
|
||||
match definition.prop_type {
|
||||
SendPropType::Int => {
|
||||
if definition.flags.contains(SendPropFlag::NormalVarInt) {
|
||||
Ok(SendPropDefinition::NormalVarInt {
|
||||
identifier,
|
||||
Ok(SendPropParseDefinition::NormalVarInt {
|
||||
unsigned: definition.flags.contains(SendPropFlag::Unsigned),
|
||||
})
|
||||
} else if definition.flags.contains(SendPropFlag::Unsigned) {
|
||||
Ok(SendPropDefinition::UnsignedInt {
|
||||
identifier,
|
||||
Ok(SendPropParseDefinition::UnsignedInt {
|
||||
bit_count: definition.bit_count.unwrap_or(32) as u8,
|
||||
})
|
||||
} else {
|
||||
Ok(SendPropDefinition::Int {
|
||||
identifier,
|
||||
Ok(SendPropParseDefinition::Int {
|
||||
bit_count: definition.bit_count.unwrap_or(32) as u8,
|
||||
})
|
||||
}
|
||||
}
|
||||
SendPropType::Float => Ok(SendPropDefinition::Float {
|
||||
identifier,
|
||||
SendPropType::Float => Ok(SendPropParseDefinition::Float {
|
||||
definition: FloatDefinition::new(
|
||||
definition.flags,
|
||||
definition.bit_count,
|
||||
|
|
@ -436,9 +418,8 @@ impl TryFrom<&RawSendPropDefinition> for SendPropDefinition {
|
|||
definition.low_value,
|
||||
)?,
|
||||
}),
|
||||
SendPropType::String => Ok(SendPropDefinition::String { identifier }),
|
||||
SendPropType::Vector => Ok(SendPropDefinition::Vector {
|
||||
identifier,
|
||||
SendPropType::String => Ok(SendPropParseDefinition::String),
|
||||
SendPropType::Vector => Ok(SendPropParseDefinition::Vector {
|
||||
definition: FloatDefinition::new(
|
||||
definition.flags,
|
||||
definition.bit_count,
|
||||
|
|
@ -446,8 +427,7 @@ impl TryFrom<&RawSendPropDefinition> for SendPropDefinition {
|
|||
definition.low_value,
|
||||
)?,
|
||||
}),
|
||||
SendPropType::VectorXY => Ok(SendPropDefinition::VectorXY {
|
||||
identifier,
|
||||
SendPropType::VectorXY => Ok(SendPropParseDefinition::VectorXY {
|
||||
definition: FloatDefinition::new(
|
||||
definition.flags,
|
||||
definition.bit_count,
|
||||
|
|
@ -466,9 +446,10 @@ impl TryFrom<&RawSendPropDefinition> for SendPropDefinition {
|
|||
.array_property
|
||||
.as_deref()
|
||||
.ok_or(MalformedSendPropDefinitionError::UntypedArray)?;
|
||||
Ok(SendPropDefinition::Array {
|
||||
identifier,
|
||||
inner_definition: Box::new(SendPropDefinition::try_from(child_definition)?),
|
||||
Ok(SendPropParseDefinition::Array {
|
||||
inner_definition: Box::new(SendPropParseDefinition::try_from(
|
||||
child_definition,
|
||||
)?),
|
||||
count_bit_count,
|
||||
})
|
||||
}
|
||||
|
|
@ -557,31 +538,33 @@ impl fmt::Display for SendPropValue {
|
|||
}
|
||||
|
||||
impl SendPropValue {
|
||||
pub fn parse(stream: &mut Stream, definition: &SendPropDefinition) -> Result<Self> {
|
||||
pub fn parse(stream: &mut Stream, definition: &SendPropParseDefinition) -> Result<Self> {
|
||||
match definition {
|
||||
SendPropDefinition::NormalVarInt { unsigned, .. } => read_var_int(stream, !*unsigned)
|
||||
SendPropParseDefinition::NormalVarInt { unsigned, .. } => {
|
||||
read_var_int(stream, !*unsigned)
|
||||
.map_err(ParseError::from)
|
||||
.map(|int| int as i64)
|
||||
.map(SendPropValue::from),
|
||||
SendPropDefinition::UnsignedInt { bit_count, .. } => {
|
||||
.map(SendPropValue::from)
|
||||
}
|
||||
SendPropParseDefinition::UnsignedInt { bit_count, .. } => {
|
||||
Ok((stream.read_sized::<u32>(*bit_count as usize)? as i64).into())
|
||||
}
|
||||
SendPropDefinition::Int { bit_count, .. } => stream
|
||||
SendPropParseDefinition::Int { bit_count, .. } => stream
|
||||
.read_int::<i32>((*bit_count) as usize)
|
||||
.map_err(ParseError::from)
|
||||
.map(SendPropValue::from),
|
||||
SendPropDefinition::Float {
|
||||
SendPropParseDefinition::Float {
|
||||
definition: float_definition,
|
||||
..
|
||||
} => Self::read_float(stream, float_definition).map(SendPropValue::from),
|
||||
SendPropDefinition::String { .. } => {
|
||||
SendPropParseDefinition::String { .. } => {
|
||||
let length = stream.read_int(9)?;
|
||||
stream
|
||||
.read_sized::<String>(length)
|
||||
.map_err(ParseError::from)
|
||||
.map(SendPropValue::from)
|
||||
}
|
||||
SendPropDefinition::Vector {
|
||||
SendPropParseDefinition::Vector {
|
||||
definition: float_definition,
|
||||
..
|
||||
} => Ok(Vector {
|
||||
|
|
@ -590,7 +573,7 @@ impl SendPropValue {
|
|||
z: Self::read_float(stream, float_definition)?,
|
||||
}
|
||||
.into()),
|
||||
SendPropDefinition::VectorXY {
|
||||
SendPropParseDefinition::VectorXY {
|
||||
definition: float_definition,
|
||||
..
|
||||
} => Ok(VectorXY {
|
||||
|
|
@ -598,7 +581,7 @@ impl SendPropValue {
|
|||
y: Self::read_float(stream, float_definition)?,
|
||||
}
|
||||
.into()),
|
||||
SendPropDefinition::Array {
|
||||
SendPropParseDefinition::Array {
|
||||
count_bit_count,
|
||||
inner_definition,
|
||||
..
|
||||
|
|
@ -746,28 +729,22 @@ impl<'a> TryFrom<&'a SendPropValue> for &'a [SendPropValue] {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct SendPropDefinitionIndex(u32);
|
||||
#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash, Display)]
|
||||
pub struct SendPropIdentifier(u64);
|
||||
|
||||
impl SendPropDefinitionIndex {
|
||||
pub fn new(table: usize, prop: usize) -> Self {
|
||||
// there can be at most 1024 (10 bits) props per table
|
||||
SendPropDefinitionIndex((table * 1024 + prop) as u32)
|
||||
impl SendPropIdentifier {
|
||||
pub fn new(table: &str, prop: &str) -> Self {
|
||||
let mut hasher = FnvHasher::default();
|
||||
table.hash(&mut hasher);
|
||||
prop.hash(&mut hasher);
|
||||
SendPropIdentifier(hasher.finish())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Display)]
|
||||
#[display("{owner_table}::{name}")]
|
||||
pub struct SendPropIdentifier {
|
||||
pub index: SendPropDefinitionIndex,
|
||||
pub name: SendPropName,
|
||||
pub owner_table: SendTableName,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Display)]
|
||||
#[display("{identifier} = {value}")]
|
||||
#[display("{index} = {value}")]
|
||||
pub struct SendProp {
|
||||
pub identifier: Rc<SendPropIdentifier>,
|
||||
pub index: SendPropIdentifier,
|
||||
pub value: SendPropValue,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +3,16 @@ use serde_repr::{Deserialize_repr, Serialize_repr};
|
|||
use std::fs::{self, File};
|
||||
use test_case::test_case;
|
||||
|
||||
use fnv::FnvHashMap;
|
||||
use std::collections::HashMap;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use tf_demo_parser::demo::message::packetentities::{EntityId, PacketEntity, PVS};
|
||||
use tf_demo_parser::demo::message::Message;
|
||||
use tf_demo_parser::demo::packet::datatable::{ServerClass, ServerClassName};
|
||||
use tf_demo_parser::demo::packet::datatable::{
|
||||
ParseSendTable, SendTableName, ServerClass, ServerClassName,
|
||||
};
|
||||
use tf_demo_parser::demo::parser::MessageHandler;
|
||||
use tf_demo_parser::demo::sendprop::SendPropValue;
|
||||
use tf_demo_parser::demo::sendprop::{SendPropIdentifier, SendPropName, SendPropValue};
|
||||
use tf_demo_parser::{Demo, DemoParser, MessageType, ParserState};
|
||||
|
||||
/// Compatible serialization with the js parser entity dumps
|
||||
|
|
@ -44,7 +47,12 @@ struct EntityDump {
|
|||
}
|
||||
|
||||
impl EntityDump {
|
||||
pub fn from_entity(entity: PacketEntity, tick: u32, classes: &[ServerClass]) -> Self {
|
||||
pub fn from_entity(
|
||||
entity: PacketEntity,
|
||||
tick: u32,
|
||||
classes: &[ServerClass],
|
||||
prop_names: &FnvHashMap<SendPropIdentifier, (SendTableName, SendPropName)>,
|
||||
) -> Self {
|
||||
EntityDump {
|
||||
tick,
|
||||
server_class: classes[usize::from(entity.server_class)].name.clone(),
|
||||
|
|
@ -53,10 +61,8 @@ impl EntityDump {
|
|||
.props
|
||||
.into_iter()
|
||||
.map(|prop| {
|
||||
(
|
||||
format!("{}.{}", prop.identifier.owner_table, prop.identifier.name),
|
||||
prop.value,
|
||||
)
|
||||
let (table_name, prop_name) = &prop_names[&prop.index];
|
||||
(format!("{}.{}", table_name, prop_name), prop.value)
|
||||
})
|
||||
.collect(),
|
||||
pvs: entity.pvs.into(),
|
||||
|
|
@ -66,12 +72,14 @@ impl EntityDump {
|
|||
|
||||
struct EntityDumper {
|
||||
entities: Vec<(u32, PacketEntity)>,
|
||||
prop_names: FnvHashMap<SendPropIdentifier, (SendTableName, SendPropName)>,
|
||||
}
|
||||
|
||||
impl EntityDumper {
|
||||
pub fn new() -> Self {
|
||||
EntityDumper {
|
||||
entities: Vec::with_capacity(128),
|
||||
prop_names: FnvHashMap::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -98,10 +106,24 @@ impl MessageHandler for EntityDumper {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_data_tables(&mut self, tables: &[ParseSendTable], _server_classes: &[ServerClass]) {
|
||||
for table in tables {
|
||||
for prop_def in &table.props {
|
||||
self.prop_names.insert(
|
||||
prop_def.identifier(),
|
||||
(prop_def.owner_table.clone(), prop_def.name.clone()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn into_output(self, state: &ParserState) -> Self::Output {
|
||||
let prop_names = self.prop_names;
|
||||
self.entities
|
||||
.into_iter()
|
||||
.map(|(tick, entity)| EntityDump::from_entity(entity, tick, &state.server_classes))
|
||||
.map(|(tick, entity)| {
|
||||
EntityDump::from_entity(entity, tick, &state.server_classes, &prop_names)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ fn flatten_test(input_file: &str, snapshot_file: &str) {
|
|||
table
|
||||
.flatten_props(&send_tables)
|
||||
.into_iter()
|
||||
.map(|prop| format!("{}.{}", prop.identifier.owner_table, prop.identifier.name))
|
||||
.map(|prop| format!("{}.{}", prop.owner_table, prop.name))
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue