mirror of
https://github.com/zkldi/Tachi.git
synced 2026-09-28 01:48:11 +03:00
[maimaidx] Update seeds to 2025/12/05 (#1402)
This commit is contained in:
@@ -11041,6 +11041,70 @@
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "455372326d56ff36c9a817ad9e3db862a5f6c2f0",
|
||||
"data": {
|
||||
"displayVersion": "maimaiでらっくす PRiSM PLUS",
|
||||
"inGameID": 10187
|
||||
},
|
||||
"difficulty": "DX Advanced",
|
||||
"isPrimary": true,
|
||||
"level": "7+",
|
||||
"levelNum": 7.8,
|
||||
"playtype": "Single",
|
||||
"songID": 95,
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "591ea8f3a3f15a5f75c5a7cbb33719150b6a3828",
|
||||
"data": {
|
||||
"displayVersion": "maimaiでらっくす PRiSM PLUS",
|
||||
"inGameID": 10187
|
||||
},
|
||||
"difficulty": "DX Basic",
|
||||
"isPrimary": true,
|
||||
"level": "4",
|
||||
"levelNum": 4,
|
||||
"playtype": "Single",
|
||||
"songID": 95,
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "d598fd3a830ed70bdf76b681857296330cd88b3d",
|
||||
"data": {
|
||||
"displayVersion": "maimaiでらっくす PRiSM PLUS",
|
||||
"inGameID": 10187
|
||||
},
|
||||
"difficulty": "DX Expert",
|
||||
"isPrimary": true,
|
||||
"level": "10+",
|
||||
"levelNum": 10.9,
|
||||
"playtype": "Single",
|
||||
"songID": 95,
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "283fbbe68113da289059a81c7635a2f7d0dc6db9",
|
||||
"data": {
|
||||
"displayVersion": "maimaiでらっくす PRiSM PLUS",
|
||||
"inGameID": 10187
|
||||
},
|
||||
"difficulty": "DX Master",
|
||||
"isPrimary": true,
|
||||
"level": "13",
|
||||
"levelNum": 13.3,
|
||||
"playtype": "Single",
|
||||
"songID": 95,
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "dbf525efab45d1c9147363da9836749f8a9402e5",
|
||||
"data": {
|
||||
@@ -150633,5 +150697,133 @@
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "798bddcca4ef4fc2a0403ba0a9bd120fa45bde4e",
|
||||
"data": {
|
||||
"displayVersion": "maimaiでらっくす PRiSM PLUS",
|
||||
"inGameID": 11864
|
||||
},
|
||||
"difficulty": "DX Advanced",
|
||||
"isPrimary": true,
|
||||
"level": "6",
|
||||
"levelNum": 6.5,
|
||||
"playtype": "Single",
|
||||
"songID": 1527,
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "1fa9ffa83add19468a408f727351b5fbff5d2704",
|
||||
"data": {
|
||||
"displayVersion": "maimaiでらっくす PRiSM PLUS",
|
||||
"inGameID": 11864
|
||||
},
|
||||
"difficulty": "DX Basic",
|
||||
"isPrimary": true,
|
||||
"level": "2",
|
||||
"levelNum": 2,
|
||||
"playtype": "Single",
|
||||
"songID": 1527,
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "3199545db1e72b754ef838d4993011ad9f0ee282",
|
||||
"data": {
|
||||
"displayVersion": "maimaiでらっくす PRiSM PLUS",
|
||||
"inGameID": 11864
|
||||
},
|
||||
"difficulty": "DX Expert",
|
||||
"isPrimary": true,
|
||||
"level": "9+",
|
||||
"levelNum": 9.9,
|
||||
"playtype": "Single",
|
||||
"songID": 1527,
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "134e15e7fdd0544b5b2f4928642e7572cc7c1804",
|
||||
"data": {
|
||||
"displayVersion": "maimaiでらっくす PRiSM PLUS",
|
||||
"inGameID": 11864
|
||||
},
|
||||
"difficulty": "DX Master",
|
||||
"isPrimary": true,
|
||||
"level": "12+",
|
||||
"levelNum": 12.9,
|
||||
"playtype": "Single",
|
||||
"songID": 1527,
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "0bd5f4cb68729b5b9dbac0ef91623ffcd341059b",
|
||||
"data": {
|
||||
"displayVersion": "maimaiでらっくす PRiSM PLUS",
|
||||
"inGameID": 11866
|
||||
},
|
||||
"difficulty": "DX Advanced",
|
||||
"isPrimary": true,
|
||||
"level": "6",
|
||||
"levelNum": 6,
|
||||
"playtype": "Single",
|
||||
"songID": 1528,
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "78f2c32e5fa920b8d1da1c4e6fce0030e049b00f",
|
||||
"data": {
|
||||
"displayVersion": "maimaiでらっくす PRiSM PLUS",
|
||||
"inGameID": 11866
|
||||
},
|
||||
"difficulty": "DX Basic",
|
||||
"isPrimary": true,
|
||||
"level": "2",
|
||||
"levelNum": 2,
|
||||
"playtype": "Single",
|
||||
"songID": 1528,
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "59a97f033d5d208b48b6972075b457201e7c7f22",
|
||||
"data": {
|
||||
"displayVersion": "maimaiでらっくす PRiSM PLUS",
|
||||
"inGameID": 11866
|
||||
},
|
||||
"difficulty": "DX Expert",
|
||||
"isPrimary": true,
|
||||
"level": "9",
|
||||
"levelNum": 9.2,
|
||||
"playtype": "Single",
|
||||
"songID": 1528,
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
},
|
||||
{
|
||||
"chartID": "7d697ad800d479111da3a709a45e8e9264df8ac4",
|
||||
"data": {
|
||||
"displayVersion": "maimaiでらっくす PRiSM PLUS",
|
||||
"inGameID": 11866
|
||||
},
|
||||
"difficulty": "DX Master",
|
||||
"isPrimary": true,
|
||||
"level": "13",
|
||||
"levelNum": 13.3,
|
||||
"playtype": "Single",
|
||||
"songID": 1528,
|
||||
"versions": [
|
||||
"prismplus"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -19553,5 +19553,33 @@
|
||||
"id": 1526,
|
||||
"searchTerms": [],
|
||||
"title": "Destined Marionette"
|
||||
},
|
||||
{
|
||||
"altTitles": [],
|
||||
"artist": "みきとP",
|
||||
"data": {
|
||||
"duration": 159.6,
|
||||
"genre": "niconico&ボーカロイド"
|
||||
},
|
||||
"id": 1527,
|
||||
"searchTerms": [
|
||||
"shoujo rei",
|
||||
"ghost girl"
|
||||
],
|
||||
"title": "少女レイ"
|
||||
},
|
||||
{
|
||||
"altTitles": [],
|
||||
"artist": "R Sound Design",
|
||||
"data": {
|
||||
"duration": 163.022,
|
||||
"genre": "niconico&ボーカロイド"
|
||||
},
|
||||
"id": 1528,
|
||||
"searchTerms": [
|
||||
"imperial girl",
|
||||
"teikoku shoujou"
|
||||
],
|
||||
"title": "帝国少女"
|
||||
}
|
||||
]
|
||||
@@ -25,3 +25,25 @@ ts-node merge-options.ts --version <VERSION> --input /path/to/maimai/App/Package
|
||||
4. Manually add search terms in `seeds/collections/songs-maimaidx.json`. At a minimum, songs with
|
||||
Japanese titles should be romanized.
|
||||
5. In the root project folder, run `just seeds test`.
|
||||
|
||||
## Adding a new version
|
||||
|
||||
1. Add a new version in `common/src/config/game-support/maimai-dx.ts`.
|
||||
- Also, add an Omnimix variant for the previous version.
|
||||
2. Create tables and folders for the new version (and the omnimix version).
|
||||
See `seeds/scripts/rerunners/maimaidx/add-maimaidx-table-and-folders.js`. You will have
|
||||
to adjust the constants for the version you're adding.
|
||||
3. Deactivate old tables using `seeds/scripts/rerunners/toggle-table-inactive.js`:
|
||||
|
||||
```
|
||||
node toggle-table-inactive.js -t maimaidx-Single-<VERSION>-levels
|
||||
```
|
||||
|
||||
Keep tables for the current and last (aka n-1) versions.
|
||||
|
||||
4. Switch the new table to the default one by editing `seeds/collections/tables.json`.
|
||||
Change to `"default": true` for the current version, and `"default": false` for all
|
||||
other tables of the game.
|
||||
|
||||
5. Verify you've done everything correctly by running `just seeds test` in the root project
|
||||
folder.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# List of charts to ignore when parsing game data.
|
||||
# Each line is a regex, and these regexes are matched against the strings:
|
||||
# - S<song ID>
|
||||
# - C<song ID>-<difficulty>
|
||||
# Empty lines, or lines starting with # are ignored.
|
||||
|
||||
# Ignore all UTAGEs (ID >=100000) since they're unsupported on Kamaitachi.
|
||||
S1\d{5}$
|
||||
|
||||
# Ignore Xaleid◆scopiX (2): event chart used to implement the KALEIDXSCOPE event,
|
||||
# not normally playable.
|
||||
S11879$
|
||||
|
||||
S11856$
|
||||
S11857$
|
||||
S11858$
|
||||
S11859$
|
||||
S11861$
|
||||
S11874$
|
||||
S11875$
|
||||
S11876$
|
||||
S11877$
|
||||
S11878$
|
||||
@@ -155,32 +155,37 @@ for (const chart of existingCharts) {
|
||||
songTitleArtistMap.set(`${song.title}-${song.artist}`, song.id);
|
||||
}
|
||||
|
||||
const parser = new XMLParser({
|
||||
numberParseOptions: {
|
||||
hex: false,
|
||||
leadingZeros: false,
|
||||
// do not coerce any number-like strings to numbers, since song titles
|
||||
// may also be numbers. we coerce anything we know to be a number later.
|
||||
skipLike: /.*/u,
|
||||
},
|
||||
});
|
||||
const blacklist = readFileSync(path.join(__dirname, "blacklist.txt"), "utf-8")
|
||||
.split("\n")
|
||||
.filter((e) => !e.startsWith("#") && e.trim() !== "")
|
||||
.map((e) => new RegExp(e, "u"));
|
||||
|
||||
const newSongs: Array<SongDocument<"maimaidx">> = [];
|
||||
const newCharts: Array<ChartDocument<"maimaidx:Single">> = [];
|
||||
|
||||
const songIDGenerator = GetFreshSongIDGenerator("maimaidx");
|
||||
|
||||
for (const optionsDir of options.input) {
|
||||
for (const option of readdirSync(optionsDir)) {
|
||||
if (!option.match(/^[A-Z]\d{3}$/u)) {
|
||||
continue;
|
||||
function isInBlacklist(str: string) {
|
||||
for (const regex of blacklist) {
|
||||
if (regex.exec(str)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const optionDir = path.join(optionsDir, option);
|
||||
const musicsDir = path.join(optionDir, "music");
|
||||
const soundDataDir = path.join(optionDir, "SoundData");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read all audio files ahead of time so the correct file is used, in case of
|
||||
// audio fixes
|
||||
if (options.vgmsBinary) {
|
||||
for (const optionsDir of options.input) {
|
||||
for (const option of readdirSync(optionsDir)) {
|
||||
if (!option.match(/^[A-Z]\d{3}$/u)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const optionDir = path.join(optionsDir, option);
|
||||
const soundDataDir = path.join(optionDir, "SoundData");
|
||||
|
||||
if (!existsSync(soundDataDir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (options.vgmsBinary && existsSync(soundDataDir)) {
|
||||
for (const cueFileName of readdirSync(soundDataDir)) {
|
||||
if (!cueFileName.match(/music\d+\.awb$/u)) {
|
||||
continue;
|
||||
@@ -211,6 +216,32 @@ for (const optionsDir of options.input) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const parser = new XMLParser({
|
||||
numberParseOptions: {
|
||||
hex: false,
|
||||
leadingZeros: false,
|
||||
// do not coerce any number-like strings to numbers, since song titles
|
||||
// may also be numbers. we coerce anything we know to be a number later.
|
||||
skipLike: /.*/u,
|
||||
},
|
||||
});
|
||||
|
||||
const newSongs: Array<SongDocument<"maimaidx">> = [];
|
||||
const newCharts: Array<ChartDocument<"maimaidx:Single">> = [];
|
||||
|
||||
const songIDGenerator = GetFreshSongIDGenerator("maimaidx");
|
||||
|
||||
for (const optionsDir of options.input) {
|
||||
for (const option of readdirSync(optionsDir)) {
|
||||
if (!option.match(/^[A-Z]\d{3}$/u)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const optionDir = path.join(optionsDir, option);
|
||||
const musicsDir = path.join(optionDir, "music");
|
||||
|
||||
if (!existsSync(musicsDir)) {
|
||||
logger.warn(`Option at ${optionDir} does not have a "music" folder.`);
|
||||
@@ -241,10 +272,10 @@ for (const optionsDir of options.input) {
|
||||
const musicData = data.MusicData;
|
||||
const inGameID = Number(musicData.name.id);
|
||||
|
||||
if (inGameID >= 100000 || inGameID === 11879) {
|
||||
// Ignore UTAGE charts, which are not supported by Tachi.
|
||||
// Ignore Xaleid◆scopiX (2): event chart used to implement the KALEIDXSCOPE event,
|
||||
// not normally playable.
|
||||
if (isInBlacklist(`S${inGameID}`)) {
|
||||
logger.verbose(
|
||||
`Ignored ${musicData.artistName.str} - ${musicData.name.str} (inGameID ${inGameID}) as it is in the blacklist.`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -322,7 +353,9 @@ for (const optionsDir of options.input) {
|
||||
songTitleArtistMap.set(`${songDoc.title}-${songDoc.artist}`, tachiSongID);
|
||||
songMap.set(tachiSongID, songDoc);
|
||||
|
||||
logger.info(`Added new song ${songDoc.artist} - ${songDoc.title}.`);
|
||||
logger.info(
|
||||
`Added new song ${songDoc.artist} - ${songDoc.title} (inGameID ${inGameID}, tachiSongID ${tachiSongID}).`
|
||||
);
|
||||
} else {
|
||||
const songDoc = songMap.get(tachiSongID)!;
|
||||
|
||||
@@ -347,6 +380,13 @@ for (const optionsDir of options.input) {
|
||||
);
|
||||
}
|
||||
|
||||
if (isInBlacklist(`C${inGameID}-${difficultyName}`)) {
|
||||
logger.verbose(
|
||||
`Ignoring ${musicData.artistName.str} - ${musicData.name.str} [${difficultyName}] (inGameID ${inGameID}) as it is in the blacklist.`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inGameID > 10000) {
|
||||
difficultyName = `DX ${difficultyName}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user