Skip to content

Commit

Permalink
Merge pull request #11536 from bdach/grade-circles
Browse files Browse the repository at this point in the history
Fix incorrect cutoffs on grade dial when displaying lazer scores and stable scores in lazer mode
  • Loading branch information
nanaya authored Oct 11, 2024
2 parents a430cf1 + 8f58f1f commit f2e46c5
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 48 deletions.
13 changes: 7 additions & 6 deletions resources/css/colors.less
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,10 @@ body {

@group-colour-default: #0087ca;

@colour-rank-d: #ff5858;
@colour-rank-c: #ea7948;
@colour-rank-b: #d99d03;
@colour-rank-a: #72c904;
@colour-rank-s: #0096a2;
@colour-rank-ss: #be0089;
// cross-reference: https://github.com/ppy/osu/blob/b658d9a681a04101900d5ce6c5b84d56320e08e7/osu.Game/Graphics/OsuColour.cs#L42-L73
@colour-rank-d: #ff5a5a;
@colour-rank-c: #ff8e5d;
@colour-rank-b: #e3b130;
@colour-rank-a: #88da20;
@colour-rank-s: #02b5c3;
@colour-rank-ss: #de31ae;
41 changes: 2 additions & 39 deletions resources/js/scores-show/dial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@

import * as d3 from 'd3';
import Rank from 'interfaces/rank';
import Ruleset from 'interfaces/ruleset';
import * as React from 'react';

interface Props {
accuracy: number;
mode: Ruleset;
rank: Rank;
rankCutoffs: number[];
}

const displayRank: Record<Rank, string> = {
Expand All @@ -24,46 +23,10 @@ const displayRank: Record<Rank, string> = {
XH: 'SS',
};

const refDataMap: Record<Ruleset, number[]> = {
// <rank>: minimum acc => (higher rank acc - current acc)
// for SS, use minimum accuracy of 0.99 (any less and it's too small)
// actual array is reversed as it's rendered from D to SS clockwise

// SS: 0.99 => 0.01
// S: 0.9801 => 0.0099
// A: 0.9401 => 0.04
// B: 0.9001 => 0.04
// C: 0.8501 => 0.05
// D: 0 => 0.8501
fruits: [0.8501, 0.05, 0.04, 0.04, 0.0099, 0.01],
// SS: 0.99 => 0.01
// S: 0.95 => 0.04
// A: 0.9 => 0.05
// B: 0.8 => 0.1
// C: 0.7 => 0.1
// D: 0 => 0.7
mania: [0.7, 0.1, 0.1, 0.05, 0.04, 0.01],
// SS: 0.99 => 0.01
// S: (0.9 * 300 + 0.1 * 100) / 300 = 0.933 => 0.057
// A: (0.8 * 300 + 0.2 * 100) / 300 = 0.867 => 0.066
// B: (0.7 * 300 + 0.3 * 100) / 300 = 0.8 => 0.067
// C: 0.6 => 0.2
// D: 0 => 0.6
osu: [0.6, 0.2, 0.067, 0.066, 0.057, 0.01],
// SS: 0.99 => 0.01
// S: (0.9 * 300 + 0.1 * 50) / 300 = 0.917 => 0.073
// A: (0.8 * 300 + 0.2 * 50) / 300 = 0.833 => 0.084
// B: (0.7 * 300 + 0.3 * 50) / 300 = 0.75 => 0.083
// C: 0.6 => 0.15
// D: 0 => 0.6
taiko: [0.6, 0.15, 0.083, 0.084, 0.073, 0.01],
};

export default function Dial(props: Props) {
const arc = d3.arc();
const pie = d3.pie().sortValues(null);
const valueData = [props.accuracy, 1 - props.accuracy];
const refData = refDataMap[props.mode];

return (
<div className='score-dial'>
Expand All @@ -76,7 +39,7 @@ export default function Dial(props: Props) {
</linearGradient>
</defs>
<g transform='translate(100, 100)'>
{pie(refData).map((d) => (
{pie(props.rankCutoffs).map((d) => (
<path
key={d.index}
className={`score-dial__inner score-dial__inner--${d.index}`}
Expand Down
5 changes: 2 additions & 3 deletions resources/js/scores-show/info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
import BeatmapsetCover from 'components/beatmapset-cover';
import { SoloScoreJsonForShow } from 'interfaces/solo-score-json';
import * as React from 'react';
import { rulesetName } from 'utils/beatmap-helper';
import { accuracy, rank } from 'utils/score-helper';
import { accuracy, rank, rankCutoffs } from 'utils/score-helper';
import Buttons from './buttons';
import Dial from './dial';
import Player from './player';
Expand All @@ -27,7 +26,7 @@ export default function Info({ score }: Props) {
</div>

<div className='score-info__item score-info__item--dial'>
<Dial accuracy={accuracy(score)} mode={rulesetName(score.ruleset_id)} rank={rank(score)} />
<Dial accuracy={accuracy(score)} rank={rank(score)} rankCutoffs={rankCutoffs(score)} />
</div>

<div className='score-info__item score-info__item--player'>
Expand Down
60 changes: 60 additions & 0 deletions resources/js/utils/score-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,66 @@ export function rank(score: SoloScoreJson) {
: score.rank;
}

export function rankCutoffs(score: SoloScoreJson): number[] {
// for SS, use minimum accuracy of 0.99 (any less and it's too small)
// actual array is reversed as it's rendered from D to SS clockwise

let absoluteCutoffs: number[] = [];
const ruleset = rulesetName(score.ruleset_id);

if (shouldReturnLegacyValue(score)) {
switch (ruleset) {
case 'fruits':
absoluteCutoffs = [0, 0.8501, 0.9001, 0.9401, 0.9801, 0.99, 1];
break;

case 'mania':
absoluteCutoffs = [0, 0.7, 0.8, 0.9, 0.95, 0.99, 1];
break;

case 'osu':
// S: (0.9 * 300 + 0.1 * 100) / 300 = 0.933
// A: (0.8 * 300 + 0.2 * 100) / 300 = 0.867
// B: (0.7 * 300 + 0.3 * 100) / 300 = 0.8
absoluteCutoffs = [0, 0.6, 0.8, 0.867, 0.933, 0.99, 1];
break;

case 'taiko':
// S: (0.9 * 300 + 0.1 * 50) / 300 = 0.917
// A: (0.8 * 300 + 0.2 * 50) / 300 = 0.833
// B: (0.7 * 300 + 0.3 * 50) / 300 = 0.75
absoluteCutoffs = [0, 0.6, 0.75, 0.833, 0.917, 0.99, 1];
break;
}
} else {
switch (ruleset) {
case 'fruits':
// cross-reference: https://github.com/ppy/osu/blob/b658d9a681a04101900d5ce6c5b84d56320e08e7/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs#L108-L135
absoluteCutoffs = [0, 0.85, 0.9, 0.94, 0.98, 0.99, 1];
break;

case 'mania':
case 'osu':
case 'taiko':
// cross-reference: https://github.com/ppy/osu/blob/b658d9a681a04101900d5ce6c5b84d56320e08e7/osu.Game/Rulesets/Scoring/ScoreProcessor.cs#L541-L572
absoluteCutoffs = [0, 0.7, 0.8, 0.9, 0.95, 0.99, 1];
break;
}
}

return differenceBetweenConsecutiveElements(absoluteCutoffs);
}

function differenceBetweenConsecutiveElements(arr: number[]): number[] {
const result = [];

for (let i = 1; i < arr.length; ++i) {
result.push(arr[i] - arr[i - 1]);
}

return result;
}

export function scoreDownloadUrl(score: SoloScoreJson) {
if (score.type === 'solo_score') {
return route('scores.download', { score: score.id });
Expand Down

0 comments on commit f2e46c5

Please sign in to comment.