Skip to content

Commit

Permalink
Add support for new score structure
Browse files Browse the repository at this point in the history
  • Loading branch information
stanriders committed Feb 3, 2024
1 parent d4878dc commit c7c4ed2
Show file tree
Hide file tree
Showing 12 changed files with 408 additions and 46 deletions.
5 changes: 1 addition & 4 deletions den0bot.Modules.Osu/ModBeatmap.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// den0bot (c) StanR 2023 - MIT License
// den0bot (c) StanR 2024 - MIT License
//#define PARSE_PHOTOS
using den0bot.Modules.Osu.Types.V2;
using den0bot.Modules.Osu.WebAPI;
using den0bot.Modules.Osu.WebAPI.Requests.V2;
using den0bot.Types;
using den0bot.Util;
Expand All @@ -13,9 +12,7 @@
using System.Threading.Tasks;
using den0bot.Modules.Osu.Parsers;
using den0bot.Modules.Osu.Types;
using den0bot.Modules.Osu.Types.Enums;
using IronOcr;
using Pettanko;
using Serilog;
using Telegram.Bot.Types;
using Telegram.Bot.Types.InputFiles;
Expand Down
4 changes: 2 additions & 2 deletions den0bot.Modules.Osu/ModProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ private async Task<string> FormatPlayerInfo(string playerID)

for (int i = 0; i < topscores.Count; i++)
{
Score score = topscores[i];
LazerScore score = topscores[i];

string mods = string.Empty;
if (score.Mods.Length > 0)
mods = $" +{string.Join("", score.Mods)}";
mods = $" +{string.Join("", score.Mods.Where(x=> x.Acronym != "CL").Select(x=> x.Acronym))}";

// 1. 123pp | Artist - Title [Diffname] +Mods (Rank, Accuracy%)
string mapName = $"{score.BeatmapSet.Artist} - {score.BeatmapSet.Title} [{score.Beatmap.Version}]".FilterToHTML();
Expand Down
123 changes: 116 additions & 7 deletions den0bot.Modules.Osu/ModRecentScores.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
// den0bot (c) StanR 2023 - MIT License
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using den0bot.DB;
using den0bot.Modules.Osu.Parsers;
using den0bot.Modules.Osu.WebAPI;
using den0bot.Modules.Osu.WebAPI.Requests.V2;
using den0bot.Modules.Osu.Types;
using den0bot.Modules.Osu.Types.Enums;
using den0bot.Modules.Osu.Types.V2;
using den0bot.Modules.Osu.Util;
using den0bot.Util;
using Telegram.Bot.Types.Enums;
using den0bot.Types;
using den0bot.Types.Answers;
using Pettanko;
using Serilog;
using Score = den0bot.Modules.Osu.Types.V2.Score;

Expand Down Expand Up @@ -107,7 +105,7 @@ private async Task<ICommandAnswer> GetLastScores(Telegram.Bot.Types.Message mess
if (playerId == 0)
return Localization.GetAnswer("generic_fail", message.Chat.Id);

List<Score> lastScores = await new GetUserScores(playerId, ScoreType.Recent, true).Execute();
List<LazerScore> lastScores = await new GetUserScores(playerId, ScoreType.Recent, true).Execute();
if (lastScores != null)
{
if (lastScores.Count == 0)
Expand All @@ -120,7 +118,7 @@ private async Task<ICommandAnswer> GetLastScores(Telegram.Bot.Types.Message mess
ChatBeatmapCache.StoreLastMap(message.Chat.Id, new ChatBeatmapCache.CachedBeatmap { BeatmapId = score.BeatmapShort.Id, BeatmapSetId = score.BeatmapShort.BeatmapSetId });

var beatmap = await new GetBeatmap(score.BeatmapShort.Id).Execute();
result += await FormatScore(score, beatmap, true);
result += await FormatLazerScore(score, beatmap, true);
}

return new TextCommandAnswer(result);
Expand Down Expand Up @@ -163,7 +161,7 @@ private async Task<ICommandAnswer> GetPass(Telegram.Bot.Types.Message message)
ChatBeatmapCache.StoreLastMap(message.Chat.Id, new ChatBeatmapCache.CachedBeatmap { BeatmapId = score.BeatmapShort.Id, BeatmapSetId = score.BeatmapShort.BeatmapSetId});

var beatmap = await new GetBeatmap(score.BeatmapShort.Id).Execute();
return new TextCommandAnswer(await FormatScore(score, beatmap, true));
return new TextCommandAnswer(await FormatLazerScore(score, beatmap, true));
}

return Localization.GetAnswer("generic_fail", message.Chat.Id);
Expand Down Expand Up @@ -359,7 +357,11 @@ private static async Task<string> FormatScore(Score score, Beatmap beatmap, bool

if (shouldCalculatePp)
{
attributes = await new GetBeatmapAttributes(beatmap.Id, score.Mods.Select(x=> Mod.AllMods.FirstOrDefault(y=> y.Acronym == x)).ToArray()).Execute();
var difficultyMods = score.Mods.Select(x => Pettanko.Mod.AllMods.FirstOrDefault(y => y.Acronym == x))
.Select(x=> new Mod { Acronym = x.Acronym })
.ToArray();

attributes = await new GetBeatmapAttributes(beatmap.Id, difficultyMods).Execute();
}

double scorePp = score.Pp ?? PpCalculation.CalculatePerformance(score, attributes, beatmap);
Expand Down Expand Up @@ -405,5 +407,112 @@ private static async Task<string> FormatScore(Score score, Beatmap beatmap, bool
$"{score.Combo}/{beatmap.MaxCombo}x ({score.Statistics.Count300} / {score.Statistics.Count100} / {score.Statistics.Count50} / {score.Statistics.CountMiss}) {pp}{Environment.NewLine}" +
$"{position}{date}{completion}{Environment.NewLine}{Environment.NewLine}";
}

private static async Task<string> FormatLazerScore(LazerScore score, Beatmap beatmap, bool useAgo)
{
string mods = string.Empty;
if (score.Mods.Length > 0)
{
mods = " +";
foreach (var mod in score.Mods)
{
if (mod.Acronym != "DA")
mods += mod.Acronym;

if (mod.Settings.Any())
{
if (mod.Settings.ContainsKey("speed_change"))
{
mods += $"({double.Parse(mod.Settings["speed_change"]!, CultureInfo.InvariantCulture)}x) ";
}
if (mod.Settings.ContainsKey("approach_rate"))
{
mods += $"AR{double.Parse(mod.Settings["approach_rate"]!, CultureInfo.InvariantCulture)} ";
}
if (mod.Settings.ContainsKey("circle_size"))
{
mods += $"CS{double.Parse(mod.Settings["circle_size"]!, CultureInfo.InvariantCulture)} ";
}
if (mod.Settings.ContainsKey("overall_difficulty"))
{
mods += $"OD{double.Parse(mod.Settings["overall_difficulty"]!, CultureInfo.InvariantCulture)} ";
}
}
}

mods = mods.TrimEnd();
}

string date = score.Date?.ToShortDateString();
if (useAgo && score.Date != null)
{
TimeSpan ago = DateTime.Now.ToUniversalTime() - score.Date.Value;
date = $"{ago:hh\\:mm\\:ss} ago";
}

// html-filtered map title
string mapInfo = $"{beatmap.BeatmapSet.Artist} - {beatmap.BeatmapSet.Title} [{score.Beatmap.Version}]".FilterToHTML();

string pp = $"| {score.Pp:N2}pp";
if (beatmap.Mode == Mode.Osu)
{
try
{
// Add pp values
var shouldCalculatePp = score.Pp is null ||
score.ComboBasedMissCount(beatmap.MaxCombo, beatmap.Sliders) > 0;

Pettanko.Difficulty.OsuDifficultyAttributes attributes = null;

if (shouldCalculatePp)
{
var difficultyMods = score.Mods.Where(x => Pettanko.Mod.AllMods.Any(y => y.Acronym == x.Acronym))
.ToArray();
attributes = await new GetBeatmapAttributes(beatmap.Id, difficultyMods).Execute();
}

double scorePp = score.Pp ?? PpCalculation.CalculatePerformance(score, attributes, beatmap);
string possiblePp = string.Empty;

if (score.ComboBasedMissCount(beatmap.MaxCombo, beatmap.Sliders) > 0)
{
// Add possible pp value if they missed
var fcScore = new LazerScore
{
Statistics = new LazerScore.ScoreStatistics
{
Count300 = (score.Beatmap.ObjectsTotal - score.Statistics.Count100 - score.Statistics.Count50) ?? 0,
Count100 = score.Statistics.Count100,
Count50 = score.Statistics.Count50,
},
Combo = beatmap.MaxCombo,
Mods = score.Mods
};

double possiblePPval = PpCalculation.CalculatePerformance(fcScore, attributes, beatmap);
possiblePp = $"(~{possiblePPval:N2}pp if FC)";
}

pp = $"| {(score.Pp == null ? "~" : "")}{scorePp:N2}pp {possiblePp}";
}
catch (Exception e)
{
Log.Error($"Oppai failed: {e.InnerMessageIfAny()}");
}
}

var position = string.Empty;
if (score.LeaderboardPosition != null)
position = $"#{score.LeaderboardPosition} | ";

var completion = string.Empty;
if (useAgo)
completion = $" | {(double)(score.Statistics.Count300 + score.Statistics.Count100 + score.Statistics.Count50 + score.Statistics.CountMiss) / score.Beatmap.ObjectsTotal * 100.0:N1}% completion";

return
$"<b>({score.Grade.GetDescription()})</b> <a href=\"{score.Beatmap.Link}\">{mapInfo}</a><b>{mods} ({score.Accuracy:N2}%)</b>{Environment.NewLine}" +
$"{score.Combo}/{beatmap.MaxCombo}x ({score.Statistics.Count300} / {score.Statistics.Count100} / {score.Statistics.Count50} / {score.Statistics.CountMiss}) {pp}{Environment.NewLine}" +
$"{position}{date}{completion}{Environment.NewLine}{Environment.NewLine}";
}
}
}
9 changes: 7 additions & 2 deletions den0bot.Modules.Osu/Parsers/BeatmapLinkParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
using System.Linq;
using System.Text.RegularExpressions;
using den0bot.Modules.Osu.Types.Enums;
using den0bot.Modules.Osu.Types.V2;
using den0bot.Util;
using Pettanko;
using Match = System.Text.RegularExpressions.Match;

namespace den0bot.Modules.Osu.Parsers
{
Expand Down Expand Up @@ -88,7 +89,11 @@ private static Mod[] ConvertToMods(string modString)
var mods = new List<Mod>();
for (var i = 0; i < modString.Length; i += 2)
{
var mod = Mod.AllMods.FirstOrDefault(x => x.Acronym == modString.Substring(i, 2));
var mod = Pettanko.Mod.AllMods
.Where(x => x.Acronym == modString.Substring(i, 2))
.Select(x=> new Mod {Acronym = x.Acronym})
.FirstOrDefault();

if (mod != null)
{
mods.Add(mod);
Expand Down
36 changes: 34 additions & 2 deletions den0bot.Modules.Osu/PpCalculation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ public static double CalculatePerformance(Types.V2.Score score, OsuDifficultyAtt
difficultyAttributes.SliderCount = beatmap.Sliders;
difficultyAttributes.SpinnerCount = beatmap.Spinners;

var mods = new List<Mod>();
var mods = new List<Pettanko.Mod>();
foreach (var mod in score.Mods)
{
var pettankoMod = Mod.AllMods.FirstOrDefault(x => x.Acronym == mod);
var pettankoMod = Pettanko.Mod.AllMods.FirstOrDefault(x => x.Acronym == mod);
if (pettankoMod != null)
mods.Add(pettankoMod);
}
Expand All @@ -58,5 +58,37 @@ public static double CalculatePerformance(Types.V2.Score score, OsuDifficultyAtt

return perfAttributes.Total;
}

public static double CalculatePerformance(Types.V2.LazerScore score, OsuDifficultyAttributes difficultyAttributes, Beatmap beatmap)
{
difficultyAttributes.HitCircleCount = beatmap.Circles;
difficultyAttributes.SliderCount = beatmap.Sliders;
difficultyAttributes.SpinnerCount = beatmap.Spinners;

var mods = new List<Pettanko.Mod>();
foreach (var mod in score.Mods)
{
var pettankoMod = Pettanko.Mod.AllMods.FirstOrDefault(x => x.Acronym == mod.Acronym);
if (pettankoMod != null)
mods.Add(pettankoMod);
}

var perfAttributes = Pettanko.Pettanko.Calculate(difficultyAttributes, new Pettanko.Score
{
Accuracy = score.Accuracy / 100.0,
MaxCombo = score.Combo,
RulesetId = 0,
Statistics = new Statistics
{
Count300 = score.Statistics.Count300,
Count100 = score.Statistics.Count100,
Count50 = score.Statistics.Count50,
CountMiss = score.Statistics.CountMiss
},
Mods = mods.ToArray()
});

return perfAttributes.Total;
}
}
}
Loading

0 comments on commit c7c4ed2

Please sign in to comment.