Skip to content

Commit

Permalink
feat: more options on tierlist view (#1200)
Browse files Browse the repository at this point in the history
* feat: more options on tierlist view

wait...

* fix: actually this was always clear tier

---------

Co-authored-by: zkldi <[email protected]>
  • Loading branch information
zkrising and zkrising authored Oct 28, 2024
1 parent 21183ef commit 3c62d3d
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import ReferToUser from "components/util/ReferToUser";
import SelectLinkButton from "components/util/SelectLinkButton";
import useApiQuery from "components/util/query/useApiQuery";
import useUGPTBase from "components/util/useUGPTBase";
import { GPT_CLIENT_IMPLEMENTATIONS } from "lib/game-implementations";
import { GetEnumColour, GPT_CLIENT_IMPLEMENTATIONS } from "lib/game-implementations";
import { GPTRatingSystem } from "lib/types";
import React, { useContext, useEffect, useMemo, useState } from "react";
import { Col, Form, Row } from "react-bootstrap";
Expand All @@ -40,6 +40,7 @@ import {
SongDocument,
UserDocument,
integer,
GetGPTString,
} from "tachi-common";
import { ConfEnumScoreMetric } from "tachi-common/types/metrics";
import { UGPTFolderReturns } from "types/api-returns";
Expand Down Expand Up @@ -425,6 +426,8 @@ function TierlistBreakdown({ game, folderDataset, playtype, reqUser }: InfoProps
const gptImpl = GPT_CLIENT_IMPLEMENTATIONS[`${game}:${playtype}` as GPTString];

const [tierlist, setTierlist] = useState<string>(gptImpl.ratingSystems[0].name);
const [useFancyColour, setUseFancyColour] = useState(false);
const [forceGridView, setForceGridView] = useState(false);

const playerStats = useMemo(
() => FolderDatasetAchievedStatus(folderDataset, game, playtype, tierlist),
Expand Down Expand Up @@ -464,6 +467,30 @@ function TierlistBreakdown({ game, folderDataset, playtype, reqUser }: InfoProps
)}
<Col xs={12}>
<Divider />
<Form.Check
type="checkbox"
checked={!useFancyColour}
onChange={() => {
setUseFancyColour((e) => !e);
}}
label="Use simple clear/fail colours"
/>
<Form.Text>
<span>
If enabled, this will show green when you've achieved the tierlist
requirements, and red if you haven't, instead of fancier colours.
</span>
</Form.Text>
<Form.Check
className="d-block d-lg-none"
type="checkbox"
checked={forceGridView}
onChange={() => {
setForceGridView((e) => !e);
}}
label="Force desktop grid view"
/>
<Divider />
</Col>
<Col xs={12}>
<TierlistInfoLadder
Expand All @@ -473,6 +500,8 @@ function TierlistBreakdown({ game, folderDataset, playtype, reqUser }: InfoProps
reqUser={reqUser}
folderDataset={folderDataset}
tierlistImpl={tierlistImpl}
useFancyColour={useFancyColour}
forceGridView={forceGridView}
/>
</Col>
</Row>
Expand All @@ -486,13 +515,17 @@ function TierlistInfoLadder({
reqUser,
folderDataset,
tierlistImpl,
useFancyColour,
forceGridView,
}: {
playerStats: Record<string, { status: AchievedStatuses; score: string | null }>;
game: Game;
playtype: Playtype;
reqUser: UserDocument;
tierlistImpl: GPTRatingSystem<GPTString>;
folderDataset: FolderDataset;
useFancyColour: boolean;
forceGridView: boolean;
}) {
const buckets: TierlistInfo[][] = useMemo(() => {
const buckets: TierlistInfo[][] = [];
Expand Down Expand Up @@ -569,7 +602,17 @@ function TierlistInfoLadder({
)
</div>

<TierlistBucket {...{ bucket, game, playtype, reqUser }} />
<TierlistBucket
{...{
bucket,
game,
playtype,
reqUser,
useFancyColour,
tierlistImpl,
forceGridView,
}}
/>
</div>
))}
</>
Expand All @@ -579,28 +622,39 @@ function TierlistInfoLadder({
function TierlistBucket({
bucket,
game,
playtype,
reqUser,
useFancyColour,
forceGridView,
tierlistImpl,
}: {
game: Game;
playtype: Playtype;
reqUser: UserDocument;
bucket: TierlistInfo[];
useFancyColour: boolean;
forceGridView: boolean;
tierlistImpl: GPTRatingSystem<GPTString>;
}) {
const {
breakpoint: { isLg },
} = useContext(WindowContext);
// xs view is tabular
if (!isLg) {
if (!isLg && !forceGridView) {
return (
<MiniTable>
{bucket.map((tierlistInfo, i) => (
<TierlistInfoBucketValues
tierlistInfo={tierlistInfo}
key={`${tierlistInfo.chart.chartID}-${tierlistInfo.text}`}
game={game}
playtype={playtype}
bucket={bucket}
i={i}
reqUser={reqUser}
useFancyColour={useFancyColour}
tierlistImpl={tierlistImpl}
forceGridView={forceGridView}
/>
))}
</MiniTable>
Expand All @@ -614,9 +668,13 @@ function TierlistBucket({
tierlistInfo={tierlistInfo}
key={`${tierlistInfo.chart.chartID}-${tierlistInfo.text}`}
game={game}
playtype={playtype}
bucket={bucket}
i={i}
reqUser={reqUser}
useFancyColour={useFancyColour}
forceGridView={forceGridView}
tierlistImpl={tierlistImpl}
/>
))}
</div>
Expand All @@ -626,13 +684,21 @@ function TierlistBucket({
function TierlistInfoBucketValues({
tierlistInfo,
game,
playtype,
reqUser,
useFancyColour,
forceGridView,
tierlistImpl,
}: {
tierlistInfo: TierlistInfo;
bucket: TierlistInfo[];
game: Game;
playtype: Playtype;
i: integer;
reqUser: UserDocument;
useFancyColour: boolean;
forceGridView: boolean;
tierlistImpl: GPTRatingSystem<GPTString>;
}) {
const { breakpoint } = useContext(WindowContext);

Expand All @@ -643,10 +709,26 @@ function TierlistInfoBucketValues({
[AchievedStatuses.SCORE_BASED]: "bg-transparent",
};

let colourClass: string | undefined;
let colourCss: string | undefined;

if (useFancyColour) {
const gptImpl = GPT_CLIENT_IMPLEMENTATIONS[GetGPTString(game, playtype)];

// @ts-expect-error lol
colourCss = gptImpl.enumColours[tierlistImpl.enumName][tierlistInfo.score];
} else {
colourClass = statusClasses[tierlistInfo.status];
}

if (tierlistInfo.status === AchievedStatuses.NOT_PLAYED) {
colourClass = "bg-body-tertiary";
}

const data = tierlistInfo.chart;

// xs view
if (!breakpoint.isLg) {
if (!breakpoint.isLg && !forceGridView) {
return (
<tr>
<DifficultyCell game={game} chart={tierlistInfo.chart} alwaysShort noTierlist />
Expand All @@ -664,7 +746,7 @@ function TierlistInfoBucketValues({
)}
</div>
</td>
<TierlistInfoCell tierlistInfo={tierlistInfo} />
<TierlistInfoCell tierlistInfo={tierlistInfo} colourCss={colourCss} />
</tr>
);
}
Expand All @@ -682,7 +764,10 @@ function TierlistInfoBucketValues({
) : undefined
}
>
<div className={`${statusClasses[tierlistInfo.status]} bg-opacity-50 rounded p-2`}>
<div
className={`${colourClass} bg-opacity-50 rounded p-2`}
style={{ backgroundColor: colourCss ? ChangeOpacity(colourCss, 0.5) : undefined }}
>
<Link className="text-decoration-none" to={CreateChartLink(data, game)}>
{data.__related.song.title}
</Link>{" "}
Expand Down Expand Up @@ -714,28 +799,35 @@ function TierlistInfoBucketValues({
);
}

function TierlistInfoCell({ tierlistInfo }: { tierlistInfo: TierlistInfo }) {
let colour;
const text = tierlistInfo.score ?? "NOT PLAYED";
function TierlistInfoCell({
tierlistInfo,
colourCss,
}: {
tierlistInfo: TierlistInfo;
colourCss: string | undefined;
}) {
let colour = colourCss;

if (tierlistInfo.status === AchievedStatuses.FAILED) {
colour = COLOUR_SET.red;
} else if (tierlistInfo.status === AchievedStatuses.NOT_PLAYED) {
colour = COLOUR_SET.red;
} else {
colour = COLOUR_SET.green;
if (!colour) {
if (tierlistInfo.status === AchievedStatuses.FAILED) {
colour = COLOUR_SET.red;
} else if (tierlistInfo.status === AchievedStatuses.NOT_PLAYED) {
colour = COLOUR_SET.red;
} else {
colour = COLOUR_SET.green;
}
}

return (
<td
style={{
backgroundColor: ChangeOpacity(colour, 0.2),
backgroundColor: colour ? ChangeOpacity(colour, 0.5) : undefined,
width: "60px",
minWidth: "60px",
maxWidth: "60px",
}}
>
{text}
{tierlistInfo.score ?? "NOT PLAYED"}
</td>
);
}
Expand Down
16 changes: 1 addition & 15 deletions client/src/lib/game-implementations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -672,21 +672,7 @@ export const GPT_CLIENT_IMPLEMENTATIONS: GPTClientImplementations = {
// this game has dynamic difficulties. Formatting is handled elsewhere.
},
classColours: {},
ratingSystems: [
CreateRatingSys(
"BPM",
"How fast are the streams in this chart?",
(c) => c.data.streamBPM,
(c) => c.data.streamBPM?.toString(),
() => undefined,
(s) => [
s.scoreData.lamp === "FAILED"
? `Failed ${s.scoreData.survivedPercent.toFixed(2)}%`
: s.scoreData.lamp,
s.scoreData.lamp !== "FAILED",
]
),
],
ratingSystems: [],
scoreHeaders: [
["Score", "Score", NumericSOV((x) => x.scoreData.finalPercent)],
["Judgements", "Hits", NumericSOV((x) => x.scoreData.scorePercent)],
Expand Down
2 changes: 2 additions & 0 deletions client/src/lib/games/_util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { GPTString } from "tachi-common";
export function CreateRatingSys<GPT extends GPTString>(
name: string,
description: string,
enumName: string,
toNumber: GPTRatingSystem<GPT>["toNumber"],
toString: GPTRatingSystem<GPT>["toString"],
idvDifference: GPTRatingSystem<GPT>["idvDifference"] = () => false,
achievementFn: GPTRatingSystem<GPT>["achievementFn"] = undefined
): GPTRatingSystem<GPT> {
return {
description,
enumName,
name,
toNumber,
toString,
Expand Down
3 changes: 3 additions & 0 deletions client/src/lib/games/iidx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export const IIDX_SP_IMPL: GPTClientImplementation<"iidx:SP"> = {
CreateRatingSys(
"NC Tier",
"Tierlist Ratings for Normal Clears.",
"lamp",
(c) => c.data.ncTier?.value,
(c) => c.data.ncTier?.text,
(c) => c.data.ncTier?.individualDifference,
Expand All @@ -147,6 +148,7 @@ export const IIDX_SP_IMPL: GPTClientImplementation<"iidx:SP"> = {
CreateRatingSys(
"HC Tier",
"Tierlist Ratings for Hard Clears.",
"lamp",
(c) => c.data.hcTier?.value,
(c) => c.data.hcTier?.text,
(c) => c.data.hcTier?.individualDifference,
Expand All @@ -155,6 +157,7 @@ export const IIDX_SP_IMPL: GPTClientImplementation<"iidx:SP"> = {
CreateRatingSys(
"EXHC Tier",
"Tierlist Ratings for EX-HARD Clears.",
"lamp",
(c) => c.data.exhcTier?.value,
(c) => c.data.exhcTier?.text,
(c) => c.data.exhcTier?.individualDifference,
Expand Down
1 change: 1 addition & 0 deletions client/src/lib/games/sdvx-usc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export const SDVX_IMPL: GPTClientImplementation<"sdvx:Single"> = {
CreateRatingSys(
"Tierlist",
"The unofficial SDVX clearing tierlist",
"lamp",
(c) => c.data.clearTier?.value,
(c) => c.data.clearTier?.text,
(c) => c.data.clearTier?.individualDifference,
Expand Down
2 changes: 2 additions & 0 deletions client/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export type GPTDifficultyColours<GPT extends GPTString> = Record<Difficulties[GP
export type GPTRatingSystem<GPT extends GPTString> = {
name: string;
description: string;
enumName: string;

toNumber: (c: ChartDocument<GPT>) => number | null | undefined;
toString: (c: ChartDocument<GPT>) => string | null | undefined;

Expand Down

0 comments on commit 3c62d3d

Please sign in to comment.