added kamaitachi export
This commit is contained in:
@ -0,0 +1,209 @@
|
|||||||
|
"use server";
|
||||||
|
import { getAuth } from "@/auth/queries/getauth";
|
||||||
|
import { getSupportedVersionNumber } from "@/lib/api";
|
||||||
|
import { artemis } from "@/lib/prisma";
|
||||||
|
import { fromZonedTime, toZonedTime } from "date-fns-tz";
|
||||||
|
import { parse } from "date-fns";
|
||||||
|
|
||||||
|
const TACHI_CLASSES = [
|
||||||
|
undefined,
|
||||||
|
"DAN_I",
|
||||||
|
"DAN_II",
|
||||||
|
"DAN_III",
|
||||||
|
"DAN_IV",
|
||||||
|
"DAN_V",
|
||||||
|
"DAN_INFINITE",
|
||||||
|
] as const;
|
||||||
|
const TACHI_DIFFICULTIES = [
|
||||||
|
"BASIC",
|
||||||
|
"ADVANCED",
|
||||||
|
"EXPERT",
|
||||||
|
"MASTER",
|
||||||
|
"ULTIMA",
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
type BatchManualLamp =
|
||||||
|
| "ALL JUSTICE CRITICAL"
|
||||||
|
| "ALL JUSTICE"
|
||||||
|
| "FULL COMBO"
|
||||||
|
| "CLEAR"
|
||||||
|
| "FAILED";
|
||||||
|
interface BatchManualScore {
|
||||||
|
identifier: string;
|
||||||
|
matchType: "inGameID";
|
||||||
|
score: number;
|
||||||
|
lamp: BatchManualLamp;
|
||||||
|
difficulty: "BASIC" | "ADVANCED" | "EXPERT" | "MASTER" | "ULTIMA";
|
||||||
|
timeAchieved?: number;
|
||||||
|
judgements?: {
|
||||||
|
jcrit: number;
|
||||||
|
justice: number;
|
||||||
|
attack: number;
|
||||||
|
miss: number;
|
||||||
|
};
|
||||||
|
optional?: {
|
||||||
|
maxCombo: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface BatchManualImport {
|
||||||
|
meta: {
|
||||||
|
game: string;
|
||||||
|
playtype: string;
|
||||||
|
service: string;
|
||||||
|
};
|
||||||
|
scores: BatchManualScore[];
|
||||||
|
classes?: {
|
||||||
|
dan?: string;
|
||||||
|
emblem?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getTachiExport() {
|
||||||
|
const { user } = await getAuth();
|
||||||
|
const version = await getSupportedVersionNumber();
|
||||||
|
|
||||||
|
if (!user || !user.accessCode) {
|
||||||
|
throw new Error("User is not authenticated or accessCode is missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
const profile = await artemis.chuni_profile_data.findFirst({
|
||||||
|
where: {
|
||||||
|
user: user.UserId,
|
||||||
|
version,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
classEmblemBase: true,
|
||||||
|
classEmblemMedal: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const playlog = await artemis.chuni_score_playlog.findMany({
|
||||||
|
where: {
|
||||||
|
user: user.UserId,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
romVersion: true,
|
||||||
|
userPlayDate: true,
|
||||||
|
musicId: true,
|
||||||
|
level: true,
|
||||||
|
score: true,
|
||||||
|
maxCombo: true,
|
||||||
|
judgeGuilty: true,
|
||||||
|
judgeAttack: true,
|
||||||
|
judgeJustice: true,
|
||||||
|
judgeCritical: true,
|
||||||
|
judgeHeaven: true,
|
||||||
|
isFullCombo: true,
|
||||||
|
isAllJustice: true,
|
||||||
|
isClear: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const tachiExport: BatchManualImport = {
|
||||||
|
meta: {
|
||||||
|
game: "chunithm",
|
||||||
|
playtype: "Single",
|
||||||
|
service: "Cozynet",
|
||||||
|
},
|
||||||
|
scores: [],
|
||||||
|
classes: {
|
||||||
|
dan: TACHI_CLASSES[profile?.classEmblemBase ?? 0],
|
||||||
|
emblem: TACHI_CLASSES[profile?.classEmblemMedal ?? 0],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const log of playlog) {
|
||||||
|
const {
|
||||||
|
romVersion,
|
||||||
|
userPlayDate,
|
||||||
|
musicId,
|
||||||
|
level,
|
||||||
|
score,
|
||||||
|
judgeHeaven,
|
||||||
|
judgeCritical,
|
||||||
|
judgeJustice,
|
||||||
|
judgeAttack,
|
||||||
|
judgeGuilty,
|
||||||
|
maxCombo,
|
||||||
|
isAllJustice,
|
||||||
|
isFullCombo,
|
||||||
|
isClear,
|
||||||
|
} = log;
|
||||||
|
|
||||||
|
if (
|
||||||
|
romVersion === null ||
|
||||||
|
musicId === null ||
|
||||||
|
level === null ||
|
||||||
|
score === null ||
|
||||||
|
judgeJustice === null ||
|
||||||
|
isAllJustice === null ||
|
||||||
|
isFullCombo === null ||
|
||||||
|
isClear === null
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter out WORLD'S END scores
|
||||||
|
if (romVersion.startsWith("1.") && level === 4) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (romVersion.startsWith("2.") && level === 5) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lamp: BatchManualLamp = "FAILED";
|
||||||
|
|
||||||
|
if (isAllJustice && judgeJustice === 0) {
|
||||||
|
lamp = "ALL JUSTICE CRITICAL";
|
||||||
|
} else if (isAllJustice) {
|
||||||
|
lamp = "ALL JUSTICE";
|
||||||
|
} else if (isFullCombo) {
|
||||||
|
lamp = "FULL COMBO";
|
||||||
|
} else if (isClear) {
|
||||||
|
lamp = "CLEAR";
|
||||||
|
}
|
||||||
|
|
||||||
|
const tachiScore: BatchManualScore = {
|
||||||
|
score,
|
||||||
|
lamp,
|
||||||
|
identifier: musicId.toString(),
|
||||||
|
matchType: "inGameID",
|
||||||
|
difficulty: TACHI_DIFFICULTIES[level],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (userPlayDate !== null) {
|
||||||
|
tachiScore.timeAchieved = fromZonedTime(
|
||||||
|
parse(
|
||||||
|
userPlayDate,
|
||||||
|
"yyyy-MM-dd HH:mm:ss",
|
||||||
|
toZonedTime(new Date(), "Asia/Tokyo"),
|
||||||
|
),
|
||||||
|
"Asia/Tokyo",
|
||||||
|
).valueOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
judgeCritical !== null &&
|
||||||
|
judgeJustice !== null &&
|
||||||
|
judgeAttack !== null &&
|
||||||
|
judgeGuilty !== null
|
||||||
|
) {
|
||||||
|
tachiScore.judgements = {
|
||||||
|
jcrit: (judgeHeaven ?? 0) + judgeCritical,
|
||||||
|
justice: judgeJustice,
|
||||||
|
attack: judgeAttack,
|
||||||
|
miss: judgeGuilty,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxCombo !== null) {
|
||||||
|
tachiScore.optional = {
|
||||||
|
maxCombo,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
tachiExport.scores.push(tachiScore);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tachiExport;
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
"use client";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import { useToast } from "@/components/ui/use-toast";
|
||||||
|
|
||||||
|
// Server action imported from server-side code
|
||||||
|
import { getTachiExport } from "./action";
|
||||||
|
|
||||||
|
const TachiExport = () => {
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
|
const handleExport = async () => {
|
||||||
|
try {
|
||||||
|
const result = await getTachiExport();
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
const exportedFile = new Blob([JSON.stringify(result, null, 2)], {
|
||||||
|
type: "application/json",
|
||||||
|
});
|
||||||
|
const url = URL.createObjectURL(exportedFile);
|
||||||
|
const kamafile = document.createElement("a");
|
||||||
|
kamafile.href = url;
|
||||||
|
kamafile.download = "tachi_export.json";
|
||||||
|
document.body.appendChild(kamafile);
|
||||||
|
kamafile.click();
|
||||||
|
document.body.removeChild(kamafile);
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "Success",
|
||||||
|
description: "Data exported successfully!",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: "Error",
|
||||||
|
description: "Failed to export data",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
toast({
|
||||||
|
title: "Error",
|
||||||
|
description: error.message || "An error occurred while exporting data",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card x-chunk="aimecard">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-2xl">Export to kamaitachi</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
|
||||||
|
<CardContent>
|
||||||
|
<Button onClick={handleExport} className="w-full">
|
||||||
|
Export
|
||||||
|
</Button>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { TachiExport };
|
@ -0,0 +1,10 @@
|
|||||||
|
import { TachiExport } from "./kamaitachiexport";
|
||||||
|
|
||||||
|
const SecuritySettingsPage = async () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TachiExport />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default SecuritySettingsPage;
|
@ -2,7 +2,7 @@ import SecuritySettings from "./security";
|
|||||||
|
|
||||||
const SecuritySettingsPage = async () => {
|
const SecuritySettingsPage = async () => {
|
||||||
return (
|
return (
|
||||||
<div className="flex min-h-screen w-full flex-col">
|
<div>
|
||||||
<SecuritySettings />
|
<SecuritySettings />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -29,7 +29,7 @@ import {
|
|||||||
PopoverContent,
|
PopoverContent,
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from "@/components/ui/popover";
|
} from "@/components/ui/popover";
|
||||||
import { getGameList, updatePlayerGameVersionChuni } from "./actions";
|
import { getGameList, updatePlayerGameVersionChuni } from "./action";
|
||||||
|
|
||||||
type ChunithmGameVersionSelectionProps = {
|
type ChunithmGameVersionSelectionProps = {
|
||||||
chunithmGameVersionNumber: {
|
chunithmGameVersionNumber: {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { PlayerChangableChunithmGameVersionSelection } from "./gameSelection";
|
import { PlayerChangableChunithmGameVersionSelection } from "./gameSelection";
|
||||||
import { getGameList } from "./actions";
|
import { getGameList } from "./action";
|
||||||
import { Card, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
|
||||||
const getAllGamesChunithm = async () => {
|
const getAllGamesChunithm = async () => {
|
||||||
|
@ -6,6 +6,8 @@ import { usePathname } from "next/navigation";
|
|||||||
const NAV_ITEMS = [
|
const NAV_ITEMS = [
|
||||||
{ href: "/settings/home", label: "General" },
|
{ href: "/settings/home", label: "General" },
|
||||||
{ href: "/settings/security", label: "Security" },
|
{ href: "/settings/security", label: "Security" },
|
||||||
|
{ href: "/settings/kamaitachi", label: "Kamaitachi Export" },
|
||||||
|
|
||||||
{ href: "/settings/versions", label: "Edit Game Version" },
|
{ href: "/settings/versions", label: "Edit Game Version" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.0",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
|
"date-fns-tz": "^3.1.3",
|
||||||
"embla-carousel-react": "^8.1.5",
|
"embla-carousel-react": "^8.1.5",
|
||||||
"encoding-japanese": "^2.2.0",
|
"encoding-japanese": "^2.2.0",
|
||||||
"geist": "^1.3.0",
|
"geist": "^1.3.0",
|
||||||
|
Reference in New Issue
Block a user