pub struct Parser<'a, R = SliceReader<'a>>where
R: BitsReader + MessageReader,{ /* private fields */ }Expand description
Main parser for Source 2 demo files.
The parser maintains the replay state and processes demo commands sequentially. It supports multiple observers that can react to different types of events.
§Examples
§Basic usage with chat messages
use source2_demo::prelude::*;
#[derive(Default)]
struct ChatLogger;
#[observer]
impl ChatLogger {
#[on_message]
fn on_chat(&mut self, ctx: &Context, msg: CDotaUserMsgChatMessage) -> ObserverResult {
println!("{}", msg.message_text());
Ok(())
}
}
fn main() -> anyhow::Result<()> {
let replay = std::fs::File::open("replay.dem")?;
let mut parser = Parser::from_reader(&replay)?;
parser.register_observer::<ChatLogger>();
parser.run_to_end()?;
Ok(())
}§Processing entities
use source2_demo::prelude::*;
#[derive(Default)]
struct HeroTracker;
impl Observer for HeroTracker {
fn interests(&self) -> Interests {
Interests::ENABLE_ENTITY | Interests::TRACK_ENTITY
}
fn on_entity(&mut self, ctx: &Context, event: EntityEvents, entity: &Entity) -> ObserverResult {
if entity.class().name().starts_with("CDOTA_Unit_Hero_") {
let health: i32 = property!(entity, "m_iHealth");
println!("Hero {} health: {}", entity.class().name(), health);
}
Ok(())
}
}Implementations§
Source§impl<'a> Parser<'a, SliceReader<'a>>
impl<'a> Parser<'a, SliceReader<'a>>
Sourcepub fn new(replay: &'a [u8]) -> Result<Self, ParserError>
pub fn new(replay: &'a [u8]) -> Result<Self, ParserError>
Creates a new parser instance from replay bytes.
This method validates the replay file format and reads the file header. The replay data should remain valid for the lifetime of the parser.
§Arguments
replay- Byte slice containing the demo file data (typically memory-mapped)
§Errors
Returns ParserError::WrongMagic if the file is not a valid Source 2 demo file.
Returns ParserError::ReplayEncodingError if the file header is corrupted.
§Examples
use source2_demo::prelude::*;
use std::fs::File;
// Using memory-mapped file (recommended for large files)
let file = File::open("replay.dem")?;
let replay = unsafe { memmap2::Mmap::map(&file)? };
let parser = Parser::new(&replay)?;
// Or read into memory (for small files)
let replay = std::fs::read("replay.dem")?;
let parser = Parser::new(&replay)?;Sourcepub fn from_slice(replay: &'a [u8]) -> Result<Self, ParserError>
pub fn from_slice(replay: &'a [u8]) -> Result<Self, ParserError>
Creates a new parser from replay bytes (same as new).
This is an alias for Parser::new that makes it explicit if you’re using a slice.
§Arguments
replay- Byte slice containing the demo file data
§Errors
Returns ParserError::WrongMagic if the file is not a valid Source 2 demo file.
Source§impl<S> Parser<'static, SeekableReader<S>>
impl<S> Parser<'static, SeekableReader<S>>
Sourcepub fn from_reader(reader: S) -> Result<Self, ParserError>
pub fn from_reader(reader: S) -> Result<Self, ParserError>
Creates a new parser from a reader.
Uses SeekableReader for reading data from the reader, but internally uses SliceReader for parsing message buffers for maximum performance.
§Arguments
reader- Any type implementing Read + Seek (e.g., File, Cursor, BufReader)
§Errors
Returns an error if reading from the reader fails or data is invalid.
§Examples
use source2_demo::prelude::*;
use std::fs::File;
let file = File::open("replay.dem")?;
let mut parser = Parser::from_reader(file)?;
parser.run_to_end()?;Source§impl<'a, R> Parser<'a, R>where
R: BitsReader + MessageReader,
impl<'a, R> Parser<'a, R>where
R: BitsReader + MessageReader,
Sourcepub fn context(&self) -> &Context
pub fn context(&self) -> &Context
Returns a reference to the current parser context.
The context contains the current state of the replay, including
- Entities and their properties
- String tables
- Game events
- Current tick and game build
§Examples
use source2_demo::prelude::*;
let parser = Parser::from_reader(&replay)?;
let ctx = parser.context();
println!("Current tick: {}", ctx.tick());
println!("Game build: {}", ctx.game_build());Sourcepub fn replay_info(&self) -> &CDemoFileInfo
pub fn replay_info(&self) -> &CDemoFileInfo
Returns replay file information. Contains metadata about the replay including:
- Playback duration
- Server information
- Game-specific details
§Examples
use source2_demo::prelude::*;
let parser = Parser::from_reader(&replay)?;
let info = parser.replay_info();
println!("Playback ticks: {}", info.playback_ticks());Sourcepub fn register_observer<T>(&mut self) -> Rc<RefCell<T>>
pub fn register_observer<T>(&mut self) -> Rc<RefCell<T>>
Registers an observer and returns a reference-counted handle to it.
Observers must implement the Observer trait and Default.
Use the #[observer] attribute macro to automatically implement the trait.
The returned Rc<RefCell<T>> allows you to access the observer’s state
after parsing completes.
§Type Parameters
§Examples
use source2_demo::prelude::*;
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Default)]
struct Stats {
message_count: usize,
}
#[observer]
impl Stats {
#[on_message]
fn on_chat(&mut self, ctx: &Context, msg: CDotaUserMsgChatMessage) -> ObserverResult {
self.message_count += 1;
Ok(())
}
}
let mut parser = Parser::from_reader(&replay)?;
let stats = parser.register_observer::<Stats>();
parser.run_to_end()?;
println!("Total messages: {}", stats.borrow().message_count);