1use rosu_replay::{Replay, ReplayEvent};
2use std::path::Path;
3
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 let osr_path = Path::new("assets/test.osr");
6
7 if !osr_path.exists() {
9 eprintln!("Error: File 'assets/test.osr' not found!");
10 eprintln!("Please place a valid .osr file at 'assets/test.osr' to run this example.");
11 return Ok(());
12 }
13
14 println!("Reading replay from: {}", osr_path.display());
15
16 match Replay::from_path(osr_path) {
18 Ok(replay) => {
19 println!("\n=== Replay Information ===");
20 println!("Username: {}", replay.username);
21 println!("Game Mode: {:?}", replay.mode);
22 println!("Game Version: {}", replay.game_version);
23 println!("Beatmap Hash: {}", replay.beatmap_hash);
24 println!("Score: {}", replay.score);
25 println!("Max Combo: {}", replay.max_combo);
26 println!("Perfect: {}", replay.perfect);
27 println!("Mods: {:?} (value: {})", replay.mods, replay.mods.value());
28 println!("Timestamp: {}", replay.timestamp);
29 println!("Replay ID: {}", replay.replay_id);
30
31 println!("\n=== Hit Counts ===");
33 println!("300s: {}", replay.count_300);
34 println!("100s: {}", replay.count_100);
35 println!("50s: {}", replay.count_50);
36 println!("Gekis: {}", replay.count_geki);
37 println!("Katus: {}", replay.count_katu);
38 println!("Misses: {}", replay.count_miss);
39
40 if let Some(seed) = replay.rng_seed {
42 println!("\n=== RNG Seed ===");
43 println!("Seed: {}", seed);
44 }
45
46 if let Some(ref life_bar) = replay.life_bar_graph {
48 println!("\n=== Life Bar ===");
49 println!("Life bar states: {}", life_bar.len());
50 if !life_bar.is_empty() {
51 println!(
52 "First state: time={}ms, life={}",
53 life_bar[0].time, life_bar[0].life
54 );
55 println!(
56 "Last state: time={}ms, life={}",
57 life_bar[life_bar.len() - 1].time,
58 life_bar[life_bar.len() - 1].life
59 );
60 }
61 } else {
62 println!("\n=== Life Bar ===");
63 println!("No life bar data available");
64 }
65
66 println!("\n=== Replay Data ===");
68 println!("Total events: {}", replay.replay_data.len());
69
70 if !replay.replay_data.is_empty() {
71 println!("\nFirst 5 events:");
72 for (i, event) in replay.replay_data.iter().take(5).enumerate() {
73 match event {
74 ReplayEvent::Osu(e) => {
75 println!(
76 " {}: Osu - time_delta={}ms, x={}, y={}, keys={}",
77 i + 1,
78 e.time_delta,
79 e.x,
80 e.y,
81 e.keys.value()
82 );
83 }
84 ReplayEvent::Taiko(e) => {
85 println!(
86 " {}: Taiko - time_delta={}ms, x={}, keys={}",
87 i + 1,
88 e.time_delta,
89 e.x,
90 e.keys.value()
91 );
92 }
93 ReplayEvent::Catch(e) => {
94 println!(
95 " {}: Catch - time_delta={}ms, x={}, dashing={}",
96 i + 1,
97 e.time_delta,
98 e.x,
99 e.dashing
100 );
101 }
102 ReplayEvent::Mania(e) => {
103 println!(
104 " {}: Mania - time_delta={}ms, keys={}",
105 i + 1,
106 e.time_delta,
107 e.keys.value()
108 );
109 }
110 }
111 }
112
113 if replay.replay_data.len() > 5 {
114 println!(" ... and {} more events", replay.replay_data.len() - 5);
115 }
116 }
117
118 let total_time: i32 = replay
120 .replay_data
121 .iter()
122 .map(|event| event.time_delta())
123 .sum();
124
125 if total_time > 0 {
126 let minutes = total_time / 60000;
127 let seconds = (total_time % 60000) / 1000;
128 let milliseconds = total_time % 1000;
129 println!(
130 "\nTotal replay duration: {}:{:02}.{:03}",
131 minutes, seconds, milliseconds
132 );
133 }
134
135 println!("\n=== Testing Write Functionality ===");
137 let output_path = "assets/test_output.osr";
138 match replay.write_path(output_path) {
139 Ok(()) => {
140 println!("Successfully wrote replay to: {}", output_path);
141
142 match Replay::from_path(output_path) {
144 Ok(replay_copy) => {
145 println!("Successfully verified written replay!");
146 println!("Original username: {}", replay.username);
147 println!("Copy username: {}", replay_copy.username);
148 println!("Scores match: {}", replay.score == replay_copy.score);
149 }
150 Err(e) => {
151 eprintln!("Error reading back written replay: {}", e);
152 }
153 }
154 }
155 Err(e) => {
156 eprintln!("Error writing replay: {}", e);
157 }
158 }
159
160 println!("\n=== Testing Uncompressed Packing ===");
162 let uncompressed_path = "assets/test_uncompressed.osr";
163 match replay.pack_uncompressed() {
164 Ok(uncompressed_data) => {
165 std::fs::write(uncompressed_path, &uncompressed_data)?;
166 println!(
167 "Successfully wrote uncompressed replay to: {}",
168 uncompressed_path
169 );
170
171 let compressed_size = std::fs::metadata(output_path)?.len();
173 let uncompressed_size = std::fs::metadata(uncompressed_path)?.len();
174
175 println!("Compressed file size: {} bytes", compressed_size);
176 println!("Uncompressed file size: {} bytes", uncompressed_size);
177 println!(
178 "Size difference: {} bytes ({}%)",
179 uncompressed_size as i64 - compressed_size as i64,
180 ((uncompressed_size as f64 - compressed_size as f64)
181 / compressed_size as f64
182 * 100.0) as i32
183 );
184
185 match Replay::from_path(uncompressed_path) {
187 Ok(replay_uncompressed) => {
188 println!("Successfully verified uncompressed replay!");
189 println!(
190 "Scores match: {}",
191 replay.score == replay_uncompressed.score
192 );
193 println!(
194 "Event counts match: {}",
195 replay.replay_data.len() == replay_uncompressed.replay_data.len()
196 );
197 }
198 Err(e) => {
199 eprintln!("Error reading back uncompressed replay: {}", e);
200 }
201 }
202 }
203 Err(e) => {
204 eprintln!("Error packing uncompressed replay: {}", e);
205 }
206 }
207 }
208 Err(e) => {
209 eprintln!("Error reading replay: {}", e);
210 eprintln!("Make sure the file is a valid .osr replay file.");
211 }
212 }
213
214 Ok(())
215}