mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 18:24:05 +02:00
remove the need for full reserve
This commit is contained in:
parent
f253e824d2
commit
522b282962
5 changed files with 80 additions and 66 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -79,9 +79,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitbuffer"
|
name = "bitbuffer"
|
||||||
version = "0.9.7"
|
version = "0.9.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c69c4d2ef0cb9cd4cbb53bf5cd13746e6bc73c6ff2aedbfee0951c18553232d3"
|
checksum = "72133b9e2c77f4bc4243ad82b246f2c6d0f1399e519258eeb0644f84a9d9bae5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitbuffer_derive",
|
"bitbuffer_derive",
|
||||||
"err-derive",
|
"err-derive",
|
||||||
|
|
@ -526,9 +526,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.27"
|
version = "1.0.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
|
checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
@ -665,9 +665,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.73"
|
version = "1.0.74"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
|
checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ const COPY_TYPES: &[PacketType] = &[
|
||||||
// PacketType::SyncTick, // bit perfect
|
// PacketType::SyncTick, // bit perfect
|
||||||
// PacketType::ConsoleCmd, // bit perfect
|
// PacketType::ConsoleCmd, // bit perfect
|
||||||
// PacketType::DataTables, // bit perfect
|
// PacketType::DataTables, // bit perfect
|
||||||
// PacketType::StringTables, // clone enough
|
// PacketType::StringTables, // close enough
|
||||||
// PacketType::UserCmd, // bit perfect
|
// PacketType::UserCmd, // close enough
|
||||||
];
|
];
|
||||||
|
|
||||||
fn main() -> Result<(), MainError> {
|
fn main() -> Result<(), MainError> {
|
||||||
|
|
@ -63,21 +63,15 @@ fn main() -> Result<(), MainError> {
|
||||||
match &mut packet {
|
match &mut packet {
|
||||||
Packet::Sigon(message_packet) | Packet::Message(message_packet) => {
|
Packet::Sigon(message_packet) | Packet::Message(message_packet) => {
|
||||||
message_packet.meta.view_angles = Default::default();
|
message_packet.meta.view_angles = Default::default();
|
||||||
let messages = std::mem::take(&mut message_packet.messages);
|
message_packet
|
||||||
let messages = messages
|
.messages
|
||||||
.into_iter()
|
.iter_mut()
|
||||||
.filter(|msg| msg.get_message_type() != MessageType::SetView)
|
.for_each(|msg| match msg {
|
||||||
.map(|mut msg| {
|
|
||||||
match &mut msg {
|
|
||||||
Message::ServerInfo(info) => {
|
Message::ServerInfo(info) => {
|
||||||
info.stv = true;
|
info.stv = true;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
});
|
||||||
msg
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
message_packet.messages = messages;
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ fn test_bit_var_roundtrip() {
|
||||||
write.bit_len()
|
write.bit_len()
|
||||||
};
|
};
|
||||||
let mut read = BitReadStream::new(BitReadBuffer::new(&data, LittleEndian));
|
let mut read = BitReadStream::new(BitReadBuffer::new(&data, LittleEndian));
|
||||||
assert_eq!(val, read_bit_var(&mut read).unwrap());
|
assert_eq!(val, read_bit_var::<u32>(&mut read).unwrap());
|
||||||
assert_eq!(pos, read.pos());
|
assert_eq!(pos, read.pos());
|
||||||
}
|
}
|
||||||
bit_var_normal(0);
|
bit_var_normal(0);
|
||||||
|
|
@ -291,7 +291,7 @@ impl Encode for PacketEntitiesMessage {
|
||||||
self.base_line.write_sized(stream, 1)?;
|
self.base_line.write_sized(stream, 1)?;
|
||||||
self.entities.len().write_sized(stream, 11)?;
|
self.entities.len().write_sized(stream, 11)?;
|
||||||
|
|
||||||
stream.reserve(20, |length_stream, stream| {
|
stream.reserve_int(20, |stream| {
|
||||||
self.updated_base_line.write(stream)?;
|
self.updated_base_line.write(stream)?;
|
||||||
|
|
||||||
let length_start = stream.bit_len();
|
let length_start = stream.bit_len();
|
||||||
|
|
@ -338,9 +338,7 @@ impl Encode for PacketEntitiesMessage {
|
||||||
|
|
||||||
let length_end = stream.bit_len();
|
let length_end = stream.bit_len();
|
||||||
|
|
||||||
(length_end - length_start).write_sized(length_stream, 20)?;
|
Ok((length_end - length_start) as u64)
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -164,33 +164,24 @@ impl Encode for CreateStringTableMessage<'_> {
|
||||||
let encode_bits = log_base2(table.max_entries) as usize;
|
let encode_bits = log_base2(table.max_entries) as usize;
|
||||||
(table.entries.len() as u16).write_sized(stream, encode_bits + 1)?;
|
(table.entries.len() as u16).write_sized(stream, encode_bits + 1)?;
|
||||||
|
|
||||||
// since length is encoded with a dynamic bit size, we can't use the normal "reserve" tricks
|
stream.reserve_int::<ParseError, _>(40, |stream| {
|
||||||
// so instead we write the body to a temporary vec first
|
table.fixed_user_data_size.is_some().write(stream)?;
|
||||||
let mut target_vec = Vec::with_capacity(table.entries.len() * 32);
|
|
||||||
let (target_length_start, target_end) = {
|
|
||||||
let mut target = BitWriteStream::new(&mut target_vec, LittleEndian);
|
|
||||||
|
|
||||||
table.fixed_user_data_size.is_some().write(&mut target)?;
|
|
||||||
if let Some(fixed_size) = table.fixed_user_data_size {
|
if let Some(fixed_size) = table.fixed_user_data_size {
|
||||||
fixed_size.write(&mut target)?;
|
fixed_size.write(stream)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// no compression for now
|
// no compression for now
|
||||||
false.write(&mut target)?;
|
false.write(stream)?;
|
||||||
|
|
||||||
let target_length_start = target.bit_len();
|
let start = stream.bit_len();
|
||||||
|
|
||||||
let table_meta = table.get_table_meta();
|
let table_meta = table.get_table_meta();
|
||||||
|
|
||||||
write_string_table_update(&table.entries, &mut target, &table_meta)?;
|
write_string_table_update(&table.entries, stream, &table_meta)?;
|
||||||
let target_end = target.bit_len();
|
|
||||||
(target_length_start, target_end)
|
|
||||||
};
|
|
||||||
let mut body_reader =
|
|
||||||
BitReadStream::new(BitReadBuffer::new_owned(target_vec, LittleEndian));
|
|
||||||
|
|
||||||
write_var_int((target_end - target_length_start) as u32, stream)?;
|
let end = stream.bit_len();
|
||||||
body_reader.read_bits(target_end)?.write(stream)?;
|
Ok(encode_var_int_fixed((end - start) as u32))
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -728,6 +719,19 @@ pub fn write_var_int(mut int: u32, stream: &mut BitWriteStream<LittleEndian>) ->
|
||||||
(int as u8).write(stream)
|
(int as u8).write(stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encode the int in such a way that it has a fixed size, but still decodes the same
|
||||||
|
// result is the first 40 bits of the return value
|
||||||
|
pub fn encode_var_int_fixed(mut int: u32) -> u64 {
|
||||||
|
let mut out = 0;
|
||||||
|
for i in 0..4 {
|
||||||
|
let byte: u8 = int as u8 & 0x7F;
|
||||||
|
out |= ((byte | 0x80) as u64) << i * 8;
|
||||||
|
int >>= 7;
|
||||||
|
}
|
||||||
|
out |= (int as u64) << 32;
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_var_int_roundtrip() {
|
fn test_var_int_roundtrip() {
|
||||||
fn var_int_roundtrip(int: u32) {
|
fn var_int_roundtrip(int: u32) {
|
||||||
|
|
@ -750,6 +754,30 @@ fn test_var_int_roundtrip() {
|
||||||
var_int_roundtrip(123125412);
|
var_int_roundtrip(123125412);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_var_int_fixed_roundtrip() {
|
||||||
|
fn var_int_roundtrip(int: u32) {
|
||||||
|
let mut data = Vec::new();
|
||||||
|
let pos = {
|
||||||
|
let mut write = BitWriteStream::new(&mut data, LittleEndian);
|
||||||
|
let encoded = encode_var_int_fixed(int);
|
||||||
|
encoded.write_sized(&mut write, 40).unwrap();
|
||||||
|
write.bit_len()
|
||||||
|
};
|
||||||
|
assert_eq!(40, pos);
|
||||||
|
let mut read = BitReadStream::new(BitReadBuffer::new(&data, LittleEndian));
|
||||||
|
assert_eq!(int, read_var_int(&mut read).unwrap());
|
||||||
|
assert_eq!(pos, read.pos());
|
||||||
|
}
|
||||||
|
var_int_roundtrip(0);
|
||||||
|
var_int_roundtrip(1);
|
||||||
|
var_int_roundtrip(10);
|
||||||
|
var_int_roundtrip(55);
|
||||||
|
var_int_roundtrip(355);
|
||||||
|
var_int_roundtrip(12354);
|
||||||
|
var_int_roundtrip(123125412);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn log_base2<T: PrimInt + Unsigned>(num: T) -> u32 {
|
pub fn log_base2<T: PrimInt + Unsigned>(num: T) -> u32 {
|
||||||
// log(0) = inf, but that's a useless result
|
// log(0) = inf, but that's a useless result
|
||||||
// since this would only happen in malformed demos, we just return 0
|
// since this would only happen in malformed demos, we just return 0
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
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::{log_base2, write_var_int};
|
use crate::demo::message::stringtable::{encode_var_int_fixed, log_base2};
|
||||||
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;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use crate::{Parse, ParseError, ParserState, Stream};
|
use crate::{Parse, ParseError, ParserState, Stream};
|
||||||
use bitbuffer::{
|
use bitbuffer::{BitWrite, BitWriteSized, BitWriteStream, LittleEndian};
|
||||||
BitReadBuffer, BitReadStream, BitWrite, BitWriteSized, BitWriteStream, LittleEndian,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct TempEntitiesMessage {
|
pub struct TempEntitiesMessage {
|
||||||
|
|
@ -107,26 +105,25 @@ impl Encode for TempEntitiesMessage {
|
||||||
};
|
};
|
||||||
count.write(stream)?;
|
count.write(stream)?;
|
||||||
|
|
||||||
let mut out = Vec::with_capacity(self.events.len() * 16);
|
stream.reserve_int::<ParseError, _>(40, |stream| {
|
||||||
let bits = {
|
let start = stream.bit_len();
|
||||||
let mut write = BitWriteStream::new(&mut out, LittleEndian);
|
|
||||||
let mut last_class_id = u16::MAX.into();
|
let mut last_class_id = u16::MAX.into();
|
||||||
|
|
||||||
for event in self.events.iter() {
|
for event in self.events.iter() {
|
||||||
if event.fire_delay > 0.0 {
|
if event.fire_delay > 0.0 {
|
||||||
true.write(&mut write)?;
|
true.write(stream)?;
|
||||||
((event.fire_delay * 100.0) as u8).write(&mut write)?;
|
((event.fire_delay * 100.0) as u8).write(stream)?;
|
||||||
} else {
|
} else {
|
||||||
false.write(&mut write)?;
|
false.write(stream)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if event.class_id != last_class_id {
|
if event.class_id != last_class_id {
|
||||||
true.write(&mut write)?;
|
true.write(stream)?;
|
||||||
let bits = log_base2(state.server_classes.len()) + 1;
|
let bits = log_base2(state.server_classes.len()) + 1;
|
||||||
let id: u16 = event.class_id.into();
|
let id: u16 = event.class_id.into();
|
||||||
(id + 1).write_sized(&mut write, bits as usize)?;
|
(id + 1).write_sized(stream, bits as usize)?;
|
||||||
} else {
|
} else {
|
||||||
false.write(&mut write)?;
|
false.write(stream)?;
|
||||||
}
|
}
|
||||||
last_class_id = event.class_id;
|
last_class_id = event.class_id;
|
||||||
|
|
||||||
|
|
@ -134,14 +131,11 @@ impl Encode for TempEntitiesMessage {
|
||||||
.send_tables
|
.send_tables
|
||||||
.get(usize::from(event.class_id))
|
.get(usize::from(event.class_id))
|
||||||
.ok_or(ParseError::UnknownServerClass(event.class_id))?;
|
.ok_or(ParseError::UnknownServerClass(event.class_id))?;
|
||||||
PacketEntitiesMessage::write_update(&event.props, &mut write, send_table)?;
|
PacketEntitiesMessage::write_update(&event.props, stream, send_table)?;
|
||||||
}
|
}
|
||||||
write.bit_len()
|
let end = stream.bit_len();
|
||||||
};
|
Ok(encode_var_int_fixed((end - start) as u32))
|
||||||
let mut data = BitReadStream::new(BitReadBuffer::new(&out, LittleEndian));
|
})?;
|
||||||
|
|
||||||
write_var_int(bits as u32, stream)?;
|
|
||||||
data.read_bits(bits)?.write(stream)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue