### Build TF Demo Parser with Cargo Source: https://github.com/demostf/parser/blob/master/README.md This command builds the TF Demo Parser project in release mode using Cargo. It requires Rust and Cargo to be installed. The resulting binary will be placed in the `target/release/` directory. ```bash cargo build --release ``` -------------------------------- ### Handle Demo Data with Custom Analyzer in Rust Source: https://github.com/demostf/parser/blob/master/README.md This Rust code illustrates how to use a custom `Analyser` with the `tf_demo_parser` crate to process demo data. It shows the instantiation of `DemoParser` with a custom analyzer and the subsequent parsing of the demo file, returning the header and state. ```rust DemoParser::new_all_with_analyser(demo.get_stream(), CustomAnalyser::new()); let (header, state) = parser.parse()?; ``` -------------------------------- ### Process Demo Data Packet by Packet for Memory-Efficient Streaming (Rust) Source: https://context7.com/demostf/parser/llms.txt Reads a demo file, initializes a `DemoHandler` and `RawPacketStream`, and processes the demo data packet by packet. This method is memory-efficient for large demo files. It reads the header first and then streams packets, allowing for real-time handling of game events. Includes a warning for incomplete demo files. Requires `tf_demo_parser` and `bitbuffer` crates. ```rust use bitbuffer::BitRead; use std::fs; use tf_demo_parser::demo::header::Header; use tf_demo_parser::demo::parser::{DemoHandler, RawPacketStream}; use tf_demo_parser::Demo; fn main() -> Result<(), Box> { let file = fs::read("match.dem")?; let demo = Demo::new(&file); // Initialize handler let mut handler = DemoHandler::default(); // Read header let mut stream = demo.get_stream(); let header = Header::read(&mut stream)?; handler.handle_header(&header); println!("Processing demo: {} on {}", header.nick, header.map); // Stream packets let mut packets = RawPacketStream::new(stream); let mut packet_count = 0; while let Some(packet) = packets.next(&handler.state_handler)? { handler.handle_packet(packet)?; packet_count += 1; if packet_count % 1000 == 0 { println!("Processed {} packets", packet_count); } } // Check if demo was complete if packets.incomplete { eprintln!("Warning: Demo file is incomplete"); } println!("Total packets: {}", packet_count); Ok(()) } ``` -------------------------------- ### Parse Demo File and Extract Match Summary with Player Statistics (Rust) Source: https://context7.com/demostf/parser/llms.txt Initializes a Demo object from a file, parses it using the default analyzer, and extracts header information like map, server, and duration, along with match state data such as deaths, rounds, and player counts. It iterates through deaths and chat messages to display detailed event information. Requires the `tf_demo_parser` crate. ```rust use std::fs; use tf_demo_parser::{Demo, DemoParser}; fn main() -> Result<(), Box> { // Read demo file let file = fs::read("match.dem")?; // Create demo instance let demo = Demo::new(&file); // Parse with default analyzer let parser = DemoParser::new(demo.get_stream()); let (header, state) = parser.parse()?; // Access header information println!("Map: {}", header.map); println!("Server: {}", header.server); println!("Duration: {}s", header.duration); println!("Player nick: {}", header.nick); // Access match state println!("\nDeaths: {}", state.deaths.len()); println!("Rounds: {}", state.rounds.len()); println!("Players: {}", state.users.len()); // Iterate through deaths for death in &state.deaths { println!("Player {} killed by {} with {}", death.victim, death.killer, death.weapon); } // Access chat messages for chat in &state.chat { println!("[{}] {}: {}", chat.tick, chat.from, chat.text); } Ok(()) } ``` -------------------------------- ### Create Demo from Owned Bytes in Rust Source: https://context7.com/demostf/parser/llms.txt This Rust code reads a demo file into an owned `Vec`, creates a `Demo` object using `Demo::owned()`, and then parses it. It demonstrates how the owned `Demo` can be passed to other functions, such as `process_demo_elsewhere`, without lifetime constraints. ```rust use std::fs; use tf_demo_parser::{Demo, DemoParser}; fn main() -> Result<(), Box> { // Read file into owned Vec let bytes = fs::read("match.dem")?; // Create demo with owned data (static lifetime) let demo = Demo::owned(bytes); // Parse normally let parser = DemoParser::new(demo.get_stream()); let (header, state) = parser.parse()?; println!("Parsed demo: {}", header.map); println!("Players: {}", state.users.len()); // Demo now owns the data and can be moved freely process_demo_elsewhere(demo)?; Ok(()) } fn process_demo_elsewhere(demo: Demo<'static>) -> Result<(), Box> { // Can use demo in different context with static lifetime let parser = DemoParser::new(demo.get_stream()); let (_, state) = parser.parse()?; println!("Found {} deaths", state.deaths.len()); Ok(()) } ``` -------------------------------- ### Untitled No description -------------------------------- ### Parse Player Statistics and Class Info in Rust Source: https://context7.com/demostf/parser/llms.txt Parses a TF2 demo file to extract detailed player statistics, including class playtime, kills, deaths, assists, and top weapon usage. It reads the demo file, parses its content, and iterates through player data to display collected information. No external dependencies beyond the `tf_demo_parser` crate are required. ```rust use std::fs; use tf_demo_parser::demo::parser::analyser::{Class, Team}; use tf_demo_parser::{Demo, DemoParser}; fn main() -> Result<(), Box> { let file = fs::read("match.dem")?; let demo = Demo::new(&file); let parser = DemoParser::new(demo.get_stream()); let (header, state) = parser.parse()?; println!("Match on {} ", header.map); // Analyze each player for (user_id, user_info) in &state.users { println!("Player: {} ({})", user_info.name, user_info.steam_id); println!(" Team: {}", user_info.team); // Get classes sorted by playtime let classes: Vec<_> = user_info.classes.sorted().collect(); println!(" Classes played:"); for (class, spawns) in classes { println!(" {}: {} spawns", class, spawns); } // Count kills and deaths let kills = state.deaths.iter() .filter(|d| d.killer == *user_id) .count(); let deaths = state.deaths.iter() .filter(|d| d.victim == *user_id) .count(); let assists = state.deaths.iter() .filter(|d| d.assister.map_or(false, |a| a == *user_id)) .count(); println!(" K/D/A: {}/{}/{}", kills, deaths, assists); // Weapon usage let mut weapons: std::collections::HashMap<&str, usize> = std::collections::HashMap::new(); for death in &state.deaths { if death.killer == *user_id { *weapons.entry(&death.weapon).or_insert(0) += 1; } } if !weapons.is_empty() { println!(" Weapon usage:"); let mut weapon_list: Vec<_> = weapons.into_iter().collect(); weapon_list.sort_by_key(|(_, count)| std::cmp::Reverse(*count)); for (weapon, count) in weapon_list.iter().take(3) { println!(" {}: {} kills", weapon, count); } } println!(); } // Round information println!("Rounds played: {}", state.rounds.len()); for (i, round) in state.rounds.iter().enumerate() { println!( " Round {}: {} won in {:.1}s (tick {})", i + 1, round.winner, round.length, round.end_tick ); } Ok(()) } ``` -------------------------------- ### Loop Through Demo Packets in Rust Source: https://github.com/demostf/parser/blob/master/README.md This Rust code snippet demonstrates how to read a tf2 demo file, parse its header, and then iterate through all the raw packets within the stream. It uses the `tf_demo_parser` crate and `bitbuffer` for reading packet data. The handler processes each packet, and an assertion checks for incomplete streams. ```rust use bitbuffer::BitRead; use main_error::MainError; use std::fs; use tf_demo_parser::demo::header::Header; use tf_demo_parser::demo::parser::{DemoHandler, RawPacketStream}; use tf_demo_parser::Demo; fn main() -> Result<(), MainError> { let file = fs::read("demofile.dem")?; let demo = Demo::new(&file); let mut handler = DemoHandler::default(); let mut stream = demo.get_stream(); let header = Header::read(&mut stream)?; handler.handle_header(&header); let mut packets = RawPacketStream::new(stream); while let Some(packet) = packets.next(&handler.state_handler)? { handler.handle_packet(packet).unwrap(); } assert_eq!(false, packets.incomplete); Ok(()) } ``` -------------------------------- ### Process Game Events and Chat Messages in Rust Source: https://context7.com/demostf/parser/llms.txt Demonstrates parsing a TF2 demo file to analyze game events like player spawns, deaths, and round outcomes, as well as extracting chat messages. It utilizes a custom `MessageHandler` implementation for game events and then re-parses the demo for chat data. Requires the `tf_demo_parser` crate. ```rust use std::fs; use tf_demo_parser::demo::gameevent_gen::GameEvent; use tf_demo_parser::demo::parser::MessageHandler; use tf_demo_parser::demo::message::Message; use tf_demo_parser::demo::data::DemoTick; use tf_demo_parser::{Demo, DemoParser, MessageType, ParserState}; #[derive(Default)] struct EventAnalyzer { player_spawns: usize, player_deaths: usize, round_events: usize, } impl MessageHandler for EventAnalyzer { type Output = Self; fn does_handle(message_type: MessageType) -> bool { matches!(message_type, MessageType::GameEvent) } fn handle_message(&mut self, message: &Message, _tick: DemoTick, _state: &ParserState) { if let Message::GameEvent(msg) = message { match &msg.event { GameEvent::PlayerSpawn(_) => self.player_spawns += 1, GameEvent::PlayerDeath(_) => self.player_deaths += 1, GameEvent::TeamPlayRoundWin(_) | GameEvent::TeamPlayRoundStart(_) => self.round_events += 1, _ => {} } } } fn into_output(self, _state: &ParserState) -> Self::Output { self } } fn main() -> Result<(), Box> { let file = fs::read("match.dem")?; let demo = Demo::new(&file); // Parse with event analyzer let parser = DemoParser::new_with_analyser( demo.get_stream(), EventAnalyzer::default() ); let (header, events) = parser.parse()?; println!("Demo: {} on {} ", header.nick, header.map); println!("Game Events:"); println!(" Player spawns: {}", events.player_spawns); println!(" Player deaths: {}", events.player_deaths); println!(" Round events: {}", events.round_events); // Re-parse for chat messages let demo2 = Demo::new(&file); let parser2 = DemoParser::new(demo2.get_stream()); let (_, state) = parser2.parse()?; println!("\nChat Messages:"); for chat in &state.chat { let time = (chat.tick as f32) * state.interval_per_tick; println!("[{:.1}s] {}: {}", time, chat.from, chat.text); } Ok(()) } ``` -------------------------------- ### Untitled No description -------------------------------- ### Untitled No description -------------------------------- ### Tick-by-Tick State Inspection with tf-demo-parser in Rust Source: https://context7.com/demostf/parser/llms.txt This snippet demonstrates how to use the ticker functionality of tf-demo-parser in Rust to inspect the game state at each tick of a Team Fortress 2 demo file. It creates a parser with an analyser, retrieves a ticker for step-by-step processing, and then iterates through each tick to access and print information about deaths and entity counts. Finally, it prints the final statistics of the demo. ```rust use std::fs; use tf_demo_parser::demo::parser::analyser::{Analyser, MatchState}; use tf_demo_parser::{Demo, DemoParser}; fn main() -> Result<(), Box> { let file = fs::read("match.dem")?; let demo = Demo::new(&file); // Create parser with analyzer that supports borrowing let parser = DemoParser::new_with_analyser(demo.get_stream(), Analyser::new()); // Get ticker for step-by-step processing let (header, mut ticker) = parser.ticker()?; println!("Analyzing demo: {} on {}", header.nick, header.map); let mut tick_count = 0; let mut previous_deaths = 0; // Process each tick while let Some(tick_state) = ticker.next()? { tick_count += 1; // Access state at current tick let current_deaths = tick_state.state.deaths.len(); // Detect new deaths if current_deaths > previous_deaths { let death = &tick_state.state.deaths[current_deaths - 1]; println!( "Tick {}: Player {} killed by {} with {}", tick_state.tick, death.victim, death.killer, death.weapon ); } previous_deaths = current_deaths; // Access parser state for entity information let entity_count = tick_state.parser_state.entities.len(); if tick_count % 1000 == 0 { println!("Tick {}: {} entities tracked", tick_state.tick, entity_count); } } // Get final state let final_state = ticker.into_state(); println!("\nFinal statistics:"); println!(" Total deaths: {}", final_state.deaths.len()); println!(" Total rounds: {}", final_state.rounds.len()); println!(" Players: {}", final_state.users.len()); Ok(()) } ``` -------------------------------- ### Custom Analyzer for Entity Properties in Rust Source: https://context7.com/demostf/parser/llms.txt This snippet demonstrates how to implement a custom analyzer with tf-demo-parser in Rust to track and extract specific entity properties from a Team Fortress 2 demo file. It defines a `PropAnalyzer` struct that implements the `MessageHandler` trait to collect send property identifiers and names. The analyzer outputs a sorted list of unique properties found in the demo. ```rust use fnv::{FnvHashMap, FnvHashSet}; use std::fs; use tf_demo_parser::demo::data::DemoTick; use tf_demo_parser::demo::message::Message; use tf_demo_parser::demo::packet::datatable::{ParseSendTable, ServerClass}; use tf_demo_parser::demo::parser::MessageHandler; use tf_demo_parser::demo::sendprop::{SendPropIdentifier, SendPropName}; use tf_demo_parser::{Demo, DemoParser, MessageType, ParserState}; // Custom analyzer to track all entity properties #[derive(Default)] struct PropAnalyzer { props: FnvHashSet, prop_names: FnvHashMap, } impl MessageHandler for PropAnalyzer { type Output = Vec; fn does_handle(message_type: MessageType) -> bool { matches!(message_type, MessageType::PacketEntities) } fn handle_message(&mut self, message: &Message, _tick: DemoTick, _state: &ParserState) { if let Message::PacketEntities(msg) = message { for entity in &msg.entities { for prop in &entity.props { self.props.insert(prop.identifier); } } } } fn handle_data_tables( &mut self, parse_tables: &[ParseSendTable], _server_classes: &[ServerClass], _state: &ParserState, ) { for table in parse_tables { for prop_def in &table.props { self.prop_names.insert( prop_def.identifier(), (table.name.to_string(), prop_def.name.clone()), ); } } } fn into_output(self, _state: &ParserState) -> Self::Output { let mut props: Vec = self.props .into_iter() .filter_map(|prop| { self.prop_names.get(&prop).map(|(table, name)| { format!("{}.{}", table, name) }) }) .collect(); props.sort(); props } } fn main() -> Result<(), Box> { let file = fs::read("match.dem")?; let demo = Demo::new(&file); // Use custom analyzer let parser = DemoParser::new_with_analyser( demo.get_stream(), PropAnalyzer::default() ); let (header, props) = parser.parse()?; println!("Demo: {} on {}", header.nick, header.map); println!("Found {} unique properties:", props.len()); for prop in props.iter().take(10) { println!(" {}", prop); } Ok(()) } ``` -------------------------------- ### Untitled No description -------------------------------- ### Untitled No description === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.