mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 18:24:05 +02:00
remove some bounds checks
This commit is contained in:
parent
b328db85e9
commit
6ef2b1cea8
9 changed files with 102 additions and 93 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -132,6 +132,12 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-fnv1a-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
|
|
@ -985,6 +991,7 @@ dependencies = [
|
||||||
"Inflector",
|
"Inflector",
|
||||||
"better-panic",
|
"better-panic",
|
||||||
"bitbuffer",
|
"bitbuffer",
|
||||||
|
"const-fnv1a-hash",
|
||||||
"enumflags2",
|
"enumflags2",
|
||||||
"fnv",
|
"fnv",
|
||||||
"iai-callgrind",
|
"iai-callgrind",
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ steamid-ng = "1.0.0"
|
||||||
tracing = { version = "0.1.40", optional = true }
|
tracing = { version = "0.1.40", optional = true }
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"], optional = true }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"], optional = true }
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
|
const-fnv1a-hash = "1.1.0"
|
||||||
|
|
||||||
# schema
|
# schema
|
||||||
schemars = { version = "0.8.21", optional = true }
|
schemars = { version = "0.8.21", optional = true }
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
|
||||||
use parse_display::Display;
|
use parse_display::Display;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use const_fnv1a_hash::fnv1a_hash_str_64;
|
||||||
|
|
||||||
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|
@ -17,7 +18,8 @@ pub struct GameEventDefinition {
|
||||||
|
|
||||||
impl GameEventDefinition {
|
impl GameEventDefinition {
|
||||||
pub fn get_entry(&self, name: &str) -> Option<&GameEventEntry> {
|
pub fn get_entry(&self, name: &str) -> Option<&GameEventEntry> {
|
||||||
self.entries.iter().find(|entry| entry.name == name)
|
let hash = fnv1a_hash_str_64(name);
|
||||||
|
self.entries.iter().find(|entry| entry.hash == hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,9 +47,21 @@ impl Ord for GameEventDefinition {
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct GameEventEntry {
|
pub struct GameEventEntry {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub hash: u64,
|
||||||
pub kind: GameEventValueType,
|
pub kind: GameEventValueType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GameEventEntry {
|
||||||
|
pub fn new<S: Into<String>>(name: S, kind: GameEventValueType) -> Self {
|
||||||
|
let name = name.into();
|
||||||
|
GameEventEntry {
|
||||||
|
hash: fnv1a_hash_str_64(&name),
|
||||||
|
name: name.into(),
|
||||||
|
kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
||||||
#[derive(BitRead, BitWrite, Debug, Clone, Copy, PartialEq, Display, Serialize, Deserialize)]
|
#[derive(BitRead, BitWrite, Debug, Clone, Copy, PartialEq, Display, Serialize, Deserialize)]
|
||||||
#[discriminant_bits = 3]
|
#[discriminant_bits = 3]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use bitbuffer::{BitRead, BitWrite, BitWriteSized, BitWriteStream, LittleEndian};
|
use bitbuffer::{BitRead, BitWrite, BitWriteSized, BitWriteStream, LittleEndian};
|
||||||
use parse_display::Display;
|
use parse_display::Display;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::demo::gameevent_gen::GameEventType;
|
use crate::demo::gameevent_gen::GameEventType;
|
||||||
use crate::demo::gamevent::{
|
use crate::demo::gamevent::{
|
||||||
|
|
@ -75,18 +76,15 @@ fn test_game_event_roundtrip() {
|
||||||
GameEventDefinition {
|
GameEventDefinition {
|
||||||
id: GameEventTypeId(0),
|
id: GameEventTypeId(0),
|
||||||
event_type: GameEventType::ServerShutdown,
|
event_type: GameEventType::ServerShutdown,
|
||||||
entries: vec![GameEventEntry {
|
entries: vec![GameEventEntry::new("reason", GameEventValueType::String)],
|
||||||
name: "reason".to_string(),
|
|
||||||
kind: GameEventValueType::String,
|
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
GameEventDefinition {
|
GameEventDefinition {
|
||||||
id: GameEventTypeId(1),
|
id: GameEventTypeId(1),
|
||||||
event_type: GameEventType::ServerChangeLevelFailed,
|
event_type: GameEventType::ServerChangeLevelFailed,
|
||||||
entries: vec![GameEventEntry {
|
entries: vec![GameEventEntry::new(
|
||||||
name: "level_name".to_string(),
|
"level_name",
|
||||||
kind: GameEventValueType::String,
|
GameEventValueType::String,
|
||||||
}],
|
)],
|
||||||
},
|
},
|
||||||
GameEventDefinition {
|
GameEventDefinition {
|
||||||
id: GameEventTypeId(2),
|
id: GameEventTypeId(2),
|
||||||
|
|
@ -168,11 +166,8 @@ impl BitRead<'_, LittleEndian> for GameEventDefinition {
|
||||||
|
|
||||||
let mut entry_type = stream.read()?;
|
let mut entry_type = stream.read()?;
|
||||||
while entry_type != GameEventValueType::None {
|
while entry_type != GameEventValueType::None {
|
||||||
let entry_name = stream.read()?;
|
let entry_name: Cow<str> = stream.read()?;
|
||||||
entries.push(GameEventEntry {
|
entries.push(GameEventEntry::new(entry_name, entry_type));
|
||||||
name: entry_name,
|
|
||||||
kind: entry_type,
|
|
||||||
});
|
|
||||||
entry_type = stream.read()?;
|
entry_type = stream.read()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,10 +202,10 @@ fn test_event_definition_roundtrip() {
|
||||||
crate::test_roundtrip_write(GameEventDefinition {
|
crate::test_roundtrip_write(GameEventDefinition {
|
||||||
id: GameEventTypeId(0),
|
id: GameEventTypeId(0),
|
||||||
event_type: GameEventType::ServerChangeLevelFailed,
|
event_type: GameEventType::ServerChangeLevelFailed,
|
||||||
entries: vec![GameEventEntry {
|
entries: vec![GameEventEntry::new(
|
||||||
name: "level_name".to_string(),
|
"level_name",
|
||||||
kind: GameEventValueType::String,
|
GameEventValueType::String,
|
||||||
}],
|
)],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -244,10 +239,7 @@ fn test_event_list_roundtrip() {
|
||||||
event_list: vec![GameEventDefinition {
|
event_list: vec![GameEventDefinition {
|
||||||
id: GameEventTypeId(0),
|
id: GameEventTypeId(0),
|
||||||
event_type: GameEventType::ServerChangeLevelFailed,
|
event_type: GameEventType::ServerChangeLevelFailed,
|
||||||
entries: vec![GameEventEntry {
|
entries: vec![GameEventEntry::new("level_name", GameEventValueType::String)],
|
||||||
name: "level_name".to_string(),
|
|
||||||
kind: GameEventValueType::String,
|
|
||||||
}],
|
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
crate::test_roundtrip_write(GameEventListMessage {
|
crate::test_roundtrip_write(GameEventListMessage {
|
||||||
|
|
@ -256,55 +248,25 @@ fn test_event_list_roundtrip() {
|
||||||
id: GameEventTypeId(0),
|
id: GameEventTypeId(0),
|
||||||
event_type: GameEventType::ServerSpawn,
|
event_type: GameEventType::ServerSpawn,
|
||||||
entries: vec![
|
entries: vec![
|
||||||
GameEventEntry {
|
GameEventEntry::new("hostname", GameEventValueType::String),
|
||||||
name: "hostname".to_string(),
|
GameEventEntry::new("address", GameEventValueType::String),
|
||||||
kind: GameEventValueType::String,
|
GameEventEntry::new("ip", GameEventValueType::Long),
|
||||||
},
|
GameEventEntry::new("port", GameEventValueType::Short),
|
||||||
GameEventEntry {
|
GameEventEntry::new("game", GameEventValueType::String),
|
||||||
name: "address".to_string(),
|
GameEventEntry::new("map_name", GameEventValueType::String),
|
||||||
kind: GameEventValueType::String,
|
GameEventEntry::new("max_players", GameEventValueType::Long),
|
||||||
},
|
GameEventEntry::new("os", GameEventValueType::String),
|
||||||
GameEventEntry {
|
GameEventEntry::new("dedicated", GameEventValueType::Boolean),
|
||||||
name: "ip".to_string(),
|
GameEventEntry::new("password", GameEventValueType::Boolean),
|
||||||
kind: GameEventValueType::Long,
|
|
||||||
},
|
|
||||||
GameEventEntry {
|
|
||||||
name: "port".to_string(),
|
|
||||||
kind: GameEventValueType::Short,
|
|
||||||
},
|
|
||||||
GameEventEntry {
|
|
||||||
name: "game".to_string(),
|
|
||||||
kind: GameEventValueType::String,
|
|
||||||
},
|
|
||||||
GameEventEntry {
|
|
||||||
name: "map_name".to_string(),
|
|
||||||
kind: GameEventValueType::String,
|
|
||||||
},
|
|
||||||
GameEventEntry {
|
|
||||||
name: "max_players".to_string(),
|
|
||||||
kind: GameEventValueType::Long,
|
|
||||||
},
|
|
||||||
GameEventEntry {
|
|
||||||
name: "os".to_string(),
|
|
||||||
kind: GameEventValueType::String,
|
|
||||||
},
|
|
||||||
GameEventEntry {
|
|
||||||
name: "dedicated".to_string(),
|
|
||||||
kind: GameEventValueType::Boolean,
|
|
||||||
},
|
|
||||||
GameEventEntry {
|
|
||||||
name: "password".to_string(),
|
|
||||||
kind: GameEventValueType::Boolean,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
GameEventDefinition {
|
GameEventDefinition {
|
||||||
id: GameEventTypeId(1),
|
id: GameEventTypeId(1),
|
||||||
event_type: GameEventType::ServerChangeLevelFailed,
|
event_type: GameEventType::ServerChangeLevelFailed,
|
||||||
entries: vec![GameEventEntry {
|
entries: vec![GameEventEntry::new(
|
||||||
name: "level_name".to_string(),
|
"level_name",
|
||||||
kind: GameEventValueType::String,
|
GameEventValueType::String,
|
||||||
}],
|
)],
|
||||||
},
|
},
|
||||||
GameEventDefinition {
|
GameEventDefinition {
|
||||||
id: GameEventTypeId(2),
|
id: GameEventTypeId(2),
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ use serde::{Deserialize, Serialize};
|
||||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::demo::message::stringtable::log_base2;
|
|
||||||
use crate::demo::packet::datatable::{ClassId, SendTable};
|
use crate::demo::packet::datatable::{ClassId, SendTable};
|
||||||
use crate::demo::parser::{Encode, ParseBitSkip};
|
use crate::demo::parser::{Encode, ParseBitSkip};
|
||||||
use crate::demo::sendprop::{SendProp, SendPropIdentifier, SendPropValue};
|
use crate::demo::sendprop::{SendProp, SendPropIdentifier, SendPropValue};
|
||||||
|
|
@ -352,10 +351,21 @@ impl Parse<'_> for PacketEntitiesMessage {
|
||||||
fn parse(stream: &mut Stream, state: &ParserState) -> Result<Self> {
|
fn parse(stream: &mut Stream, state: &ParserState) -> Result<Self> {
|
||||||
let max_entries = stream.read_sized(11)?;
|
let max_entries = stream.read_sized(11)?;
|
||||||
let delta: Option<ServerTick> = stream.read()?;
|
let delta: Option<ServerTick> = stream.read()?;
|
||||||
let base_line = stream.read()?;
|
#[derive(BitRead)]
|
||||||
let updated_entries: u16 = stream.read_sized(11)?;
|
struct Header {
|
||||||
let length: u32 = stream.read_sized(20)?;
|
base_line: BaselineIndex,
|
||||||
let updated_base_line = stream.read()?;
|
#[bitbuffer(size = 11)]
|
||||||
|
updated_entries: u16,
|
||||||
|
#[bitbuffer(size = 20)]
|
||||||
|
length: u32,
|
||||||
|
updated_base_line: bool,
|
||||||
|
}
|
||||||
|
let Header {
|
||||||
|
base_line,
|
||||||
|
updated_entries,
|
||||||
|
length,
|
||||||
|
updated_base_line,
|
||||||
|
} = stream.read()?;
|
||||||
|
|
||||||
let mut data = stream.read_bits(length as usize)?;
|
let mut data = stream.read_bits(length as usize)?;
|
||||||
|
|
||||||
|
|
@ -486,10 +496,16 @@ impl PacketEntitiesMessage {
|
||||||
baseline_index: BaselineIndex,
|
baseline_index: BaselineIndex,
|
||||||
delta: Option<ServerTick>,
|
delta: Option<ServerTick>,
|
||||||
) -> Result<PacketEntity> {
|
) -> Result<PacketEntity> {
|
||||||
let bits = log_base2(state.server_classes.len()) + 1;
|
let bits = state.server_class_bits;
|
||||||
let class_index: ClassId = stream.read_sized::<u16>(bits as usize)?.into();
|
#[derive(BitReadSized)]
|
||||||
|
struct Data {
|
||||||
let serial = stream.read_sized(10)?;
|
#[bitbuffer(size = "input_size")]
|
||||||
|
raw_index: u16,
|
||||||
|
#[bitbuffer(size = 10)]
|
||||||
|
serial: u32,
|
||||||
|
}
|
||||||
|
let Data { raw_index, serial } = stream.read_sized(bits)?;
|
||||||
|
let class_index: ClassId = raw_index.into();
|
||||||
|
|
||||||
Ok(PacketEntity {
|
Ok(PacketEntity {
|
||||||
server_class: class_index,
|
server_class: class_index,
|
||||||
|
|
@ -509,8 +525,7 @@ impl PacketEntitiesMessage {
|
||||||
stream: &mut BitWriteStream<LittleEndian>,
|
stream: &mut BitWriteStream<LittleEndian>,
|
||||||
state: &ParserState,
|
state: &ParserState,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let bits = log_base2(state.server_classes.len()) + 1;
|
u16::from(entity.server_class).write_sized(stream, state.server_class_bits)?;
|
||||||
u16::from(entity.server_class).write_sized(stream, bits as usize)?;
|
|
||||||
entity.serial_number.write_sized(stream, 10)?;
|
entity.serial_number.write_sized(stream, 10)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -613,12 +628,12 @@ impl ParseBitSkip<'_> for PacketEntitiesMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_packet_entitier_message_roundtrip() {
|
fn test_packet_entity_message_roundtrip() {
|
||||||
use crate::demo::packet::datatable::{SendTable, SendTableName, ServerClass, ServerClassName};
|
use crate::demo::packet::datatable::{SendTable, SendTableName, ServerClass, ServerClassName};
|
||||||
use crate::demo::sendprop::{FloatDefinition, SendPropDefinition, SendPropParseDefinition};
|
use crate::demo::sendprop::{FloatDefinition, SendPropDefinition, SendPropParseDefinition};
|
||||||
|
|
||||||
let mut state = ParserState::new(24, |_| false, false);
|
let mut state = ParserState::new(24, |_| false, false);
|
||||||
state.server_classes = vec![
|
state.set_server_classes(vec![
|
||||||
ServerClass {
|
ServerClass {
|
||||||
id: ClassId::from(0),
|
id: ClassId::from(0),
|
||||||
name: ServerClassName::from("class1"),
|
name: ServerClassName::from("class1"),
|
||||||
|
|
@ -629,7 +644,7 @@ fn test_packet_entitier_message_roundtrip() {
|
||||||
name: ServerClassName::from("class2"),
|
name: ServerClassName::from("class2"),
|
||||||
data_table: SendTableName::from("table2"),
|
data_table: SendTableName::from("table2"),
|
||||||
},
|
},
|
||||||
];
|
]);
|
||||||
state.send_tables = vec![
|
state.send_tables = vec![
|
||||||
SendTable {
|
SendTable {
|
||||||
name: SendTableName::from("table1"),
|
name: SendTableName::from("table1"),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use super::stringtable::read_var_int;
|
use super::stringtable::read_var_int;
|
||||||
use crate::demo::message::packetentities::PacketEntitiesMessage;
|
use crate::demo::message::packetentities::PacketEntitiesMessage;
|
||||||
use crate::demo::message::stringtable::{encode_var_int_fixed, log_base2};
|
use crate::demo::message::stringtable::{encode_var_int_fixed};
|
||||||
use crate::demo::packet::datatable::ClassId;
|
use crate::demo::packet::datatable::ClassId;
|
||||||
use crate::demo::parser::{Encode, ParseBitSkip};
|
use crate::demo::parser::{Encode, ParseBitSkip};
|
||||||
use crate::demo::sendprop::SendProp;
|
use crate::demo::sendprop::SendProp;
|
||||||
|
|
@ -53,8 +53,8 @@ impl Parse<'_> for TempEntitiesMessage {
|
||||||
};
|
};
|
||||||
|
|
||||||
let class_id = if stream.read()? {
|
let class_id = if stream.read()? {
|
||||||
let bits = log_base2(state.server_classes.len()) + 1;
|
let bits = state.server_class_bits;
|
||||||
(stream.read_sized::<u16>(bits as usize)?.saturating_sub(1)).into()
|
(stream.read_sized::<u16>(bits)?.saturating_sub(1)).into()
|
||||||
} else {
|
} else {
|
||||||
let last = events.last().ok_or(ParseError::InvalidDemo(
|
let last = events.last().ok_or(ParseError::InvalidDemo(
|
||||||
"temp entity update without previous",
|
"temp entity update without previous",
|
||||||
|
|
@ -118,9 +118,9 @@ impl Encode for TempEntitiesMessage {
|
||||||
|
|
||||||
if event.class_id != last_class_id {
|
if event.class_id != last_class_id {
|
||||||
true.write(stream)?;
|
true.write(stream)?;
|
||||||
let bits = log_base2(state.server_classes.len()) + 1;
|
let bits = state.server_class_bits;
|
||||||
let id: u16 = event.class_id.into();
|
let id: u16 = event.class_id.into();
|
||||||
(id + 1).write_sized(stream, bits as usize)?;
|
(id + 1).write_sized(stream, bits)?;
|
||||||
} else {
|
} else {
|
||||||
false.write(stream)?;
|
false.write(stream)?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,7 @@ use crate::demo::sendprop::{
|
||||||
RawSendPropDefinition, SendPropDefinition, SendPropFlag, SendPropIdentifier, SendPropType,
|
RawSendPropDefinition, SendPropDefinition, SendPropFlag, SendPropIdentifier, SendPropType,
|
||||||
};
|
};
|
||||||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||||
use bitbuffer::{
|
use bitbuffer::{BitRead, BitReadStream, BitWrite, BitWriteSized, BitWriteStream, Endianness, LittleEndian};
|
||||||
BitRead, BitReadStream, BitWrite, BitWriteSized, BitWriteStream, Endianness, LittleEndian,
|
|
||||||
};
|
|
||||||
use parse_display::{Display, FromStr};
|
use parse_display::{Display, FromStr};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
@ -133,7 +131,7 @@ impl SendTableName {
|
||||||
|
|
||||||
impl<E: Endianness> BitRead<'_, E> for SendTableName {
|
impl<E: Endianness> BitRead<'_, E> for SendTableName {
|
||||||
fn read(stream: &mut BitReadStream<'_, E>) -> bitbuffer::Result<Self> {
|
fn read(stream: &mut BitReadStream<'_, E>) -> bitbuffer::Result<Self> {
|
||||||
String::read(stream).map(SendTableName::from)
|
<String as BitRead<'_, E>>::read(stream).map(SendTableName::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,11 @@ impl GameStateAnalyser {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_world_entity(&mut self, entity: &PacketEntity, parser_state: &ParserState) {
|
pub fn handle_world_entity(&mut self, entity: &PacketEntity, parser_state: &ParserState) {
|
||||||
|
const MINS: SendPropIdentifier =
|
||||||
|
SendPropIdentifier::new("DT_WORLD", "m_WorldMins");
|
||||||
|
const MAXS: SendPropIdentifier =
|
||||||
|
SendPropIdentifier::new("DT_WORLD", "m_WorldMaxs");
|
||||||
|
|
||||||
if let (
|
if let (
|
||||||
Some(SendProp {
|
Some(SendProp {
|
||||||
value: SendPropValue::Vector(boundary_min),
|
value: SendPropValue::Vector(boundary_min),
|
||||||
|
|
@ -195,8 +200,8 @@ impl GameStateAnalyser {
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
) = (
|
) = (
|
||||||
entity.get_prop_by_name("DT_WORLD", "m_WorldMins", parser_state),
|
entity.get_prop_by_identifier(&MINS, parser_state),
|
||||||
entity.get_prop_by_name("DT_WORLD", "m_WorldMaxs", parser_state),
|
entity.get_prop_by_identifier(&MAXS, parser_state),
|
||||||
) {
|
) {
|
||||||
self.state.world = Some(World {
|
self.state.world = Some(World {
|
||||||
boundary_min,
|
boundary_min,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use crate::demo::message::packetentities::{
|
||||||
BaselineIndex, EntityId, PacketEntitiesMessage, PacketEntity, UpdateType,
|
BaselineIndex, EntityId, PacketEntitiesMessage, PacketEntity, UpdateType,
|
||||||
};
|
};
|
||||||
use crate::demo::message::stringtable::StringTableMeta;
|
use crate::demo::message::stringtable::StringTableMeta;
|
||||||
use crate::demo::message::{Message, MessageType};
|
use crate::demo::message::{log_base2, Message, MessageType};
|
||||||
use crate::demo::packet::datatable::{
|
use crate::demo::packet::datatable::{
|
||||||
ClassId, ParseSendTable, SendTable, SendTableName, ServerClass,
|
ClassId, ParseSendTable, SendTable, SendTableName, ServerClass,
|
||||||
};
|
};
|
||||||
|
|
@ -40,6 +40,7 @@ pub struct ParserState {
|
||||||
// indexed by ClassId
|
// indexed by ClassId
|
||||||
pub send_tables: Vec<SendTable>,
|
pub send_tables: Vec<SendTable>,
|
||||||
pub server_classes: Vec<ServerClass>,
|
pub server_classes: Vec<ServerClass>,
|
||||||
|
pub server_class_bits: usize,
|
||||||
pub instance_baselines: [Baseline; 2],
|
pub instance_baselines: [Baseline; 2],
|
||||||
pub demo_meta: DemoMeta,
|
pub demo_meta: DemoMeta,
|
||||||
analyser_handles: fn(message_type: MessageType) -> bool,
|
analyser_handles: fn(message_type: MessageType) -> bool,
|
||||||
|
|
@ -85,6 +86,7 @@ impl ParserState {
|
||||||
entity_classes: HashMap::with_hasher(NullHasherBuilder),
|
entity_classes: HashMap::with_hasher(NullHasherBuilder),
|
||||||
send_tables: Vec::new(),
|
send_tables: Vec::new(),
|
||||||
server_classes: Vec::new(),
|
server_classes: Vec::new(),
|
||||||
|
server_class_bits: 0,
|
||||||
instance_baselines: [Baseline::default(), Baseline::default()],
|
instance_baselines: [Baseline::default(), Baseline::default()],
|
||||||
demo_meta: DemoMeta::default(),
|
demo_meta: DemoMeta::default(),
|
||||||
analyser_handles,
|
analyser_handles,
|
||||||
|
|
@ -94,6 +96,11 @@ impl ParserState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_server_classes(&mut self, server_classes: Vec<ServerClass>) {
|
||||||
|
self.server_class_bits = log_base2(server_classes.len()) as usize + 1;
|
||||||
|
self.server_classes = server_classes;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_static_baseline(
|
pub fn get_static_baseline(
|
||||||
&self,
|
&self,
|
||||||
class_id: ClassId,
|
class_id: ClassId,
|
||||||
|
|
@ -193,7 +200,7 @@ impl ParserState {
|
||||||
})
|
})
|
||||||
.collect::<Result<_>>()?;
|
.collect::<Result<_>>()?;
|
||||||
|
|
||||||
self.server_classes = server_classes;
|
self.set_server_classes(server_classes);
|
||||||
|
|
||||||
self.send_tables.reserve(self.server_classes.len());
|
self.send_tables.reserve(self.server_classes.len());
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue