Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cognition difficulty calculation rework: High AR part #28112

Open
wants to merge 112 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
b95d69b
initial
apollo-dw Jun 21, 2022
ee8f207
Make changes which I forgot lol
apollo-dw Jun 21, 2022
ec543c1
Clarify that variable names currently suck
apollo-dw Jun 21, 2022
d8f1866
Wave of changes
apollo-dw Jun 21, 2022
d83f1c4
Adjust note-density and hidden buffs
apollo-dw Jun 24, 2022
2527ad1
Merge branch 'master' into cognition
apollo-dw Jul 19, 2022
06b1425
WIP
apollo-dw Jul 19, 2022
8991a73
Merge branch 'ppy:master' into cognition
apollo-dw Aug 9, 2022
422c24b
Merge branch 'cognition' of https://github.com/apollo-dw/osu into cog…
apollo-dw Aug 9, 2022
c09e5ae
Merge branch 'ppy:master' into cognition
apollo-dw Aug 9, 2022
f7720e7
Merge branch 'cognition' of https://github.com/apollo-dw/osu into cog…
apollo-dw Aug 9, 2022
3c38c9e
Fix null objects
apollo-dw Aug 9, 2022
e6193e8
Use past objects for note density
apollo-dw Aug 10, 2022
152a195
Add HD support
apollo-dw Aug 10, 2022
2d5f2fc
Buff stream-spacing objects slightly, reduce velocity factor in HD
apollo-dw Aug 10, 2022
ca55fec
Merge branch 'master' into cognition
apollo-dw Aug 11, 2022
f1f1e10
Change low spacing influence, add time separation factor, and moar hi…
apollo-dw Aug 25, 2022
35c7201
Various high AR tweaks
apollo-dw Aug 27, 2022
b0d47e4
Allow hidden difficulty and high AR difficulty to co-exist.
apollo-dw Aug 27, 2022
97f3f28
Time factor, improve spacing and rhythm buffs
apollo-dw Aug 28, 2022
f1e14b3
Add constant rhythm nerf, reduce repeat angle nerf, buff spacing
apollo-dw Aug 31, 2022
c690ecf
Merge branch 'master' into cognition
apollo-dw Sep 7, 2022
9797493
Nerf linear, readjust hidden parameters
apollo-dw Sep 13, 2022
8e614e2
Don't nerf object influence if stream
apollo-dw Oct 5, 2022
cd0b2b2
Change some AR11 calc
apollo-dw Oct 7, 2022
08fa391
Merge branch 'ppymaster' into cognition
apollo-dw Oct 7, 2022
f42004f
Remove outdated argument
apollo-dw Oct 7, 2022
b6d4fbf
Add constant angle nerf to note density difficulty
apollo-dw Oct 10, 2022
d50e67f
Remove WIP ar11 stuff from Cognition
apollo-dw Oct 17, 2022
441bea5
Make angle nerf requirement narrower
apollo-dw Oct 17, 2022
090b408
Apply various changes
apollo-dw Oct 18, 2022
82cbdcc
Rename cognition to reading
apollo-dw Oct 18, 2022
a7070b5
Improve code quality
apollo-dw Oct 19, 2022
a9e9e50
Capitalize member
apollo-dw Oct 19, 2022
4a535fe
Revert high AR changes
apollo-dw Oct 24, 2022
ed07dbe
Merge branch 'ppy:master' into cognition
apollo-dw Nov 9, 2022
8937080
Merge branch 'ppy:master' into cognition
apollo-dw Jul 29, 2023
c171274
Balance streams and HD aim
apollo-dw Jul 30, 2023
07df5d9
Further balance values
apollo-dw Aug 9, 2023
ef30961
Merge branch 'ppy:master' into cognition
Givikap120 Jan 5, 2024
ffeb46a
Initial overlap calc
Givikap120 Jan 8, 2024
c64430f
Improved overlap calc
Givikap120 Jan 16, 2024
8c2405d
Big bump
Givikap120 Jan 20, 2024
f429f21
Fixed low AR
Givikap120 Jan 23, 2024
77ce1ae
Slight balancing
Givikap120 Jan 23, 2024
f6df247
Added infra and hidden
Givikap120 Jan 24, 2024
cede416
Added full-memory cap
Givikap120 Jan 26, 2024
394af04
Added inpredictability calculation
Givikap120 Jan 26, 2024
58159a5
Update Reading.cs
Givikap120 Jan 26, 2024
8ba3f2e
Changed reading cap
Givikap120 Jan 27, 2024
7c294c8
Merge branch 'ppy:master' into cognition
Givikap120 Jan 27, 2024
51eb5c0
Alternating angle nerf
Givikap120 Jan 28, 2024
ba265ac
Update LegacyScoreDecoder.cs
Givikap120 Jan 28, 2024
1a68e29
Big amount of changes
Givikap120 Feb 2, 2024
639f877
Minor SR adjust for high AR bonus
Givikap120 Feb 4, 2024
e6f1a40
Change scaling to make high AR woth more on low SR
Givikap120 Feb 12, 2024
83d391e
Merge branch 'master' into cognition
Givikap120 Feb 13, 2024
9e6ae35
Changes to highAR and angle nerf
Givikap120 Feb 23, 2024
5d4c782
added density aim multiplier
Givikap120 Feb 23, 2024
c8e9602
Update ReadingEvaluator.cs
Givikap120 Feb 28, 2024
c2e5d76
Fixed reading cap
Givikap120 Mar 7, 2024
4b5d463
Update Reading.cs
Givikap120 Mar 7, 2024
a8b6ae9
high AR speed nerf
Givikap120 Mar 8, 2024
d3cdb67
low AR streams balancing
Givikap120 Mar 16, 2024
5e35121
Merge branch 'ppy:master' into cognition
Givikap120 Mar 16, 2024
5e2f3e3
Increased stability
Givikap120 Mar 17, 2024
ab47d39
Balancing
Givikap120 Mar 21, 2024
333bfd2
added acc bonus for low AR
Givikap120 Mar 21, 2024
cead94d
minor balancing update
Givikap120 Mar 23, 2024
53b918e
deleted more db-stuff
Givikap120 Mar 23, 2024
529bd84
more clean-up
Givikap120 Mar 23, 2024
4d2cb57
fixed very stupid bug
Givikap120 Mar 23, 2024
6b1320e
increased stability of the overlaps
Givikap120 Mar 23, 2024
c016ed0
Update OsuDifficultyHitObject.cs
Givikap120 Mar 23, 2024
403dc5b
Walk This Way bandaid
Givikap120 Mar 23, 2024
4051413
rubik's cube bandaid
Givikap120 Mar 24, 2024
98873e2
fixed high AR (i hope)
Givikap120 Mar 24, 2024
b4fadc3
change SR scalig
Givikap120 Mar 24, 2024
d96eeeb
high AR changes
Givikap120 Mar 25, 2024
6ec5bb5
Fixed the overlap bug
Givikap120 Mar 26, 2024
c4af2bb
optimisation
Givikap120 Mar 26, 2024
71df659
bandaid for Rainbow Dash +EZ
Givikap120 Mar 26, 2024
23808be
new experimental overlap summing
Givikap120 Mar 30, 2024
2dbdd4f
balancing
Givikap120 Apr 4, 2024
ae4f0a1
Many changes
Givikap120 Apr 7, 2024
801843b
Update ReadingEvaluator.cs
Givikap120 Apr 7, 2024
a2e4cb8
Minor fixes
Givikap120 Apr 7, 2024
af92559
fixed the bug
Givikap120 Apr 8, 2024
faf18e1
heavy optimisations
Givikap120 Apr 8, 2024
33d1e2f
bit of high AR balancing
Givikap120 Apr 8, 2024
8d080cc
Angle penalty change
Givikap120 Apr 14, 2024
9a7c21b
high AR clean-up and balancing
Givikap120 Apr 14, 2024
84b7bad
minor changes
Givikap120 Apr 15, 2024
6a4bd64
better reading cap curve
Givikap120 Apr 16, 2024
463a6ce
many HD-related changes
Givikap120 Apr 18, 2024
0d6a4c5
balancing HD
Givikap120 Apr 22, 2024
81f1136
added old HD bonus to merge with master
Givikap120 Apr 25, 2024
7750b43
Update OsuPerformanceCalculator.cs
Givikap120 Apr 25, 2024
d4f8340
Merge branch 'ppy:master' into cognition
Givikap120 Apr 25, 2024
3888bd4
removed old HD bonus
Givikap120 Apr 25, 2024
856b631
Merge branch 'cognition' of https://github.com/Givikap120/osu into co…
Givikap120 Apr 25, 2024
07cb701
Balancing
Givikap120 Apr 28, 2024
3d9584d
more balancing
Givikap120 Apr 28, 2024
e4d8ed9
optimizations
Givikap120 May 2, 2024
86f7b7d
optimization and code quality
Givikap120 May 2, 2024
fd4beb5
lil bit clean-up
Givikap120 May 5, 2024
d50df4e
Update OsuPerformanceCalculator.cs
Givikap120 May 5, 2024
de91242
added TD and RX support
Givikap120 May 5, 2024
4f79096
cut out high AR
Givikap120 May 5, 2024
b652304
more clean-up
Givikap120 May 5, 2024
242ca61
removed attributes
Givikap120 May 5, 2024
9b14156
refactoring and balancing
Givikap120 May 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Objects;

namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
{
// Main class with some util functions
public static class ReadingEvaluator
{
// Returns value from 0 to 1, where 0 is very predictable and 1 is very unpredictable
public static double EvaluateInpredictabilityOf(DifficultyHitObject current)
{
// make the sum equal to 1
const double velocity_change_part = 0.8;
const double angle_change_part = 0.1;
const double rhythm_change_part = 0.1;

if (current.BaseObject is Spinner || current.Index == 0 || current.Previous(0).BaseObject is Spinner)
return 0;

var osuCurrObj = (OsuDifficultyHitObject)current;
var osuLastObj = (OsuDifficultyHitObject)current.Previous(0);

// Rhythm difference punishment for velocity and angle bonuses
double rhythmSimilarity = 1 - getRhythmDifference(osuCurrObj.StrainTime, osuLastObj.StrainTime);

// Make differentiation going from 1/4 to 1/2 and bigger difference
// To 1/3 to 1/2 and smaller difference
rhythmSimilarity = Math.Clamp(rhythmSimilarity, 0.5, 0.75);
rhythmSimilarity = 4 * (rhythmSimilarity - 0.5);

double velocityChangeBonus = getVelocityChangeFactor(osuCurrObj, osuLastObj) * rhythmSimilarity;

double currVelocity = osuCurrObj.LazyJumpDistance / osuCurrObj.StrainTime;
double prevVelocity = osuLastObj.LazyJumpDistance / osuLastObj.StrainTime;

double angleChangeBonus = 0;

if (osuCurrObj.Angle != null && osuLastObj.Angle != null && currVelocity > 0 && prevVelocity > 0)
{
angleChangeBonus = 1 - osuCurrObj.AnglePredictability;
angleChangeBonus *= Math.Min(currVelocity, prevVelocity) / Math.Max(currVelocity, prevVelocity); // Prevent cheesing
}

angleChangeBonus *= rhythmSimilarity;

// This bonus only awards rhythm changes if they're not filled with sliderends
double rhythmChangeBonus = 0;

if (current.Index > 1)
{
var osuLastLastObj = (OsuDifficultyHitObject)current.Previous(1);

double currDelta = osuCurrObj.StrainTime;
double lastDelta = osuLastObj.StrainTime;

if (osuLastObj.BaseObject is Slider sliderCurr)
{
currDelta -= sliderCurr.Duration / osuCurrObj.ClockRate;
currDelta = Math.Max(0, currDelta);
}

if (osuLastLastObj.BaseObject is Slider sliderLast)
{
lastDelta -= sliderLast.Duration / osuLastObj.ClockRate;
lastDelta = Math.Max(0, lastDelta);
}

rhythmChangeBonus = getRhythmDifference(currDelta, lastDelta);
}

double result = velocity_change_part * velocityChangeBonus + angle_change_part * angleChangeBonus + rhythm_change_part * rhythmChangeBonus;
return result;
}

private static double getVelocityChangeFactor(OsuDifficultyHitObject osuCurrObj, OsuDifficultyHitObject osuLastObj)
{
double currVelocity = osuCurrObj.LazyJumpDistance / osuCurrObj.StrainTime;
double prevVelocity = osuLastObj.LazyJumpDistance / osuLastObj.StrainTime;

double velocityChangeFactor = 0;

// https://www.desmos.com/calculator/kqxmqc8pkg
if (currVelocity > 0 || prevVelocity > 0)
{
double velocityChange = Math.Max(0,
Math.Min(
Math.Abs(prevVelocity - currVelocity) - 0.5 * Math.Min(currVelocity, prevVelocity),
Math.Max(((OsuHitObject)osuCurrObj.BaseObject).Radius / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), Math.Min(currVelocity, prevVelocity))
)); // Stealed from xexxar
velocityChangeFactor = velocityChange / Math.Max(currVelocity, prevVelocity); // maxiumum is 0.4
velocityChangeFactor /= 0.4;
}

return velocityChangeFactor;
}

private static double getRhythmDifference(double t1, double t2) => 1 - Math.Min(t1, t2) / Math.Max(t1, t2);
}
public static class ReadingHighAREvaluator
{
public static double EvaluateDifficultyOf(DifficultyHitObject current, bool applyAdjust = false)
{
var currObj = (OsuDifficultyHitObject)current;

double result = GetDifficulty(currObj.Preempt);

if (applyAdjust)
{
double inpredictability = ReadingEvaluator.EvaluateInpredictabilityOf(current);

// follow lines make high AR easier, so apply nerf if object isn't new combo
inpredictability *= 1 + 0.1 * (800 - currObj.FollowLineTime) / 800;

result *= 0.98 + 0.6 * inpredictability;
}

return result;
}

// High AR curve (this curve is without Math.Pow(value, 2))
// https://www.desmos.com/calculator/xuuwd77cbq
public static double GetDifficulty(double preempt)
{
// Get preempt in seconds
preempt /= 1000;
double value;

if (preempt < 0.375) // We have stop in the point of AR10.5, the value here = 0.396875, derivative = -10.5833,
value = 0.63 * Math.Pow(8 - 20 * preempt, 2.0 / 3); // This function is matching live high AR bonus
else
value = Math.Exp(9.07583 - 80.0 * preempt / 3);

// The power is 2 times higher to compensate sqrt in high AR skill
return Math.Pow(value, 2);
}
}
}
12 changes: 12 additions & 0 deletions osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,24 @@ public class OsuDifficultyAttributes : DifficultyAttributes
[JsonProperty("speed_note_count")]
public double SpeedNoteCount { get; set; }

/// <summary>
/// The difficulty corresponding to the reading skill. High AR branch.
/// </summary>
[JsonProperty("reading_high_ar_difficulty")]
public double ReadingDifficultyHighAR { get; set; }

/// <summary>
/// The difficulty corresponding to the flashlight skill.
/// </summary>
[JsonProperty("flashlight_difficulty")]
public double FlashlightDifficulty { get; set; }

/// <summary>
/// The difficulty corresponding to the flashlight skill with HD (used in capping cognition performance).
/// </summary>
[JsonProperty("hidden_flashlight_difficulty")]
public double HiddenFlashlightDifficulty { get; set; }

/// <summary>
/// Describes how much of <see cref="AimDifficulty"/> is contributed to by hitcircles or sliders.
/// A value closer to 1.0 indicates most of <see cref="AimDifficulty"/> is contributed by hitcircles.
Expand Down
70 changes: 45 additions & 25 deletions osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
{
public class OsuDifficultyCalculator : DifficultyCalculator
{
private const double difficulty_multiplier = 0.0675;

public const double DIFFICULTY_MULTIPLIER = 0.0675;
public const double SUM_POWER = 1.1;
public const double FL_SUM_POWER = 1.5;
public override int Version => 20220902;

public OsuDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
Expand All @@ -36,57 +37,72 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
if (beatmap.HitObjects.Count == 0)
return new OsuDifficultyAttributes { Mods = mods };

double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
double aimRatingNoSliders = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
double speedRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier;
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * DIFFICULTY_MULTIPLIER;
double aimRatingNoSliders = Math.Sqrt(skills[1].DifficultyValue()) * DIFFICULTY_MULTIPLIER;
double speedRating = Math.Sqrt(skills[2].DifficultyValue()) * DIFFICULTY_MULTIPLIER;
double speedNotes = ((Speed)skills[2]).RelevantNoteCount();

double flashlightRating = 0.0;
double hiddenFlashlightRating = Math.Sqrt(skills[3].DifficultyValue()) * DIFFICULTY_MULTIPLIER;

if (mods.Any(h => h is OsuModFlashlight))
flashlightRating = Math.Sqrt(skills[3].DifficultyValue()) * difficulty_multiplier;
double readingHighARRating = Math.Sqrt(skills[4].DifficultyValue()) * DIFFICULTY_MULTIPLIER;

double flashlightRating = 0;

double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1;

double baseFlashlightPerformance = 0.0;
if (mods.Any(h => h is OsuModFlashlight))
{
flashlightRating = Math.Sqrt(skills[5].DifficultyValue()) * DIFFICULTY_MULTIPLIER;
baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating);
}

if (mods.Any(m => m is OsuModTouchDevice))
{
aimRating = Math.Pow(aimRating, 0.8);
readingHighARRating = Math.Pow(readingHighARRating, 0.9);
flashlightRating = Math.Pow(flashlightRating, 0.8);
}

if (mods.Any(h => h is OsuModRelax))
{
aimRating *= 0.9;
speedRating = 0.0;
readingHighARRating *= 0.7;
flashlightRating *= 0.7;
}

double baseAimPerformance = Math.Pow(5 * Math.Max(1, aimRating / 0.0675) - 4, 3) / 100000;
double baseSpeedPerformance = Math.Pow(5 * Math.Max(1, speedRating / 0.0675) - 4, 3) / 100000;
double baseFlashlightPerformance = 0.0;

if (mods.Any(h => h is OsuModFlashlight))
baseFlashlightPerformance = Math.Pow(flashlightRating, 2.0) * 25.0;
double baseAimPerformance = OsuStrainSkill.DifficultyToPerformance(aimRating);
double baseSpeedPerformance = OsuStrainSkill.DifficultyToPerformance(speedRating);

double basePerformance =
Math.Pow(
Math.Pow(baseAimPerformance, 1.1) +
Math.Pow(baseSpeedPerformance, 1.1) +
Math.Pow(baseFlashlightPerformance, 1.1), 1.0 / 1.1
);
// Cognition
double baseReadingHighARPerformance = OsuStrainSkill.DifficultyToPerformance(readingHighARRating);
double baseReadingARPerformance = baseReadingHighARPerformance;

double starRating = basePerformance > 0.00001
? Math.Cbrt(OsuPerformanceCalculator.PERFORMANCE_BASE_MULTIPLIER) * 0.027 * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4)
: 0;
double baseFlashlightARPerformance = Math.Pow(Math.Pow(baseFlashlightPerformance, FL_SUM_POWER) + Math.Pow(baseReadingARPerformance, FL_SUM_POWER), 1.0 / FL_SUM_POWER);

double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate;

double drainRate = beatmap.Difficulty.DrainRate;
int maxCombo = beatmap.GetMaxCombo();

int hitCirclesCount = beatmap.HitObjects.Count(h => h is HitCircle);
int sliderCount = beatmap.HitObjects.Count(h => h is Slider);
int spinnerCount = beatmap.HitObjects.Count(h => h is Spinner);

double cognitionPerformance = baseFlashlightARPerformance;
double mechanicalPerformance = Math.Pow(Math.Pow(baseAimPerformance, SUM_POWER) + Math.Pow(baseSpeedPerformance, SUM_POWER), 1.0 / SUM_POWER);

// Limit cognition by full memorisation difficulty, what is assumed to be mechanicalPerformance + hiddenFlashlightPerformance
double hiddenFlashlightPerformance = OsuPerformanceCalculator.ComputePerfectFlashlightValue(hiddenFlashlightRating, hitCirclesCount + sliderCount);
cognitionPerformance = OsuPerformanceCalculator.AdjustCognitionPerformance(cognitionPerformance, mechanicalPerformance, hiddenFlashlightPerformance);

double basePerformance = mechanicalPerformance + cognitionPerformance;

double starRating = basePerformance > 0.00001
? Math.Cbrt(OsuPerformanceCalculator.PERFORMANCE_BASE_MULTIPLIER) * 0.027 * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4)
: 0;

HitWindows hitWindows = new OsuHitWindows();
hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);

Expand All @@ -99,9 +115,11 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
AimDifficulty = aimRating,
SpeedDifficulty = speedRating,
SpeedNoteCount = speedNotes,
ReadingDifficultyHighAR = readingHighARRating,
FlashlightDifficulty = flashlightRating,
HiddenFlashlightDifficulty = hiddenFlashlightRating,
SliderFactor = sliderFactor,
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
ApproachRate = IBeatmapDifficultyInfo.InverseDifficultyRange(preempt, 1800, 1200, 450),
OverallDifficulty = (80 - hitWindowGreat) / 6,
DrainRate = drainRate,
MaxCombo = maxCombo,
Expand Down Expand Up @@ -134,7 +152,9 @@ protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clo
{
new Aim(mods, true),
new Aim(mods, false),
new Speed(mods)
new Speed(mods),
new HiddenFlashlight(mods),
new ReadingHighAR(mods),
};

if (mods.Any(h => h is OsuModFlashlight))
Expand Down
6 changes: 3 additions & 3 deletions osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public class OsuPerformanceAttributes : PerformanceAttributes
[JsonProperty("accuracy")]
public double Accuracy { get; set; }

[JsonProperty("flashlight")]
public double Flashlight { get; set; }
[JsonProperty("cognition")]
public double Cognition { get; set; }

[JsonProperty("effective_miss_count")]
public double EffectiveMissCount { get; set; }
Expand All @@ -32,7 +32,7 @@ public override IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay
yield return new PerformanceDisplayAttribute(nameof(Aim), "Aim", Aim);
yield return new PerformanceDisplayAttribute(nameof(Speed), "Speed", Speed);
yield return new PerformanceDisplayAttribute(nameof(Accuracy), "Accuracy", Accuracy);
yield return new PerformanceDisplayAttribute(nameof(Flashlight), "Flashlight Bonus", Flashlight);
yield return new PerformanceDisplayAttribute(nameof(Cognition), "Cognition", Cognition);
}
}
}
Loading
Loading