From a03ecc7ee8d8b376814a574a005d6dc36a10ffa3 Mon Sep 17 00:00:00 2001 From: Piotrekol <4990365+Piotrekol@users.noreply.github.com> Date: Sat, 18 Mar 2023 14:03:44 +0100 Subject: [PATCH] Fix: Use hit object density instead of strains for Mania --- PpCalculator/PpCalculator.cs | 33 ++++++++++++ PpCalculatorTypes/IPpCalculator.cs | 5 ++ .../Extensions/PpCalculatorExtensions.cs | 51 +++++++++++++++---- 3 files changed, 78 insertions(+), 11 deletions(-) diff --git a/PpCalculator/PpCalculator.cs b/PpCalculator/PpCalculator.cs index 910d1a93..7c61a5c9 100644 --- a/PpCalculator/PpCalculator.cs +++ b/PpCalculator/PpCalculator.cs @@ -79,6 +79,8 @@ public virtual string[] Mods private Lazy scoreMultiplier = new Lazy(() => 1d); public double ScoreMultiplier => scoreMultiplier.Value; public bool UseScoreMultiplier { get; set; } = true; + public bool HasFullBeatmap { get; private set; } = false; + static PpCalculator() { //Required for <=v4 maps @@ -94,6 +96,7 @@ public object Clone() ppCalculator.LastMods = LastMods; ppCalculator.scoreMultiplier = scoreMultiplier; ppCalculator.UseScoreMultiplier = UseScoreMultiplier; + ppCalculator.HasFullBeatmap = HasFullBeatmap; if (PerformanceCalculator != null) { ppCalculator.ScoreInfo.Mods = ScoreInfo.Mods.Select(m => m.DeepClone()).ToArray(); @@ -176,6 +179,7 @@ private PpCalculatorTypes.PerformanceAttributes InternalCalculate(CancellationTo if (!hitObjects.Any()) return null; + HasFullBeatmap = !(startTime.HasValue || endTime.HasValue); var workingBeatmap = WorkingBeatmap; if (startTime.HasValue) { @@ -219,6 +223,35 @@ private PpCalculatorTypes.PerformanceAttributes InternalCalculate(CancellationTo } } + public int[] CalculateProgressGraphValues(CancellationToken cancellationToken, int amount = 100) + { + if (!HasFullBeatmap) + Calculate(cancellationToken); + + var hitObjects = PlayableBeatmap.HitObjects; + var values = new int[amount]; + if (!hitObjects.Any()) + return Array.Empty(); + + var firstObjectTime = hitObjects.First().StartTime; + var lastObjectTime = hitObjects.Max(o => o.GetEndTime()); + + if (lastObjectTime == 0) + lastObjectTime = hitObjects.Last().StartTime; + + double interval = (lastObjectTime - firstObjectTime + 1) / amount; + foreach (var hitObject in hitObjects) + { + double endTime = hitObject.GetEndTime(); + int startRange = (int)((hitObject.StartTime - firstObjectTime) / interval); + int endRange = (int)((endTime - firstObjectTime) / interval); + for (int i = startRange; i <= endRange; i++) + values[i]++; + } + + return values; + } + private List GetOsuMods(Ruleset ruleset) { var mods = new List(); diff --git a/PpCalculatorTypes/IPpCalculator.cs b/PpCalculatorTypes/IPpCalculator.cs index 82813723..e1a7829c 100644 --- a/PpCalculatorTypes/IPpCalculator.cs +++ b/PpCalculatorTypes/IPpCalculator.cs @@ -19,9 +19,14 @@ public interface IPpCalculator int RulesetId { get; } double BeatmapLength { get; } bool UseScoreMultiplier { get; set; } + /// + /// Whenever last call was used with limited start/end times, therefore affected Difficulty results + /// + bool HasFullBeatmap { get; } void PreProcess(string file); DifficultyAttributes DifficultyAttributesAt(double time); PerformanceAttributes Calculate(CancellationToken cancellationToken, double? startTime = null, double? endTime = null); + int[] CalculateProgressGraphValues(CancellationToken cancellationToken, int amount); int GetMaxCombo(int? fromTime = null); bool IsBreakTime(double time); double FirstHitObjectTime(); diff --git a/StreamCompanion.Common/Extensions/PpCalculatorExtensions.cs b/StreamCompanion.Common/Extensions/PpCalculatorExtensions.cs index 729d85d9..34a979e4 100644 --- a/StreamCompanion.Common/Extensions/PpCalculatorExtensions.cs +++ b/StreamCompanion.Common/Extensions/PpCalculatorExtensions.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Threading; +using CollectionManager.Enums; using PpCalculatorTypes; namespace StreamCompanion.Common @@ -11,24 +11,18 @@ public static class PpCalculatorExtensions public static Dictionary CalculateStrains(this IPpCalculator ppCalculator, CancellationToken cancellationToken, int? targetAmount = null) { + if (ppCalculator.RulesetId == (int)PlayMode.OsuMania) + return CalculateHitObjectDensity(ppCalculator, cancellationToken, targetAmount); + var strains = new Dictionary(targetAmount ?? 200); if (ppCalculator == null) return strains; ppCalculator.Score = 1_000_000; var mapLength = ppCalculator.BeatmapLength; - //data for 2min map - var strainLength = 5000; - var interval = 1500; + var (interval, strainLength) = CalculateStrainParameters(ppCalculator, targetAmount); var time = 0; - if (targetAmount.HasValue) - { - strainLength = Convert.ToInt32(Math.Floor(strainLength * (mapLength / 120_000d))); - interval = Convert.ToInt32(Math.Ceiling(mapLength - strainLength / 2d) / targetAmount) + 1; - //var strainsAmount = (mapLength - strainLength / 2d) / interval; - } - while (time + strainLength / 2 < mapLength) { cancellationToken.ThrowIfCancellationRequested(); @@ -44,5 +38,40 @@ public static Dictionary CalculateStrains(this IPpCalculator ppCalc return strains; } + + public static Dictionary CalculateHitObjectDensity(this IPpCalculator ppCalculator, + CancellationToken cancellationToken, int? targetAmount = null) + { + if (ppCalculator == null) + return null; + + var strains = new Dictionary(targetAmount ?? 200); + var (interval, _) = CalculateStrainParameters(ppCalculator, targetAmount); + var graphValues = ppCalculator.CalculateProgressGraphValues(cancellationToken, targetAmount ?? 200); + var time = 0; + foreach (var graphValue in graphValues) + { + strains[time] = graphValue; + time += interval; + } + + return strains; + } + + private static (int Interval, int StrainLength) CalculateStrainParameters(IPpCalculator ppCalculator, int? targetAmount = null) + { + var mapLength = ppCalculator.BeatmapLength; + //data for 2min map + var strainLength = 5000; + var interval = 1500; + + if (targetAmount.HasValue) + { + strainLength = Convert.ToInt32(Math.Floor(strainLength * (mapLength / 120_000d))); + interval = Convert.ToInt32(Math.Ceiling(mapLength - (strainLength / 2d)) / targetAmount) + 1; + } + + return (interval, strainLength); + } } } \ No newline at end of file