mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 10:14:06 +02:00
prepare for 0.6
This commit is contained in:
parent
1fed4d8826
commit
57096ab170
4 changed files with 23 additions and 222 deletions
59
Cargo.lock
generated
59
Cargo.lock
generated
|
|
@ -44,17 +44,6 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
|
||||
|
||||
[[package]]
|
||||
name = "audiopus_sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62314a1546a2064e033665d658e88c620a62904be945f8147e6b16c3db9f8651"
|
||||
dependencies = [
|
||||
"cmake",
|
||||
"log",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.3.0"
|
||||
|
|
@ -198,15 +187,6 @@ version = "0.7.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.8"
|
||||
|
|
@ -396,12 +376,6 @@ version = "0.3.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "hound"
|
||||
version = "3.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f"
|
||||
|
||||
[[package]]
|
||||
name = "iai"
|
||||
version = "0.1.1"
|
||||
|
|
@ -724,16 +698,6 @@ version = "11.1.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
||||
|
||||
[[package]]
|
||||
name = "opus"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6526409b274a7e98e55ff59d96aafd38e6cd34d46b7dbbc32ce126dffcd75e8e"
|
||||
dependencies = [
|
||||
"audiopus_sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
|
|
@ -771,12 +735,6 @@ version = "0.2.14"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.6"
|
||||
|
|
@ -1191,7 +1149,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tf-demo-parser"
|
||||
version = "0.5.1"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"better-panic",
|
||||
|
|
@ -1199,17 +1157,16 @@ dependencies = [
|
|||
"criterion",
|
||||
"enumflags2",
|
||||
"fnv",
|
||||
"hound",
|
||||
"iai",
|
||||
"insta",
|
||||
"itertools 0.13.0",
|
||||
"jemallocator",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"main_error",
|
||||
"no-panic",
|
||||
"num-traits 0.2.19",
|
||||
"num_enum",
|
||||
"opus",
|
||||
"parse-display",
|
||||
"pretty_assertions",
|
||||
"prettyplease",
|
||||
|
|
@ -1224,7 +1181,7 @@ dependencies = [
|
|||
"syn 2.0.90",
|
||||
"tempfile",
|
||||
"test-case",
|
||||
"thiserror 2.0.4",
|
||||
"thiserror 2.0.12",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
|
@ -1240,11 +1197,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.4"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.4",
|
||||
"thiserror-impl 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1260,9 +1217,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.4"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
|||
12
Cargo.toml
12
Cargo.toml
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "tf-demo-parser"
|
||||
description = "parser for tf2 demo files"
|
||||
version = "0.5.1"
|
||||
version = "0.6.0"
|
||||
authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
|
@ -44,11 +44,6 @@ path = "src/bin/strings.rs"
|
|||
name = "direct_hits"
|
||||
path = "src/bin/direct_hits.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "voice"
|
||||
path = "src/bin/voice.rs"
|
||||
required-features = ["audio"]
|
||||
|
||||
[dependencies]
|
||||
bitbuffer = { version = "0.11.0", features = ["serde"] }
|
||||
num_enum = "0.7.2"
|
||||
|
|
@ -82,15 +77,12 @@ tempfile = { version = "3", optional = true }
|
|||
lazy_static = { version = "1", optional = true }
|
||||
prettyplease = { version = "0.2", optional = true }
|
||||
|
||||
# audio
|
||||
opus = { version = "0.3.0", optional = true }
|
||||
hound = { version = "3.5.1", optional = true }
|
||||
log = { version = "0.4.21", features = [] }
|
||||
|
||||
[features]
|
||||
schema = ["schemars", "bitbuffer/schemars"]
|
||||
trace = ["tracing", "tracing-subscriber"]
|
||||
codegen = ["better-panic", "quote", "syn", "Inflector", "proc-macro2", "tempfile", "lazy_static", "prettyplease"]
|
||||
audio = ["dep:opus", "dep:hound"]
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.4.0"
|
||||
|
|
|
|||
161
src/bin/voice.rs
161
src/bin/voice.rs
|
|
@ -1,161 +0,0 @@
|
|||
use std::env;
|
||||
use std::fs;
|
||||
use bitbuffer::{BigEndian, BitRead, BitReadStream, LittleEndian};
|
||||
use hound::{SampleFormat, WavSpec, WavWriter};
|
||||
use main_error::MainError;
|
||||
use opus::{Channels, Decoder};
|
||||
use opus::packet::parse;
|
||||
use steamid_ng::SteamID;
|
||||
use tf_demo_parser::demo::parser::MessageHandler;
|
||||
use tf_demo_parser::MessageType;
|
||||
pub use tf_demo_parser::{Demo, DemoParser, Parse, ParserState};
|
||||
use tf_demo_parser::demo::data::DemoTick;
|
||||
use tf_demo_parser::demo::message::Message;
|
||||
use tf_demo_parser::demo::message::voice::{VoiceInitMessage};
|
||||
|
||||
#[cfg(feature = "jemallocator")]
|
||||
#[global_allocator]
|
||||
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||
|
||||
fn main() -> Result<(), MainError> {
|
||||
#[cfg(feature = "better-panic")]
|
||||
better_panic::install();
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let args: Vec<_> = env::args().collect();
|
||||
if args.len() < 2 {
|
||||
println!("1 argument required");
|
||||
return Ok(());
|
||||
}
|
||||
let path = args[1].clone();
|
||||
let file = fs::read(path)?;
|
||||
let demo = Demo::new(&file);
|
||||
let parser = DemoParser::new_with_analyser(demo.get_stream(), Voice::default());
|
||||
let (_header, samples) = parser.parse()?;
|
||||
let mut sample_buf = vec![0; 16 * 1024];
|
||||
let spec = WavSpec {
|
||||
channels: 1,
|
||||
sample_rate: 44100,
|
||||
bits_per_sample: 16,
|
||||
sample_format: SampleFormat::Int,
|
||||
};
|
||||
let mut writer = WavWriter::create("out.wav", spec).unwrap();
|
||||
for sample in samples {
|
||||
let packet = decode_steam_voice_sample(&sample.data);
|
||||
let mut decoder = Decoder::new(packet.sample_rate as u32, Channels::Mono).unwrap();
|
||||
dbg!(&packet.data[0..8]);
|
||||
dbg!(parse(&packet.data));
|
||||
let samples = decoder.decode(&packet.data, &mut sample_buf, false).unwrap();
|
||||
dbg!(samples);
|
||||
for sample in &sample_buf[0..samples] {
|
||||
writer.write_sample(*sample).unwrap();
|
||||
}
|
||||
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Voice {
|
||||
pub samples: Vec<VoiceSample>,
|
||||
pub last_init: Option<VoiceInitMessage>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VoiceCodec {
|
||||
Steam,
|
||||
Speex,
|
||||
Celt,
|
||||
CeltHigh
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct VoiceSample {
|
||||
tick: DemoTick,
|
||||
codec: VoiceCodec,
|
||||
sampling_rate: u16,
|
||||
client: u8,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl MessageHandler for Voice {
|
||||
type Output = Vec<VoiceSample>;
|
||||
|
||||
fn does_handle(message_type: MessageType) -> bool {
|
||||
matches!(
|
||||
message_type,
|
||||
MessageType::VoiceInit | MessageType::VoiceData
|
||||
)
|
||||
}
|
||||
|
||||
fn handle_message(&mut self, message: &Message, tick: DemoTick, _parser_state: &ParserState) {
|
||||
match message {
|
||||
Message::VoiceInit(init) => {
|
||||
self.last_init = Some(init.clone());
|
||||
}
|
||||
Message::VoiceData(data) => {
|
||||
if let Some(init) = self.last_init.as_ref() {
|
||||
let codec = match init.codec.as_str() {
|
||||
"steam" => VoiceCodec::Steam,
|
||||
"vaudio_speex" => VoiceCodec::Speex,
|
||||
"vaudio_celt" => VoiceCodec::Celt,
|
||||
"vaudio_celt_high" => VoiceCodec::CeltHigh,
|
||||
_ => {
|
||||
eprintln!("unknown voice codex: {}", init.codec);
|
||||
return;
|
||||
}
|
||||
};
|
||||
self.samples.push(VoiceSample {
|
||||
tick,
|
||||
codec,
|
||||
sampling_rate: init.sampling_rate,
|
||||
data: data.data.clone().read_sized::<Vec<u8>>(data.length as usize / 8).unwrap(),
|
||||
client: data.client,
|
||||
})
|
||||
} else {
|
||||
eprintln!("Voice data without init");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn into_output(self, _state: &ParserState) -> Self::Output {
|
||||
self.samples
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(BitRead, Debug)]
|
||||
struct SteamVoiceHeader {
|
||||
steam_id: u64,
|
||||
ty: u8,
|
||||
sample_rate: u16,
|
||||
payload_type: u8,
|
||||
length: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SteamVoicePacket {
|
||||
steam_id: SteamID,
|
||||
sample_rate: u16,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
fn decode_steam_voice_sample(data: &[u8]) -> SteamVoicePacket {
|
||||
let mut reader = BitReadStream::<LittleEndian>::from(data);
|
||||
let header = reader.read::<SteamVoiceHeader>().unwrap();
|
||||
assert_eq!(header.ty, 11);
|
||||
let data: Vec<u8> = if header.payload_type == 6 {
|
||||
reader.read_sized(header.length as usize).unwrap()
|
||||
} else {
|
||||
dbg!(header.length, data.len());
|
||||
Vec::new()
|
||||
};
|
||||
SteamVoicePacket {
|
||||
steam_id: SteamID::from(header.steam_id),
|
||||
sample_rate: header.sample_rate,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ use std::collections::{BTreeMap, HashMap};
|
|||
pub struct Handle(pub i64);
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Default)]
|
||||
#[non_exhaustive]
|
||||
pub enum PlayerState {
|
||||
#[default]
|
||||
Alive = 0,
|
||||
|
|
@ -54,6 +55,7 @@ impl Box {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
#[non_exhaustive]
|
||||
pub struct Player {
|
||||
pub entity: EntityId,
|
||||
pub position: Vector,
|
||||
|
|
@ -109,6 +111,7 @@ impl Player {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
#[non_exhaustive]
|
||||
pub struct Sentry {
|
||||
pub entity: EntityId,
|
||||
pub builder: UserId,
|
||||
|
|
@ -128,6 +131,7 @@ pub struct Sentry {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
#[non_exhaustive]
|
||||
pub struct Dispenser {
|
||||
pub entity: EntityId,
|
||||
pub builder: UserId,
|
||||
|
|
@ -144,6 +148,7 @@ pub struct Dispenser {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
#[non_exhaustive]
|
||||
pub struct Teleporter {
|
||||
pub entity: EntityId,
|
||||
pub builder: UserId,
|
||||
|
|
@ -164,6 +169,7 @@ pub struct Teleporter {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum Building {
|
||||
Sentry(Sentry),
|
||||
Dispenser(Dispenser),
|
||||
|
|
@ -269,6 +275,7 @@ impl Building {
|
|||
}
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
pub enum BuildingClass {
|
||||
Sentry,
|
||||
Dispenser,
|
||||
|
|
@ -276,6 +283,7 @@ pub enum BuildingClass {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[non_exhaustive]
|
||||
pub struct Projectile {
|
||||
pub id: EntityId,
|
||||
pub team: Team,
|
||||
|
|
@ -305,6 +313,7 @@ impl Projectile {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
#[non_exhaustive]
|
||||
pub enum PipeType {
|
||||
Regular = 0,
|
||||
Sticky = 1,
|
||||
|
|
@ -376,6 +385,7 @@ impl From<u8> for ProjectileType {
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[non_exhaustive]
|
||||
pub struct Collision {
|
||||
pub tick: DemoTick,
|
||||
pub target: EntityId,
|
||||
|
|
@ -383,12 +393,14 @@ pub struct Collision {
|
|||
}
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct World {
|
||||
pub boundary_min: Vector,
|
||||
pub boundary_max: Vector,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct Kill {
|
||||
pub attacker_id: u16,
|
||||
pub assister_id: u16,
|
||||
|
|
@ -410,6 +422,7 @@ impl Kill {
|
|||
}
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub struct GameState {
|
||||
pub players: Vec<Player>,
|
||||
pub buildings: BTreeMap<EntityId, Building>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue