Start with entity support
This commit is contained in:
24
Cargo.lock
generated
24
Cargo.lock
generated
@@ -47,12 +47,20 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitter",
|
"bitter",
|
||||||
"phf",
|
"phf",
|
||||||
|
"pretty_assertions",
|
||||||
"prost",
|
"prost",
|
||||||
"prost-build",
|
"prost-build",
|
||||||
"prost-types",
|
"prost-types",
|
||||||
|
"regex",
|
||||||
"snap",
|
"snap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diff"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
@@ -206,6 +214,16 @@ dependencies = [
|
|||||||
"siphasher",
|
"siphasher",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_assertions"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
|
||||||
|
dependencies = [
|
||||||
|
"diff",
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prettyplease"
|
name = "prettyplease"
|
||||||
version = "0.2.22"
|
version = "0.2.22"
|
||||||
@@ -467,3 +485,9 @@ name = "windows_x86_64_msvc"
|
|||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ snap = "1.1.1"
|
|||||||
bitter = "0.7"
|
bitter = "0.7"
|
||||||
|
|
||||||
phf = { version = "0.11", features = ["macros"] }
|
phf = { version = "0.11", features = ["macros"] }
|
||||||
|
regex = "1.10.6"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
pretty_assertions = { version = "1.4" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
prost-build = { version = "0.13.2" }
|
prost-build = { version = "0.13.2" }
|
||||||
|
|||||||
361
src/parser.rs
361
src/parser.rs
@@ -1,5 +1,12 @@
|
|||||||
use crate::{packet::DemoEvent, DemoCommand, Frame, UserId};
|
use crate::{packet::DemoEvent, DemoCommand, Frame, UserId};
|
||||||
|
|
||||||
|
mod fieldpath;
|
||||||
|
pub use fieldpath::{FieldPath, Paths};
|
||||||
|
|
||||||
|
mod decoder;
|
||||||
|
mod sendtables;
|
||||||
|
mod variant;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FirstPassError {
|
pub enum FirstPassError {
|
||||||
DecompressFrame,
|
DecompressFrame,
|
||||||
@@ -35,6 +42,11 @@ pub struct Player {
|
|||||||
pub color: i32,
|
pub color: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Entity {
|
||||||
|
pub cls: u32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FirstPassOutput {
|
pub struct FirstPassOutput {
|
||||||
pub header: crate::csgo_proto::CDemoFileHeader,
|
pub header: crate::csgo_proto::CDemoFileHeader,
|
||||||
@@ -54,6 +66,13 @@ struct GameEventMapping {
|
|||||||
>,
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Class {
|
||||||
|
class_id: i32,
|
||||||
|
name: String,
|
||||||
|
serializer: sendtables::Serializer,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse<'b, FI>(frames: FI) -> Result<FirstPassOutput, FirstPassError>
|
pub fn parse<'b, FI>(frames: FI) -> Result<FirstPassOutput, FirstPassError>
|
||||||
where
|
where
|
||||||
FI: IntoIterator<Item = Frame<'b>>,
|
FI: IntoIterator<Item = Frame<'b>>,
|
||||||
@@ -66,6 +85,16 @@ where
|
|||||||
mapping: std::collections::HashMap::new(),
|
mapping: std::collections::HashMap::new(),
|
||||||
};
|
};
|
||||||
let mut player_info = std::collections::HashMap::new();
|
let mut player_info = std::collections::HashMap::new();
|
||||||
|
let mut entities = std::collections::HashMap::new();
|
||||||
|
let mut cls_to_class = std::collections::HashMap::<u32, Class>::new();
|
||||||
|
let mut paths = Paths::new();
|
||||||
|
let mut qf_mapper = decoder::QfMapper {
|
||||||
|
idx: 0,
|
||||||
|
map: std::collections::HashMap::new(),
|
||||||
|
};
|
||||||
|
let mut serializers = std::collections::HashMap::new();
|
||||||
|
|
||||||
|
let mut baselines = std::collections::HashMap::new();
|
||||||
|
|
||||||
for mut frame in frames.into_iter() {
|
for mut frame in frames.into_iter() {
|
||||||
frame
|
frame
|
||||||
@@ -83,15 +112,86 @@ where
|
|||||||
file_info = Some(raw);
|
file_info = Some(raw);
|
||||||
}
|
}
|
||||||
DemoCommand::SignonPacket | DemoCommand::Packet => {
|
DemoCommand::SignonPacket | DemoCommand::Packet => {
|
||||||
parse_packet(data, &mut events, &mut event_mapping, &mut player_info)?;
|
parse_packet(
|
||||||
|
data,
|
||||||
|
&mut events,
|
||||||
|
&mut event_mapping,
|
||||||
|
&mut player_info,
|
||||||
|
&mut entities,
|
||||||
|
&mut cls_to_class,
|
||||||
|
&mut paths,
|
||||||
|
&mut qf_mapper,
|
||||||
|
&mut baselines,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
DemoCommand::FullPacket => {
|
DemoCommand::FullPacket => {
|
||||||
parse_fullpacket(data, &mut events, &mut event_mapping, &mut player_info)?;
|
parse_fullpacket(
|
||||||
|
data,
|
||||||
|
&mut events,
|
||||||
|
&mut event_mapping,
|
||||||
|
&mut player_info,
|
||||||
|
&mut entities,
|
||||||
|
&mut cls_to_class,
|
||||||
|
&mut paths,
|
||||||
|
&mut qf_mapper,
|
||||||
|
&mut baselines,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
// TODO
|
// TODO
|
||||||
DemoCommand::AnimationData => {}
|
DemoCommand::AnimationData => {}
|
||||||
DemoCommand::AnimationHeader => {}
|
DemoCommand::AnimationHeader => {}
|
||||||
_ => {}
|
DemoCommand::StringTables => {
|
||||||
|
let raw: crate::csgo_proto::CDemoStringTables = prost::Message::decode(data)?;
|
||||||
|
|
||||||
|
for table in raw.tables.iter() {
|
||||||
|
if table.table_name() == "instancebaseline" {
|
||||||
|
for item in table.items.iter() {
|
||||||
|
let k = item.str().parse::<u32>().unwrap_or(u32::MAX);
|
||||||
|
baselines.insert(k, item.data().to_vec());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DemoCommand::SendTables => {
|
||||||
|
let tables: crate::csgo_proto::CDemoSendTables = prost::Message::decode(data)?;
|
||||||
|
|
||||||
|
let mut bitreader = crate::bitreader::Bitreader::new(tables.data());
|
||||||
|
|
||||||
|
let n_bytes = bitreader.read_varint()?;
|
||||||
|
let bytes = bitreader.read_n_bytes(n_bytes as usize)?;
|
||||||
|
|
||||||
|
let serializer_msg: crate::csgo_proto::CsvcMsgFlattenedSerializer =
|
||||||
|
prost::Message::decode(bytes.as_slice())?;
|
||||||
|
|
||||||
|
// std::fs::write("send_table.b", bytes.as_slice());
|
||||||
|
|
||||||
|
assert!(serializers.is_empty());
|
||||||
|
serializers = sendtables::get_serializers(&serializer_msg, &mut qf_mapper)?;
|
||||||
|
}
|
||||||
|
DemoCommand::ClassInfo => {
|
||||||
|
let raw: crate::csgo_proto::CDemoClassInfo = prost::Message::decode(data)?;
|
||||||
|
|
||||||
|
cls_to_class.clear();
|
||||||
|
|
||||||
|
for class_t in raw.classes {
|
||||||
|
let cls_id = class_t.class_id();
|
||||||
|
let network_name = class_t.network_name();
|
||||||
|
|
||||||
|
if let Some(ser) = serializers.remove(network_name) {
|
||||||
|
cls_to_class.insert(
|
||||||
|
cls_id as u32,
|
||||||
|
Class {
|
||||||
|
name: network_name.to_owned(),
|
||||||
|
class_id: cls_id,
|
||||||
|
serializer: ser,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
dbg!(other);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,15 +211,33 @@ fn parse_fullpacket(
|
|||||||
events: &mut Vec<DemoEvent>,
|
events: &mut Vec<DemoEvent>,
|
||||||
event_mapper: &mut GameEventMapping,
|
event_mapper: &mut GameEventMapping,
|
||||||
player_info: &mut std::collections::HashMap<UserId, Player>,
|
player_info: &mut std::collections::HashMap<UserId, Player>,
|
||||||
|
entities: &mut std::collections::HashMap<i32, Entity>,
|
||||||
|
cls_to_class: &mut std::collections::HashMap<u32, Class>,
|
||||||
|
paths: &mut Paths,
|
||||||
|
qf_mapper: &mut decoder::QfMapper,
|
||||||
|
baselines: &mut std::collections::HashMap<u32, Vec<u8>>,
|
||||||
) -> Result<(), FirstPassError> {
|
) -> Result<(), FirstPassError> {
|
||||||
let raw: crate::csgo_proto::CDemoFullPacket = prost::Message::decode(data)?;
|
let raw: crate::csgo_proto::CDemoFullPacket = prost::Message::decode(data)?;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// Handle string table stuff
|
// Handle string table stuff
|
||||||
|
for item in raw.string_table.iter().flat_map(|st| st.tables.iter()) {
|
||||||
|
// dbg!(&item.table_name);
|
||||||
|
}
|
||||||
|
|
||||||
match raw.packet {
|
match raw.packet {
|
||||||
Some(packet) => {
|
Some(packet) => {
|
||||||
inner_parse_packet(&packet, events, event_mapper, player_info)?;
|
inner_parse_packet(
|
||||||
|
&packet,
|
||||||
|
events,
|
||||||
|
event_mapper,
|
||||||
|
player_info,
|
||||||
|
entities,
|
||||||
|
cls_to_class,
|
||||||
|
paths,
|
||||||
|
qf_mapper,
|
||||||
|
baselines,
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -132,10 +250,25 @@ fn parse_packet(
|
|||||||
events: &mut Vec<DemoEvent>,
|
events: &mut Vec<DemoEvent>,
|
||||||
event_mapper: &mut GameEventMapping,
|
event_mapper: &mut GameEventMapping,
|
||||||
player_info: &mut std::collections::HashMap<UserId, Player>,
|
player_info: &mut std::collections::HashMap<UserId, Player>,
|
||||||
|
entities: &mut std::collections::HashMap<i32, Entity>,
|
||||||
|
cls_to_class: &mut std::collections::HashMap<u32, Class>,
|
||||||
|
paths: &mut Paths,
|
||||||
|
qf_mapper: &mut decoder::QfMapper,
|
||||||
|
baselines: &mut std::collections::HashMap<u32, Vec<u8>>,
|
||||||
) -> Result<(), FirstPassError> {
|
) -> Result<(), FirstPassError> {
|
||||||
let raw: crate::csgo_proto::CDemoPacket = prost::Message::decode(data)?;
|
let raw: crate::csgo_proto::CDemoPacket = prost::Message::decode(data)?;
|
||||||
|
|
||||||
inner_parse_packet(&raw, events, event_mapper, player_info)?;
|
inner_parse_packet(
|
||||||
|
&raw,
|
||||||
|
events,
|
||||||
|
event_mapper,
|
||||||
|
player_info,
|
||||||
|
entities,
|
||||||
|
cls_to_class,
|
||||||
|
paths,
|
||||||
|
qf_mapper,
|
||||||
|
baselines,
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -145,6 +278,11 @@ fn inner_parse_packet(
|
|||||||
events: &mut Vec<DemoEvent>,
|
events: &mut Vec<DemoEvent>,
|
||||||
event_mapper: &mut GameEventMapping,
|
event_mapper: &mut GameEventMapping,
|
||||||
player_info: &mut std::collections::HashMap<UserId, Player>,
|
player_info: &mut std::collections::HashMap<UserId, Player>,
|
||||||
|
entities: &mut std::collections::HashMap<i32, Entity>,
|
||||||
|
cls_to_class: &mut std::collections::HashMap<u32, Class>,
|
||||||
|
paths: &mut Paths,
|
||||||
|
qf_mapper: &mut decoder::QfMapper,
|
||||||
|
baselines: &mut std::collections::HashMap<u32, Vec<u8>>,
|
||||||
) -> Result<(), FirstPassError> {
|
) -> Result<(), FirstPassError> {
|
||||||
let mut bitreader = crate::bitreader::Bitreader::new(raw.data());
|
let mut bitreader = crate::bitreader::Bitreader::new(raw.data());
|
||||||
|
|
||||||
@@ -153,6 +291,8 @@ fn inner_parse_packet(
|
|||||||
let size = bitreader.read_varint()?;
|
let size = bitreader.read_varint()?;
|
||||||
let msg_bytes = bitreader.read_n_bytes(size as usize)?;
|
let msg_bytes = bitreader.read_n_bytes(size as usize)?;
|
||||||
|
|
||||||
|
assert_eq!(msg_bytes.len(), size as usize);
|
||||||
|
|
||||||
let net_msg_type = match crate::netmessagetypes::NetmessageType::try_from(msg_type as i32) {
|
let net_msg_type = match crate::netmessagetypes::NetmessageType::try_from(msg_type as i32) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -196,7 +336,70 @@ fn inner_parse_packet(
|
|||||||
crate::netmessagetypes::NetmessageType::net_SetConVar => {}
|
crate::netmessagetypes::NetmessageType::net_SetConVar => {}
|
||||||
crate::netmessagetypes::NetmessageType::svc_ClassInfo => {}
|
crate::netmessagetypes::NetmessageType::svc_ClassInfo => {}
|
||||||
crate::netmessagetypes::NetmessageType::svc_VoiceInit => {}
|
crate::netmessagetypes::NetmessageType::svc_VoiceInit => {}
|
||||||
crate::netmessagetypes::NetmessageType::svc_PacketEntities => {}
|
crate::netmessagetypes::NetmessageType::svc_PacketEntities => {
|
||||||
|
let raw: crate::csgo_proto::CsvcMsgPacketEntities =
|
||||||
|
prost::Message::decode(msg_bytes.as_slice())?;
|
||||||
|
|
||||||
|
let mut bitreader = crate::bitreader::Bitreader::new(raw.entity_data());
|
||||||
|
let mut entity_id: i32 = -1;
|
||||||
|
for _ in 0..raw.updated_entries() {
|
||||||
|
entity_id += 1 + (bitreader.read_u_bit_var()? as i32);
|
||||||
|
|
||||||
|
match bitreader.read_nbits(2)? {
|
||||||
|
0b01 | 0b11 => {
|
||||||
|
entities.remove(&entity_id);
|
||||||
|
}
|
||||||
|
0b10 => {
|
||||||
|
let (id, entity) = create_entity(entity_id, &mut bitreader, baselines)?;
|
||||||
|
let cls = entity.cls;
|
||||||
|
|
||||||
|
entities.insert(entity_id, entity);
|
||||||
|
if let Some(baseline_bytes) = baselines.get(&cls) {
|
||||||
|
let mut br = crate::bitreader::Bitreader::new(&baseline_bytes);
|
||||||
|
update_entity(
|
||||||
|
entity_id,
|
||||||
|
&mut br,
|
||||||
|
entities,
|
||||||
|
cls_to_class,
|
||||||
|
paths,
|
||||||
|
qf_mapper,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
update_entity(
|
||||||
|
entity_id,
|
||||||
|
&mut bitreader,
|
||||||
|
entities,
|
||||||
|
cls_to_class,
|
||||||
|
paths,
|
||||||
|
qf_mapper,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
0b00 => {
|
||||||
|
if raw.has_pvs_vis_bits() > 0 {
|
||||||
|
if bitreader.read_nbits(2)? & 0x01 == 1 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update_entity(
|
||||||
|
entity_id,
|
||||||
|
&mut bitreader,
|
||||||
|
entities,
|
||||||
|
cls_to_class,
|
||||||
|
paths,
|
||||||
|
qf_mapper,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
unknown => {
|
||||||
|
panic!("{:?}", unknown);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// dbg!("PacketEntities");
|
||||||
|
}
|
||||||
crate::netmessagetypes::NetmessageType::svc_UserCmds => {}
|
crate::netmessagetypes::NetmessageType::svc_UserCmds => {}
|
||||||
crate::netmessagetypes::NetmessageType::GE_SosStartSoundEvent => {}
|
crate::netmessagetypes::NetmessageType::GE_SosStartSoundEvent => {}
|
||||||
crate::netmessagetypes::NetmessageType::GE_SosStopSoundEvent => {}
|
crate::netmessagetypes::NetmessageType::GE_SosStopSoundEvent => {}
|
||||||
@@ -243,7 +446,11 @@ 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 => {}
|
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())?;
|
||||||
@@ -274,3 +481,143 @@ fn inner_parse_packet(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_entity(
|
||||||
|
entity_id: i32,
|
||||||
|
bitreader: &mut crate::bitreader::Bitreader,
|
||||||
|
baselines: &mut std::collections::HashMap<u32, Vec<u8>>,
|
||||||
|
) -> Result<(i32, Entity), FirstPassError> {
|
||||||
|
let cls_id: u32 = bitreader.read_nbits(8)?;
|
||||||
|
let _serial = bitreader.read_nbits(17)?;
|
||||||
|
let _unknown = bitreader.read_varint()?;
|
||||||
|
|
||||||
|
Ok((entity_id, Entity { cls: cls_id }))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_entity(
|
||||||
|
entity_id: i32,
|
||||||
|
bitreader: &mut crate::bitreader::Bitreader,
|
||||||
|
entities: &mut std::collections::HashMap<i32, Entity>,
|
||||||
|
cls_to_class: &mut std::collections::HashMap<u32, Class>,
|
||||||
|
paths: &mut Paths,
|
||||||
|
qf_mapper: &mut decoder::QfMapper,
|
||||||
|
) -> Result<(), FirstPassError> {
|
||||||
|
let n_updates = fieldpath::parse_paths(bitreader, paths)?;
|
||||||
|
let n_updated_values = decode_entity_update(
|
||||||
|
entity_id,
|
||||||
|
bitreader,
|
||||||
|
n_updates,
|
||||||
|
entities,
|
||||||
|
cls_to_class,
|
||||||
|
paths,
|
||||||
|
qf_mapper,
|
||||||
|
)?;
|
||||||
|
if n_updated_values > 0 {
|
||||||
|
gather_extra_info()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gather_extra_info() -> Result<(), FirstPassError> {
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_entity_update(
|
||||||
|
entity_id: i32,
|
||||||
|
bitreader: &mut crate::bitreader::Bitreader,
|
||||||
|
n_updates: usize,
|
||||||
|
entities: &mut std::collections::HashMap<i32, Entity>,
|
||||||
|
cls_to_class: &mut std::collections::HashMap<u32, Class>,
|
||||||
|
paths: &mut Paths,
|
||||||
|
qf_mapper: &mut decoder::QfMapper,
|
||||||
|
) -> Result<usize, FirstPassError> {
|
||||||
|
let entity = match entities.get_mut(&entity_id) {
|
||||||
|
Some(e) => e,
|
||||||
|
None => panic!("ID: {:?} - Entities: {:?}", entity_id, entities),
|
||||||
|
};
|
||||||
|
let class = match cls_to_class.get_mut(&entity.cls) {
|
||||||
|
Some(c) => c,
|
||||||
|
None => panic!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// dbg!(&class.name);
|
||||||
|
for path in paths.paths().take(n_updates) {
|
||||||
|
// dbg!(&path);
|
||||||
|
|
||||||
|
let field = path.find(&class.serializer)?;
|
||||||
|
let field_info = field.get_propinfo(path);
|
||||||
|
let decoder = field.get_decoder()?;
|
||||||
|
let result = decoder.decode(bitreader, qf_mapper)?;
|
||||||
|
|
||||||
|
// dbg!(&field, &field_info, &decoder, &result);
|
||||||
|
|
||||||
|
if let Some(fi) = field_info {
|
||||||
|
// dbg!(&fi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(n_updates)
|
||||||
|
}
|
||||||
|
|
||||||
|
static HUFFMAN_LOOKUP_TABLE: std::sync::LazyLock<Vec<(u8, u8)>> = std::sync::LazyLock::new(|| {
|
||||||
|
let buf = include_bytes!("huf.b");
|
||||||
|
let mut huf2 = Vec::with_capacity((1 << 17) - 1);
|
||||||
|
for chunk in buf.chunks_exact(2) {
|
||||||
|
huf2.push((chunk[0], chunk[1]));
|
||||||
|
}
|
||||||
|
huf2
|
||||||
|
});
|
||||||
|
|
||||||
|
fn do_op(
|
||||||
|
symbol: u8,
|
||||||
|
bitreader: &mut crate::bitreader::Bitreader,
|
||||||
|
field_path: &mut FieldPath,
|
||||||
|
) -> Result<(), FirstPassError> {
|
||||||
|
use fieldpath::ops::*;
|
||||||
|
|
||||||
|
match symbol {
|
||||||
|
0 => plus_one(bitreader, field_path),
|
||||||
|
1 => plus_two(bitreader, field_path),
|
||||||
|
2 => plus_three(bitreader, field_path),
|
||||||
|
3 => plus_four(bitreader, field_path),
|
||||||
|
4 => plus_n(bitreader, field_path),
|
||||||
|
5 => push_one_left_delta_zero_right_zero(bitreader, field_path),
|
||||||
|
6 => push_one_left_delta_zero_right_non_zero(bitreader, field_path),
|
||||||
|
7 => push_one_left_delta_one_right_zero(bitreader, field_path),
|
||||||
|
8 => push_one_left_delta_one_right_non_zero(bitreader, field_path),
|
||||||
|
9 => push_one_left_delta_n_right_zero(bitreader, field_path),
|
||||||
|
10 => push_one_left_delta_n_right_non_zero(bitreader, field_path),
|
||||||
|
11 => push_one_left_delta_n_right_non_zero_pack6_bits(bitreader, field_path),
|
||||||
|
12 => push_one_left_delta_n_right_non_zero_pack8_bits(bitreader, field_path),
|
||||||
|
13 => push_two_left_delta_zero(bitreader, field_path),
|
||||||
|
14 => push_two_pack5_left_delta_zero(bitreader, field_path),
|
||||||
|
15 => push_three_left_delta_zero(bitreader, field_path),
|
||||||
|
16 => push_three_pack5_left_delta_zero(bitreader, field_path),
|
||||||
|
17 => push_two_left_delta_one(bitreader, field_path),
|
||||||
|
18 => push_two_pack5_left_delta_one(bitreader, field_path),
|
||||||
|
19 => push_three_left_delta_one(bitreader, field_path),
|
||||||
|
20 => push_three_pack5_left_delta_one(bitreader, field_path),
|
||||||
|
21 => push_two_left_delta_n(bitreader, field_path),
|
||||||
|
22 => push_two_pack5_left_delta_n(bitreader, field_path),
|
||||||
|
23 => push_three_left_delta_n(bitreader, field_path),
|
||||||
|
24 => push_three_pack5_left_delta_n(bitreader, field_path),
|
||||||
|
25 => push_n(bitreader, field_path),
|
||||||
|
26 => push_n_and_non_topological(bitreader, field_path),
|
||||||
|
27 => pop_one_plus_one(bitreader, field_path),
|
||||||
|
28 => pop_one_plus_n(bitreader, field_path),
|
||||||
|
29 => pop_all_but_one_plus_one(bitreader, field_path),
|
||||||
|
30 => pop_all_but_one_plus_n(bitreader, field_path),
|
||||||
|
31 => pop_all_but_one_plus_n_pack3_bits(bitreader, field_path),
|
||||||
|
32 => pop_all_but_one_plus_n_pack6_bits(bitreader, field_path),
|
||||||
|
33 => pop_n_plus_one(bitreader, field_path),
|
||||||
|
34 => pop_n_plus_n(bitreader, field_path),
|
||||||
|
35 => pop_n_and_non_topographical(bitreader, field_path),
|
||||||
|
36 => non_topo_complex(bitreader, field_path),
|
||||||
|
37 => non_topo_penultimate_plus_one(bitreader, field_path),
|
||||||
|
38 => non_topo_complex_pack4_bits(bitreader, field_path),
|
||||||
|
other => todo!("Other OP: {:?}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
370
src/parser/decoder.rs
Normal file
370
src/parser/decoder.rs
Normal file
@@ -0,0 +1,370 @@
|
|||||||
|
mod quantizedfloat;
|
||||||
|
pub use quantizedfloat::{QfMapper, QuantalizedFloat};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum Decoder {
|
||||||
|
QuantalizedFloatDecoder(u8),
|
||||||
|
VectorNormalDecoder,
|
||||||
|
VectorNoscaleDecoder,
|
||||||
|
VectorFloatCoordDecoder,
|
||||||
|
Unsigned64Decoder,
|
||||||
|
CentityHandleDecoder,
|
||||||
|
NoscaleDecoder,
|
||||||
|
BooleanDecoder,
|
||||||
|
StringDecoder,
|
||||||
|
SignedDecoder,
|
||||||
|
UnsignedDecoder,
|
||||||
|
ComponentDecoder,
|
||||||
|
FloatCoordDecoder,
|
||||||
|
FloatSimulationTimeDecoder,
|
||||||
|
Fixed64Decoder,
|
||||||
|
QanglePitchYawDecoder,
|
||||||
|
Qangle3Decoder,
|
||||||
|
QangleVarDecoder,
|
||||||
|
BaseDecoder,
|
||||||
|
AmmoDecoder,
|
||||||
|
QanglePresDecoder,
|
||||||
|
GameModeRulesDecoder,
|
||||||
|
}
|
||||||
|
use Decoder::*;
|
||||||
|
|
||||||
|
pub static BASETYPE_DECODERS: phf::Map<&'static str, Decoder> = phf::phf_map! {
|
||||||
|
"bool" => BooleanDecoder,
|
||||||
|
"char" => StringDecoder,
|
||||||
|
"int16" => SignedDecoder,
|
||||||
|
"int32" => SignedDecoder,
|
||||||
|
"int64" => SignedDecoder,
|
||||||
|
"int8" => SignedDecoder,
|
||||||
|
"uint16" => UnsignedDecoder,
|
||||||
|
"uint32" => UnsignedDecoder,
|
||||||
|
"uint8" => UnsignedDecoder,
|
||||||
|
"color32" => UnsignedDecoder,
|
||||||
|
"GameTime_t" => NoscaleDecoder,
|
||||||
|
"CBodyComponent" => ComponentDecoder,
|
||||||
|
"CGameSceneNodeHandle" => UnsignedDecoder,
|
||||||
|
"Color" => UnsignedDecoder,
|
||||||
|
"CPhysicsComponent" => ComponentDecoder,
|
||||||
|
"CRenderComponent" => ComponentDecoder,
|
||||||
|
"CUtlString" => StringDecoder,
|
||||||
|
"CUtlStringToken" => UnsignedDecoder,
|
||||||
|
"CUtlSymbolLarge" => StringDecoder,
|
||||||
|
"Quaternion" => NoscaleDecoder,
|
||||||
|
"CTransform" => NoscaleDecoder,
|
||||||
|
"HSequence" => Unsigned64Decoder,
|
||||||
|
"AttachmentHandle_t"=> Unsigned64Decoder,
|
||||||
|
"CEntityIndex"=> Unsigned64Decoder,
|
||||||
|
"MoveCollide_t"=> Unsigned64Decoder,
|
||||||
|
"MoveType_t"=> Unsigned64Decoder,
|
||||||
|
"RenderMode_t"=> Unsigned64Decoder,
|
||||||
|
"RenderFx_t"=> Unsigned64Decoder,
|
||||||
|
"SolidType_t"=> Unsigned64Decoder,
|
||||||
|
"SurroundingBoundsType_t"=> Unsigned64Decoder,
|
||||||
|
"ModelConfigHandle_t"=> Unsigned64Decoder,
|
||||||
|
"NPC_STATE"=> Unsigned64Decoder,
|
||||||
|
"StanceType_t"=> Unsigned64Decoder,
|
||||||
|
"AbilityPathType_t"=> Unsigned64Decoder,
|
||||||
|
"WeaponState_t"=> Unsigned64Decoder,
|
||||||
|
"DoorState_t"=> Unsigned64Decoder,
|
||||||
|
"RagdollBlendDirection"=> Unsigned64Decoder,
|
||||||
|
"BeamType_t"=> Unsigned64Decoder,
|
||||||
|
"BeamClipStyle_t"=> Unsigned64Decoder,
|
||||||
|
"EntityDisolveType_t"=> Unsigned64Decoder,
|
||||||
|
"tablet_skin_state_t" => Unsigned64Decoder,
|
||||||
|
"CStrongHandle" => Unsigned64Decoder,
|
||||||
|
"CSWeaponMode" => Unsigned64Decoder,
|
||||||
|
"ESurvivalSpawnTileState"=> Unsigned64Decoder,
|
||||||
|
"SpawnStage_t"=> Unsigned64Decoder,
|
||||||
|
"ESurvivalGameRuleDecision_t"=> Unsigned64Decoder,
|
||||||
|
"RelativeDamagedDirection_t"=> Unsigned64Decoder,
|
||||||
|
"CSPlayerState"=> Unsigned64Decoder,
|
||||||
|
"MedalRank_t"=> Unsigned64Decoder,
|
||||||
|
"CSPlayerBlockingUseAction_t"=> Unsigned64Decoder,
|
||||||
|
"MoveMountingAmount_t"=> Unsigned64Decoder,
|
||||||
|
"QuestProgress::Reason"=> Unsigned64Decoder,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn find_decoder(field: &super::sendtables::ConstructorField, qf_map: &mut QfMapper) -> Decoder {
|
||||||
|
if field.var_name.as_str() == "m_iClip1" {
|
||||||
|
return Decoder::AmmoDecoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
match BASETYPE_DECODERS.get(field.field_type.base_type.as_str()) {
|
||||||
|
Some(d) => d.clone(),
|
||||||
|
None => match field.field_type.base_type.as_str() {
|
||||||
|
"float32" => float_decoder(field, qf_map),
|
||||||
|
"Vector" => find_vector_type(3, field, qf_map),
|
||||||
|
"Vector2D" => find_vector_type(2, field, qf_map),
|
||||||
|
"Vector4D" => find_vector_type(4, field, qf_map),
|
||||||
|
"uint64" => find_uint_decoder(field),
|
||||||
|
"QAngle" => find_qangle_decoder(field),
|
||||||
|
"CHandle" => Decoder::UnsignedDecoder,
|
||||||
|
"CNetworkedQuantizedFloat" => float_decoder(field, qf_map),
|
||||||
|
"CStrongHandle" => find_uint_decoder(field),
|
||||||
|
"CEntityHandle" => find_uint_decoder(field),
|
||||||
|
_ => Decoder::UnsignedDecoder,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_qangle_decoder(field: &super::sendtables::ConstructorField) -> Decoder {
|
||||||
|
match field.var_name.as_str() {
|
||||||
|
"m_angEyeAngles" => Decoder::QanglePitchYawDecoder,
|
||||||
|
_ => {
|
||||||
|
if field.bitcount != 0 {
|
||||||
|
Decoder::Qangle3Decoder
|
||||||
|
} else {
|
||||||
|
Decoder::QangleVarDecoder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_uint_decoder(field: &super::sendtables::ConstructorField) -> Decoder {
|
||||||
|
match field.encoder.as_str() {
|
||||||
|
"fixed64" => Decoder::Fixed64Decoder,
|
||||||
|
_ => Decoder::Unsigned64Decoder,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn float_decoder(field: &super::sendtables::ConstructorField, qf_map: &mut QfMapper) -> Decoder {
|
||||||
|
match field.var_name.as_str() {
|
||||||
|
"m_flSimulationTime" => return Decoder::FloatSimulationTimeDecoder,
|
||||||
|
"m_flAnimTime" => return Decoder::FloatSimulationTimeDecoder,
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
match field.encoder.as_str() {
|
||||||
|
"coord" => Decoder::FloatCoordDecoder,
|
||||||
|
"m_flSimulationTime" => Decoder::FloatSimulationTimeDecoder,
|
||||||
|
_ => {
|
||||||
|
if field.bitcount <= 0 || field.bitcount >= 32 {
|
||||||
|
return Decoder::NoscaleDecoder;
|
||||||
|
} else {
|
||||||
|
let qf = QuantalizedFloat::new(
|
||||||
|
field.bitcount as u32,
|
||||||
|
Some(field.encode_flags),
|
||||||
|
Some(field.low_value),
|
||||||
|
Some(field.high_value),
|
||||||
|
);
|
||||||
|
let idx = qf_map.idx;
|
||||||
|
qf_map.map.insert(idx, qf);
|
||||||
|
qf_map.idx += 1;
|
||||||
|
Decoder::QuantalizedFloatDecoder(idx as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_vector_type(
|
||||||
|
dimensions: usize,
|
||||||
|
field: &super::sendtables::ConstructorField,
|
||||||
|
qf_map: &mut QfMapper,
|
||||||
|
) -> Decoder {
|
||||||
|
if dimensions == 3 && field.encoder.as_str() == "normal" {
|
||||||
|
return Decoder::VectorNormalDecoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
let float_type = float_decoder(field, qf_map);
|
||||||
|
match float_type {
|
||||||
|
Decoder::NoscaleDecoder => Decoder::VectorNoscaleDecoder,
|
||||||
|
Decoder::FloatCoordDecoder => Decoder::VectorFloatCoordDecoder,
|
||||||
|
_ => Decoder::VectorNormalDecoder,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decoder {
|
||||||
|
pub fn decode(
|
||||||
|
&self,
|
||||||
|
bitreader: &mut crate::bitreader::Bitreader,
|
||||||
|
qf_map: &mut QfMapper,
|
||||||
|
) -> Result<super::variant::Variant, super::FirstPassError> {
|
||||||
|
use super::variant::Variant;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Self::NoscaleDecoder => Ok(Variant::F32(f32::from_bits(bitreader.read_nbits(32)?))),
|
||||||
|
Self::FloatSimulationTimeDecoder => Ok(Variant::F32(bitreader.decode_simul_time()?)),
|
||||||
|
Self::UnsignedDecoder => Ok(Variant::U32(bitreader.read_varint()?)),
|
||||||
|
Self::QuantalizedFloatDecoder(qf_idx) => Ok(bitreader.decode_qfloat(*qf_idx, qf_map)?),
|
||||||
|
Self::Qangle3Decoder => Ok(Variant::VecXYZ(bitreader.decode_qangle_all_3()?)),
|
||||||
|
Self::SignedDecoder => Ok(Variant::I32(bitreader.read_varint32()?)),
|
||||||
|
Self::VectorNoscaleDecoder => Ok(Variant::VecXYZ(bitreader.decode_vector_noscale()?)),
|
||||||
|
Self::BooleanDecoder => Ok(Variant::Bool(bitreader.read_boolean()?)),
|
||||||
|
Self::BaseDecoder => Ok(Variant::U32(bitreader.read_varint()?)),
|
||||||
|
Self::CentityHandleDecoder => Ok(Variant::U32(bitreader.read_varint()?)),
|
||||||
|
Self::ComponentDecoder => Ok(Variant::Bool(bitreader.read_boolean()?)),
|
||||||
|
Self::FloatCoordDecoder => Ok(Variant::F32(bitreader.read_bit_coord()?)),
|
||||||
|
Self::StringDecoder => Ok(Variant::String(bitreader.read_string()?)),
|
||||||
|
Self::QanglePitchYawDecoder => {
|
||||||
|
Ok(Variant::VecXYZ(bitreader.decode_qangle_pitch_yaw()?))
|
||||||
|
}
|
||||||
|
Self::QangleVarDecoder => Ok(Variant::VecXYZ(bitreader.decode_qangle_variant()?)),
|
||||||
|
Self::VectorNormalDecoder => Ok(Variant::VecXYZ(bitreader.decode_normal_vec()?)),
|
||||||
|
Self::Unsigned64Decoder => Ok(Variant::U64(bitreader.read_varint_u_64()?)),
|
||||||
|
Self::Fixed64Decoder => Ok(Variant::U64(bitreader.decode_uint64()?)),
|
||||||
|
Self::VectorFloatCoordDecoder => {
|
||||||
|
Ok(Variant::VecXYZ(bitreader.decode_vector_float_coord()?))
|
||||||
|
}
|
||||||
|
Self::AmmoDecoder => Ok(Variant::U32(bitreader.decode_ammo()?)),
|
||||||
|
Self::QanglePresDecoder => Ok(Variant::VecXYZ(bitreader.decode_qangle_variant_pres()?)),
|
||||||
|
Self::GameModeRulesDecoder => Ok(Variant::U32(bitreader.read_nbits(7)?)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> crate::bitreader::Bitreader<'b> {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_qfloat(
|
||||||
|
&mut self,
|
||||||
|
qf_idx: u8,
|
||||||
|
qf_map: &QfMapper,
|
||||||
|
) -> Result<super::variant::Variant, super::FirstPassError> {
|
||||||
|
match qf_map.map.get(&(qf_idx as u32)) {
|
||||||
|
Some(qf) => Ok(super::variant::Variant::F32(qf.decode(self)?)),
|
||||||
|
None => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_ammo(&mut self) -> Result<u32, super::FirstPassError> {
|
||||||
|
let ammo = self.read_varint()?;
|
||||||
|
if ammo > 0 {
|
||||||
|
return Ok(ammo - 1);
|
||||||
|
}
|
||||||
|
return Ok(ammo);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_uint64(&mut self) -> Result<u64, super::FirstPassError> {
|
||||||
|
let bytes = self.read_n_bytes(8)?;
|
||||||
|
match bytes.try_into() {
|
||||||
|
Err(_) => panic!(),
|
||||||
|
Ok(arr) => Ok(u64::from_ne_bytes(arr)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_noscale(&mut self) -> Result<f32, super::FirstPassError> {
|
||||||
|
Ok(f32::from_le_bytes(self.read_nbits(32)?.to_le_bytes()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_string(&mut self) -> Result<String, super::FirstPassError> {
|
||||||
|
let mut s: Vec<u8> = vec![];
|
||||||
|
loop {
|
||||||
|
let c = self.read_nbits(8)? as u8;
|
||||||
|
if c == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s.push(c);
|
||||||
|
}
|
||||||
|
Ok(String::from_utf8_lossy(&s).to_string())
|
||||||
|
}
|
||||||
|
pub fn decode_float_coord(&mut self) -> Result<f32, super::FirstPassError> {
|
||||||
|
Ok(self.read_bit_coord()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_simul_time(&mut self) -> Result<f32, super::FirstPassError> {
|
||||||
|
Ok(self.read_varint()? as f32 * (1.0 / 30.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_vector_noscale(&mut self) -> Result<[f32; 3], super::FirstPassError> {
|
||||||
|
let mut v = [0.0; 3];
|
||||||
|
for idx in 0..3 {
|
||||||
|
v[idx] = self.decode_noscale()?;
|
||||||
|
}
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_qangle_pitch_yaw(&mut self) -> Result<[f32; 3], super::FirstPassError> {
|
||||||
|
let mut v = [0.0; 3];
|
||||||
|
v[0] = self.read_angle(32)?;
|
||||||
|
v[1] = self.read_angle(32)?;
|
||||||
|
v[2] = self.read_angle(32)?;
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
pub fn decode_qangle_all_3(&mut self) -> Result<[f32; 3], super::FirstPassError> {
|
||||||
|
// Used by aimpunch props (not exposed atm) maybe wrong format? correct number of bits anyhow.
|
||||||
|
let mut v = [0.0; 3];
|
||||||
|
v[0] = self.decode_noscale()?;
|
||||||
|
v[1] = self.decode_noscale()?;
|
||||||
|
v[2] = self.decode_noscale()?;
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
pub fn decode_qangle_variant(&mut self) -> Result<[f32; 3], super::FirstPassError> {
|
||||||
|
let mut v = [0.0; 3];
|
||||||
|
let has_x = self.read_boolean()?;
|
||||||
|
let has_y = self.read_boolean()?;
|
||||||
|
let has_z = self.read_boolean()?;
|
||||||
|
if has_x {
|
||||||
|
v[0] = self.read_bit_coord()?;
|
||||||
|
}
|
||||||
|
if has_y {
|
||||||
|
v[1] = self.read_bit_coord()?;
|
||||||
|
}
|
||||||
|
if has_z {
|
||||||
|
v[2] = self.read_bit_coord()?;
|
||||||
|
}
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
pub fn read_angle(&mut self, n: usize) -> Result<f32, super::FirstPassError> {
|
||||||
|
return Ok(self.decode_noscale()? / ((1 << n) as f32));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_normal(&mut self) -> Result<f32, super::FirstPassError> {
|
||||||
|
let is_neg = self.read_boolean()?;
|
||||||
|
let len = self.read_nbits(11)?;
|
||||||
|
let result = (len as f64 * (1.0 / ((1 << 11) as f64) - 1.0)) as f32;
|
||||||
|
match is_neg {
|
||||||
|
true => Ok(-result),
|
||||||
|
false => Ok(result),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn decode_normal_vec(&mut self) -> Result<[f32; 3], super::FirstPassError> {
|
||||||
|
let mut v = [0.0; 3];
|
||||||
|
let has_x = self.read_boolean()?;
|
||||||
|
let has_y = self.read_boolean()?;
|
||||||
|
if has_x {
|
||||||
|
v[0] = self.decode_normal()?;
|
||||||
|
}
|
||||||
|
if has_y {
|
||||||
|
v[1] = self.decode_normal()?;
|
||||||
|
}
|
||||||
|
let neg_z = self.read_boolean()?;
|
||||||
|
let prod_sum = v[0] * v[0] + v[1] * v[1];
|
||||||
|
if prod_sum < 1.0 {
|
||||||
|
v[2] = (1.0 - prod_sum).sqrt() as f32;
|
||||||
|
} else {
|
||||||
|
v[2] = 0.0;
|
||||||
|
}
|
||||||
|
if neg_z {
|
||||||
|
v[2] = -v[2];
|
||||||
|
}
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_vector_float_coord(&mut self) -> Result<[f32; 3], super::FirstPassError> {
|
||||||
|
let mut v = [0.0; 3];
|
||||||
|
for idx in 0..3 {
|
||||||
|
v[idx] = self.decode_float_coord()?;
|
||||||
|
}
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_qangle_variant_pres(&mut self) -> Result<[f32; 3], super::FirstPassError> {
|
||||||
|
let mut v = [0.0; 3];
|
||||||
|
|
||||||
|
let has_x = self.read_boolean()?;
|
||||||
|
let has_y = self.read_boolean()?;
|
||||||
|
let has_z = self.read_boolean()?;
|
||||||
|
|
||||||
|
if has_x {
|
||||||
|
v[0] = self.read_bit_coord_pres()?;
|
||||||
|
}
|
||||||
|
if has_y {
|
||||||
|
v[1] = self.read_bit_coord_pres()?;
|
||||||
|
}
|
||||||
|
if has_z {
|
||||||
|
v[2] = self.read_bit_coord_pres()?;
|
||||||
|
}
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
208
src/parser/decoder/quantizedfloat.rs
Normal file
208
src/parser/decoder/quantizedfloat.rs
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
use crate::{bitreader::Bitreader, parser::FirstPassError};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub struct QuantalizedFloat {
|
||||||
|
low: f32,
|
||||||
|
high: f32,
|
||||||
|
high_low_mul: f32,
|
||||||
|
dec_mul: f32,
|
||||||
|
offset: f32,
|
||||||
|
bit_count: u32,
|
||||||
|
flags: u32,
|
||||||
|
no_scale: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct QfMapper {
|
||||||
|
pub idx: u32,
|
||||||
|
pub map: std::collections::HashMap<u32, QuantalizedFloat>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const QFF_ROUNDDOWN: u32 = 1 << 0;
|
||||||
|
const QFF_ROUNDUP: u32 = 1 << 1;
|
||||||
|
const QFF_ENCODE_ZERO: u32 = 1 << 2;
|
||||||
|
const QFF_ENCODE_INTEGERS: u32 = 1 << 3;
|
||||||
|
|
||||||
|
impl QuantalizedFloat {
|
||||||
|
// More or less directly translated from here:
|
||||||
|
// https://github.com/dotabuff/manta/blob/09a1d60ef77f68eef84b79e9ca519caf76a1f291/quantizedfloat.go
|
||||||
|
fn validate_flags(&mut self) {
|
||||||
|
if self.flags == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (self.low == 0.0 && (self.flags & QFF_ROUNDDOWN) != 0)
|
||||||
|
|| (self.high == 0.0 && (self.flags & QFF_ROUNDUP) != 0)
|
||||||
|
{
|
||||||
|
self.flags &= !QFF_ENCODE_ZERO;
|
||||||
|
}
|
||||||
|
if self.low == 0.0 && (self.flags & QFF_ENCODE_ZERO) != 0 {
|
||||||
|
self.flags |= QFF_ROUNDDOWN;
|
||||||
|
self.flags &= !QFF_ENCODE_ZERO;
|
||||||
|
}
|
||||||
|
if self.high == 0.0 && (self.flags & QFF_ENCODE_ZERO) != 0 {
|
||||||
|
self.flags |= QFF_ROUNDUP;
|
||||||
|
self.flags &= !QFF_ENCODE_ZERO;
|
||||||
|
}
|
||||||
|
if self.low > 0.0 || self.high < 0.0 {
|
||||||
|
self.flags &= !QFF_ENCODE_ZERO;
|
||||||
|
}
|
||||||
|
if (self.flags & QFF_ENCODE_INTEGERS) != 0 {
|
||||||
|
self.flags &= !(QFF_ROUNDUP | QFF_ROUNDDOWN | QFF_ENCODE_ZERO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn assign_multipliers(&mut self, steps: u32) {
|
||||||
|
self.high_low_mul = 0.0;
|
||||||
|
let range = self.high - self.low;
|
||||||
|
|
||||||
|
let high: u32;
|
||||||
|
if self.bit_count == 32 {
|
||||||
|
high = 0xFFFFFFFE;
|
||||||
|
} else {
|
||||||
|
high = (1 << self.bit_count) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut high_mul: f32;
|
||||||
|
// Xd?
|
||||||
|
if range.abs() <= 0.0 {
|
||||||
|
high_mul = high as f32;
|
||||||
|
} else {
|
||||||
|
high_mul = (high as f32) / range;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (high_mul * range > (high as f32))
|
||||||
|
|| (((high_mul * range) as f64) > ((high as f32) as f64))
|
||||||
|
{
|
||||||
|
let multipliers = vec![0.9999, 0.99, 0.9, 0.8, 0.7];
|
||||||
|
for multiplier in multipliers {
|
||||||
|
high_mul = (high as f32) / range * multiplier;
|
||||||
|
if (high_mul * range > (high as f32))
|
||||||
|
|| (((high_mul * range) as f64) > (high as f32) as f64)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.high_low_mul = high_mul;
|
||||||
|
self.dec_mul = 1.0 / (steps - 1) as f32;
|
||||||
|
}
|
||||||
|
pub fn quantize(&mut self, val: f32) -> f32 {
|
||||||
|
if val < self.low {
|
||||||
|
return self.low;
|
||||||
|
} else if val > self.high {
|
||||||
|
return self.high;
|
||||||
|
}
|
||||||
|
let i = ((val - self.low) * self.high_low_mul) as u32;
|
||||||
|
self.low + (self.high - self.low) * ((i as f32) * self.dec_mul)
|
||||||
|
}
|
||||||
|
pub fn decode(&self, bitreader: &mut Bitreader) -> Result<f32, FirstPassError> {
|
||||||
|
if self.flags & QFF_ROUNDDOWN != 0 && bitreader.read_boolean()? {
|
||||||
|
return Ok(self.low);
|
||||||
|
}
|
||||||
|
if self.flags & QFF_ROUNDUP != 0 && bitreader.read_boolean()? {
|
||||||
|
return Ok(self.high);
|
||||||
|
}
|
||||||
|
if self.flags & QFF_ENCODE_ZERO != 0 && bitreader.read_boolean()? {
|
||||||
|
return Ok(0.0);
|
||||||
|
}
|
||||||
|
let bits = bitreader.read_nbits(self.bit_count)?;
|
||||||
|
Ok(self.low + (self.high - self.low) * bits as f32 * self.dec_mul)
|
||||||
|
}
|
||||||
|
pub fn new(
|
||||||
|
bitcount: u32,
|
||||||
|
flags: Option<i32>,
|
||||||
|
low_value: Option<f32>,
|
||||||
|
high_value: Option<f32>,
|
||||||
|
) -> Self {
|
||||||
|
let mut qf = QuantalizedFloat {
|
||||||
|
no_scale: false,
|
||||||
|
bit_count: 0,
|
||||||
|
dec_mul: 0.0,
|
||||||
|
low: 0.0,
|
||||||
|
high: 0.0,
|
||||||
|
high_low_mul: 0.0,
|
||||||
|
offset: 0.0,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
if bitcount == 0 || bitcount >= 32 {
|
||||||
|
qf.no_scale = true;
|
||||||
|
qf.bit_count = 32;
|
||||||
|
return qf;
|
||||||
|
} else {
|
||||||
|
qf.no_scale = false;
|
||||||
|
qf.bit_count = bitcount;
|
||||||
|
qf.offset = 0.0;
|
||||||
|
|
||||||
|
if low_value.is_some() {
|
||||||
|
qf.low = low_value.unwrap_or(0.0);
|
||||||
|
} else {
|
||||||
|
qf.low = 0.0;
|
||||||
|
}
|
||||||
|
if high_value.is_some() {
|
||||||
|
qf.high = high_value.unwrap_or(0.0);
|
||||||
|
} else {
|
||||||
|
qf.high = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if flags.is_some() {
|
||||||
|
qf.flags = flags.unwrap_or(0) as u32;
|
||||||
|
} else {
|
||||||
|
qf.flags = 0;
|
||||||
|
}
|
||||||
|
qf.validate_flags();
|
||||||
|
let mut steps = 1 << qf.bit_count;
|
||||||
|
|
||||||
|
if (qf.flags & QFF_ROUNDDOWN) != 0 {
|
||||||
|
let range = qf.high - qf.low;
|
||||||
|
qf.offset = range / (steps as f32);
|
||||||
|
qf.high -= qf.offset;
|
||||||
|
} else if (qf.flags & QFF_ROUNDUP) != 0 {
|
||||||
|
let range = qf.high - qf.low;
|
||||||
|
qf.offset = range / (steps as f32);
|
||||||
|
qf.low += qf.offset;
|
||||||
|
}
|
||||||
|
if (qf.flags & QFF_ENCODE_INTEGERS) != 0 {
|
||||||
|
let mut delta = qf.high - qf.low;
|
||||||
|
if delta < 1.0 {
|
||||||
|
delta = 1.0;
|
||||||
|
}
|
||||||
|
let delta_log2 = delta.log2().ceil();
|
||||||
|
let range_2: u32 = 1 << delta_log2 as u32;
|
||||||
|
let mut bit_count = qf.bit_count;
|
||||||
|
loop {
|
||||||
|
if (1 << bit_count) > range_2 {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
bit_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bit_count > qf.bit_count {
|
||||||
|
qf.bit_count = bit_count;
|
||||||
|
steps = 1 << qf.bit_count;
|
||||||
|
}
|
||||||
|
qf.offset = range_2 as f32 / steps as f32;
|
||||||
|
qf.high = qf.low + ((range_2 as f32 - qf.offset) as f32);
|
||||||
|
}
|
||||||
|
|
||||||
|
qf.assign_multipliers(steps);
|
||||||
|
|
||||||
|
if (qf.flags & QFF_ROUNDDOWN) != 0 {
|
||||||
|
if qf.quantize(qf.low) == qf.low {
|
||||||
|
qf.flags &= !QFF_ROUNDDOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (qf.flags & QFF_ROUNDUP) != 0 {
|
||||||
|
if qf.quantize(qf.high) == qf.high {
|
||||||
|
qf.flags &= !QFF_ROUNDUP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (qf.flags & QFF_ENCODE_ZERO) != 0 {
|
||||||
|
if qf.quantize(0.0) == 0.0 {
|
||||||
|
qf.flags &= !QFF_ENCODE_ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qf
|
||||||
|
}
|
||||||
|
}
|
||||||
411
src/parser/fieldpath.rs
Normal file
411
src/parser/fieldpath.rs
Normal file
@@ -0,0 +1,411 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Paths(Vec<FieldPath>);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct FieldPath {
|
||||||
|
pub path: [i32; 7],
|
||||||
|
pub last: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Paths {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_path() -> FieldPath {
|
||||||
|
FieldPath {
|
||||||
|
path: [-1, 0, 0, 0, 0, 0, 0],
|
||||||
|
last: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self, fp: &FieldPath, idx: usize) {
|
||||||
|
match self.0.get_mut(idx) {
|
||||||
|
Some(entry) => {
|
||||||
|
*entry = *fp;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.0.resize(idx + 1, Self::new_path());
|
||||||
|
let entry = self.0.get_mut(idx).expect("We just resized the Vec");
|
||||||
|
*entry = *fp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn paths(&self) -> impl Iterator<Item = &FieldPath> {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_paths(
|
||||||
|
bitreader: &mut crate::bitreader::Bitreader,
|
||||||
|
paths: &mut Paths,
|
||||||
|
) -> Result<usize, super::FirstPassError> {
|
||||||
|
let mut path = Paths::new_path();
|
||||||
|
let mut idx = 0;
|
||||||
|
loop {
|
||||||
|
if bitreader.bits_left < 17 {
|
||||||
|
bitreader.refill();
|
||||||
|
}
|
||||||
|
|
||||||
|
let peeked_bits = bitreader.peek(17);
|
||||||
|
let (symbol, code_len) = super::HUFFMAN_LOOKUP_TABLE[peeked_bits as usize];
|
||||||
|
bitreader.consume(code_len as u32);
|
||||||
|
|
||||||
|
if symbol == 39 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
super::do_op(symbol, bitreader, &mut path)?;
|
||||||
|
paths.write(&path, idx);
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FieldPath {
|
||||||
|
pub fn pop_special(&mut self, n: usize) -> Result<(), super::FirstPassError> {
|
||||||
|
for _ in 0..n {
|
||||||
|
*self.get_entry_mut(self.last)? = 0;
|
||||||
|
self.last -= 1;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_entry_mut(&mut self, idx: usize) -> Result<&mut i32, super::FirstPassError> {
|
||||||
|
match self.path.get_mut(idx) {
|
||||||
|
Some(e) => Ok(e),
|
||||||
|
None => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find<'ser>(
|
||||||
|
&self,
|
||||||
|
ser: &'ser super::sendtables::Serializer,
|
||||||
|
) -> Result<&'ser super::sendtables::Field, super::FirstPassError> {
|
||||||
|
let f = match ser.fields.get(self.path[0] as usize) {
|
||||||
|
Some(entry) => entry,
|
||||||
|
None => panic!("Field-Len: {:?} - Path: {:?}", ser.fields.len(), self.path),
|
||||||
|
};
|
||||||
|
|
||||||
|
match self.last {
|
||||||
|
0 => Ok(f),
|
||||||
|
1 => Ok(f.get_inner(self.path[1] as usize)?),
|
||||||
|
2 => Ok(f.get_inner(self.path[1] as usize)?.get_inner(self.path[2] as usize)?),
|
||||||
|
3 => Ok(f.get_inner(self.path[1] as usize)?.get_inner(self.path[2] as usize)?.get_inner(self.path[3] as usize)?),
|
||||||
|
other => panic!("{:?}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod ops {
|
||||||
|
use super::FieldPath;
|
||||||
|
use crate::{bitreader::Bitreader, parser::FirstPassError};
|
||||||
|
|
||||||
|
pub fn plus_one(_bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn plus_two(_bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += 2;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn plus_three(_bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += 3;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn plus_four(_bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += 4;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn plus_n(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32 + 5;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_one_left_delta_zero_right_zero(_bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = 0;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_one_left_delta_zero_right_non_zero(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_one_left_delta_one_right_zero(_bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += 1;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = 0;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_one_left_delta_one_right_non_zero(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += 1;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_one_left_delta_n_right_zero(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = 0;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_one_left_delta_n_right_non_zero(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32 + 2;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = bitreader.read_ubit_var_fp()? as i32 + 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_one_left_delta_n_right_non_zero_pack6_bits(
|
||||||
|
bitreader: &mut Bitreader,
|
||||||
|
field_path: &mut FieldPath,
|
||||||
|
) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += (bitreader.read_nbits(3)? + 2) as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = (bitreader.read_nbits(3)? + 1) as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_one_left_delta_n_right_non_zero_pack8_bits(
|
||||||
|
bitreader: &mut Bitreader,
|
||||||
|
field_path: &mut FieldPath,
|
||||||
|
) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += (bitreader.read_nbits(4)? + 2) as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = (bitreader.read_nbits(4)? + 1) as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_two_left_delta_zero(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_two_pack5_left_delta_zero(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = bitreader.read_nbits(5)? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = bitreader.read_nbits(5)? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_three_left_delta_zero(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_three_pack5_left_delta_zero(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = bitreader.read_nbits(5)? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = bitreader.read_nbits(5)? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = bitreader.read_nbits(5)? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_two_left_delta_one(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += 1;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_two_pack5_left_delta_one(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += 1;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_nbits(5)? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_nbits(5)? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_three_left_delta_one(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += 1;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_three_pack5_left_delta_one(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += 1;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_nbits(5)? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_nbits(5)? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_nbits(5)? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_two_left_delta_n(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += (bitreader.read_u_bit_var()? + 2) as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_two_pack5_left_delta_n(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += (bitreader.read_u_bit_var()? + 2) as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_nbits(5)? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_nbits(5)? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_three_left_delta_n(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += (bitreader.read_u_bit_var()? + 2) as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_three_pack5_left_delta_n(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += (bitreader.read_u_bit_var()? + 2) as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_nbits(5)? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_nbits(5)? as i32;
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_nbits(5)? as i32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_n(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
let n = bitreader.read_u_bit_var()? as i32;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_u_bit_var()? as i32;
|
||||||
|
for _ in 0..n {
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_n_and_non_topological(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
for i in 0..field_path.last + 1 {
|
||||||
|
if bitreader.read_boolean()? {
|
||||||
|
*field_path.get_entry_mut(i)? += bitreader.read_varint32()? + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let count = bitreader.read_u_bit_var()?;
|
||||||
|
for _ in 0..count {
|
||||||
|
field_path.last += 1;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? = bitreader.read_ubit_var_fp()? as i32;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_one_plus_one(_bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.pop_special(1)?;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_one_plus_n(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.pop_special(1)?;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_ubit_var_fp()? as i32 + 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_all_but_one_plus_one(_bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.pop_special(field_path.last)?;
|
||||||
|
*field_path.get_entry_mut(0)? += 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_all_but_one_plus_n(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.pop_special(field_path.last)?;
|
||||||
|
*field_path.get_entry_mut(0)? += bitreader.read_ubit_var_fp()? as i32 + 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_all_but_one_plus_n_pack3_bits(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.pop_special(field_path.last)?;
|
||||||
|
*field_path.get_entry_mut(0)? += bitreader.read_nbits(3)? as i32 + 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_all_but_one_plus_n_pack6_bits(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.pop_special(field_path.last)?;
|
||||||
|
*field_path.get_entry_mut(0)? += bitreader.read_nbits(6)? as i32 + 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_n_plus_one(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.pop_special(bitreader.read_ubit_var_fp()? as usize)?;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_n_plus_n(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.pop_special(bitreader.read_ubit_var_fp()? as usize)?;
|
||||||
|
*field_path.get_entry_mut(field_path.last)? += bitreader.read_varint32()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_n_and_non_topographical(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
field_path.pop_special(bitreader.read_ubit_var_fp()? as usize)?;
|
||||||
|
for i in 0..field_path.last + 1 {
|
||||||
|
if bitreader.read_boolean()? {
|
||||||
|
*field_path.get_entry_mut(i)? += bitreader.read_varint32()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn non_topo_complex(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
for i in 0..field_path.last + 1 {
|
||||||
|
if bitreader.read_boolean()? {
|
||||||
|
*field_path.get_entry_mut(i)? += bitreader.read_varint32()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn non_topo_penultimate_plus_one(_bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
*field_path.get_entry_mut(field_path.last - 1)? += 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn non_topo_complex_pack4_bits(bitreader: &mut Bitreader, field_path: &mut FieldPath) -> Result<(), FirstPassError> {
|
||||||
|
for i in 0..field_path.last + 1 {
|
||||||
|
if bitreader.read_boolean()? {
|
||||||
|
*field_path.get_entry_mut(i)? += bitreader.read_nbits(4)? as i32 - 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
1449
src/parser/sendtables.rs
Normal file
1449
src/parser/sendtables.rs
Normal file
File diff suppressed because it is too large
Load Diff
26
src/parser/variant.rs
Normal file
26
src/parser/variant.rs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Variant {
|
||||||
|
Bool(bool),
|
||||||
|
U32(u32),
|
||||||
|
I32(i32),
|
||||||
|
I16(i16),
|
||||||
|
F32(f32),
|
||||||
|
U64(u64),
|
||||||
|
U8(u8),
|
||||||
|
String(String),
|
||||||
|
VecXY([f32; 2]),
|
||||||
|
VecXYZ([f32; 3]),
|
||||||
|
// Todo change to Vec<T>
|
||||||
|
StringVec(Vec<String>),
|
||||||
|
U32Vec(Vec<u32>),
|
||||||
|
U64Vec(Vec<u64>),
|
||||||
|
Stickers(Vec<Sticker>),
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Sticker {
|
||||||
|
pub name: String,
|
||||||
|
pub wear: f32,
|
||||||
|
pub id: u32,
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
}
|
||||||
BIN
testfiles/ancient_sendtables.b
Normal file
BIN
testfiles/ancient_sendtables.b
Normal file
Binary file not shown.
@@ -27,13 +27,15 @@ fn mirage_1() {
|
|||||||
.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!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user