Skip to content

Commit

Permalink
Fix: Use hit object density instead of strains for Mania
Browse files Browse the repository at this point in the history
  • Loading branch information
Piotrekol committed Mar 18, 2023
1 parent 77b078c commit a03ecc7
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 11 deletions.
33 changes: 33 additions & 0 deletions PpCalculator/PpCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ public virtual string[] Mods
private Lazy<double> scoreMultiplier = new Lazy<double>(() => 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
Expand All @@ -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();
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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<int>();

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<IMod> GetOsuMods(Ruleset ruleset)
{
var mods = new List<IMod>();
Expand Down
5 changes: 5 additions & 0 deletions PpCalculatorTypes/IPpCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ public interface IPpCalculator
int RulesetId { get; }
double BeatmapLength { get; }
bool UseScoreMultiplier { get; set; }
/// <summary>
/// Whenever last <see cref="Calculate"/> call was used with limited start/end times, therefore affected Difficulty results
/// </summary>
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();
Expand Down
51 changes: 40 additions & 11 deletions StreamCompanion.Common/Extensions/PpCalculatorExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using CollectionManager.Enums;
using PpCalculatorTypes;

namespace StreamCompanion.Common
Expand All @@ -11,24 +11,18 @@ public static class PpCalculatorExtensions
public static Dictionary<int, double> CalculateStrains(this IPpCalculator ppCalculator,
CancellationToken cancellationToken, int? targetAmount = null)
{
if (ppCalculator.RulesetId == (int)PlayMode.OsuMania)
return CalculateHitObjectDensity(ppCalculator, cancellationToken, targetAmount);

var strains = new Dictionary<int, double>(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();
Expand All @@ -44,5 +38,40 @@ public static Dictionary<int, double> CalculateStrains(this IPpCalculator ppCalc

return strains;
}

public static Dictionary<int, double> CalculateHitObjectDensity(this IPpCalculator ppCalculator,
CancellationToken cancellationToken, int? targetAmount = null)
{
if (ppCalculator == null)
return null;

var strains = new Dictionary<int, double>(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);
}
}
}

0 comments on commit a03ecc7

Please sign in to comment.