Skip to main content

example_1/
example_1.rs

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    // Check if the file exists
8    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    // Parse the replay file
17    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            // Hit counts
32            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            // RNG seed
41            if let Some(seed) = replay.rng_seed {
42                println!("\n=== RNG Seed ===");
43                println!("Seed: {}", seed);
44            }
45
46            // Life bar information
47            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            // Replay data information
67            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            // Calculate total replay duration
119            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            // Try to write the replay back to verify our packer works
136            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                    // Verify by reading it back
143                    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            // Test uncompressed packing
161            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                    // Compare file sizes
172                    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                    // Verify uncompressed replay can be read back
186                    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}