checkpoint: insanity ascends (35)

127 errors to go
This commit is contained in:
zkldi
2023-01-19 16:39:42 +00:00
parent 2b0e65f0c8
commit 5cbb2d5f8a
131 changed files with 2106 additions and 1886 deletions
@@ -115,7 +115,8 @@ export default function SessionFolderRaiseBreakdown({
const chartMap = CreateChartMap(sessionData.charts);
const songMap = CreateSongMap(sessionData.songs);
const preferredScoreBucket = settings?.preferences.scoreBucket ?? gptConfig.scoreBucket;
const preferredScoreBucket =
settings?.preferences.preferredDefaultEnum ?? gptConfig.preferredDefaultEnum;
if (selectedTable === "LOADING") {
return <Loading />;
@@ -5,7 +5,7 @@ import ScoreTable from "components/tables/scores/ScoreTable";
import Divider from "components/util/Divider";
import React, { useState } from "react";
import { Col, Row } from "react-bootstrap";
import { GetGamePTConfig, ScoreDocument, SessionDocument } from "tachi-common";
import { AnySessionRatingAlg, GetGamePTConfig, ScoreDocument, SessionDocument } from "tachi-common";
import { SessionReturns } from "types/api-returns";
import { ScoreDataset } from "types/tables";
import { SetState } from "types/react";
@@ -73,15 +73,15 @@ function RatingsOverview({ session }: { session: SessionDocument }) {
<Divider />
<Card header="Ratings">
<div className="d-flex text-center" style={{ justifyContent: "space-evenly" }}>
{gptConfig.sessionRatingAlgs.map((e) => (
{Object.keys(gptConfig.sessionRatingAlgs).map((e) => (
<div key={e}>
<div className="display-4">{UppercaseFirst(e)}</div>
<div style={{ fontSize: "1.2rem" }}>
{FormatSessionRating(
session.game,
session.playtype,
e,
session.calculatedData[e]
e as AnySessionRatingAlg,
session.calculatedData[e as AnySessionRatingAlg]
)}
</div>
</div>
@@ -1,35 +1,38 @@
import { APIFetchV1 } from "util/api";
import { ChangeOpacity } from "util/color-opacity";
import { CreateChartMap, CreateScoreIDMap, CreateSongMap } from "util/data";
import { PartialArrayRecordAssign } from "util/misc";
import { PartialArrayRecordAssign, UppercaseFirst } from "util/misc";
import DifficultyCell from "components/tables/cells/DifficultyCell";
import LampCell from "components/tables/cells/LampCell";
import ScoreCell from "components/tables/cells/ScoreCell";
import TitleCell from "components/tables/cells/TitleCell";
import MiniTable from "components/tables/components/MiniTable";
import { CommentModal, ModifyScore } from "components/tables/dropdowns/components/ScoreEditButtons";
import ScoreCoreCells from "components/tables/game-core-cells/ScoreCoreCells";
import Divider from "components/util/Divider";
import Icon from "components/util/Icon";
import Loading from "components/util/Loading";
import SelectButton from "components/util/SelectButton";
import { UserContext } from "context/UserContext";
import deepmerge from "deepmerge";
import { GPT_CLIENT_IMPLEMENTATIONS } from "lib/game-implementations";
import { GPTClientImplementation } from "lib/types";
import React, { useContext, useEffect, useMemo, useState } from "react";
import { useQuery } from "react-query";
import {
ChartDocument,
GPTString,
Game,
GamePTConfig,
GetGPTString,
GetGamePTConfig,
Grades,
IDStrings,
integer,
Lamps,
GetScoreMetricConf,
GetScoreMetrics,
ScoreDocument,
SessionScoreInfo,
SongDocument,
TableDocument,
integer,
} from "tachi-common";
import { ConfEnumScoreMetric } from "tachi-common/types/metrics";
import { SessionReturns } from "types/api-returns";
type SetScores = (scores: ScoreDocument[]) => void;
@@ -57,7 +60,10 @@ export default function SessionRaiseBreakdown({
return res.body;
});
const [view, setView] = useState<"lamps" | "both" | "grades">("both");
// null -> view all in small format
// string -> view this specific metric.
const [view, setView] = useState<string | null>(null);
if (error) {
return <>{(error as Error).message}</>;
@@ -75,17 +81,17 @@ export default function SessionRaiseBreakdown({
<div className="col-12 col-lg-6 offset-lg-3">
<div className="d-none d-lg-flex justify-content-center">
<div className="btn-group">
<SelectButton value={view} setValue={setView} id="lamps">
<SelectButton value={view} setValue={setView} id="lamp">
<Icon type="lightbulb" />
Lamps Only
</SelectButton>
<SelectButton value={view} setValue={setView} id="both">
<SelectButton value={view} setValue={setView} id={null}>
<Icon type="bolt" />
Both
All
</SelectButton>
<SelectButton value={view} setValue={setView} id="grades">
<SelectButton value={view} setValue={setView} id="grade">
<Icon type="sort-alpha-up" />
Grades Only
</SelectButton>
@@ -115,122 +121,103 @@ function SessionScoreStatBreakdown({
}: {
sessionData: SessionReturns;
setScores?: SetScores;
view: "lamps" | "both" | "grades";
view: string | null;
}) {
const songMap = CreateSongMap(sessionData.songs);
const chartMap = CreateChartMap(sessionData.charts);
const scoreMap = CreateScoreIDMap(sessionData.scores);
const gptConfig = GetGamePTConfig(sessionData.session.game, sessionData.session.playtype);
const [newLamps, newGrades] = useMemo(() => {
const newLamps: Partial<
Record<Lamps[IDStrings], { score: ScoreDocument; scoreInfo: SessionScoreInfo }[]>
> = {};
const newGrades: Partial<
Record<Grades[IDStrings], { score: ScoreDocument; scoreInfo: SessionScoreInfo }[]>
const enumMetrics = GetScoreMetrics(gptConfig, "ENUM");
const newEnums = useMemo(() => {
const newEnums: Record<
string,
Record<string, { score: ScoreDocument; scoreInfo: SessionScoreInfo }[]>
> = {};
for (const scoreInfo of sessionData.scoreInfo) {
const score = scoreMap.get(scoreInfo.scoreID);
for (const metric of enumMetrics) {
newEnums[metric] = {};
if (!score) {
console.error(
`Session score info contains scoreID ${scoreInfo.scoreID}, but no score exists?`
);
continue;
}
for (const scoreInfo of sessionData.scoreInfo) {
const score = scoreMap.get(scoreInfo.scoreID);
if (scoreInfo.isNewScore) {
PartialArrayRecordAssign(newLamps, score.scoreData.lamp, { score, scoreInfo });
PartialArrayRecordAssign(newGrades, score.scoreData.grade, { score, scoreInfo });
} else {
if (scoreInfo.lampDelta > 0) {
PartialArrayRecordAssign(newLamps, score.scoreData.lamp, { score, scoreInfo });
if (!score) {
console.error(
`Session score info contains scoreID ${scoreInfo.scoreID}, but no score exists?`
);
continue;
}
if (scoreInfo.gradeDelta > 0) {
PartialArrayRecordAssign(newGrades, score.scoreData.grade, {
score,
scoreInfo,
});
if (scoreInfo.isNewScore || scoreInfo.deltas[metric] > 0) {
PartialArrayRecordAssign(
newEnums[metric],
// @ts-expect-error yeah this is fine pls
score.scoreData[metric] as string,
{
score,
scoreInfo,
}
);
}
}
}
return [newLamps, newGrades];
return newEnums;
}, [view]);
const gptConfig = GetGamePTConfig(sessionData.session.game, sessionData.session.playtype);
const gptImpl =
GPT_CLIENT_IMPLEMENTATIONS[
GetGPTString(sessionData.session.game, sessionData.session.playtype)
];
return (
<>
{view === "both" ? (
<>
<div className="col-12 col-lg-6">
<MiniTable
headers={["Lamp", "New Lamps"]}
colSpan={[1, 2]}
className="table-sm"
>
<ElementStatTable
scores={sessionData.scores}
setScores={setScores}
chartMap={chartMap}
songMap={songMap}
counts={newLamps}
game={sessionData.session.game}
type="lamp"
gptConfig={gptConfig}
/>
</MiniTable>
</div>
<div className="col-12 col-lg-6">
<MiniTable
headers={["Grade", "New Grades"]}
colSpan={[1, 2]}
className="table-sm"
>
<ElementStatTable
scores={sessionData.scores}
setScores={setScores}
chartMap={chartMap}
songMap={songMap}
counts={newGrades}
game={sessionData.session.game}
type="grade"
gptConfig={gptConfig}
/>
</MiniTable>
</div>
</>
) : view === "grades" ? (
<div className="col-12">
<MiniTable headers={["Grade", "New Grades"]} colSpan={[1, 100]}>
<ElementStatTable
scores={sessionData.scores}
setScores={setScores}
fullSize
chartMap={chartMap}
songMap={songMap}
counts={newGrades}
game={sessionData.session.game}
type="grade"
gptConfig={gptConfig}
/>
</MiniTable>
{view === null ? (
<div className="d-flex w-100">
{enumMetrics.map((metric) => (
<div style={{ flex: 1 }}>
<MiniTable
headers={[
`${UppercaseFirst(metric)}s`,
`New ${UppercaseFirst(metric)}s`,
]}
colSpan={[1, 100]}
>
<ElementStatTable
scores={sessionData.scores}
setScores={setScores}
fullSize
chartMap={chartMap}
songMap={songMap}
counts={newEnums[metric]!}
game={sessionData.session.game}
metric={metric}
gptConfig={gptConfig}
gptImpl={gptImpl}
/>
</MiniTable>
</div>
))}
</div>
) : (
<div className="col-12">
<MiniTable headers={["Lamps", "New Lamps"]} colSpan={[1, 100]}>
<MiniTable
headers={[`${UppercaseFirst(view)}s`, `New ${UppercaseFirst(view)}s`]}
colSpan={[1, 100]}
>
<ElementStatTable
scores={sessionData.scores}
setScores={setScores}
fullSize
chartMap={chartMap}
songMap={songMap}
counts={newLamps}
counts={newEnums[view]!}
game={sessionData.session.game}
type="lamp"
gptConfig={gptConfig}
gptImpl={gptImpl}
metric={view}
/>
</MiniTable>
</div>
@@ -240,7 +227,7 @@ function SessionScoreStatBreakdown({
}
function ElementStatTable({
type,
metric: metric,
counts,
gptConfig,
songMap,
@@ -249,27 +236,26 @@ function ElementStatTable({
fullSize = false,
scores,
setScores,
gptImpl,
}: {
type: "lamp" | "grade";
metric: string;
setScores?: SetScores;
scores: ScoreDocument[];
counts: Record<string, { score: ScoreDocument; scoreInfo: SessionScoreInfo }[]>;
gptConfig: GamePTConfig;
gptImpl: GPTClientImplementation<any>;
songMap: Map<integer, SongDocument<Game>>;
chartMap: Map<string, ChartDocument<IDStrings>>;
chartMap: Map<string, ChartDocument<GPTString>>;
game: Game;
fullSize?: boolean;
}) {
const tableContents = useMemo(() => {
// relements.. haha
const relevantElements =
type === "lamp"
? gptConfig.lamps.slice(gptConfig.lamps.indexOf(gptConfig.clearLamp) - 1).reverse()
: gptConfig.grades
.slice(gptConfig.grades.indexOf(gptConfig.clearGrade) - 1)
.reverse();
const conf = GetScoreMetricConf(gptConfig, metric) as ConfEnumScoreMetric<string>;
const colours = type === "lamp" ? gptConfig.lampColours : gptConfig.gradeColours;
// relements.. haha
const relevantElements = conf.values.slice(conf.values.indexOf(conf.minimumRelevantValue));
const colours = gptImpl.enumColours[metric];
const tableContents = [];
for (const element of relevantElements) {
@@ -283,7 +269,6 @@ function ElementStatTable({
<tr key={element} className="breakdown-hover-row">
<td
style={{
// @ts-expect-error this is a hack due to the funky type of colours and element.
backgroundColor: ChangeOpacity(colours[element], 0.1),
}}
rowSpan={counts[element]!.length}
@@ -298,7 +283,7 @@ function ElementStatTable({
fullSize,
game,
gptConfig,
type,
metric: metric,
scores,
setScores,
}}
@@ -317,7 +302,7 @@ function ElementStatTable({
fullSize,
game,
gptConfig,
type,
metric: metric,
scores,
setScores,
}}
@@ -328,7 +313,7 @@ function ElementStatTable({
}
return tableContents;
}, [type, counts, fullSize, game, scores]);
}, [metric, counts, fullSize, game, scores]);
if (tableContents.length === 0) {
return (
@@ -349,7 +334,7 @@ function BreakdownChartContents({
chartMap,
fullSize,
gptConfig,
type,
metric,
scores,
setScores,
}: {
@@ -360,7 +345,7 @@ function BreakdownChartContents({
songMap: Map<integer, SongDocument>;
chartMap: Map<string, ChartDocument>;
gptConfig: GamePTConfig;
type: "lamp" | "grade";
metric: string;
scores: Array<ScoreDocument>;
setScores?: SetScores;
}) {
@@ -425,25 +410,24 @@ function BreakdownChartContents({
let preScoreCell = <td>No Play</td>;
if (!scoreInfo.isNewScore) {
const oldGradeIndex = score.scoreData.gradeIndex - scoreInfo.gradeDelta;
const oldLampIndex = score.scoreData.lampIndex - scoreInfo.lampDelta;
const newScoreData = score.scoreData;
for (const [k, d] of Object.entries(scoreInfo.deltas)) {
// @ts-expect-error ugh
if (typeof score.scoreData[k] === "string") {
// @ts-expect-error ugh
newScoreData.enumIndexes[k] = score.scoreData.enumIndexes[k] - d;
} else {
// @ts-expect-error ugh
newScoreData[k] = score.scoreData[k] - d;
}
}
const mockScore = deepmerge(score, {
scoreData: {
score: score.scoreData.score - scoreInfo.scoreDelta,
percent: score.scoreData.percent - scoreInfo.percentDelta,
grade: gptConfig.grades[oldGradeIndex],
gradeIndex: oldGradeIndex,
lamp: gptConfig.lamps[oldLampIndex],
lampIndex: oldLampIndex,
},
scoreData: newScoreData,
}) as ScoreDocument;
if (type === "grade") {
preScoreCell = <ScoreCell score={mockScore} />;
} else {
preScoreCell = <LampCell score={mockScore} />;
}
preScoreCell = <ScoreCoreCells chart={chart} game={game} score={mockScore} />;
}
if (score) {
@@ -453,11 +437,7 @@ function BreakdownChartContents({
<DifficultyCell chart={chart} game={game} />
{preScoreCell}
<td>⟶</td>
{type === "grade" ? (
<ScoreCell {...{ score, game, playtype: score.playtype }} />
) : (
<LampCell score={score} />
)}
<ScoreCoreCells chart={chart} game={game} score={score} />
</>
);
}