Skip to content

Commit 05b8945

Browse files
committed
[R&doc]优化CLI和README
1 parent b483eb0 commit 05b8945

2 files changed

Lines changed: 94 additions & 51 deletions

File tree

Program.cs

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ private static void RunConvert(string inputPath, string? levelsRaw)
156156
throw new ArgumentException($"找不到路径: {inputPath}");
157157
}
158158

159-
private static readonly string[] chuExtentions = new[] { ".c2s", ".ugc", ".sus" };
159+
private static readonly string[] supportedPostfixs = new[] { "maidata.txt", ".ma2", ".c2s", ".ugc", ".sus" };
160160

161161
private static void RunConvertDirectory(string dir, string? levelsRaw)
162162
{
@@ -166,42 +166,22 @@ private static void RunConvertDirectory(string dir, string? levelsRaw)
166166
MatchCasing = MatchCasing.CaseInsensitive,
167167
RecurseSubdirectories = false
168168
};
169+
var inputPaths = Directory.EnumerateFiles(dir, "*", enumOpts)
170+
.Where(file => supportedPostfixs.Any(file.EndsWith)).ToArray();
169171

170-
var maidataPaths = Directory.GetFiles(dir, "maidata.txt", enumOpts);
171-
var ma2Paths = Directory.GetFiles(dir, "*.ma2", enumOpts);
172-
var chuPaths = Directory.EnumerateFiles(dir, "*", enumOpts)
173-
.Where(file => chuExtentions.Contains(Path.GetExtension(file).ToLower())).ToArray();
174-
175-
var hasMaidata = maidataPaths.Length > 0;
176-
var hasMa2 = ma2Paths.Length > 0;
177-
var hasChu = chuPaths.Length > 0;
178-
179-
if (hasMaidata && hasMa2)
180-
throw new ArgumentException("目录中同时存在 maidata.txt 与 .ma2,请只保留其中一种输入。");
181-
if ((hasMaidata || hasMa2) && hasChu)
182-
throw new ArgumentException("目录中不能同时存在 maimai 谱(maidata.txt / .ma2)与中二谱(.c2s / .ugc / .sus),请分开转换。");
183-
if (!hasMaidata && !hasMa2 && !hasChu)
184-
throw new ArgumentException("目录中未找到任何支持的谱面文件");
185-
186-
string filename = "";
187-
if (hasMaidata)
188-
{
189-
if (maidataPaths.Length > 1) throw new ArgumentException("目录中存在多个 maidata.txt,请只保留一个。");
190-
filename = maidataPaths[0];
191-
}
192-
else if (hasMa2)
172+
if (inputPaths.Length > 1)
193173
{
194-
if (ma2Paths.Length > 1)
195-
{ // 多个文件,无法直接转发给RunConvertFile,故自行调用ConvertMa2PathsToMaidata
174+
if (inputPaths.All(file=>file.EndsWith(".ma2")))
175+
{ // 只有多个MA2这种情况是允许的,直接调用ConvertMa2PathsToMaidata
196176
var title = new DirectoryInfo(dir).Name;
197-
ConvertMa2PathsToMaidata(dir, title, ma2Paths, levelsRaw);
198-
return;
177+
ConvertMa2PathsToMaidata(dir, title, inputPaths, levelsRaw);
178+
}
179+
else
180+
{
181+
throw new ArgumentException($"目录中存在多种/多个谱面文件:{string.Join(", ", inputPaths)}。请直接指定到具体的文件路径,或者删除多余的文件。");
199182
}
200-
else filename = ma2Paths[0];
201183
}
202-
else filename = chuPaths[0];
203-
204-
RunConvertFile(filename, levelsRaw);
184+
else RunConvertFile(inputPaths[0], levelsRaw);
205185
}
206186

207187
private static void RunConvertFile(string filePath, string? levelsRaw)

README.md

Lines changed: 82 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,15 @@ MuConvert 是一个支持**Simai与MA2互转**的转谱器。
2929
#### 基本用法
3030

3131
```shell
32-
MuConvert.exe <path> [-l|--levels N[,N...]] [-o|--output <输出路径或->] [--strict|--lax]
32+
MuConvert.exe <path> [-l|--levels N[,N...]] [-t|--target <format>] [-o|--output <输出路径或->] [--strict|--lax]
3333
```
3434
35-
- **`path`**:输入路径(必填),可以是 `.txt` / `.ma2` / 目录(见下文)
35+
- **`path`**:输入路径(必填),可以是单个文件或目录,输入目录时会自动找到和处理目录下的谱面文件(详见下文)。
3636
- **`-l, --levels`**:仅转换指定难度(以 `maidata.txt``&inote_编号` 为准),多个难度用英文逗号分隔;省略则转换全部难度
37+
- **`-t, --target`**:强制指定输出格式(不区分大小写)。
38+
- 多数情况下不需要指定,直接使用默认值即可。默认值根据输入类型的不同而不同,但一般来说能满足常见的场景需求。
39+
- 具体而言,默认的转换输出格式为:Simai → `ma2`,MA2 → `simai`,C2S → `ugc`,UGC/SUS → `c2s`
40+
- 目前仅有一种情况是必须指定该参数的:即想要C2S转SUS的情况,必须指定`-t sus`(否则默认转出来的是UGC)
3741
- **`-o, --output`**:指定输出位置(可选);不传入此参数时,文件将保存到“输入文件所在的目录”。
3842
- 会智能识别你传入的是目录还是文件,做智能的处理,将转谱结果输入到目录下或保存为文件。
3943
- 此外,还可以传入 `-` ,表示输出到stdout。
@@ -44,19 +48,24 @@ MuConvert.exe <path> [-l|--levels N[,N...]] [-o|--output <输出路径或->] [--
4448
4549
#### `path` 支持的输入形式与输出规则
4650
通过命令行传入的参数,既可以是文件,也可以是目录。
47-
- **输入 `.txt``maidata.txt` 或“纯 simai 单谱”)**:把Simai转为MA2。
48-
- **如果是 `maidata.txt`(含 `&inote_`**:会在输入文件的相同目录下,产生 `lv_{id}.ma2`(每个难度一个文件)。
49-
- 可用类似 `-l 5,6` 的选项,只导出部分难度
50-
- **如果是纯 simai Notes(不含 maidata 头信息)**:会在输入文件的相同目录下,产生 `lv_0.ma2`
51-
52-
- **输入 `.ma2` 文件**:把MA2转为Simai。
53-
- 输出:会在输入文件的相同目录下,产生 `maidata.txt`(当然,里面只有您传入的MA2所对应的一个难度)。
54-
- 如果想把多张不同难度的 `.ma2` 合并进一个 `maidata.txt`,请直接传入目录(见下一条)。
55-
56-
- **输入目录**:智能识别
57-
- **目录中包含 `maidata.txt`**:等价于输入该 `maidata.txt`
58-
- **目录中包含一个或多个 `.ma2`**:将它们合并转为同目录的 `maidata.txt`
59-
- 若目录中 **同时存在** `maidata.txt``.ma2`,或两者都不存在,会报错
51+
- **输入单个 maimai 相关格式文件**`.txt` / `.ma2`)时:
52+
- **输入 `.txt`**:把Simai转为MA2。
53+
- **如果是 `maidata.txt`(含 `&inote_`**:会在输入文件的相同目录下,产生 `lv_{id}.ma2`(每个难度一个文件)。
54+
- 可用类似 `-l 5,6` 的选项,只导出部分难度。
55+
- **如果是纯 simai Notes(不含 maidata 头信息)**:会在输入文件的相同目录下,产生 `lv_0.ma2`
56+
- **输入 `.ma2` 文件**:把MA2转为Simai。
57+
- 输出:会在输入文件的相同目录下,产生 `maidata.txt`(当然,里面只有您传入的MA2所对应的一个难度)。
58+
- 如果想把多张不同难度的 `.ma2` 合并进一个 `maidata.txt`,请直接传入目录(见下一条)。
59+
60+
- **输入单个 CHUNITHM 相关格式文件**`.c2s` / `.ugc` / `.sus`)时:在 C2S、UGC、SUS之间互转。
61+
- 不指定 `-t` 时,默认:`.c2s` → 同目录下同名 `.ugc``.ugc``.sus` → 同目录下同名 `.c2s`
62+
- 如果想从 C2S 转出 SUS ,则须显式指定 `-t sus`
63+
64+
- **输入目录**时:会尝试在该目录下寻找谱面文件:
65+
- 如果找到恰好一个:则等价于上面的输入单个文件的情况、处理这一个文件。
66+
- 如果找到多个:
67+
- 如果都是MA2文件,会把这多张不同难度的 `.ma2`谱面转为simai,并合并进同一个 `maidata.txt`
68+
- 否则,则是输入不明确的情况,会报错退出。
6069
6170
#### 示例
6271
- **Simai(maidata)→ MA2(按难度导出)**
@@ -75,6 +84,31 @@ MuConvert "D:\charts\MyChart" -l 5,6 # 只转紫谱和白谱
7584
# 生成的转谱结果位于D:\charts\MyChart\maidata.txt
7685
```
7786
87+
<details>
88+
<summary><strong>CHUNITHM转谱相关示例</strong></summary>
89+
90+
**UGC/SUS → C2S**(默认输出同名 `.c2s`
91+
92+
```shell
93+
MuConvert "D:\charts\Song\0003_00.ugc" # UGC -> C2S
94+
MuConvert "D:\charts\Song\0003_00.sus" # SUS -> C2S
95+
# 转谱结果与输入同目录,生成 0003_00.c2s
96+
97+
MuConvert "D:\charts\Song\0003_00.ugc" -t sus # 也可 UGC直接 -> C2S
98+
```
99+
100+
**C2S → UGC / SUS**
101+
102+
```shell
103+
MuConvert "D:\charts\Song\0003_00.c2s"
104+
# 默认同目录生成同名 .ugc
105+
106+
MuConvert "D:\charts\Song\0003_00.c2s" -t sus
107+
# 需要 SUS 时须显式指定 -t sus(否则默认为 UGC)
108+
```
109+
110+
</details>
111+
78112
### 2) 将本项目作为依赖库使用
79113
#### 导入依赖库
80114
- **推荐做法**:把本仓库作为 git submodule 引入你的工程仓库,然后把 `MuConvert.csproj` 加入你的 `.sln`/`.slnx`
@@ -84,7 +118,7 @@ git submodule add https://github.com/MuNET-OSS/MuConvert MuConvert # 将本项
84118
dotnet sln .\YourSolution.sln add .\MuConvert\MuConvert.csproj # 将项目加入解决方案
85119
```
86120
87-
#### 使用方法(TLDR):
121+
#### maimai转谱 - 使用方法(TLDR):
88122
> 以下 C# 示例中的 `Maidata``MaiChart``SimaiParser``MA2Parser``SimaiGenerator``MA2Generator` 等均位于命名空间 `MuConvert.mai`中,使用时需添加 `using MuConvert.mai;`
89123
90124
**Simai → MA2**
@@ -118,6 +152,24 @@ var maidataText = maidata.ToString(); // 通过ToString方法将Maidata对象序
118152
return maidataText; // maidataText即为转谱结果
119153
```
120154
155+
#### CHUNITHM转谱 - 使用方法(TLDR):
156+
> 以下 C# 示例中的各种Parser、Generator等,均位于命名空间 `MuConvert.chu`中,使用时需添加 `using MuConvert.chu;`
157+
158+
```csharp
159+
// 首先使用File.ReadAllText等方法,将谱面整体读取为字符串
160+
var (c2sChart, alerts) = new C2sParser().Parse(c2sText); // 解析 C2S 谱面字符串
161+
var (ugcChart, alerts) = new UgcParser().Parse(ugcText); // 解析 UGC 谱面字符串
162+
var (susChart, alerts) = new SusParser().Parse(susText); // 解析 SUS 谱面字符串
163+
// 以上得到的c2sChart、ugcChart、susChart,都是IChuChart类型的谱面表示对象;
164+
// alerts是解析过程中可能产生的警告信息等,建议打印出来。
165+
166+
var (c2sText, alerts) = new C2sGenerator().Generate(ugcChart); // UGC -> C2S
167+
var (ugcText, alerts) = new UgcGenerator().Generate(c2sChart); // C2S -> UGC
168+
var (susText, alerts) = new SusGenerator().Generate(c2sChart); // C2S -> SUS
169+
// 各种Generator的Generate方法,均接受任意的IChuChart对象。
170+
// 同上,alerts是生成过程中可能产生的警告信息等,建议打印出来。
171+
```
172+
121173
#### parser和generator的选项
122174
- 部分parser和generator,在其构造参数中带有可选的选项参数,可以控制转谱时的一些行为。
123175
- SimaiParser带有以下选项:
@@ -163,15 +215,26 @@ finally
163215
- **parser(解析器)**:把“源格式文本”解析成中间表示
164216
- `SimaiParser.Parse(string)``MaiChart`
165217
- `MA2Parser.Parse(string)``MaiChart`
166-
- 返回值同时带有 `List<Alert>`;如果遇到致命错误会抛出 `ConversionException`
218+
- CHUNITHM的三种Parser(`C2sParser``UgcParser``SusParser`):`Parse(string)``IChuChart`
219+
> <details>
220+
> <summary>关于IChuChart</summary>
221+
> 当前实现IChuChart是一个通用的接口而非具体的类型,这是因为目前不同Parser解析出的谱面的IR尚未能够完全统一,所以只能都各自继承自IChuChart。
222+
> 不过不用担心,任意的Generator都接受任意IChuChart对象,因此你可以不在意它们之间的差异,直接拿来用就行了。
223+
> 未来如果有机会的话,我们会把它们进一步统一成同一个具体类型的IR,以进一步提升代码的可维护性和可读性。
224+
> </details>
225+
- 解析成功时,**返回值会同时带有 `List<Alert>`**,这是转谱过程中可能遇到的警告等信息,建议打印出来(直接对`Alert`对象`ToString()`即可)。
226+
- 如果解析失败,会抛出 `ConversionException`;该异常对象中同样含有一个 `List<Alert>`,是导致转谱失败的错误信息,可以同上打印出来。
167227
168228
- **中间表示 IR(Chart)**:MuConvert 内部统一的谱面数据结构
169229
- 对maimai,类型为 `MuConvert.mai.MaiChart`
170230
- 关键字段包括 `Chart.BpmList``Chart.Notes`,以及 `Touch/Hold/Slide` 等具体 `Note` 子类
171231
172232
- **generator(生成器)**:把中间表示转回“目标格式文本”
173-
- `SimaiGenerator.Generate(MaiChart)` → simai 文本(可写入 `maidata.txt``&inote_*`
174-
- `MA2Generator.Generate(MaiChart)``.ma2` 文本
233+
- `SimaiGenerator.Generate(MaiChart)` → Simai 单谱文本(可写入 `maidata.txt``&inote_*`
234+
- `MA2Generator.Generate(MaiChart)` → MA2 文本
235+
- CHUNITHM的三种Generator(`C2sGenerator``UgcGenerator``SusGenerator`):`Generate(IChuChart)` → 目标格式的谱面文本
236+
- 与parser类似,成功生成时,**返回值会同时带有 `List<Alert>`**,这是转谱过程中可能遇到的警告等信息,建议打印出来(直接对`Alert`对象`ToString()`即可)。
237+
- 如果生成失败,会抛出 `ConversionException`;该异常对象中同样含有一个 `List<Alert>`,是导致转谱失败的错误信息,可以同上打印出来。
175238
176239
177240
## 开发者指南

0 commit comments

Comments
 (0)