updated pp-gen & pp-plot w.r.t. osu-tools output

This commit is contained in:
MaxOhn
2022-01-08 18:43:37 +01:00
parent 7c8fa159d3
commit 7b9bd0b1f4
3 changed files with 260 additions and 88 deletions
+89 -47
View File
@@ -28,7 +28,8 @@ async fn async_main() {
println!("Deserializing data from output.json...");
let file = StdFile::open("../pp-gen/output.json").expect("failed to open `output.json` file");
let data: Vec<Data> = serde_json::from_reader(file).expect("failed to deserialize data");
let data: Vec<SimulateData> =
serde_json::from_reader(file).expect("failed to deserialize data");
println!(
"Calculating values for {} map-mod combinations...",
@@ -39,10 +40,10 @@ async fn async_main() {
let result = data
.into_iter()
.map(|data| async move {
let path = format!("{}/{}.osu", map_path, data.map_id);
let path = format!("{}/{}.osu", map_path, data.score.map_id);
let file = File::open(path).await?;
let map = Beatmap::parse(file).await?;
let mods = parse_mods(&data.inner.mods);
let mods = parse_mods(&data.score.mods);
let attrs = map.max_pp(mods);
Ok::<_, Error>((data, attrs, mods))
@@ -67,7 +68,7 @@ async fn async_main() {
];
for (data, attributes, mods) in tuples {
evaluators[data.mode as usize].process(data, attributes, mods);
evaluators[data.score.mode as usize].process(data, attributes, mods);
}
for evaluator in evaluators {
@@ -78,8 +79,6 @@ async fn async_main() {
print_err(err);
}
}
println!("Done");
}
/// Mode specific evaluator containing differences
@@ -109,61 +108,62 @@ impl Evaluator {
/// For all mode-specific data points, calculate the
/// differences of `data`'s value and `attrs`' value
fn process(&mut self, data: Data, attrs: PerformanceAttributes, mods: u32) {
fn process(&mut self, data: SimulateData, attrs: PerformanceAttributes, mods: u32) {
self.count += 1;
self.stars.push(difference(data.inner.stars, attrs.stars()));
self.pp.push(difference(data.inner.pp, attrs.pp()));
self.stars
.push(difference(data.difficulty.stars, attrs.stars()));
self.pp.push(difference(data.performance.pp, attrs.pp()));
match attrs {
PerformanceAttributes::Fruits(_) => {}
PerformanceAttributes::Mania(attrs) => {
if let Some(acc) = data.inner.accuracy {
if let Some(acc) = data.performance.acc {
let values = self.accuracy.get_or_insert_with(Vec::new);
let entry = difference(acc, attrs.pp_acc);
values.push(entry);
}
if let Some(strain) = data.inner.strain {
if let Some(strain) = data.performance.difficulty {
let values = self.strain.get_or_insert_with(Vec::new);
let entry = difference(strain, attrs.pp_strain);
values.push(entry);
}
}
PerformanceAttributes::Osu(attrs) => {
if let Some(acc) = data.inner.accuracy {
if let Some(acc) = data.performance.acc {
let values = self.accuracy.get_or_insert_with(Vec::new);
let entry = difference(acc, attrs.pp_acc);
values.push(entry);
}
if let Some(aim) = data.inner.aim {
if let Some(aim) = data.performance.aim {
let values = self.aim.get_or_insert_with(Vec::new);
let entry = difference(aim, attrs.pp_aim);
values.push(entry);
}
if mods & 1024 > 0 {
if let Some(flashlight) = data.inner.flashlight {
if let Some(flashlight) = data.performance.flashlight {
let values = self.flashlight.get_or_insert_with(Vec::new);
let entry = difference(flashlight, attrs.pp_flashlight);
values.push(entry);
}
}
if let Some(speed) = data.inner.speed {
if let Some(speed) = data.performance.speed {
let values = self.speed.get_or_insert_with(Vec::new);
let entry = difference(speed, attrs.pp_speed);
values.push(entry);
}
}
PerformanceAttributes::Taiko(attrs) => {
if let Some(acc) = data.inner.accuracy {
if let Some(acc) = data.performance.acc {
let values = self.accuracy.get_or_insert_with(Vec::new);
let entry = difference(acc, attrs.pp_acc);
values.push(entry);
}
if let Some(strain) = data.inner.strain {
if let Some(strain) = data.performance.difficulty {
let values = self.strain.get_or_insert_with(Vec::new);
let entry = difference(strain, attrs.pp_strain);
values.push(entry);
@@ -220,7 +220,6 @@ impl Evaluator {
}
root.present()?;
println!("Finished plotting {}", mode);
Ok(())
}
@@ -295,8 +294,6 @@ impl Evaluator {
vec.reverse();
println!("---");
vec
}
}
@@ -350,12 +347,11 @@ fn difference(actual: f64, calculated: f64) -> f64 {
(actual - calculated).abs()
}
fn parse_mods(mods_str: &str) -> u32 {
fn parse_mods(mods_list: &[String]) -> u32 {
let mut mods = 0;
for m in mods_str.split(", ") {
match m {
"None" => {}
for m in mods_list {
match m.as_str() {
"NF" => mods += 1,
"EZ" => mods += 2,
"TD" => mods += 4,
@@ -382,33 +378,79 @@ fn print_err(err: Error) {
}
}
#[derive(Debug, Deserialize)]
struct Data {
mode: u32,
map_id: u32,
#[serde(flatten)]
inner: GenericData,
#[derive(Deserialize)]
struct SimulateData {
score: Score,
performance: Performance,
difficulty: Difficulty,
}
#[derive(Debug, Deserialize)]
struct GenericData {
#[serde(default, alias = "Aim")]
#[derive(Deserialize)]
struct Score {
mode: u32,
map_id: u32,
mods: Vec<String>,
total_score: u32,
acc: f64,
combo: u32,
stats: Statistics,
}
#[derive(Deserialize)]
struct Statistics {
#[serde(default)]
perfect: usize,
great: usize,
#[serde(default)]
good: usize,
ok: usize,
meh: usize,
miss: usize,
}
#[derive(Deserialize)]
struct Performance {
#[serde(default)]
aim: Option<f64>,
#[serde(default, alias = "Speed")]
#[serde(default)]
speed: Option<f64>,
#[serde(default, alias = "Accuracy")]
accuracy: Option<f64>,
#[serde(default, alias = "Flashlight")]
#[serde(default)]
acc: Option<f64>,
#[serde(default)]
flashlight: Option<f64>,
#[serde(default, alias = "Strain")]
strain: Option<f64>,
#[serde(default, alias = "OD")]
od: Option<f64>,
#[serde(default, alias = "AR")]
ar: Option<f64>,
#[serde(alias = "Mods")]
mods: String,
#[serde(alias = "Stars")]
stars: f64,
#[serde(default)]
effective_miss_count: Option<f64>,
#[serde(default)]
scaled_score: Option<f64>,
#[serde(default)]
difficulty: Option<f64>,
pp: f64,
}
#[derive(Deserialize)]
struct Difficulty {
stars: f64,
max_combo: u32,
#[serde(default)]
aim: Option<f64>,
#[serde(default)]
speed: Option<f64>,
#[serde(default)]
flashlight: Option<f64>,
#[serde(default)]
slider_factor: Option<f64>,
#[serde(default)]
stamina: Option<f64>,
#[serde(default)]
rhythm: Option<f64>,
#[serde(default)]
colour: Option<f64>,
#[serde(default)]
ar: Option<f64>,
#[serde(default)]
od: Option<f64>,
#[serde(default)]
great_hit_window: Option<f64>,
#[serde(default)]
score_multiplier: Option<f64>,
}