From 5b699a2c3ccf8d2d415737d7cc34243572fe6b4d Mon Sep 17 00:00:00 2001 From: crxmsxn <59166650+asterisk727@users.noreply.github.com> Date: Thu, 24 Jul 2025 22:04:16 -0500 Subject: [PATCH] feature: Batch-Manual export for CHUNITHM (#161) --- .../components/settings/ChuniSettings.svelte | 123 ++++++++++++++++++ AquaNet/src/libs/i18n/en_ref.ts | 1 + AquaNet/src/libs/i18n/zh.ts | 1 + 3 files changed, 125 insertions(+) diff --git a/AquaNet/src/components/settings/ChuniSettings.svelte b/AquaNet/src/components/settings/ChuniSettings.svelte index a17ffeac..5e1b0fd1 100644 --- a/AquaNet/src/components/settings/ChuniSettings.svelte +++ b/AquaNet/src/components/settings/ChuniSettings.svelte @@ -106,6 +106,125 @@ .finally(() => submitting = "") } + async function exportBatchManual() { + submitting = "batchExport" + + const DIFFICULTY_MAP: Record = { + 0: "BASIC", + 1: "ADVANCED", + 2: "EXPERT", + 3: "MASTER", + 4: "ULTIMA" + } // WORLD'S END scores not supported by Tachi + const DAN_MAP: Record = { + 1: "DAN_I", + 2: "DAN_II", + 3: "DAN_III", + 4: "DAN_IV", + 5: "DAN_V", + 6: "DAN_INFINITE" + } + const CATASTROPHY_SKILL_IDS: number[] = [100009, 102009, 103007] + const ABSOLUTE_SKILL_IDS: number[] = [100008, 101008, 102008, 103006] + const BRAVE_SKILL_IDS: number[] = [100007, 101007, 102007, 103005] // Needs to be updated every major version :( + const HARD_SKILL_IDS: number[] = [100005, 100006, 101004, 101005, 101006, 102004, 102005, 102006, 103002, 103003, 103004] // Shamelessly stolen from https://github.com/beer-psi/saekawa/commit/b3bee13e126df2f4e2a449bdf971debb8c95ba40 + + let data: any + let output: any = { + "meta": { + "game": "chunithm", + "playtype": "Single", + "service": "AquaDX-Manual" + }, + "scores": [], + "classes": {} + } + + try { + data = await GAME.export('chu3'); + } + catch (e) { + error = e.message; + submitting = "" + return; + } + + if (data && "userPlaylogList" in data) { + for (let score of data.userPlaylogList) { + let level = score.level + let clearLamp = null; + let noteLamp = null; + + if (level in DIFFICULTY_MAP) { + if (score.isClear) { + if (CATASTROPHY_SKILL_IDS.includes(score.skillId)) { + clearLamp = "CATASTROPHY"; + } + else if (ABSOLUTE_SKILL_IDS.includes(score.skillId)) { + clearLamp = "ABSOLUTE"; + } + else if (BRAVE_SKILL_IDS.includes(score.skillId)) { + clearLamp = "BRAVE"; + } + else if (HARD_SKILL_IDS.includes(score.skillId)) { + clearLamp = "HARD"; + } + else { + clearLamp = "CLEAR"; + } + } + else { + clearLamp = "FAILED"; + } + + + if (score.isAllPerfect) { + noteLamp = "ALL JUSTICE CRITICAL" + } + else if (score.isAllJustice) { + noteLamp = "ALL JUSTICE" + } + else if (score.isFullCombo) { + noteLamp = "FULL COMBO" + } + else { + noteLamp = "NONE" + } + + output.scores.push({ + "score": score.score, + "clearLamp": clearLamp, + "noteLamp": noteLamp, + "judgements": { + "jcrit": score.judgeHeaven + score.judgeCritical, + "justice": score.judgeJustice, + "attack": score.judgeAttack, + "miss": score.judgeGuilty + }, + "matchType": "inGameID", + "identifier": score.musicId.toString(), + "difficulty": DIFFICULTY_MAP[level], + "timeAchieved": new Date(score.userPlayDate).getTime(), + "optional": { + "maxCombo": score.maxCombo + } + }) + } + } + } + + if (data.userData.classEmblemMedal in DAN_MAP) { + output.classes["dan"] = DAN_MAP[data.userData.classEmblemMedal] + } + + if (data.userData.classEmblemBase in DAN_MAP) { + output.classes["emblem"] = DAN_MAP[data.userData.classEmblemBase] + } + + download(JSON.stringify(output), `AquaDX_chu3_BatchManualExport_${userbox.userName}.json`) + submitting = "" + } + function download(data: string, filename: string) { const blob = new Blob([data]); const url = URL.createObjectURL(blob); @@ -301,6 +420,10 @@ {t('settings.export')} + {/if} diff --git a/AquaNet/src/libs/i18n/en_ref.ts b/AquaNet/src/libs/i18n/en_ref.ts index 1b8cab27..0f523b21 100644 --- a/AquaNet/src/libs/i18n/en_ref.ts +++ b/AquaNet/src/libs/i18n/en_ref.ts @@ -183,6 +183,7 @@ export const EN_REF_SETTINGS = { 'settings.profile.logout': 'Log out', 'settings.profile.unchanged': 'Unchanged', 'settings.export': 'Export Player Data', + 'settings.batchManualExport': "Export in Batch Manual (for Tachi)", 'settings.cabNotice': "Note: These settings will only affect your own cab/setup. If you're playing on someone else's setup, please contact them to change these settings.", 'settings.gameNotice': "These only apply to Mai and Wacca." } diff --git a/AquaNet/src/libs/i18n/zh.ts b/AquaNet/src/libs/i18n/zh.ts index fa37cf36..4712364e 100644 --- a/AquaNet/src/libs/i18n/zh.ts +++ b/AquaNet/src/libs/i18n/zh.ts @@ -195,6 +195,7 @@ const zhSettings: typeof EN_REF_SETTINGS = { 'settings.profile.logout': '登出', 'settings.profile.unchanged': '未更改', 'settings.export': '导出玩家数据', + 'settings.batchManualExport': "导出 Batch Manual 格式(用于 Tachi)", 'settings.cabNotice': '注意:下面这些设置只会影响你自己的机器,如果你是在其他人的机器上玩的话,请联系机主来改设置', 'settings.gameNotice': "这些设置仅对舞萌和华卡生效。", }