From 2cbdcda64ffc70b1744303672ec7e53ec078879d Mon Sep 17 00:00:00 2001 From: Starrah Date: Wed, 28 Jan 2026 12:37:51 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=E5=9C=A8Music.xml=E4=B8=AD?= =?UTF-8?q?=E6=96=B0=E5=A2=9E"X-MCM/ShiftMethod"=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=EF=BC=8C=E8=AE=B0=E5=BD=95=E5=AF=BC=E5=85=A5=E6=97=B6=E7=9A=84?= =?UTF-8?q?=E5=BB=B6=E8=BF=9F=E8=B0=83=E6=95=B4=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Charts/ImportChartController.cs | 1 + MaiChartManager/Models/MusicXml.cs | 52 ++++++++++++------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/MaiChartManager/Controllers/Charts/ImportChartController.cs b/MaiChartManager/Controllers/Charts/ImportChartController.cs index 20bf25a..1466ab5 100644 --- a/MaiChartManager/Controllers/Charts/ImportChartController.cs +++ b/MaiChartManager/Controllers/Charts/ImportChartController.cs @@ -559,6 +559,7 @@ public ImportChartResult ImportChart( music.AddVersionId = addVersionId; music.GenreId = genreId; music.Version = version; + music.ShiftMethod = shift.ToString(); float wholebpm; if (float.TryParse(maiData.GetValueOrDefault("wholebpm"), out wholebpm)) music.Bpm = wholebpm; diff --git a/MaiChartManager/Models/MusicXml.cs b/MaiChartManager/Models/MusicXml.cs index 86f6da8..7136519 100644 --- a/MaiChartManager/Models/MusicXml.cs +++ b/MaiChartManager/Models/MusicXml.cs @@ -377,16 +377,7 @@ public string UtageKanji set { Modified = true; - var node = RootNode.SelectSingleNode(utageKanjiNode); - if (node is null) - { - node = xmlDoc.CreateNode(XmlNodeType.Element, utageKanjiNode, null); - node.InnerText = value; - RootNode.AppendChild(node); - return; - } - - RootNode.SelectSingleNode(utageKanjiNode).InnerText = value; + SelectSingleNodeOrCreate(RootNode, utageKanjiNode).InnerText = value; } } @@ -398,16 +389,7 @@ public string Comment set { Modified = true; - var node = RootNode.SelectSingleNode(commentNode); - if (node is null) - { - node = xmlDoc.CreateNode(XmlNodeType.Element, commentNode, null); - node.InnerText = value; - RootNode.AppendChild(node); - return; - } - - RootNode.SelectSingleNode(commentNode).InnerText = value; + SelectSingleNodeOrCreate(RootNode, commentNode).InnerText = value; } } @@ -466,6 +448,18 @@ public bool LongMusic node.InnerText = value ? "1" : "0"; } } + + // 以下是游戏本体不会使用、而是由MCM使用的扩展字段,统一放到"X-MCM"下。 + + public string ShiftMethod + { + get => RootNode.SelectSingleNode("X-MCM/shiftMethod")?.InnerText; + set + { + Modified = true; + SelectSingleNodeOrCreate(RootNode, "X-MCM/shiftMethod").InnerText = value; + } + } public class Chart { @@ -571,4 +565,22 @@ public void Save() Modified = false; xmlDoc.Save(FilePath); } + + private XmlNode SelectSingleNodeOrCreate(XmlNode parent, string xpath) + { + var node = parent.SelectSingleNode(xpath); + if (node is not null) return node; + // 由于xmlDoc.CreateNode不支持xpath,因此当xpath有多层时,必须对每一层依次分别创建 + foreach (var s in xpath.Split('/')) + { + node = parent.SelectSingleNode(s); + if (node is null) + { + node = xmlDoc.CreateNode(XmlNodeType.Element, s, null); + parent.AppendChild(node); + } + parent = node; // 继续下一层的处理 + } + return node; + } } \ No newline at end of file From 104429d481ee0617c36bd41e3dab8a65d25c724a Mon Sep 17 00:00:00 2001 From: Starrah Date: Wed, 28 Jan 2026 12:46:21 +0800 Subject: [PATCH 2/4] =?UTF-8?q?refactor:=20=E5=88=9D=E6=AD=A5=E9=87=8D?= =?UTF-8?q?=E6=9E=84=20ReplaceChartModal.tsx=20=E4=B8=BA=E5=92=8C=E5=85=B6?= =?UTF-8?q?=E4=BB=96=E6=9B=BF=E6=8D=A2=E5=8A=9F=E8=83=BD=E4=B8=80=E6=A0=B7?= =?UTF-8?q?=E7=9A=84=E2=80=9C=E5=B8=A6=E5=8F=AF=E9=80=89fileHandle?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E7=9A=84=E5=87=BD=E6=95=B0=E2=80=9D=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=EF=BC=8C=E4=BB=A5=E4=BE=BF=E5=90=8E=E7=BB=AD=E5=BC=80?= =?UTF-8?q?=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DragDropDispatcher/ReplaceChartModal.tsx | 34 +++++++++++++++++-- .../components/DragDropDispatcher/index.tsx | 6 ++-- MaiChartManager/Front/src/locales/en.yaml | 2 ++ MaiChartManager/Front/src/locales/zh-TW.yaml | 2 ++ MaiChartManager/Front/src/locales/zh.yaml | 2 ++ 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/MaiChartManager/Front/src/components/DragDropDispatcher/ReplaceChartModal.tsx b/MaiChartManager/Front/src/components/DragDropDispatcher/ReplaceChartModal.tsx index a0cbf59..dd3fa83 100644 --- a/MaiChartManager/Front/src/components/DragDropDispatcher/ReplaceChartModal.tsx +++ b/MaiChartManager/Front/src/components/DragDropDispatcher/ReplaceChartModal.tsx @@ -1,11 +1,14 @@ import { t } from '@/locales'; import { globalCapture, selectedADir, selectedLevel, selectedMusic, selectMusicId, updateMusicList } from '@/store/refs'; -import { NButton, NFlex, NModal, useMessage } from 'naive-ui'; -import { defineComponent, PropType, ref, computed, watch, shallowRef } from 'vue'; +import { NButton, NFlex, NModal, useDialog, useMessage } from 'naive-ui'; +import { defineComponent, shallowRef } from 'vue'; import JacketBox from '../JacketBox'; import { DIFFICULTY, LEVEL_COLOR } from '@/consts'; import api from '@/client/api'; +export let prepareReplaceChart = async (fileHandle?: FileSystemFileHandle) => { +} + export const replaceChartFileHandle = shallowRef(null); export default defineComponent({ @@ -13,6 +16,33 @@ export default defineComponent({ // }, setup(props, { emit }) { const message = useMessage(); + const dialog = useDialog(); + + prepareReplaceChart = async (fileHandle?: FileSystemFileHandle) => { + if (!fileHandle) { + [fileHandle] = await window.showOpenFilePicker({ + id: 'chart', + startIn: 'downloads', + types: [ + { + description: t('music.edit.supportedFileTypes'), + accept: { + "application/x-supported": [".ma2", ".txt"], // 没办法限定只匹配maidata.txt,就只好先把一切txt都作为匹配 + }, + }, + ], + }); + } + if (!fileHandle) return // 用户未选择文件 + const name = fileHandle.name + if (!(name.endsWith(".ma2") || name == "maidata.txt")) { + dialog.error({title: t('error.unsupportedFileType'), content: t('music.edit.notValidChartFile')}) + return + } + // TODO:对ma2和maidata.txt分类讨论,后者执行ImportCheck + console.log(fileHandle.name) + replaceChartFileHandle.value = fileHandle + } const replaceChart = async () => { if (!replaceChartFileHandle.value) return; diff --git a/MaiChartManager/Front/src/components/DragDropDispatcher/index.tsx b/MaiChartManager/Front/src/components/DragDropDispatcher/index.tsx index 86e0d7e..3cb9fb5 100644 --- a/MaiChartManager/Front/src/components/DragDropDispatcher/index.tsx +++ b/MaiChartManager/Front/src/components/DragDropDispatcher/index.tsx @@ -5,7 +5,7 @@ import { uploadFlow as uploadFlowMovie } from '@/components/MusicEdit/SetMovieBu import { uploadFlow as uploadFlowAcbAwb } from '@/components/MusicEdit/AcbAwb'; import { selectedADir, selectedMusic } from '@/store/refs'; import { upload as uploadJacket } from '@/components/JacketBox'; -import ReplaceChartModal, { replaceChartFileHandle } from './ReplaceChartModal'; +import ReplaceChartModal, { prepareReplaceChart } from './ReplaceChartModal'; import AquaMaiManualInstaller, { setManualInstallAquaMai } from './AquaMaiManualInstaller'; export const mainDivRef = shallowRef(); @@ -48,8 +48,8 @@ export default defineComponent({ else if (file.kind === 'file' && (firstType.startsWith('image/') || file.name.endsWith('.jpeg') || file.name.endsWith('.jpg') || file.name.endsWith('.png'))) { uploadJacket(file); } - else if (file.kind === 'file' && file.name.endsWith('.ma2')) { - replaceChartFileHandle.value = file; + else if (file.kind === 'file' && (file.name.endsWith('.ma2') || file.name == "maidata.txt")) { + prepareReplaceChart(file); } } } diff --git a/MaiChartManager/Front/src/locales/en.yaml b/MaiChartManager/Front/src/locales/en.yaml index 8dd7b27..75f5943 100644 --- a/MaiChartManager/Front/src/locales/en.yaml +++ b/MaiChartManager/Front/src/locales/en.yaml @@ -133,6 +133,7 @@ music: replaceChartConfirm: Confirm to replace {level}? replaceChartFailed: Failed to replace chart replaceChartSuccess: Chart replaced successfully + notValidChartFile: Chart file must be .ma2 or maidata.txt. batch: title: Batch Actions batchAndSearch: Batch Actions & Search @@ -456,6 +457,7 @@ error: confirm: Got it file: notSelected: No file selected + unsupportedFileType: 'Unsupported file type' message: notice: Notice saveSuccess: Saved successfully diff --git a/MaiChartManager/Front/src/locales/zh-TW.yaml b/MaiChartManager/Front/src/locales/zh-TW.yaml index da16da8..49fdaf7 100644 --- a/MaiChartManager/Front/src/locales/zh-TW.yaml +++ b/MaiChartManager/Front/src/locales/zh-TW.yaml @@ -126,6 +126,7 @@ music: replaceChartConfirm: 確認要替換 {level} 譜面嗎? replaceChartFailed: 替換譜面失敗 replaceChartSuccess: 替換譜面成功 + notValidChartFile: 譜面檔案必須是 .ma2 或 maidata.txt。 batch: title: 批次操作 batchAndSearch: 批次操作與搜尋 @@ -417,6 +418,7 @@ error: feedbackError: 回饋錯誤 file: notSelected: 未選擇檔案 + unsupportedFileType: '不支援的檔案類型' message: notice: 提示 saveSuccess: 儲存成功 diff --git a/MaiChartManager/Front/src/locales/zh.yaml b/MaiChartManager/Front/src/locales/zh.yaml index f9c02ec..05b10a8 100644 --- a/MaiChartManager/Front/src/locales/zh.yaml +++ b/MaiChartManager/Front/src/locales/zh.yaml @@ -126,6 +126,7 @@ music: replaceChartConfirm: 确认要替换 {level} 谱面吗? replaceChartFailed: 替换谱面失败 replaceChartSuccess: 替换谱面成功 + notValidChartFile: 谱面文件必须是.ma2或maidata.txt batch: title: 批量操作 batchAndSearch: 批量操作与搜索 @@ -418,6 +419,7 @@ error: feedbackError: 反馈错误 file: notSelected: 未选择文件 + unsupportedFileType: 不支持的文件类型 message: notice: 提示 saveSuccess: 保存成功 From 6f99149fa7f9a0c92d07b770e1371385025d7d84 Mon Sep 17 00:00:00 2001 From: Starrah Date: Wed, 28 Jan 2026 14:16:51 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20ReplaceChart=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=88=E7=9B=B4=E6=8E=A5=E6=9B=BF=E6=8D=A2MA2=EF=BC=89?= =?UTF-8?q?=E4=B8=8D=E4=BC=9A=E8=87=AA=E5=8A=A8=E4=BF=AE=E6=AD=A3=E9=9F=B3?= =?UTF-8?q?=E7=AC=A6=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Charts/ChartController.cs | 12 ++++++++++++ .../Controllers/Charts/ImportChartController.cs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/MaiChartManager/Controllers/Charts/ChartController.cs b/MaiChartManager/Controllers/Charts/ChartController.cs index 91a726a..bf867b6 100644 --- a/MaiChartManager/Controllers/Charts/ChartController.cs +++ b/MaiChartManager/Controllers/Charts/ChartController.cs @@ -105,5 +105,17 @@ public void ReplaceChart(int id, int level, IFormFile file, string assetDir) file.CopyTo(stream); targetChart.Problems.Clear(); stream.Close(); + + // 检查新谱面ma2的音符数量是否有变化,如果有修正之 + string fileContent; + using (var reader = new StreamReader(file.OpenReadStream())) + { + fileContent = reader.ReadToEnd(); + } + var newMaxNotes = ImportChartController.ParseTNumAllFromMa2(fileContent); + if (newMaxNotes != 0 && targetChart.MaxNotes != newMaxNotes) + { + targetChart.MaxNotes = newMaxNotes; + } } } \ No newline at end of file diff --git a/MaiChartManager/Controllers/Charts/ImportChartController.cs b/MaiChartManager/Controllers/Charts/ImportChartController.cs index 1466ab5..e5536be 100644 --- a/MaiChartManager/Controllers/Charts/ImportChartController.cs +++ b/MaiChartManager/Controllers/Charts/ImportChartController.cs @@ -569,7 +569,7 @@ public ImportChartResult ImportChart( } - private static int ParseTNumAllFromMa2(string ma2Content) + public static int ParseTNumAllFromMa2(string ma2Content) { var lines = ma2Content.Split('\n'); // 从后往前读取,因为 T_NUM_ALL 在文件最后 From 3c01ae0e0cee5652ccaa545f6a1f28256d69e33c Mon Sep 17 00:00:00 2001 From: Starrah Date: Wed, 28 Jan 2026 14:21:36 +0800 Subject: [PATCH 4/4] =?UTF-8?q?[WIP]=201.=20ImportChartCheckApi=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=8F=82=E6=95=B0=EF=BC=9AisReplacement=EF=BC=8C?= =?UTF-8?q?=E8=A1=A8=E7=A4=BA=E8=AF=A5=E6=A3=80=E6=9F=A5=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E6=98=AF=E7=94=B1=E2=80=9C=E6=9B=BF=E6=8D=A2=E8=B0=B1=E9=9D=A2?= =?UTF-8?q?=E2=80=9D=E5=8A=9F=E8=83=BD=E5=8F=91=E8=B5=B7=E7=9A=84=EF=BC=8C?= =?UTF-8?q?=E8=BF=98=E6=98=AF=E6=99=AE=E9=80=9A=E7=9A=84=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E8=B0=B1=E9=9D=A2=E5=8A=9F=E8=83=BD=E5=8F=91=E8=B5=B7=E7=9A=84?= =?UTF-8?q?=E3=80=82=202.=20ReplaceChart=E6=96=B0=E5=A2=9E=E5=8F=82?= =?UTF-8?q?=E6=95=B0shift=EF=BC=8C=E4=BB=85=E5=9C=A8=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E7=9A=84=E6=98=AFMA2=E6=97=B6=E9=9C=80=E8=A6=81=E4=BC=A0?= =?UTF-8?q?=E5=85=A5=EF=BC=8C=E8=A1=A8=E7=A4=BA=E5=BB=B6=E8=BF=9F=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E6=A8=A1=E5=BC=8F=E3=80=82=203.=20=E5=B9=B6=E8=BF=9B?= =?UTF-8?q?=E4=B8=80=E6=AD=A5=E9=87=8D=E6=9E=84=20ReplaceChartModal.tsx?= =?UTF-8?q?=EF=BC=8C=E7=A1=AE=E4=BF=9D=E5=8E=9F=E6=9D=A5=E7=9A=84=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E6=9B=BF=E6=8D=A2MA2=E5=8A=9F=E8=83=BD=E5=8F=AF?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E5=90=8C=E6=97=B6=EF=BC=8C=E9=A2=84=E7=95=99?= =?UTF-8?q?=E6=96=B0=E5=8A=9F=E8=83=BD=E7=9A=84=E7=A9=BA=E9=97=B4=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Charts/ChartController.cs | 4 +- .../Charts/ImportChartController.cs | 9 +- MaiChartManager/Front/src/client/apiGen.ts | 4 + .../DragDropDispatcher/ReplaceChartModal.tsx | 97 +++++++++++-------- .../src/components/MusicEdit/ChartPanel.tsx | 6 +- MaiChartManager/Locale.Designer.cs | 9 ++ MaiChartManager/Locale.resx | 3 + MaiChartManager/Locale.zh-hans.resx | 3 + MaiChartManager/Locale.zh-hant.resx | 3 + 9 files changed, 95 insertions(+), 43 deletions(-) diff --git a/MaiChartManager/Controllers/Charts/ChartController.cs b/MaiChartManager/Controllers/Charts/ChartController.cs index bf867b6..a802a63 100644 --- a/MaiChartManager/Controllers/Charts/ChartController.cs +++ b/MaiChartManager/Controllers/Charts/ChartController.cs @@ -95,10 +95,12 @@ public void EditChartEnable(int id, int level, [FromBody] bool value, string ass } [HttpPost] - public void ReplaceChart(int id, int level, IFormFile file, string assetDir) + public void ReplaceChart(int id, int level, IFormFile file, string assetDir, + [FromForm] ImportChartController.ShiftMethod? shift) { var music = settings.GetMusic(id, assetDir); if (music == null || file == null) return; + // TODO 判断是MA2还是maidata.txt,走不同的逻辑 var targetChart = music.Charts[level]; targetChart.Path = $"{id:000000}_0{level}.ma2"; using var stream = System.IO.File.Open(Path.Combine(StaticSettings.StreamingAssets, assetDir, "music", $"music{id:000000}", targetChart.Path), FileMode.Create); diff --git a/MaiChartManager/Controllers/Charts/ImportChartController.cs b/MaiChartManager/Controllers/Charts/ImportChartController.cs index e5536be..5776969 100644 --- a/MaiChartManager/Controllers/Charts/ImportChartController.cs +++ b/MaiChartManager/Controllers/Charts/ImportChartController.cs @@ -191,11 +191,18 @@ public record ImportChartMessage(string Message, MessageLevel Level); public record ImportChartCheckResult(bool Accept, IEnumerable Errors, float MusicPadding, bool IsDx, string? Title, float first, float bar); [HttpPost] - public ImportChartCheckResult ImportChartCheck(IFormFile file) + public ImportChartCheckResult ImportChartCheck(IFormFile file, [FromForm] bool isReplacement = false) { var errors = new List(); var fatal = false; + if (isReplacement) + { + // 替换谱面的操作也需要检查的过程,但检查的逻辑和导入谱面时可以说是一模一样的,故直接共用逻辑 + // 唯一的区别是给用户一个警告,明确说明直接替换谱面功能的适用范围 + errors.Add(new ImportChartMessage(Locale.NotesReplacementWarning, MessageLevel.Warning)); + } + try { var kvps = new SimaiFile(file.OpenReadStream()).ToKeyValuePairs(); diff --git a/MaiChartManager/Front/src/client/apiGen.ts b/MaiChartManager/Front/src/client/apiGen.ts index c0aa133..7fe258b 100644 --- a/MaiChartManager/Front/src/client/apiGen.ts +++ b/MaiChartManager/Front/src/client/apiGen.ts @@ -266,6 +266,7 @@ export interface MusicXmlWithABJacket { subLockType?: number; disable?: boolean; longMusic?: boolean; + shiftMethod?: string | null; charts?: Chart[] | null; assetBundleJacket?: string | null; pseudoAssetBundleJacket?: string | null; @@ -965,6 +966,7 @@ export class Api extends HttpClient @@ -1236,6 +1238,8 @@ export class Api extends HttpClient diff --git a/MaiChartManager/Front/src/components/DragDropDispatcher/ReplaceChartModal.tsx b/MaiChartManager/Front/src/components/DragDropDispatcher/ReplaceChartModal.tsx index dd3fa83..06fb0ae 100644 --- a/MaiChartManager/Front/src/components/DragDropDispatcher/ReplaceChartModal.tsx +++ b/MaiChartManager/Front/src/components/DragDropDispatcher/ReplaceChartModal.tsx @@ -1,16 +1,15 @@ import { t } from '@/locales'; import { globalCapture, selectedADir, selectedLevel, selectedMusic, selectMusicId, updateMusicList } from '@/store/refs'; import { NButton, NFlex, NModal, useDialog, useMessage } from 'naive-ui'; -import { defineComponent, shallowRef } from 'vue'; +import { defineComponent, ref, shallowRef } from 'vue'; import JacketBox from '../JacketBox'; import { DIFFICULTY, LEVEL_COLOR } from '@/consts'; import api from '@/client/api'; +import CheckingModal from "@/components/ImportCreateChartButton/ImportChartButton/CheckingModal"; export let prepareReplaceChart = async (fileHandle?: FileSystemFileHandle) => { } -export const replaceChartFileHandle = shallowRef(null); - export default defineComponent({ // props: { // }, @@ -18,6 +17,9 @@ export default defineComponent({ const message = useMessage(); const dialog = useDialog(); + const checking = ref(false); + const ma2Handle = shallowRef(null); + prepareReplaceChart = async (fileHandle?: FileSystemFileHandle) => { if (!fileHandle) { [fileHandle] = await window.showOpenFilePicker({ @@ -33,22 +35,34 @@ export default defineComponent({ ], }); } - if (!fileHandle) return // 用户未选择文件 - const name = fileHandle.name - if (!(name.endsWith(".ma2") || name == "maidata.txt")) { + if (!fileHandle) return; // 用户未选择文件 + + const name = fileHandle.name; + // 对maidata.txt和ma2分类讨论,前者执行ImportCheck + if (name == "maidata.txt") { + try { + checking.value = true; + const file = await fileHandle.getFile(); + const checkRet = (await api.ImportChartCheck({file, isReplacement: true})).data; + if (!checking.value) return; // 说明检查期间用户点击了关闭按钮、取消了操作。则不再执行后续流程。 + // TODO 显示导入界面(类似ErrorDisplayIdInput)、完成导入流程 + console.log(checkRet) + dialog.error({title: "NotImplemented"}) + } finally { + checking.value = false; + } + } else if (name.endsWith(".ma2")) { + ma2Handle.value = fileHandle + } else { dialog.error({title: t('error.unsupportedFileType'), content: t('music.edit.notValidChartFile')}) - return } - // TODO:对ma2和maidata.txt分类讨论,后者执行ImportCheck - console.log(fileHandle.name) - replaceChartFileHandle.value = fileHandle } - const replaceChart = async () => { - if (!replaceChartFileHandle.value) return; + const replaceMa2 = async () => { + if (!ma2Handle.value) return; try { - const file = await replaceChartFileHandle.value.getFile(); - replaceChartFileHandle.value = null; + const file = await ma2Handle.value.getFile(); + ma2Handle.value = null; await api.ReplaceChart(selectMusicId.value, selectedLevel.value, selectedADir.value, { file }); message.success(t('music.edit.replaceChartSuccess')); await updateMusicList(); @@ -58,34 +72,37 @@ export default defineComponent({ } } - return () => replaceChartFileHandle.value = null} - >{{ - default: () =>
- {t('music.edit.replaceChartConfirm', { level: DIFFICULTY[selectedLevel.value!] })} -
{replaceChartFileHandle.value?.name}
-
-
- -
-
#{selectMusicId.value}
-
{selectedMusic.value!.name}
-
-
- {selectedMusic.value!.charts![selectedLevel.value!]?.level}.{selectedMusic.value!.charts![selectedLevel.value!]?.levelDecimal} + return () =>
+ ma2Handle.value = null} + >{{ + default: () =>
+ {t('music.edit.replaceChartConfirm', { level: DIFFICULTY[selectedLevel.value!] })} +
{ma2Handle.value?.name}
+
+
+ +
+
#{selectMusicId.value}
+
{selectedMusic.value!.name}
+
+
+ {selectedMusic.value!.charts![selectedLevel.value!]?.level}.{selectedMusic.value!.charts![selectedLevel.value!]?.levelDecimal} +
-
-
, - footer: () => - replaceChartFileHandle.value = null}>{t('common.cancel')} - {t('common.confirm')} - - }}; +
, + footer: () => + ma2Handle.value = null}>{t('common.cancel')} + {t('common.confirm')} + + }} + checking.value=false} /> +
; }, }); diff --git a/MaiChartManager/Front/src/components/MusicEdit/ChartPanel.tsx b/MaiChartManager/Front/src/components/MusicEdit/ChartPanel.tsx index 1fd51cf..c780e60 100644 --- a/MaiChartManager/Front/src/components/MusicEdit/ChartPanel.tsx +++ b/MaiChartManager/Front/src/components/MusicEdit/ChartPanel.tsx @@ -1,12 +1,13 @@ import { computed, defineComponent, PropType, watch } from "vue"; import { Chart } from "@/client/apiGen"; -import { NFlex, NForm, NFormItem, NInput, NInputNumber, NSelect, NSwitch } from "naive-ui"; +import { NButton, NFlex, NForm, NFormItem, NInput, NInputNumber, NSelect, NSwitch } from "naive-ui"; import api from "@/client/api"; import { selectedADir, selectedMusic } from "@/store/refs"; import { LEVELS } from "@/consts"; import ProblemsDisplay from "@/components/ProblemsDisplay"; import PreviewChartButton from "@/components/MusicEdit/PreviewChartButton"; import { useI18n } from 'vue-i18n'; +import { prepareReplaceChart } from "@/components/DragDropDispatcher/ReplaceChartModal"; const LEVELS_OPTIONS = LEVELS.map((level, index) => ({label: level, value: index})); @@ -43,6 +44,9 @@ export default defineComponent({ + prepareReplaceChart()}> + {t('music.edit.replaceChart')} + diff --git a/MaiChartManager/Locale.Designer.cs b/MaiChartManager/Locale.Designer.cs index 98c5e49..4961999 100644 --- a/MaiChartManager/Locale.Designer.cs +++ b/MaiChartManager/Locale.Designer.cs @@ -630,6 +630,15 @@ internal static string MusicNoTitle { } } + /// + /// Looks up a localized string similar to Caution! This "Replace Chart" function should only be used when modifying the note content of the existing chart, while the audio remains unchanged, the &first offset remains unchanged, and the timing of the first note remains unchanged. Otherwise, you will need to delete the entire chart and re-import it.. + /// + internal static string NotesReplacementWarning { + get { + return ResourceManager.GetString("NotesReplacementWarning", resourceCulture); + } + } + /// /// Looks up a localized string similar to Please enter activation code. /// diff --git a/MaiChartManager/Locale.resx b/MaiChartManager/Locale.resx index 20f9e43..b89915e 100644 --- a/MaiChartManager/Locale.resx +++ b/MaiChartManager/Locale.resx @@ -293,4 +293,7 @@ If you notice any issues with the conversion result, you can try testing it in A Automatically run in server mode and minimize to the system tray upon startup. + + Caution! This "Replace Chart" function should only be used when modifying the note content of the existing chart, while the audio remains unchanged, the &first offset remains unchanged, and the timing of the first note remains unchanged. Otherwise, you will need to delete the entire chart and re-import it. + \ No newline at end of file diff --git a/MaiChartManager/Locale.zh-hans.resx b/MaiChartManager/Locale.zh-hans.resx index f6ddf3c..810a0f5 100644 --- a/MaiChartManager/Locale.zh-hans.resx +++ b/MaiChartManager/Locale.zh-hans.resx @@ -285,4 +285,7 @@ 开机自动以服务器模式运行并最小化到托盘 + + 注意!本“替换谱面”功能仅限用于:谱面音符内容在原来的基础上发生修改,且音频内容未变、&first偏移量未变、谱面中第一个音符的时刻未变的情况。否则,您需要删除整个谱面后重新导入。 + \ No newline at end of file diff --git a/MaiChartManager/Locale.zh-hant.resx b/MaiChartManager/Locale.zh-hant.resx index 91b66db..c1282c2 100644 --- a/MaiChartManager/Locale.zh-hant.resx +++ b/MaiChartManager/Locale.zh-hant.resx @@ -285,4 +285,7 @@ 開機自動以伺服器模式運作並最小化到托盤 + + >請注意!本「替換譜面」功能僅限用於:譜面音符內容在原來的基礎上發生修改,且音訊內容未變、&first偏移量未變、譜面中第一個音符的時刻未變的情況。否則,您需要刪除整個譜面後重新匯入。 + \ No newline at end of file