1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-05 10:33:22 +08:00

Compare commits

...

46 Commits

Author SHA1 Message Date
Givikap120
78cdb12a6c
Merge 0ff35eb475 into f09d8f097a 2024-12-03 03:36:47 -05:00
Dan Balasescu
f09d8f097a
Merge pull request #30953 from peppy/notification-while-chedcking-for-updates
Show an ongoing operation when checking for updates
2024-12-03 17:27:10 +09:00
Dean Herbert
457957d3b8
Refactor check-update flow to better handle unobserved exceptions 2024-12-03 14:23:10 +09:00
Dean Herbert
2ceb3f6f85
Show an ongoing operation when checking for updates
Addresses https://github.com/ppy/osu/discussions/30950.
2024-12-03 13:43:20 +09:00
Givikap120
0ff35eb475 remove leftover effective misscount func 2024-11-28 21:23:43 +02:00
Givikap120
f1a4fbc053 Update OsuPerformanceCalculator.cs 2024-11-28 18:06:06 +02:00
Givikap120
4a5f2f9236 fix CI 2024-11-28 17:52:34 +02:00
Givikap120
eef605ead2 remove math net 2024-11-28 17:39:43 +02:00
Givikap120
821158bfba change to nullable
and rename some stuff
2024-11-28 17:35:59 +02:00
Givikap120
8e46297304 Merge branch 'master' into stat_acc_anti_rake 2024-11-28 17:31:21 +02:00
Givikap120
2c8c31876d Merge branch 'master' into stat_acc_anti_rake 2024-11-15 01:29:42 +02:00
Givikap120
a2a0ffba2d Merge branch 'master' into stat_acc_anti_rake 2024-11-08 15:01:53 +02:00
Givikap120
64e694c147 Merge branch 'master' into stat_acc_anti_rake 2024-10-31 15:47:52 +02:00
Givikap120
e00a8c4b51 Merge branch 'master' into stat_acc_anti_rake 2024-10-25 02:54:21 +03:00
Givikap120
b8898d61f2 updated antirake 2024-10-15 15:02:18 +03:00
Givikap120
bba244981a adjusted rake nerf to usage of new function 2024-09-16 20:28:38 +03:00
Givikap120
06c2b192b1 Merge branch 'master' into stat_acc_anti_rake 2024-09-16 20:25:33 +03:00
Givikap120
ea954002d2 tried to bandaid the issue 2024-09-09 13:41:32 +03:00
Givikap120
6721963163 reverted acc to live 2024-09-09 13:02:54 +03:00
Givikap120
b21afb4c54 removed *0.9 and changed relevant note count 2024-08-28 02:26:22 +03:00
Givikap120
c72adc69ac ported things from main branch
slight buff for slidermaps and high-end fix
2024-08-26 22:46:55 +03:00
Givikap120
ecf1dcfcf7 changed antirake functions logic 2024-07-18 19:58:34 +03:00
Givikap120
07dd324922 removed display attributes 2024-07-18 19:44:50 +03:00
Givikap120
9cdd224237 Merge branch 'stat_acc_no_lazer' of https://github.com/Givikap120/osu into stat_acc_no_lazer 2024-07-18 19:44:12 +03:00
Givikap120
d3ceb1b520 reverted speed change 2024-07-18 19:43:55 +03:00
Givikap120
b8b8607085
Merge branch 'ppy:master' into stat_acc_no_lazer 2024-07-18 19:42:32 +03:00
Givikap120
c4d5ac7008 refactored multiplier stuff out of main func 2024-07-18 19:40:50 +03:00
Givikap120
a0e1da8775 Update OsuPerformanceCalculator.cs 2024-07-18 19:19:21 +03:00
Givikap120
dfa28e9e08 Merge branch 'stat_acc_no_lazer' of https://github.com/Givikap120/osu into stat_acc_no_lazer 2024-07-17 15:49:50 +03:00
Givikap120
c0dc878698 Update OsuPerformanceCalculator.cs 2024-07-17 15:45:34 +03:00
Givikap120
9c7bd5079c
Merge branch 'ppy:master' into stat_acc_no_lazer 2024-07-17 15:44:24 +03:00
Givikap120
42d6464d64 removed lazer stuff 2024-07-17 15:44:05 +03:00
Givikap120
3c52296d1c removed [] array literal 2024-07-01 20:31:23 +03:00
Givikap120
7f57226bdb big amount of refactoring
- put shared logic in one function
- improved sanity checks
- improved estimation of UR on sliders
2024-07-01 17:21:58 +03:00
Givikap120
e90d79babd simplified difficulty to performance formulas 2024-07-01 15:30:24 +03:00
Givikap120
92807d58f0 reworked anti-rake, again 2024-06-30 20:41:22 +03:00
Givikap120
41a3a9b15b made aim rake nerf more lenient 2024-06-28 22:58:15 +03:00
Givikap120
ce41fc58e9 anti-rake curve update 2024-06-28 20:04:53 +03:00
Givikap120
907b638663 refactoring 2024-06-28 14:44:26 +03:00
Givikap120
5196891553 removed CL huis bandaid 2024-06-28 14:23:10 +03:00
Givikap120
9aba0f6bb8 changed rake nerf
and made UR on sliders more stable
2024-06-28 01:52:47 +03:00
Givikap120
2f94eea950 removed speed object count independene from distance 2024-06-28 00:14:30 +03:00
Givikap120
588a98335b Update OsuPerformanceCalculator.cs 2024-06-27 21:20:16 +03:00
Givikap120
91e377de45 added bandaid for huis 2024-06-27 21:16:48 +03:00
Givikap120
0788f18406 fixed NaN issue in deviation calc 2024-06-27 16:44:09 +03:00
Givikap120
198f35dc63 ported my stat acc branch 2024-06-27 15:45:58 +03:00
4 changed files with 185 additions and 20 deletions

View File

@ -24,6 +24,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
[JsonProperty("effective_miss_count")] [JsonProperty("effective_miss_count")]
public double EffectiveMissCount { get; set; } public double EffectiveMissCount { get; set; }
[JsonProperty("speed_deviation")]
public double? SpeedDeviation { get; set; }
public override IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay() public override IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay()
{ {
foreach (var attribute in base.GetAttributesForDisplay()) foreach (var attribute in base.GetAttributesForDisplay())

View File

@ -4,11 +4,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Difficulty.Skills; using osu.Game.Rulesets.Osu.Difficulty.Skills;
using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Utils;
namespace osu.Game.Rulesets.Osu.Difficulty namespace osu.Game.Rulesets.Osu.Difficulty
{ {
@ -40,6 +44,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
/// </summary> /// </summary>
private double effectiveMissCount; private double effectiveMissCount;
private double hitWindow300, hitWindow100, hitWindow50;
private double? speedDeviation;
public OsuPerformanceCalculator() public OsuPerformanceCalculator()
: base(new OsuRuleset()) : base(new OsuRuleset())
{ {
@ -110,10 +117,18 @@ namespace osu.Game.Rulesets.Osu.Difficulty
effectiveMissCount = Math.Min(effectiveMissCount + countOk * okMultiplier + countMeh * mehMultiplier, totalHits); effectiveMissCount = Math.Min(effectiveMissCount + countOk * okMultiplier + countMeh * mehMultiplier, totalHits);
} }
double clockRate = getClockRate(score);
hitWindow300 = 80 - 6 * osuAttributes.OverallDifficulty;
hitWindow100 = (140 - 8 * ((80 - hitWindow300 * clockRate) / 6)) / clockRate;
hitWindow50 = (200 - 10 * ((80 - hitWindow300 * clockRate) / 6)) / clockRate;
speedDeviation = calculateSpeedDeviation(score, osuAttributes);
double aimValue = computeAimValue(score, osuAttributes); double aimValue = computeAimValue(score, osuAttributes);
double speedValue = computeSpeedValue(score, osuAttributes); double speedValue = computeSpeedValue(score, osuAttributes);
double accuracyValue = computeAccuracyValue(score, osuAttributes); double accuracyValue = computeAccuracyValue(score, osuAttributes);
double flashlightValue = computeFlashlightValue(score, osuAttributes); double flashlightValue = computeFlashlightValue(score, osuAttributes);
double totalValue = double totalValue =
Math.Pow( Math.Pow(
Math.Pow(aimValue, 1.1) + Math.Pow(aimValue, 1.1) +
@ -129,6 +144,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
Accuracy = accuracyValue, Accuracy = accuracyValue,
Flashlight = flashlightValue, Flashlight = flashlightValue,
EffectiveMissCount = effectiveMissCount, EffectiveMissCount = effectiveMissCount,
SpeedDeviation = speedDeviation,
Total = totalValue Total = totalValue
}; };
} }
@ -196,7 +212,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private double computeSpeedValue(ScoreInfo score, OsuDifficultyAttributes attributes) private double computeSpeedValue(ScoreInfo score, OsuDifficultyAttributes attributes)
{ {
if (score.Mods.Any(h => h is OsuModRelax)) if (score.Mods.Any(h => h is OsuModRelax) || speedDeviation == null)
return 0.0; return 0.0;
double speedValue = OsuStrainSkill.DifficultyToPerformance(attributes.SpeedDifficulty); double speedValue = OsuStrainSkill.DifficultyToPerformance(attributes.SpeedDifficulty);
@ -225,6 +241,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty
speedValue *= 1.0 + 0.04 * (12.0 - attributes.ApproachRate); speedValue *= 1.0 + 0.04 * (12.0 - attributes.ApproachRate);
} }
// Apply improper tapping nerf for too high deviation values
double speedHighDeviationMultiplier = calculateSpeedHighDeviationNerf(attributes);
speedValue *= speedHighDeviationMultiplier;
// Calculate accuracy assuming the worst case scenario // Calculate accuracy assuming the worst case scenario
double relevantTotalDiff = totalHits - attributes.SpeedNoteCount; double relevantTotalDiff = totalHits - attributes.SpeedNoteCount;
double relevantCountGreat = Math.Max(0, countGreat - relevantTotalDiff); double relevantCountGreat = Math.Max(0, countGreat - relevantTotalDiff);
@ -305,12 +325,124 @@ namespace osu.Game.Rulesets.Osu.Difficulty
return flashlightValue; return flashlightValue;
} }
/// <summary>
/// Using <see cref="calculateDeviation"/> estimates player's deviation on speed notes, assuming worst-case.
/// Treats all speed notes as hit circles. This is not good way to do this, but fixing this is impossible under the limitation of current speed pp.
/// If score was set with slideracc - tries to remove mistaps on sliders from total mistaps.
/// </summary>
private double? calculateSpeedDeviation(ScoreInfo score, OsuDifficultyAttributes attributes)
{
if (totalSuccessfulHits == 0)
return null;
// Calculate accuracy assuming the worst case scenario
double speedNoteCount = attributes.SpeedNoteCount;
speedNoteCount += (totalHits - attributes.SpeedNoteCount) * 0.1;
// Assume worst case: all mistakes was on speed notes
double relevantCountMiss = Math.Min(countMiss, speedNoteCount);
double relevantCountMeh = Math.Min(countMeh, speedNoteCount - relevantCountMiss);
double relevantCountOk = Math.Min(countOk, speedNoteCount - relevantCountMiss - relevantCountMeh);
double relevantCountGreat = Math.Max(0, speedNoteCount - relevantCountMiss - relevantCountMeh - relevantCountOk);
// Calculate and return deviation on speed notes
return calculateDeviation(relevantCountGreat, relevantCountOk, relevantCountMeh, relevantCountMiss);
}
/// <summary>
/// Estimates the player's tap deviation based on the OD, given number of 300s, 100s, 50s and misses,
/// assuming the player's mean hit error is 0. The estimation is consistent in that two SS scores on the same map with the same settings
/// will always return the same deviation. Misses are ignored because they are usually due to misaiming.
/// 300s and 100s are assumed to follow a normal distribution, whereas 50s are assumed to follow a uniform distribution.
/// </summary>
private double? calculateDeviation(double relevantCountGreat, double relevantCountOk, double relevantCountMeh, double relevantCountMiss)
{
if (relevantCountGreat + relevantCountOk + relevantCountMeh <= 0)
return null;
double objectCount = relevantCountGreat + relevantCountOk + relevantCountMeh + relevantCountMiss;
//// The probability that a player hits a circle is unknown, but we can estimate it to be
//// the number of greats on circles divided by the number of circles, and then add one
//// to the number of circles as a bias correction.
double n = Math.Max(1, objectCount - relevantCountMiss - relevantCountMeh);
const double z = 2.32634787404; // 99% critical value for the normal distribution (one-tailed).
// Proportion of greats hit on circles, ignoring misses and 50s.
double p = relevantCountGreat / n;
// We can be 99% confident that p is at least this value.
double pLowerBound = (n * p + z * z / 2) / (n + z * z) - z / (n + z * z) * Math.Sqrt(n * p * (1 - p) + z * z / 4);
// Compute the deviation assuming 300s and 100s are normally distributed, and 50s are uniformly distributed.
// Begin with 300s and 100s first. Ignoring 50s, we can be 99% confident that the deviation is not higher than:
double deviation = hitWindow300 / (Math.Sqrt(2) * SpecialFunctions.ErfInv(pLowerBound));
double randomValue = Math.Sqrt(2 / Math.PI) * hitWindow100 * Math.Exp(-0.5 * Math.Pow(hitWindow100 / deviation, 2))
/ (deviation * SpecialFunctions.Erf(hitWindow100 / (Math.Sqrt(2) * deviation)));
deviation *= Math.Sqrt(1 - randomValue);
// Value deviation approach as greatCount approaches 0
double limitValue = hitWindow100 / Math.Sqrt(3);
// If precision is not enough to compute true deviation - use limit value
if (pLowerBound == 0 || randomValue >= 1 || deviation > limitValue)
deviation = limitValue;
// Then compute the variance for 50s.
double mehVariance = (hitWindow50 * hitWindow50 + hitWindow100 * hitWindow50 + hitWindow100 * hitWindow100) / 3;
// Find the total deviation.
deviation = Math.Sqrt(((relevantCountGreat + relevantCountOk) * Math.Pow(deviation, 2) + relevantCountMeh * mehVariance) / (relevantCountGreat + relevantCountOk + relevantCountMeh));
return deviation;
}
// Calculates multiplier for speed accounting for improper tapping based on the deviation and speed difficulty
// https://www.desmos.com/calculator/dmogdhzofn
private double calculateSpeedHighDeviationNerf(OsuDifficultyAttributes attributes)
{
if (speedDeviation == null)
return 0;
// Base speed value
double speedValue = OsuStrainSkill.DifficultyToPerformance(attributes.SpeedDifficulty);
// Starting from this pp amount - penalty will be applied
double abusePoint = 100 + 220 * Math.Pow(22 / speedDeviation.Value, 6.5);
if (speedValue <= abusePoint)
return 1.0;
// Use log curve to make additional rise in difficulty unimpactful. Rescale values to make curve have correct steepness
const double scale = 50;
double adjustedSpeedValue = scale * (Math.Log((speedValue - abusePoint) / scale + 1) + abusePoint / scale);
// 200 UR and less are considered tapped correctly to ensure that normal scores would be punished as little as possible
double lerp = 1 - Math.Clamp((speedDeviation.Value - 20) / (24 - 20), 0, 1);
adjustedSpeedValue = double.Lerp(adjustedSpeedValue, speedValue, lerp);
return adjustedSpeedValue / speedValue;
}
private static double getClockRate(ScoreInfo score)
{
var track = new TrackVirtual(1);
score.Mods.OfType<IApplicableToTrack>().ForEach(m => m.ApplyToTrack(track));
return track.Rate;
}
// Miss penalty assumes that a player will miss on the hardest parts of a map, // Miss penalty assumes that a player will miss on the hardest parts of a map,
// so we use the amount of relatively difficult sections to adjust miss penalty // so we use the amount of relatively difficult sections to adjust miss penalty
// to make it more punishing on maps with lower amount of hard sections. // to make it more punishing on maps with lower amount of hard sections.
private double calculateMissPenalty(double missCount, double difficultStrainCount) => 0.96 / ((missCount / (4 * Math.Pow(Math.Log(difficultStrainCount), 0.94))) + 1); private double calculateMissPenalty(double missCount, double difficultStrainCount) => 0.96 / ((missCount / (4 * Math.Pow(Math.Log(difficultStrainCount), 0.94))) + 1);
private double getComboScalingFactor(OsuDifficultyAttributes attributes) => attributes.MaxCombo <= 0 ? 1.0 : Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(attributes.MaxCombo, 0.8), 1.0); private double getComboScalingFactor(OsuDifficultyAttributes attributes) => attributes.MaxCombo <= 0 ? 1.0 : Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(attributes.MaxCombo, 0.8), 1.0);
private int totalHits => countGreat + countOk + countMeh + countMiss; private int totalHits => countGreat + countOk + countMeh + countMiss;
private int totalSuccessfulHits => countGreat + countOk + countMeh;
private int totalImperfectHits => countOk + countMeh + countMiss; private int totalImperfectHits => countOk + countMeh + countMiss;
} }
} }

View File

@ -44,6 +44,11 @@ namespace osu.Game.Localisation
/// </summary> /// </summary>
public static LocalisableString CheckUpdate => new TranslatableString(getKey(@"check_update"), @"Check for updates"); public static LocalisableString CheckUpdate => new TranslatableString(getKey(@"check_update"), @"Check for updates");
/// <summary>
/// "Checking for updates"
/// </summary>
public static LocalisableString CheckingForUpdates => new TranslatableString(getKey(@"checking_for_updates"), @"Checking for updates");
/// <summary> /// <summary>
/// "Open osu! folder" /// "Open osu! folder"
/// </summary> /// </summary>

View File

@ -4,7 +4,6 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using osu.Framework; using osu.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Logging; using osu.Framework.Logging;
@ -13,6 +12,7 @@ using osu.Framework.Screens;
using osu.Framework.Statistics; using osu.Framework.Statistics;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Localisation; using osu.Game.Localisation;
using osu.Game.Online.Multiplayer;
using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Notifications;
using osu.Game.Overlays.Settings.Sections.Maintenance; using osu.Game.Overlays.Settings.Sections.Maintenance;
using osu.Game.Updater; using osu.Game.Updater;
@ -36,8 +36,11 @@ namespace osu.Game.Overlays.Settings.Sections.General
[Resolved] [Resolved]
private Storage storage { get; set; } = null!; private Storage storage { get; set; } = null!;
[Resolved]
private OsuGame? game { get; set; }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config, OsuGame? game) private void load(OsuConfigManager config)
{ {
Add(new SettingsEnumDropdown<ReleaseStream> Add(new SettingsEnumDropdown<ReleaseStream>
{ {
@ -50,23 +53,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
Add(checkForUpdatesButton = new SettingsButton Add(checkForUpdatesButton = new SettingsButton
{ {
Text = GeneralSettingsStrings.CheckUpdate, Text = GeneralSettingsStrings.CheckUpdate,
Action = () => Action = () => checkForUpdates().FireAndForget()
{
checkForUpdatesButton.Enabled.Value = false;
Task.Run(updateManager.CheckForUpdateAsync).ContinueWith(task => Schedule(() =>
{
if (!task.GetResultSafely())
{
notifications?.Post(new SimpleNotification
{
Text = GeneralSettingsStrings.RunningLatestRelease(game!.Version),
Icon = FontAwesome.Solid.CheckCircle,
});
}
checkForUpdatesButton.Enabled.Value = true;
}));
}
}); });
} }
@ -94,6 +81,44 @@ namespace osu.Game.Overlays.Settings.Sections.General
} }
} }
private async Task checkForUpdates()
{
if (updateManager == null || game == null)
return;
checkForUpdatesButton.Enabled.Value = false;
var checkingNotification = new ProgressNotification
{
Text = GeneralSettingsStrings.CheckingForUpdates,
};
notifications?.Post(checkingNotification);
try
{
bool foundUpdate = await updateManager.CheckForUpdateAsync().ConfigureAwait(true);
if (!foundUpdate)
{
notifications?.Post(new SimpleNotification
{
Text = GeneralSettingsStrings.RunningLatestRelease(game.Version),
Icon = FontAwesome.Solid.CheckCircle,
});
}
}
catch
{
}
finally
{
// This sequence allows the notification to be immediately dismissed.
checkingNotification.State = ProgressNotificationState.Cancelled;
checkingNotification.Close(false);
checkForUpdatesButton.Enabled.Value = true;
}
}
private void exportLogs() private void exportLogs()
{ {
ProgressNotification notification = new ProgressNotification ProgressNotification notification = new ProgressNotification