Skip to content

Commit b6030b8

Browse files
committed
tools/demo_check_seeking: Test demo seeking implementation
1 parent bc3bfd3 commit b6030b8

1 file changed

Lines changed: 157 additions & 0 deletions

File tree

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
use clap::App;
2+
use clap::Arg;
3+
use libtw2_demo::ddnet;
4+
use libtw2_demo::ddnet::DemoReader;
5+
use libtw2_gamenet_ddnet::Protocol as DDNet;
6+
use libtw2_warn as warn;
7+
use std::error::Error;
8+
use std::fs::File;
9+
use std::io::BufReader;
10+
11+
trait SeekableDemo {
12+
fn stream_position(&mut self) -> Result<u64, Box<dyn Error>>;
13+
fn seek(&mut self, pos: u64) -> Result<(), Box<dyn Error>>;
14+
fn next_keyframe(&mut self) -> Result<Option<(i32, u64)>, Box<dyn Error>>;
15+
fn seek_keyframe_for_tick(
16+
&mut self,
17+
target_tick: i32,
18+
) -> Result<Option<(i32, u64)>, Box<dyn Error>>;
19+
}
20+
21+
impl SeekableDemo for DemoReader<'static, DDNet> {
22+
fn stream_position(&mut self) -> Result<u64, Box<dyn Error>> {
23+
self.stream_position().map_err(Into::into)
24+
}
25+
fn seek(&mut self, pos: u64) -> Result<(), Box<dyn Error>> {
26+
self.seek(pos).map_err(Into::into)
27+
}
28+
fn next_keyframe(&mut self) -> Result<Option<(i32, u64)>, Box<dyn Error>> {
29+
loop {
30+
let position = self.stream_position()?;
31+
let Some(chunk) = self.next_chunk(&mut warn::Ignore)? else {
32+
return Ok(None);
33+
};
34+
if let ddnet::Chunk::Tick {
35+
keyframe: true,
36+
tick,
37+
} = chunk
38+
{
39+
return Ok(Some((tick, position)));
40+
}
41+
}
42+
}
43+
fn seek_keyframe_for_tick(
44+
&mut self,
45+
target_tick: i32,
46+
) -> Result<Option<(i32, u64)>, Box<dyn Error>> {
47+
self.next_keyframe_position_for_tick(target_tick, &mut warn::Ignore)
48+
.map_err(Into::into)
49+
}
50+
}
51+
impl SeekableDemo for libtw2_demo::Reader<'static> {
52+
fn stream_position(&mut self) -> Result<u64, Box<dyn Error>> {
53+
self.stream_position().map_err(Into::into)
54+
}
55+
fn seek(&mut self, pos: u64) -> Result<(), Box<dyn Error>> {
56+
self.seek(pos).map_err(Into::into)
57+
}
58+
fn next_keyframe(&mut self) -> Result<Option<(i32, u64)>, Box<dyn Error>> {
59+
loop {
60+
let position = self.stream_position()?;
61+
let Some(chunk) = self.read_chunk(&mut warn::Ignore)? else {
62+
return Ok(None);
63+
};
64+
if let libtw2_demo::RawChunk::Tick {
65+
keyframe: true,
66+
tick,
67+
} = chunk
68+
{
69+
return Ok(Some((tick, position)));
70+
}
71+
}
72+
}
73+
fn seek_keyframe_for_tick(
74+
&mut self,
75+
target_tick: i32,
76+
) -> Result<Option<(i32, u64)>, Box<dyn Error>> {
77+
self.next_keyframe_position_for_tick(target_tick, &mut warn::Ignore)
78+
.map_err(Into::into)
79+
}
80+
}
81+
82+
fn main() -> Result<(), Box<dyn Error>> {
83+
libtw2_logger::init();
84+
let matches = App::new("Demo Seek Tests")
85+
.about("Performs various seeks patterns on a demo to verify that seeking works as expected")
86+
.arg(
87+
Arg::with_name("INPUT_DEMO")
88+
.help("Sets the demo file to read")
89+
.required(true),
90+
)
91+
.arg(
92+
Arg::with_name("DDNET")
93+
.long("ddnet")
94+
.help("Interpret the demo as a DDNet demo"),
95+
)
96+
.get_matches();
97+
98+
let input = matches.value_of("INPUT_DEMO").unwrap();
99+
let input_file = BufReader::new(File::open(input)?);
100+
let mut reader: Box<dyn SeekableDemo> = if matches.is_present("DDNET") {
101+
Box::new(DemoReader::<DDNet>::new(input_file, &mut warn::Log)?)
102+
} else {
103+
Box::new(libtw2_demo::Reader::new(input_file, &mut warn::Ignore)?)
104+
};
105+
let start = reader.stream_position()?;
106+
let mut keyframes = Vec::new();
107+
while let Some(keyframe) = reader.next_keyframe()? {
108+
keyframes.push(keyframe);
109+
}
110+
println!(
111+
"Demo parsed without errors, found {} keyframes",
112+
keyframes.len()
113+
);
114+
115+
let mut tester = Tester {
116+
reader,
117+
start,
118+
keyframes,
119+
};
120+
tester.test_seek_all_keyframes_directly()?;
121+
println!("Seeking keyframes directly succeeded");
122+
Ok(())
123+
}
124+
125+
struct Tester {
126+
reader: Box<dyn SeekableDemo>,
127+
start: u64,
128+
keyframes: Vec<(i32, u64)>,
129+
}
130+
131+
impl Tester {
132+
fn test_seek_all_keyframes_directly(&mut self) -> Result<(), Box<dyn Error>> {
133+
// First seek from start
134+
self.reader.seek(self.start)?;
135+
for (tick, pos) in &self.keyframes {
136+
let found = self.reader.seek_keyframe_for_tick(*tick)?;
137+
assert_eq!(found, Some((*tick, *pos)));
138+
}
139+
// Seek from all previous keyframes
140+
for (i, (tick, pos)) in self.keyframes.iter().enumerate() {
141+
for (_, seek_pos) in &self.keyframes[..=i] {
142+
self.reader.seek(*seek_pos)?;
143+
let found = self.reader.seek_keyframe_for_tick(*tick)?;
144+
assert_eq!(found, Some((*tick, *pos)));
145+
}
146+
}
147+
// Seek to all previous keyframes
148+
for (i, (_, seek_pos)) in self.keyframes.iter().enumerate() {
149+
self.reader.seek(*seek_pos)?;
150+
for (tick, _) in &self.keyframes[..i] {
151+
let found = self.reader.seek_keyframe_for_tick(*tick)?;
152+
assert_eq!(found, None);
153+
}
154+
}
155+
Ok(())
156+
}
157+
}

0 commit comments

Comments
 (0)