From ab4455e3720570e4a8227c42a068fded2b97fbb2 Mon Sep 17 00:00:00 2001 From: "No.1 N[][]b" Date: Tue, 11 Apr 2023 17:32:29 +0200 Subject: [PATCH] Triangle PP Calculation --- PPPredictor/Counter/CounterInfoHolder.cs | 6 +- PPPredictor/Data/PPPBeatMapInfo.cs | 8 +- PPPredictor/Data/PPPStarRating.cs | 56 ++++++++ PPPredictor/Data/ShortScore.cs | 12 +- PPPredictor/Interfaces/IPPPredictor.cs | 8 +- PPPredictor/OpenAPIs/beatleader-v1.cs | 18 ++- PPPredictor/PPPredictor.csproj | 1 + PPPredictor/Properties/AssemblyInfo.cs | 4 +- PPPredictor/Utilities/PPCalculator.cs | 7 +- .../Utilities/PPCalculatorBeatLeader.cs | 129 +++++++++++++++--- .../Utilities/PPCalculatorNoLeaderboard.cs | 6 +- .../Utilities/PPCalculatorScoreSaber.cs | 13 +- PPPredictor/Utilities/PPPredictor.cs | 24 +--- PPPredictor/Utilities/PPPredictorMgr.cs | 19 +-- PPPredictor/Utilities/ProfileInfoMgr.cs | 2 +- PPPredictor/manifest.json | 2 +- 16 files changed, 223 insertions(+), 92 deletions(-) create mode 100644 PPPredictor/Data/PPPStarRating.cs diff --git a/PPPredictor/Counter/CounterInfoHolder.cs b/PPPredictor/Counter/CounterInfoHolder.cs index 8a79167..c0628f4 100644 --- a/PPPredictor/Counter/CounterInfoHolder.cs +++ b/PPPredictor/Counter/CounterInfoHolder.cs @@ -23,7 +23,6 @@ class CounterInfoHolder private readonly CustomConfigModel settings; private readonly CanvasUtility canvasUtility; private GameplayModifiers gameplayModifiers; - private double modifiedStars; private float positionScale; private double maxPP = -1; @@ -65,7 +64,6 @@ public CounterInfoHolder(Leaderboard leaderboard, CustomConfigModel settings, st icon = CreateIcon(canvas, iconPath, new Vector3((-1f + centerOffset) * positionScaleFactor, lineOffset, 0), Math.Abs(lineOffset)); } this.gameplayModifiers = gameplayModifiers; - modifiedStars = Plugin.pppViewController.ppPredictorMgr.GetModifiedStarsForCalculator(leaderboard, gameplayModifiers); } private float getCenterOffset() @@ -105,10 +103,10 @@ public void UpdateCounterText(double percentage, bool levelFailed) if (showInfo) { if (Plugin.ProfileInfo.CounterUseIcons) icon.enabled = true; - double pp = Plugin.pppViewController.ppPredictorMgr.GetPPAtPercentageForCalculator(leaderboard, percentage, levelFailed, modifiedStars, gameplayModifiers); + double pp = Plugin.pppViewController.ppPredictorMgr.GetPPAtPercentageForCalculator(leaderboard, percentage, levelFailed, gameplayModifiers); double ppGain = Math.Round(Plugin.pppViewController.ppPredictorMgr.GetPPGainForCalculator(leaderboard, pp), 2); - if (maxPP == -1) maxPP = Plugin.pppViewController.ppPredictorMgr.GetMaxPPForCalculator(leaderboard, modifiedStars, gameplayModifiers); + if (maxPP == -1) maxPP = Plugin.pppViewController.ppPredictorMgr.GetMaxPPForCalculator(leaderboard, gameplayModifiers); string maxPPReachedPrefix = string.Empty; string maxPPReachedSuffix = string.Empty; diff --git a/PPPredictor/Data/PPPBeatMapInfo.cs b/PPPredictor/Data/PPPBeatMapInfo.cs index 6a18af5..d498f1f 100644 --- a/PPPredictor/Data/PPPBeatMapInfo.cs +++ b/PPPredictor/Data/PPPBeatMapInfo.cs @@ -2,19 +2,19 @@ { public class PPPBeatMapInfo { - double _baseStars = 0; + PPPStarRating _baseStarRating = new PPPStarRating(); int _modifierValueId = 0; - public double BaseStars { get => _baseStars; set => _baseStars = value; } + public PPPStarRating BaseStarRating { get => _baseStarRating; set => _baseStarRating = value; } public int ModifierValueId { get => _modifierValueId; set => _modifierValueId = value; } public PPPBeatMapInfo() { } - public PPPBeatMapInfo(double baseStars, int modifierValueId) + public PPPBeatMapInfo(PPPStarRating baseStars, int modifierValueId) { - _baseStars = baseStars; + _baseStarRating = baseStars; _modifierValueId = modifierValueId; } } diff --git a/PPPredictor/Data/PPPStarRating.cs b/PPPredictor/Data/PPPStarRating.cs new file mode 100644 index 0000000..9e5a234 --- /dev/null +++ b/PPPredictor/Data/PPPStarRating.cs @@ -0,0 +1,56 @@ +using beatleaderapi; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PPPredictor.Data +{ + public class PPPStarRating + { + private double _stars = 0; + private double _predictedAcc = 0; + private double _passRating = 0; + private double _accRating = 0; + private double _techRating = 0; + private Dictionary _modifiersRating = new Dictionary(); + + [DefaultValue(0)] + public double Stars { get => _stars; set => _stars = value; } + [DefaultValue(0)] + public double PredictedAcc { get => _predictedAcc; set => _predictedAcc = value; } + [DefaultValue(0)] + public double PassRating { get => _passRating; set => _passRating = value; } + [DefaultValue(0)] + public double AccRating { get => _accRating; set => _accRating = value; } + [DefaultValue(0)] + public double TechRating { get => _techRating; set => _techRating = value; } + [DefaultValue(null)] + public Dictionary ModifiersRating { get => _modifiersRating; set => _modifiersRating = value; } + + public PPPStarRating() + { + } + + public PPPStarRating(double starRating) + { + _stars = _predictedAcc = _passRating = _accRating = _techRating = starRating; + } + + public PPPStarRating(DifficultyDescription beatLeaderDifficulty) + { + _predictedAcc = beatLeaderDifficulty.PredictedAcc.GetValueOrDefault(); + _passRating = beatLeaderDifficulty.PassRating.GetValueOrDefault(); + _accRating = beatLeaderDifficulty.AccRating.GetValueOrDefault(); + _techRating = beatLeaderDifficulty.TechRating.GetValueOrDefault(); + _modifiersRating = beatLeaderDifficulty.ModifiersRating ?? null; + } + + public bool IsRanked() + { + return _predictedAcc > 0 || _passRating > 0 || _accRating > 0 || _techRating > 0 || _stars > 0; + } + } +} diff --git a/PPPredictor/Data/ShortScore.cs b/PPPredictor/Data/ShortScore.cs index 62cdc5e..d6b82fd 100644 --- a/PPPredictor/Data/ShortScore.cs +++ b/PPPredictor/Data/ShortScore.cs @@ -7,13 +7,13 @@ public class ShortScore { private readonly string _searchstring; private double _pp; - private double _stars; + private PPPStarRating _starRating; private DateTime _fetchTime; private int _modifierValuesId; public string Searchstring { get => _searchstring; } public double Pp { get => _pp; set => _pp = value; } - public double Stars { get => _stars; set => _stars = value; } + public PPPStarRating StarRating { get => _starRating; set => _starRating = value; } public DateTime FetchTime { get => _fetchTime; set => _fetchTime = value; } public int ModifierValuesId { get => _modifierValuesId; set => _modifierValuesId = value; } @@ -23,20 +23,20 @@ public ShortScore(string searchstring, double pp) this._pp = pp; } - public ShortScore(string searchstring, double stars, DateTime fetchTime, int modifierValuesId) + public ShortScore(string searchstring, PPPStarRating starRating, DateTime fetchTime, int modifierValuesId) { this._searchstring = searchstring.ToUpper(); this._fetchTime = fetchTime; - this._stars = stars; + this._starRating = starRating; this._modifierValuesId = modifierValuesId; } [JsonConstructor] - public ShortScore(string searchstring, double pp, double stars, DateTime fetchTime, int modifierValuesId) + public ShortScore(string searchstring, double pp, PPPStarRating starRating, DateTime fetchTime, int modifierValuesId) { this._searchstring = searchstring.ToUpper(); this._pp = pp; this._fetchTime = fetchTime; - this._stars = stars; + this._starRating = starRating; this._modifierValuesId = modifierValuesId; } } diff --git a/PPPredictor/Interfaces/IPPPredictor.cs b/PPPredictor/Interfaces/IPPPredictor.cs index 35cd0eb..0afee04 100644 --- a/PPPredictor/Interfaces/IPPPredictor.cs +++ b/PPPredictor/Interfaces/IPPPredictor.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using PPPredictor.Data; +using System.ComponentModel; using System.Threading.Tasks; namespace PPPredictor.Interfaces @@ -12,9 +13,8 @@ interface IPPPredictor Task UpdateCurrentAndCheckResetSession(bool doResetSession); void RefreshCurrentData(int fetchLength); void ResetDisplay(bool resetAll); - double CalculatePPatPercentage(double stars, double percentage, GameplayModifiers gameplayModifiers, bool levelFailed = false); - double CalculateMaxPP(double stars, GameplayModifiers gameplayModifiers); - double GetModifiedStars(GameplayModifiers gameplayModifiers); + double CalculatePPatPercentage(double percentage, GameplayModifiers gameplayModifiers, bool levelFailed = false); + double CalculateMaxPP(GameplayModifiers gameplayModifiers); double CalculatePPGain(double pp); bool IsRanked(); void DisplayPP(); diff --git a/PPPredictor/OpenAPIs/beatleader-v1.cs b/PPPredictor/OpenAPIs/beatleader-v1.cs index 8b74bd0..def8657 100644 --- a/PPPredictor/OpenAPIs/beatleader-v1.cs +++ b/PPPredictor/OpenAPIs/beatleader-v1.cs @@ -665,10 +665,22 @@ public partial class DifficultyDescription [Newtonsoft.Json.JsonProperty("rankedTime", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public int RankedTime { get; set; } - + [Newtonsoft.Json.JsonProperty("stars", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public float? Stars { get; set; } - + + [Newtonsoft.Json.JsonProperty("predictedAcc", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public float? PredictedAcc { get; set; } + + [Newtonsoft.Json.JsonProperty("passRating", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public float? PassRating { get; set; } + + [Newtonsoft.Json.JsonProperty("accRating", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public float? AccRating { get; set; } + + [Newtonsoft.Json.JsonProperty("techRating", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public float? TechRating { get; set; } + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public int Type { get; set; } @@ -692,6 +704,8 @@ public partial class DifficultyDescription [Newtonsoft.Json.JsonProperty("modifierValues", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public Dictionary ModifierValues { get; set; } + [Newtonsoft.Json.JsonProperty("modifiersRating", Required = Newtonsoft.Json.Required.AllowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Dictionary ModifiersRating { get; set; } } diff --git a/PPPredictor/PPPredictor.csproj b/PPPredictor/PPPredictor.csproj index 0ff1c33..7e3e31c 100644 --- a/PPPredictor/PPPredictor.csproj +++ b/PPPredictor/PPPredictor.csproj @@ -140,6 +140,7 @@ + diff --git a/PPPredictor/Properties/AssemblyInfo.cs b/PPPredictor/Properties/AssemblyInfo.cs index f756706..ceb5886 100644 --- a/PPPredictor/Properties/AssemblyInfo.cs +++ b/PPPredictor/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.6.2")] -[assembly: AssemblyFileVersion("0.6.2")] +[assembly: AssemblyVersion("0.6.3")] +[assembly: AssemblyFileVersion("0.6.3")] diff --git a/PPPredictor/Utilities/PPCalculator.cs b/PPPredictor/Utilities/PPCalculator.cs index ebeec9b..f1cb03f 100644 --- a/PPPredictor/Utilities/PPCalculator.cs +++ b/PPPredictor/Utilities/PPCalculator.cs @@ -12,6 +12,7 @@ public abstract class PPCalculator { private List _lsPlayerRankings; internal PPPLeaderboardInfo _leaderboardInfo; + internal double accConstant = 0.965; public PPCalculator() { @@ -200,7 +201,7 @@ public async Task GetPlayerRankGain(double pp) public double WeightPP(double rawPP, int index) { - return rawPP * Math.Pow(0.965, (index - 1)); + return rawPP * Math.Pow(accConstant, (index - 1)); } public string CreateSeachString(string hash, string gameMode, int difficulty) @@ -222,11 +223,9 @@ public double Zeroizer(double pp) protected abstract Task> GetPlayers(double fetchIndexPage); - public abstract double CalculatePPatPercentage(double star, double percentage, bool levelFailed); + public abstract double CalculatePPatPercentage(PPPBeatMapInfo currentBeatMapInfo, double percentage, bool levelFailed, GameplayModifiers gameplayModifiers); public abstract Task GetBeatMapInfoAsync(LevelSelectionNavigationController lvlSelectionNavigationCtrl, IDifficultyBeatmap beatmap); - public abstract double ApplyModifierMultiplierToStars(PPPBeatMapInfo beatMapInfo, GameplayModifiers gameplayModifiers, bool levelFailed = false); - } } diff --git a/PPPredictor/Utilities/PPCalculatorBeatLeader.cs b/PPPredictor/Utilities/PPCalculatorBeatLeader.cs index de49f14..4fa584d 100644 --- a/PPPredictor/Utilities/PPCalculatorBeatLeader.cs +++ b/PPPredictor/Utilities/PPCalculatorBeatLeader.cs @@ -11,9 +11,45 @@ namespace PPPredictor.Utilities { public class PPCalculatorBeatLeader : PPCalculator { + private const string AccRating = "AccRating"; + private const string PassRating = "PassRating"; + private const string TechRating = "TechRating"; private readonly HttpClient httpClient = new HttpClient(); private readonly beatleaderapi.beatleaderapi beatLeaderClient; private readonly double ppCalcWeight = 42; + static List<(double, double)> accPointList = new List<(double, double)> { + (1.0, 7.424), + (0.999, 6.241), + (0.9975, 5.158), + (0.995, 4.010), + (0.9925, 3.241), + (0.99, 2.700), + (0.9875, 2.303), + (0.985, 2.007), + (0.9825, 1.786), + (0.98, 1.618), + (0.9775, 1.490), + (0.975, 1.392), + (0.9725, 1.315), + (0.97, 1.256), + (0.965, 1.167), + (0.96, 1.101), + (0.955, 1.047), + (0.95, 1.000), + (0.94, 0.919), + (0.93, 0.847), + (0.92, 0.786), + (0.91, 0.734), + (0.9, 0.692), + (0.875, 0.606), + (0.85, 0.537), + (0.825, 0.480), + (0.8, 0.429), + (0.75, 0.345), + (0.7, 0.286), + (0.65, 0.246), + (0.6, 0.217), + (0.0, 0.000) }; public PPCalculatorBeatLeader() : base() { @@ -68,17 +104,39 @@ protected override async Task GetRecentScores(string userId, } } - public override double CalculatePPatPercentage(double star, double percentage, bool levelFailed) + public override double CalculatePPatPercentage(PPPBeatMapInfo currentBeatMapInfo, double percentage, bool levelFailed, GameplayModifiers gameplayModifiers) { try { - if (star <= 0) return 0; - double l = 1.0 - (0.03 * ((star - 0.5) - 3) / 11); - double n = percentage / 100.0; - n = Math.Min(n, l - 0.0000000000000001); //Stop just before the calculation crashes, lets hope this works - double a = 0.96 * l; - double f = 1.2 - (0.6 * ((star - 0.5) / 14)); - return (star + 0.5) * ppCalcWeight * Math.Pow((Math.Log(l / (l - n)) / (Math.Log(l / (l - a)))), f); + percentage /= 100.0; + List lsModifiers = ParseModifiers(gameplayModifiers); + double multiplier = GenerateModifierMultiplier(lsModifiers, currentBeatMapInfo.ModifierValueId, levelFailed, currentBeatMapInfo.BaseStarRating.ModifiersRating != null); + if (multiplier != 0) //NF + { + double passRating = currentBeatMapInfo.BaseStarRating.PassRating; + double techRating = currentBeatMapInfo.BaseStarRating.TechRating; + double accRating = currentBeatMapInfo.BaseStarRating.AccRating; + + if(currentBeatMapInfo.BaseStarRating.ModifiersRating != null) + { + foreach (string modifier in lsModifiers.Select(x => x.ToLower())) + { + if (currentBeatMapInfo.BaseStarRating.ModifiersRating.ContainsKey(modifier + AccRating)) + { + accRating = currentBeatMapInfo.BaseStarRating.ModifiersRating[modifier + AccRating]; + passRating = currentBeatMapInfo.BaseStarRating.ModifiersRating[modifier + PassRating]; + techRating = currentBeatMapInfo.BaseStarRating.ModifiersRating[modifier + TechRating]; + + break; + } + } + } + + var (passPP, accPP, techPP) = CalculatePP(percentage, accRating * multiplier, passRating * multiplier, techRating * multiplier); + var rawPP = Inflate(passPP + accPP + techPP); + return rawPP; + } + return 0; } catch (Exception ex) { @@ -87,6 +145,44 @@ public override double CalculatePPatPercentage(double star, double percentage, b } } + private (double, double, double) CalculatePP(double accuracy, double accRating, double passRating, double techRating) + { + double passPP = 15.2f * Math.Exp(Math.Pow(passRating, 1 / 2.62f)) - 30f; + if (double.IsInfinity(passPP) || double.IsNaN(passPP) || double.IsNegativeInfinity(passPP) || passPP < 0) + { + passPP = 0; + } + double accPP = AccCurve(accuracy) * accRating * 34f; + double techPP = Math.Exp(1.9f * accuracy) * techRating; + + return (passPP, accPP, techPP); + } + + private double AccCurve(double acc) + { + int i = 0; + for (; i < accPointList.Count; i++) + { + if (accPointList[i].Item1 <= acc) + { + break; + } + } + + if (i == 0) + { + i = 1; + } + + double middle_dis = (acc - accPointList[i - 1].Item1) / (accPointList[i].Item1 - accPointList[i - 1].Item1); + return (accPointList[i - 1].Item2 + middle_dis * (accPointList[i].Item2 - accPointList[i - 1].Item2)); + } + + private double Inflate(double pp) + { + return (650f * Math.Pow(pp, 1.3f)) / Math.Pow(650f, 1.3f); + } + public override async Task GetBeatMapInfoAsync(LevelSelectionNavigationController lvlSelectionNavigationCtrl, IDifficultyBeatmap beatmap) { try @@ -114,17 +210,17 @@ public override async Task GetBeatMapInfoAsync(LevelSelectionNav modifierValueId = _leaderboardInfo.LsModifierValues.Select(x => x.Id).DefaultIfEmpty(-1).Max() + 1; _leaderboardInfo.LsModifierValues.Add(new PPPModifierValues(modifierValueId, diff.ModifierValues)); } - _leaderboardInfo.LsLeaderboardScores.Add(new ShortScore(searchString, diff.Stars.GetValueOrDefault(), DateTime.Now, modifierValueId)); + _leaderboardInfo.LsLeaderboardScores.Add(new ShortScore(searchString, new PPPStarRating(diff), DateTime.Now, modifierValueId)); if (diff.Stars.HasValue && (int)diff.Status == (int)BeatLeaderDifficultyStatus.ranked) { - return new PPPBeatMapInfo(diff.Stars.Value, modifierValueId); + return new PPPBeatMapInfo(new PPPStarRating(diff), modifierValueId); } } } } else { - return new PPPBeatMapInfo(cachedInfo.Stars, cachedInfo.ModifierValuesId); + return new PPPBeatMapInfo(cachedInfo.StarRating, cachedInfo.ModifierValuesId); } } return new PPPBeatMapInfo(); @@ -132,16 +228,10 @@ public override async Task GetBeatMapInfoAsync(LevelSelectionNav catch (Exception ex) { Plugin.Log?.Error($"PPCalculatorBeatLeader GetStarsForBeatmapAsync Error: {ex.Message}"); - return new PPPBeatMapInfo(-1, -1); + return new PPPBeatMapInfo(new PPPStarRating(-1), -1); } } - public override double ApplyModifierMultiplierToStars(PPPBeatMapInfo beatMapInfo, GameplayModifiers gameplayModifiers, bool levelFailed) - { - List lsModifiers = ParseModifiers(gameplayModifiers); - return beatMapInfo.BaseStars * GenerateModifierMultiplier(lsModifiers, beatMapInfo.ModifierValueId, levelFailed); - } - private List ParseModifiers(GameplayModifiers gameplayModifiers) { try @@ -171,7 +261,7 @@ private List ParseModifiers(GameplayModifiers gameplayModifiers) } } - private double GenerateModifierMultiplier(List lsModifier, int modifierValueId, bool levelFailed) + private double GenerateModifierMultiplier(List lsModifier, int modifierValueId, bool levelFailed, bool ignoreSpeedMultiplier) { try { @@ -179,6 +269,7 @@ private double GenerateModifierMultiplier(List lsModifier, int modifierV foreach (string modifier in lsModifier) { if (!levelFailed && modifier == "NF") continue; //Ignore nofail until the map is failed in gameplay + if (ignoreSpeedMultiplier && (modifier == "SF" || modifier == "SS" || modifier == "FS")) continue; //Ignore speed multies and use the precomputed values from backend multiplier += _leaderboardInfo.LsModifierValues[modifierValueId].DctModifierValues[modifier]; } return multiplier; diff --git a/PPPredictor/Utilities/PPCalculatorNoLeaderboard.cs b/PPPredictor/Utilities/PPCalculatorNoLeaderboard.cs index 98ed28f..76f1fc2 100644 --- a/PPPredictor/Utilities/PPCalculatorNoLeaderboard.cs +++ b/PPPredictor/Utilities/PPCalculatorNoLeaderboard.cs @@ -7,12 +7,8 @@ namespace PPPredictor.Utilities class PPCalculatorNoLeaderboard : PPCalculator { //Dummy class, for when no Leaderboards are selected in the options. mhh... why even use this mod then - public override double ApplyModifierMultiplierToStars(PPPBeatMapInfo beatMapInfo, GameplayModifiers gameplayModifiers, bool levelFailed) - { - return 0; - } - public override double CalculatePPatPercentage(double star, double percentage, bool levelFailed) + public override double CalculatePPatPercentage(PPPBeatMapInfo currentBeatMapInfo, double percentage, bool levelFailed, GameplayModifiers gameplayModifiers) { return 0; } diff --git a/PPPredictor/Utilities/PPCalculatorScoreSaber.cs b/PPPredictor/Utilities/PPCalculatorScoreSaber.cs index 0c44853..b400108 100644 --- a/PPPredictor/Utilities/PPCalculatorScoreSaber.cs +++ b/PPPredictor/Utilities/PPCalculatorScoreSaber.cs @@ -146,14 +146,14 @@ private double CalculateMultiplierAtPercentageWithLine((double x, double y) p1, } } - public override double CalculatePPatPercentage(double star, double percentage, bool levelFailed) + public override double CalculatePPatPercentage(PPPBeatMapInfo currentBeatMapInfo, double percentage, bool levelFailed, GameplayModifiers gameplayModifiers) { try { percentage /= 100.0; if (levelFailed) percentage /= 2.0; //Halve score if nofail triggered double multiplier = CalculateMultiplierAtPercentage(percentage); - return multiplier * star * basePPMultiplier; + return multiplier * currentBeatMapInfo.BaseStarRating.Stars * basePPMultiplier; } catch (Exception ex) { @@ -172,7 +172,7 @@ public override Task GetBeatMapInfoAsync(LevelSelectionNavigatio { if (song.GetDifficulty(out SongDifficulty songDiff, (MapDifficulty)beatmap.difficulty)) { - return Task.FromResult(new PPPBeatMapInfo(songDiff.stars, 0)); + return Task.FromResult(new PPPBeatMapInfo(new PPPStarRating(songDiff.stars), 0)); } } return Task.FromResult(new PPPBeatMapInfo()); @@ -182,13 +182,8 @@ public override Task GetBeatMapInfoAsync(LevelSelectionNavigatio catch (Exception ex) { Plugin.Log?.Error($"PPCalculatorScoreSaber GetStarsForBeatmapAsync Error: {ex.Message}"); - return Task.FromResult(new PPPBeatMapInfo(-1, -1)); + return Task.FromResult(new PPPBeatMapInfo(new PPPStarRating(-1), -1)); } } - - public override double ApplyModifierMultiplierToStars(PPPBeatMapInfo beatMapInfo, GameplayModifiers gameplayModifiers, bool levelFailed) - { - return beatMapInfo.BaseStars; - } } } diff --git a/PPPredictor/Utilities/PPPredictor.cs b/PPPredictor/Utilities/PPPredictor.cs index e372aa4..7117cf9 100644 --- a/PPPredictor/Utilities/PPPredictor.cs +++ b/PPPredictor/Utilities/PPPredictor.cs @@ -20,7 +20,6 @@ namespace PPPredictor.Utilities private string _ppGainDiffColor = "white"; private PPPBeatMapInfo _currentBeatMapInfo = new PPPBeatMapInfo(); - private double _currentSelectionStars; private string _sessionRank = ""; private string _sessionCountryRank = ""; @@ -311,7 +310,6 @@ public void ChangeGameplayModifiers(GameplaySetupViewController gameplaySetupVie if (gameplaySetupViewController != null && gameplaySetupViewController.gameplayModifiers != null) { _gameplayModifiers = gameplaySetupViewController.gameplayModifiers; - _currentSelectionStars = _ppCalculator.ApplyModifierMultiplierToStars(_currentBeatMapInfo, _gameplayModifiers); _maxPP = -1; DisplayPP(); } @@ -321,7 +319,6 @@ public async void DifficultyChanged(LevelSelectionNavigationController lvlSelect { _currentBeatMapInfo = await _ppCalculator.GetBeatMapInfoAsync(lvlSelectionNavigationCtrl, beatmap); _selectedMapSearchString = lvlSelectionNavigationCtrl.selectedBeatmapLevel is CustomBeatmapLevel selectedCustomBeatmapLevel ? _ppCalculator.CreateSeachString(Hashing.GetCustomLevelHash(selectedCustomBeatmapLevel), "SOLO" + beatmap.parentDifficultyBeatmapSet.beatmapCharacteristic.serializedName, lvlSelectionNavigationCtrl.selectedDifficultyBeatmap.difficultyRank) : string.Empty; - _currentSelectionStars = GetModifiedStars(_gameplayModifiers); _maxPP = -1; DisplayPP(); } @@ -332,26 +329,19 @@ public async void DetailContentChanged(LevelSelectionNavigationController lvlSel { _currentBeatMapInfo = await _ppCalculator.GetBeatMapInfoAsync(lvlSelectionNavigationCtrl, lvlSelectionNavigationCtrl.selectedDifficultyBeatmap); _selectedMapSearchString = lvlSelectionNavigationCtrl.selectedBeatmapLevel is CustomBeatmapLevel selectedCustomBeatmapLevel ? _ppCalculator.CreateSeachString(Hashing.GetCustomLevelHash(selectedCustomBeatmapLevel), "SOLO" + lvlSelectionNavigationCtrl.selectedDifficultyBeatmap.parentDifficultyBeatmapSet.beatmapCharacteristic.serializedName, lvlSelectionNavigationCtrl.selectedDifficultyBeatmap.difficultyRank) : string.Empty; - _currentSelectionStars = GetModifiedStars(_gameplayModifiers); _maxPP = -1; DisplayPP(); } } #endregion - public double CalculatePPatPercentage(double currentStars, double percentage, GameplayModifiers gameplayModifiers, bool levelFailed = false) + public double CalculatePPatPercentage(double percentage, GameplayModifiers gameplayModifiers, bool levelFailed = false) { - if (levelFailed) currentStars = _ppCalculator.ApplyModifierMultiplierToStars(_currentBeatMapInfo, gameplayModifiers, levelFailed); //Recalculate stars for beatleader - return _ppCalculator.CalculatePPatPercentage(currentStars, percentage, levelFailed); + return _ppCalculator.CalculatePPatPercentage(_currentBeatMapInfo, percentage, levelFailed, gameplayModifiers); } - public double CalculateMaxPP(double stars, GameplayModifiers gameplayModifiers) + public double CalculateMaxPP(GameplayModifiers gameplayModifiers) { - return CalculatePPatPercentage(stars, 100, gameplayModifiers); - } - - public double GetModifiedStars(GameplayModifiers gameplayModifiers) - { - return _ppCalculator.ApplyModifierMultiplierToStars(_currentBeatMapInfo, gameplayModifiers); + return CalculatePPatPercentage(100, gameplayModifiers); } public double CalculatePPGain(double pp) @@ -361,13 +351,13 @@ public double CalculatePPGain(double pp) public bool IsRanked() { - return _currentBeatMapInfo.BaseStars > 0; + return _currentBeatMapInfo.BaseStarRating.IsRanked(); } public async void DisplayPP() { - if (_maxPP == -1) _maxPP = CalculateMaxPP(_currentSelectionStars, _gameplayModifiers); - double pp = CalculatePPatPercentage(_currentSelectionStars, _percentage, _gameplayModifiers); + if (_maxPP == -1) _maxPP = CalculateMaxPP(_gameplayModifiers); + double pp = CalculatePPatPercentage(_percentage, _gameplayModifiers); PPGainResult ppGainResult = _ppCalculator.GetPlayerScorePPGain(_selectedMapSearchString, pp); double ppGains = _ppCalculator.Zeroizer(ppGainResult.GetDisplayPPValue()); if(_maxPP > 0 && pp >= _maxPP) diff --git a/PPPredictor/Utilities/PPPredictorMgr.cs b/PPPredictor/Utilities/PPPredictorMgr.cs index 7103f9b..2a34504 100644 --- a/PPPredictor/Utilities/PPPredictorMgr.cs +++ b/PPPredictor/Utilities/PPPredictorMgr.cs @@ -1,4 +1,5 @@ using BeatSaberMarkupLanguage.FloatingScreen; +using PPPredictor.Data; using PPPredictor.Interfaces; using System; using System.Collections.Generic; @@ -154,32 +155,22 @@ internal void ResetDisplay(bool resetAll) } } - internal double GetPPAtPercentageForCalculator(Leaderboard leaderBoardName, double percentage, bool levelFailed, double stars, GameplayModifiers gameplayModifiers) + internal double GetPPAtPercentageForCalculator(Leaderboard leaderBoardName, double percentage, bool levelFailed, GameplayModifiers gameplayModifiers) { IPPPredictor predictor = _lsPPPredictor.Find(x => x.LeaderBoardName == leaderBoardName.ToString()); if (predictor != null) { - return predictor.CalculatePPatPercentage(stars, percentage, gameplayModifiers, levelFailed); + return predictor.CalculatePPatPercentage(percentage, gameplayModifiers, levelFailed); } return 0; } - internal double GetMaxPPForCalculator(Leaderboard leaderBoardName, double stars, GameplayModifiers gameplayModifiers) + internal double GetMaxPPForCalculator(Leaderboard leaderBoardName, GameplayModifiers gameplayModifiers) { IPPPredictor predictor = _lsPPPredictor.Find(x => x.LeaderBoardName == leaderBoardName.ToString()); if (predictor != null) { - return predictor.CalculateMaxPP(stars, gameplayModifiers); - } - return 0; - } - - internal double GetModifiedStarsForCalculator(Leaderboard leaderBoardName, GameplayModifiers gameplayModifiers) - { - IPPPredictor predictor = _lsPPPredictor.Find(x => x.LeaderBoardName == leaderBoardName.ToString()); - if (predictor != null) - { - return predictor.GetModifiedStars(gameplayModifiers); + return predictor.CalculateMaxPP(gameplayModifiers); } return 0; } diff --git a/PPPredictor/Utilities/ProfileInfoMgr.cs b/PPPredictor/Utilities/ProfileInfoMgr.cs index 1520365..4a74565 100644 --- a/PPPredictor/Utilities/ProfileInfoMgr.cs +++ b/PPPredictor/Utilities/ProfileInfoMgr.cs @@ -15,7 +15,7 @@ class ProfileInfoMgr internal static FlowCoordinator _parentFlow { get; private set; } internal static PPPredictorFlowCoordinator _flow { get; private set; } private static readonly string profilePath = Path.Combine(UnityGame.UserDataPath, "PPPredictorProfileInfo.json"); - private static int _profileInfoVersion = 1; + private static int _profileInfoVersion = 2; internal static ProfileInfo LoadProfileInfo() { MenuButtons.instance.RegisterButton(new MenuButton("PPPredictor", "Predict PP gains", ShowSettingsFlow, true)); diff --git a/PPPredictor/manifest.json b/PPPredictor/manifest.json index 8cc27cc..4e94e99 100644 --- a/PPPredictor/manifest.json +++ b/PPPredictor/manifest.json @@ -3,7 +3,7 @@ "id": "PPPredictor", "name": "PPPredictor", "author": "No.1 N[][]b", - "version": "0.6.2", + "version": "0.6.3", "description": "", "gameVersion": "1.22.1", "dependsOn": {