feat: ID 映射支持叠加单独导出的数据包,并纳入 event 表
D:/A031OptDump/Root 是比 G:\Package 更新的一层增补(曲目到 12024、宴曲
111537/111765/112002),原来的 --package 只认整合包内的 A??? 目录,套不到它。
- 新增可重复的 --data-root,把一个目录直接当数据根,按传参顺序追加、后者覆盖
同 ID 行;--package 与 --data-root 可混用。
- 新增 events.json(eventId → 活动名 / alwaysOpen / infoType / disableArea)。
本地 event 表没有日期窗口,开没开由服务器 GetGameEventApi 的
GameEvent{startDate,endDate} 决定,README 里写明了这一点,免得误用它判状态。
- 合并两层后:music 1367→1378、map 168→169、title 3000→3001、event 824。
11820 在两层数据包里都不存在,结论不变。
- lockType 分布按合并后数据更正为 Unlock 1347 / Lock 18 / Challenge 5 /
Transmission 2 / KaleidScope 6,顺带说明大多数歌 lockType==Unlock、
本来就可玩,不查 itemKind 5。
This commit is contained in:
1 parent
264b1d0aa7
commit
2c7f9c1de7
7 files changed
+6066
-32
No files matched your search
@@ -168,7 +168,11 @@ data/id_mapping/ # 由 tools/gen_id_mapping.dart 从机台数据包抽
|
||||
「上传成功但没生效」。为此把机台数据包里的表抽成可查的映射:
|
||||
|
||||
```bash
|
||||
# 整合包(自动找 <pkg>/Sinmai_Data/StreamingAssets/A0xx/)
|
||||
dart run tools/gen_id_mapping.dart --package G:/Package
|
||||
|
||||
# 再叠一层单独导出的数据包,后面的覆盖前面的同 ID 行
|
||||
dart run tools/gen_id_mapping.dart --package G:/Package --data-root D:/A031OptDump/Root
|
||||
```
|
||||
|
||||
产物落在 `data/id_mapping/`:
|
||||
@@ -179,22 +183,32 @@ dart run tools/gen_id_mapping.dart --package G:/Package
|
||||
| `items.json` | 按 `ItemKind` 分组(1 姓名框 2 称号 3 头像 9 角色 10 搭档 11 背景板 12 功能票)的 id → 名称 |
|
||||
| `maps.json` | mapId → 区域名 / `IslandId` / `OpenEventId` / `ColorId` / `BonusMusicId` / `IsInfinity` / `IsCollabo` |
|
||||
| `gates.json` | 万花筒三张表:`gateList`(gateId → 门名 / `gateType` / `eventName`)、`courseList`(courseId ↔ gateId ↔ keyId)、`keyList` |
|
||||
| `events.json` | eventId → 活动名 / `alwaysOpen` / `infoType` / `disableArea` |
|
||||
|
||||
要点:
|
||||
|
||||
- 真正的 ID 在 XML 的 `<name><id>` 里,**目录名只是 `dataName`,两者不相等**
|
||||
(`icon/icon550201/Icon.xml` 的 `name.id` 实际是 1)。
|
||||
(`icon/icon550201/Icon.xml` 的 `name.id` 实际是 1;`music/music111537` 的
|
||||
`name.id` 是 111537,属宴曲段)。
|
||||
- 数据包按 `Sinmai_Data/StreamingAssets/A0xx/` 分基础包与增补包,抽取时按目录名
|
||||
升序合并、同 ID 后者覆盖前者,与客户端 `DataManager.LoadData` 的语义一致。
|
||||
- **本地 event 表没有日期窗口**:开关状态是服务器 `GetGameEventApi` 的
|
||||
`GameEvent{startDate,endDate}` 决定的。`events.json` 只能告诉你某个
|
||||
`eventName.id` 是哪个活动、是否 `alwaysOpen`,判断「现在开没开」得问服务器。
|
||||
- 放在 `data/` 而不是 `assets/`:目前还没有代码在运行时读它,进 `assets/` 会被
|
||||
原样打进每个安装包(约 1.2MB)。真要接进 App 时再连同 `pubspec.yaml` 一起挪。
|
||||
|
||||
顺手用这份表核出来的几个事实,都能解释此前的「不显示」:
|
||||
|
||||
- **musicId 11820 在曲表里根本不存在**(11819、11821 也不在;11814 之后直接跳到
|
||||
11822)。它不是万花筒锁——`lockType = 4 (KaleidScope)` 的歌整张表只有 6 首
|
||||
(11740 / 11745 / 11749 / 11753 / 11809 / 11814)。11820 属于「机台没有这首歌」,
|
||||
任何 `UpsertUserAll` 都变不出来。
|
||||
- **musicId 11820 在任何一层数据包里都不存在**(11819、11821 也不在;11814 之后
|
||||
直接跳到 11822,G:\Package 与 D:/A031OptDump 两层都查过)。它不是万花筒锁——
|
||||
`lockType = 4 (KaleidScope)` 的歌整张表只有 6 首(11740 / 11745 / 11749 /
|
||||
11753 / 11809 / 11814)。11820 属于「机台没这首歌」,任何 `UpsertUserAll`
|
||||
都变不出来。
|
||||
- `lockType` 的分布是 `Unlock=1347 / Lock=18 / Challenge=5 / Transmission=2 /
|
||||
KaleidScope=6`(合并两层数据包后共 1378 首),所以绝大多数歌根本不查
|
||||
`itemKind 5`(`lockType == Unlock` 时 `IsPlayable` 直接为 true)——这也解释了
|
||||
为什么有些「解歌」包发下去看不出效果:那首歌本来就可玩。
|
||||
- **角色(旅行伙伴)1001 不存在**,合法 ID 从 101 起,整表 983 条、上界到 605905。
|
||||
以前页面里「例如 1001」的提示正是这个坑。
|
||||
- **万花筒只有 gate 1~6**(蓝/白/紫/黑/黄/红,course 与 key 同为 1~6 一一对应)。
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -13593,6 +13593,10 @@
|
||||
{
|
||||
"id": 609000,
|
||||
"name": "WEC2026 以光之明"
|
||||
},
|
||||
{
|
||||
"id": 708106,
|
||||
"name": "OV3RCLOCK"
|
||||
}
|
||||
],
|
||||
"3": [
|
||||
|
||||
@@ -2350,5 +2350,19 @@
|
||||
"BonusMusicIdName": "Paradigm: Rebootちほーボーナス曲",
|
||||
"IsCollabo": true,
|
||||
"IsInfinity": false
|
||||
},
|
||||
{
|
||||
"id": 650056,
|
||||
"name": "ヒメヒナちほー2",
|
||||
"IslandId": 60,
|
||||
"IslandIdName": "maimaiDX CiRCLE",
|
||||
"OpenEventId": 261002041,
|
||||
"OpenEventIdName": "261002_04_1:ヒメヒナちほー2 解禁",
|
||||
"ColorId": 650056,
|
||||
"ColorIdName": "ヒメヒナ2",
|
||||
"BonusMusicId": 650056,
|
||||
"BonusMusicIdName": "ヒメヒナちほー2ボーナス曲",
|
||||
"IsCollabo": true,
|
||||
"IsInfinity": false
|
||||
}
|
||||
]
|
||||
@@ -1,19 +1,20 @@
|
||||
{
|
||||
"generatedFrom": "G:/Package",
|
||||
"dataDirs": [
|
||||
"A000",
|
||||
"A005",
|
||||
"A011",
|
||||
"A015"
|
||||
"A015",
|
||||
"Root"
|
||||
],
|
||||
"counts": {
|
||||
"music": 1367,
|
||||
"map": 168,
|
||||
"music": 1378,
|
||||
"map": 169,
|
||||
"gate": 6,
|
||||
"course": 6,
|
||||
"key": 6,
|
||||
"event": 824,
|
||||
"itemKind1": 398,
|
||||
"itemKind2": 3000,
|
||||
"itemKind2": 3001,
|
||||
"itemKind3": 1046,
|
||||
"itemKind9": 983,
|
||||
"itemKind10": 25,
|
||||
|
||||
+190
-3
@@ -18963,13 +18963,13 @@
|
||||
"genreNameName": "POPSアニメ",
|
||||
"AddVersion": 21,
|
||||
"AddVersionName": "BUDDiES",
|
||||
"eventName": 1,
|
||||
"eventNameName": "無期限常時解放",
|
||||
"eventName": 0,
|
||||
"eventNameName": "解放なし",
|
||||
"disable": false,
|
||||
"lockType": 0,
|
||||
"subLockType": 1,
|
||||
"longMusic": 0,
|
||||
"version": 24006
|
||||
"version": 24003
|
||||
},
|
||||
{
|
||||
"id": 11640,
|
||||
@@ -22252,6 +22252,142 @@
|
||||
"longMusic": 0,
|
||||
"version": 25007
|
||||
},
|
||||
{
|
||||
"id": 11997,
|
||||
"name": "キスキツネ",
|
||||
"artistName": 781,
|
||||
"artistNameName": "HIMEHINA",
|
||||
"genreName": 101,
|
||||
"genreNameName": "POPSアニメ",
|
||||
"AddVersion": 26,
|
||||
"AddVersionName": "CiRCLEPLUS",
|
||||
"eventName": 261002021,
|
||||
"eventNameName": "261002_02_1:ヒメヒナちほー2 3曲追加《キスキツネ、WWW、うたかたよいかないで》",
|
||||
"disable": false,
|
||||
"lockType": 0,
|
||||
"subLockType": 1,
|
||||
"longMusic": 0,
|
||||
"version": 26506
|
||||
},
|
||||
{
|
||||
"id": 11998,
|
||||
"name": "WWW",
|
||||
"artistName": 781,
|
||||
"artistNameName": "HIMEHINA",
|
||||
"genreName": 101,
|
||||
"genreNameName": "POPSアニメ",
|
||||
"AddVersion": 26,
|
||||
"AddVersionName": "CiRCLEPLUS",
|
||||
"eventName": 261002021,
|
||||
"eventNameName": "261002_02_1:ヒメヒナちほー2 3曲追加《キスキツネ、WWW、うたかたよいかないで》",
|
||||
"disable": false,
|
||||
"lockType": 0,
|
||||
"subLockType": 1,
|
||||
"longMusic": 0,
|
||||
"version": 26506
|
||||
},
|
||||
{
|
||||
"id": 11999,
|
||||
"name": "うたかたよいかないで",
|
||||
"artistName": 781,
|
||||
"artistNameName": "HIMEHINA",
|
||||
"genreName": 101,
|
||||
"genreNameName": "POPSアニメ",
|
||||
"AddVersion": 26,
|
||||
"AddVersionName": "CiRCLEPLUS",
|
||||
"eventName": 261002021,
|
||||
"eventNameName": "261002_02_1:ヒメヒナちほー2 3曲追加《キスキツネ、WWW、うたかたよいかないで》",
|
||||
"disable": false,
|
||||
"lockType": 0,
|
||||
"subLockType": 1,
|
||||
"longMusic": 0,
|
||||
"version": 26506
|
||||
},
|
||||
{
|
||||
"id": 12000,
|
||||
"name": "Intergalactic Bound",
|
||||
"artistName": 1127,
|
||||
"artistNameName": "Yunosuke / CircusP",
|
||||
"genreName": 102,
|
||||
"genreNameName": "niconicoボーカロイド",
|
||||
"AddVersion": 26,
|
||||
"AddVersionName": "CiRCLEPLUS",
|
||||
"eventName": 261016021,
|
||||
"eventNameName": "261016_02_1:niconico2曲、バラエティ1曲追加《Intergalactic Bound、LEMON MELON COOKIE、3rd Avenue》",
|
||||
"disable": false,
|
||||
"lockType": 0,
|
||||
"subLockType": 1,
|
||||
"longMusic": 0,
|
||||
"version": 26507
|
||||
},
|
||||
{
|
||||
"id": 12001,
|
||||
"name": "LEMON MELON COOKIE",
|
||||
"artistName": 1128,
|
||||
"artistNameName": "TAK",
|
||||
"genreName": 102,
|
||||
"genreNameName": "niconicoボーカロイド",
|
||||
"AddVersion": 26,
|
||||
"AddVersionName": "CiRCLEPLUS",
|
||||
"eventName": 261016021,
|
||||
"eventNameName": "261016_02_1:niconico2曲、バラエティ1曲追加《Intergalactic Bound、LEMON MELON COOKIE、3rd Avenue》",
|
||||
"disable": false,
|
||||
"lockType": 0,
|
||||
"subLockType": 0,
|
||||
"longMusic": 0,
|
||||
"version": 26507
|
||||
},
|
||||
{
|
||||
"id": 12002,
|
||||
"name": "3rd Avenue",
|
||||
"artistName": 1138,
|
||||
"artistNameName": "Sound Souler",
|
||||
"genreName": 104,
|
||||
"genreNameName": "ゲームバラエティ",
|
||||
"AddVersion": 26,
|
||||
"AddVersionName": "CiRCLEPLUS",
|
||||
"eventName": 261016021,
|
||||
"eventNameName": "261016_02_1:niconico2曲、バラエティ1曲追加《Intergalactic Bound、LEMON MELON COOKIE、3rd Avenue》",
|
||||
"disable": false,
|
||||
"lockType": 0,
|
||||
"subLockType": 1,
|
||||
"longMusic": 0,
|
||||
"version": 26507
|
||||
},
|
||||
{
|
||||
"id": 12019,
|
||||
"name": "Cryogenic",
|
||||
"artistName": 1148,
|
||||
"artistNameName": "Camellia ft. Petra Gurin「In Falsus」",
|
||||
"genreName": 104,
|
||||
"genreNameName": "ゲームバラエティ",
|
||||
"AddVersion": 26,
|
||||
"AddVersionName": "CiRCLEPLUS",
|
||||
"eventName": 261016022,
|
||||
"eventNameName": "261016_02_2:バラエティ1曲追加《Cryogenic》",
|
||||
"disable": false,
|
||||
"lockType": 0,
|
||||
"subLockType": 1,
|
||||
"longMusic": 0,
|
||||
"version": 26507
|
||||
},
|
||||
{
|
||||
"id": 12024,
|
||||
"name": "OV3RCLOCK",
|
||||
"artistName": 1152,
|
||||
"artistNameName": "Alicemetix",
|
||||
"genreName": 105,
|
||||
"genreNameName": "maimai",
|
||||
"AddVersion": 26,
|
||||
"AddVersionName": "CiRCLEPLUS",
|
||||
"eventName": 261002024,
|
||||
"eventNameName": "261002_02_4:伝導楽曲 1曲(Lock)",
|
||||
"disable": false,
|
||||
"lockType": 3,
|
||||
"subLockType": 1,
|
||||
"longMusic": 0,
|
||||
"version": 26506
|
||||
},
|
||||
{
|
||||
"id": 100018,
|
||||
"name": "[協]Love You",
|
||||
@@ -22949,6 +23085,23 @@
|
||||
"longMusic": 0,
|
||||
"version": 24015
|
||||
},
|
||||
{
|
||||
"id": 111537,
|
||||
"name": "[即]Straight into the lights",
|
||||
"artistName": 890,
|
||||
"artistNameName": "Cosmograph",
|
||||
"genreName": 107,
|
||||
"genreNameName": "宴会場",
|
||||
"AddVersion": 26,
|
||||
"AddVersionName": "CiRCLEPLUS",
|
||||
"eventName": 261016023,
|
||||
"eventNameName": "261016_02_3:宴譜面追加3",
|
||||
"disable": false,
|
||||
"lockType": 0,
|
||||
"subLockType": 0,
|
||||
"longMusic": 0,
|
||||
"version": 26508
|
||||
},
|
||||
{
|
||||
"id": 111557,
|
||||
"name": "[蛸]不機嫌なスリーカード",
|
||||
@@ -23051,6 +23204,23 @@
|
||||
"longMusic": 0,
|
||||
"version": 25007
|
||||
},
|
||||
{
|
||||
"id": 111765,
|
||||
"name": "[音]愛包ダンスホール",
|
||||
"artistName": 781,
|
||||
"artistNameName": "HIMEHINA",
|
||||
"genreName": 107,
|
||||
"genreNameName": "宴会場",
|
||||
"AddVersion": 26,
|
||||
"AddVersionName": "CiRCLEPLUS",
|
||||
"eventName": 261002022,
|
||||
"eventNameName": "261002_02_2:宴譜面追加4",
|
||||
"disable": false,
|
||||
"lockType": 0,
|
||||
"subLockType": 0,
|
||||
"longMusic": 0,
|
||||
"version": 26507
|
||||
},
|
||||
{
|
||||
"id": 111772,
|
||||
"name": "[宴]人マニア",
|
||||
@@ -23102,6 +23272,23 @@
|
||||
"longMusic": 0,
|
||||
"version": 25502
|
||||
},
|
||||
{
|
||||
"id": 112002,
|
||||
"name": "[覚]3rd Avenue",
|
||||
"artistName": 1138,
|
||||
"artistNameName": "Sound Souler",
|
||||
"genreName": 107,
|
||||
"genreNameName": "宴会場",
|
||||
"AddVersion": 26,
|
||||
"AddVersionName": "CiRCLEPLUS",
|
||||
"eventName": 261016023,
|
||||
"eventNameName": "261016_02_3:宴譜面追加3",
|
||||
"disable": false,
|
||||
"lockType": 0,
|
||||
"subLockType": 0,
|
||||
"longMusic": 0,
|
||||
"version": 26508
|
||||
},
|
||||
{
|
||||
"id": 120227,
|
||||
"name": "[r]Garakuta Doll Play",
|
||||
|
||||
+63
-19
@@ -4,16 +4,20 @@
|
||||
// 产物放在 data/ 而不是 assets/:目前没有代码在运行时读它,放 assets/ 会被
|
||||
// 原样打进每个安装包(约 1.2MB)。要接进 App 时再一起挪进 pubspec 的 assets。
|
||||
//
|
||||
// 用法:
|
||||
// 用法(两种根可以混用,后面的覆盖前面的同 ID 行):
|
||||
// dart run tools/gen_id_mapping.dart --package G:/Package
|
||||
// dart run tools/gen_id_mapping.dart --package G:/Package --data-root D:/A031OptDump/Root
|
||||
//
|
||||
// 数据布局:`<pkg>/Sinmai_Data/StreamingAssets/A0xx/<表名>/<前缀><dataName>/<表名>.xml`,
|
||||
// 一个实体一个目录。真正的 ID 在 XML 的 `<name><id>` 里,目录名只是 dataName,
|
||||
// 二者不相等(例如 `icon/icon550201/Icon.xml` 的 name.id 其实是 1)。
|
||||
// `--package` 会自动去找 `<pkg>/Sinmai_Data/StreamingAssets/A0xx/`;
|
||||
// `--data-root` 直接把给定目录当一个数据根(像 A031OptDump/Root 那种单独导出的包)。
|
||||
//
|
||||
// 多个 A0xx 目录要按名字升序合并、后者覆盖同 ID 的行——客户端 DataManager.LoadData
|
||||
// 数据布局:`<root>/<表名>/<前缀><dataName>/<表名>.xml`,一个实体一个目录。
|
||||
// 真正的 ID 在 XML 的 `<name><id>` 里,目录名只是 dataName(`icon/icon550201/Icon.xml`
|
||||
// 的 name.id 其实是 1;`music/music111537` 的 name.id 是 111537,属宴曲段)。
|
||||
//
|
||||
// 多根合并按名字升序、后者覆盖同 ID 的行——客户端 DataManager.LoadData
|
||||
// 就是这个语义(按 dirs 顺序遍历,`sortedDictionary[key] =` 直接覆写)。
|
||||
// 只认形如 `A???` 的目录,其余(Table/、RomConfig.xml 等)跳过。
|
||||
// `--package` 下只认形如 `A???` 的目录,其余(Table/、RomConfig.xml 等)跳过。
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
@@ -90,33 +94,59 @@ const _keySpec = _TableSpec(
|
||||
stringIds: ['name', 'gateName'],
|
||||
);
|
||||
|
||||
/// 本地事件表只有名字与 `alwaysOpen`;**开关的日期窗口不在这里**,
|
||||
/// 是服务器 `GetGameEventApi` 下发的 `GameEvent{startDate,endDate}`。
|
||||
/// 所以这张表能用来看某个 eventName.id 属于什么活动,但判断「现在开没开」
|
||||
/// 得去问服务器。
|
||||
const _eventSpec = _TableSpec(
|
||||
dirName: 'event',
|
||||
xmlFileName: 'Event.xml',
|
||||
scalars: ['infoType', 'alwaysOpen', 'disableArea'],
|
||||
stringIds: ['name'],
|
||||
);
|
||||
|
||||
void main(List<String> args) {
|
||||
final packageRoot = _argValue(args, '--package') ?? 'G:/Package';
|
||||
final outDir = Directory(
|
||||
_argValue(args, '--out') ?? 'data/id_mapping',
|
||||
);
|
||||
|
||||
final dataDirs = <String>[];
|
||||
|
||||
// 整合包:先按 A??? 升序铺进来,让高编号的增补包覆盖基础包。
|
||||
final packageRoot = _argValue(args, '--package');
|
||||
if (packageRoot != null) {
|
||||
final assetsRoot = Directory(
|
||||
'$packageRoot/Sinmai_Data/StreamingAssets',
|
||||
'${_norm(packageRoot)}/Sinmai_Data/StreamingAssets',
|
||||
);
|
||||
if (!assetsRoot.existsSync()) {
|
||||
stderr.writeln('找不到 $assetsRoot');
|
||||
stderr.writeln('找不到 ${assetsRoot.path}');
|
||||
exitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// 升序,让高编号的增补包覆盖基础包,和客户端一致。
|
||||
final dataDirs =
|
||||
dataDirs.addAll(
|
||||
assetsRoot
|
||||
.listSync()
|
||||
.whereType<Directory>()
|
||||
.where((d) => RegExp(r'^A\d{3}$').hasMatch(_baseName(d.path)))
|
||||
.map((d) => d.path)
|
||||
.map((d) => _norm(d.path))
|
||||
.where((p) => RegExp(r'^A\d{3}$').hasMatch(_baseName(p)))
|
||||
.toList()
|
||||
..sort();
|
||||
..sort(),
|
||||
);
|
||||
}
|
||||
|
||||
// 单独导出的数据根(如 D:/A031OptDump/Root),按传参顺序追加,后面的赢。
|
||||
for (final extra in _argValues(args, '--data-root')) {
|
||||
final dir = Directory(_norm(extra));
|
||||
if (!dir.existsSync()) {
|
||||
stderr.writeln('找不到数据根 ${dir.path}');
|
||||
exitCode = 1;
|
||||
return;
|
||||
}
|
||||
dataDirs.add(_norm(extra));
|
||||
}
|
||||
|
||||
if (dataDirs.isEmpty) {
|
||||
stderr.writeln('$assetsRoot 下没有 A??? 数据目录');
|
||||
stderr.writeln('没有可用数据根,给 --package 或 --data-root');
|
||||
exitCode = 1;
|
||||
return;
|
||||
}
|
||||
@@ -128,6 +158,7 @@ void main(List<String> args) {
|
||||
final gates = _mergeById(dataDirs, _gateSpec);
|
||||
final courses = _mergeById(dataDirs, _courseSpec);
|
||||
final keys = _mergeById(dataDirs, _keySpec);
|
||||
final events = _mergeById(dataDirs, _eventSpec);
|
||||
|
||||
final items = <String, List<Map<String, dynamic>>>{};
|
||||
for (final (kind, spec) in _itemTables) {
|
||||
@@ -143,15 +174,16 @@ void main(List<String> args) {
|
||||
'keyList': keys,
|
||||
},
|
||||
'items.json': items,
|
||||
'events.json': events,
|
||||
'meta.json': {
|
||||
'generatedFrom': packageRoot,
|
||||
'dataDirs': dataDirs.map(_baseName).toList(),
|
||||
'dataDirs': dataDirs.map((p) => _baseName(p)).toList(),
|
||||
'counts': {
|
||||
'music': music.length,
|
||||
'map': maps.length,
|
||||
'gate': gates.length,
|
||||
'course': courses.length,
|
||||
'key': keys.length,
|
||||
'event': events.length,
|
||||
for (final (kind, _) in _itemTables)
|
||||
'itemKind$kind': items['$kind']!.length,
|
||||
},
|
||||
@@ -310,4 +342,16 @@ String? _argValue(List<String> args, String name) {
|
||||
return args[i + 1];
|
||||
}
|
||||
|
||||
String _baseName(String path) => path.replaceAll(r'\', '/').split('/').last;
|
||||
/// 可重复参数(`--data-root A --data-root B`)。
|
||||
List<String> _argValues(List<String> args, String name) {
|
||||
final out = <String>[];
|
||||
for (var i = 0; i < args.length - 1; i++) {
|
||||
if (args[i] == name) out.add(args[i + 1]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Windows 传参常见反斜杠,统一成 slash 再拼路径。
|
||||
String _norm(String path) => path.replaceAll(r'\', '/');
|
||||
|
||||
String _baseName(String path) => _norm(path).split('/').last;
|
||||
Reference in new issue
Block a user