mirror of
https://github.com/asphyxia-core/plugins.git
synced 2026-03-21 17:34:46 -05:00
commit
0312d7dcf2
|
|
@ -1,13 +1,29 @@
|
|||
# Nostalgia
|
||||
|
||||
Plugin Version: **v1.0.0**
|
||||
Plugin Version: **v1.1.0**
|
||||
|
||||
Supported Versions
|
||||
-------------------
|
||||
- Forte (Experiment)
|
||||
- Op.2
|
||||
|
||||
|
||||
About Forte Support
|
||||
-------------------
|
||||
Forte support is live. But since it has much difference compared to Op.2, Forte is not-primary-supported version.
|
||||
It may works unexpectedly. Forte was tested very lightly. So this feature is tagged as **Experiment**.
|
||||
|
||||
Also, Technically, This *may* support First version of Nostalgia too.
|
||||
But It's highly not recommend to run First version with it.
|
||||
|
||||
Changelog
|
||||
=========
|
||||
1.1.0 (Current)
|
||||
---------------
|
||||
- Fix saving issue with brooch, island, and kentei.
|
||||
- Moved to Base64 encoded data base.
|
||||
- Forte support.
|
||||
|
||||
1.0.0
|
||||
-----
|
||||
Initial Release.
|
||||
|
|
|
|||
3
nostalgia@asphyxia/data/.gitignore
vendored
Normal file
3
nostalgia@asphyxia/data/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
*.json
|
||||
*.json
|
||||
*.xml
|
||||
71
nostalgia@asphyxia/data/ForteMusic.ts
Normal file
71
nostalgia@asphyxia/data/ForteMusic.ts
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
import { CommonMusicDataField, readB64JSON, readXML } from "./helper";
|
||||
|
||||
export async function processData() {
|
||||
if (IO.Exists("data/forte_mdb.json.b64")) {
|
||||
return await readB64JSON("data/forte_mdb.json.b64");
|
||||
}
|
||||
const data = await readJSONOrXML("data/forte_mdb.json", "data/forte_mdb.xml")
|
||||
// await IO.WriteFile("data/forte_mdb.json.b64", Buffer.from(JSON.stringify(data)).toString("base64"))
|
||||
return data
|
||||
}
|
||||
|
||||
export async function processMdbData(path: string): Promise<CommonMusicData> {
|
||||
const data = await readXML(path);
|
||||
const attr = $(data).attr("music_list");
|
||||
const mdb = $(data).elements("music_list.music_spec");
|
||||
const music: CommonMusicDataField[] = [];
|
||||
for (const m of mdb) {
|
||||
music.push(K.ATTR({ index: m.attr().index }, {
|
||||
basename: K.ITEM("str", m.str("basename")),
|
||||
title: K.ITEM("str", m.str("title", "title")),
|
||||
title_kana: K.ITEM("str", m.str("title_kana", "title_kana")),
|
||||
artist: K.ITEM("str", m.str("artist", "artist")),
|
||||
artist_kana: K.ITEM("str", m.str("artist_kana", "artist_kana")),
|
||||
priority: K.ITEM("s8", m.number("priority")),
|
||||
category_flag: K.ARRAY("s32", m.numbers("category_flag")),
|
||||
primary_category: K.ITEM("s8", m.number("primary_category")),
|
||||
level_normal: K.ITEM("s8", m.number("level_normal")),
|
||||
level_hard: K.ITEM("s8", m.number("level_hard")),
|
||||
level_extreme: K.ITEM("s8", m.number("level_extreme")),
|
||||
demo_popular: K.ITEM("bool", m.bool("demo_popular")),
|
||||
demo_bemani: K.ITEM("bool", m.bool("demo_bemani")),
|
||||
destination_j: K.ITEM("bool", true),
|
||||
destination_a: K.ITEM("bool", true),
|
||||
destination_y: K.ITEM("bool", true),
|
||||
destination_k: K.ITEM("bool", true),
|
||||
offline: K.ITEM("bool", m.bool("offline")),
|
||||
unlock_type: K.ITEM("s8", m.number("unlock_type") == 3 ? 1 : m.number("unlock_type")),
|
||||
volume_bgm: K.ITEM("s8", m.number("volume_bgm")),
|
||||
volume_key: K.ITEM("s8", m.number("volume_key")),
|
||||
start_date: K.ITEM("str", m.str("start_date")),
|
||||
end_date: K.ITEM("str", "9999-12-31 23:59"),
|
||||
description: K.ITEM("str", m.str("description", "description"))
|
||||
}));
|
||||
}
|
||||
return K.ATTR({
|
||||
release_code: attr.release_code,
|
||||
revision: attr.revision,
|
||||
}, {
|
||||
music_spec: music,
|
||||
});
|
||||
}
|
||||
|
||||
export async function readJSONOrXML(jsonPath: string, xmlPath: string): Promise<CommonMusicData> {
|
||||
if (!IO.Exists(jsonPath)) {
|
||||
const data = await processMdbData(xmlPath)
|
||||
await IO.WriteFile(jsonPath, JSON.stringify(data))
|
||||
await IO.WriteFile(jsonPath.replace(".json", ".json.b64"), Buffer.from((JSON.stringify(data))).toString('base64'));
|
||||
return data
|
||||
} else {
|
||||
const json = JSON.parse(await IO.ReadFile(jsonPath, 'utf-8'))
|
||||
return json
|
||||
}
|
||||
}
|
||||
|
||||
interface CommonMusicData {
|
||||
"@attr": {
|
||||
revision: string,
|
||||
release_code: string
|
||||
}
|
||||
music_spec: CommonMusicDataField[]
|
||||
}
|
||||
1
nostalgia@asphyxia/data/course.json.b64
Normal file
1
nostalgia@asphyxia/data/course.json.b64
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,699 +0,0 @@
|
|||
<?xml version="1.0" encoding="shift_jis"?>
|
||||
<course_data_list release_code="2019022700">
|
||||
<course_data index="1">
|
||||
<name __type="str">ベーシック10級検定</name>
|
||||
<priority __type="s32">40</priority>
|
||||
<req_nos __type="s32">1000</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">80000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">140</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">850000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">225</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">1725000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">170</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">2625000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2019-01-01 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="2">
|
||||
<name __type="str">ベーシック9級検定</name>
|
||||
<priority __type="s32">39</priority>
|
||||
<req_nos __type="s32">1500</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">120000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">199</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">875000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">209</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">1775000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">212</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">2700000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2019-01-01 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="3">
|
||||
<name __type="str">ベーシック8級検定</name>
|
||||
<priority __type="s32">38</priority>
|
||||
<req_nos __type="s32">2000</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">200000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">220</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">900000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">232</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">1825000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">82</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">2775000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2019-01-01 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="4">
|
||||
<name __type="str">ベーシック7級検定</name>
|
||||
<priority __type="s32">37</priority>
|
||||
<req_nos __type="s32">2500</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">300000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">186</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">925000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">141</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">1875000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">32</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">2850000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2019-01-01 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="5">
|
||||
<name __type="str">ベーシック6級検定</name>
|
||||
<priority __type="s32">36</priority>
|
||||
<req_nos __type="s32">3000</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">400000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">36</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">925000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">87</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">1875000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">242</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">2850000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2019-01-01 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="6">
|
||||
<name __type="str">ベーシック5級検定</name>
|
||||
<priority __type="s32">35</priority>
|
||||
<req_nos __type="s32">3500</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">450000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">122</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">925000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">40</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">1875000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">85</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">2850000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2019-01-01 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="7">
|
||||
<name __type="str">ベーシック4級検定</name>
|
||||
<priority __type="s32">34</priority>
|
||||
<req_nos __type="s32">4000</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">500000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">7</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">925000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">28</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">1875000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">49</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">2850000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2020-01-21 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="8">
|
||||
<name __type="str">ベーシック3級検定</name>
|
||||
<priority __type="s32">33</priority>
|
||||
<req_nos __type="s32">4500</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">525000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">8</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">925000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">29</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">1875000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">50</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">2850000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2020-01-21 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="9">
|
||||
<name __type="str">ベーシック2級検定</name>
|
||||
<priority __type="s32">32</priority>
|
||||
<req_nos __type="s32">5000</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">540000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">9</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">925000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">30</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">1875000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">51</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">2850000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2020-01-21 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="10">
|
||||
<name __type="str">ベーシック1級検定</name>
|
||||
<priority __type="s32">31</priority>
|
||||
<req_nos __type="s32">6000</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">550000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">10</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">925000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">31</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">1875000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">52</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">2850000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2020-01-21 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="11">
|
||||
<name __type="str">リサイタル10級検定</name>
|
||||
<priority __type="s32">30</priority>
|
||||
<req_nos __type="s32">1000</req_nos>
|
||||
<mode_type __type="s32">2</mode_type>
|
||||
<req_grade __type="s32">80000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">7</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">34000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">238</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">72000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">227</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">114000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2019-01-01 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="12">
|
||||
<name __type="str">リサイタル9級検定</name>
|
||||
<priority __type="s32">29</priority>
|
||||
<req_nos __type="s32">1500</req_nos>
|
||||
<mode_type __type="s32">2</mode_type>
|
||||
<req_grade __type="s32">120000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">19</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">36000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">220</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">76000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">214</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">120000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2019-01-01 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="13">
|
||||
<name __type="str">リサイタル8級検定</name>
|
||||
<priority __type="s32">28</priority>
|
||||
<req_nos __type="s32">2000</req_nos>
|
||||
<mode_type __type="s32">2</mode_type>
|
||||
<req_grade __type="s32">200000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">8</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">38000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">63</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">80000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">86</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">126000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2019-01-01 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="14">
|
||||
<name __type="str">リサイタル7級検定</name>
|
||||
<priority __type="s32">27</priority>
|
||||
<req_nos __type="s32">2500</req_nos>
|
||||
<mode_type __type="s32">2</mode_type>
|
||||
<req_grade __type="s32">300000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">72</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">40000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">71</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">84000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">70</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">132000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2019-01-01 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="15">
|
||||
<name __type="str">リサイタル6級検定</name>
|
||||
<priority __type="s32">26</priority>
|
||||
<req_nos __type="s32">3000</req_nos>
|
||||
<mode_type __type="s32">2</mode_type>
|
||||
<req_grade __type="s32">400000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">105</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">40000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">101</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">84000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">186</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">132000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2019-01-01 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="16">
|
||||
<name __type="str">リサイタル5級検定</name>
|
||||
<priority __type="s32">25</priority>
|
||||
<req_nos __type="s32">3500</req_nos>
|
||||
<mode_type __type="s32">2</mode_type>
|
||||
<req_grade __type="s32">450000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">26</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">40000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">160</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">84000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">133</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">132000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2019-01-01 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="17">
|
||||
<name __type="str">リサイタル4級検定</name>
|
||||
<priority __type="s32">24</priority>
|
||||
<req_nos __type="s32">4000</req_nos>
|
||||
<mode_type __type="s32">2</mode_type>
|
||||
<req_grade __type="s32">500000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">17</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">40000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">38</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">84000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">59</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">132000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2020-01-21 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="18">
|
||||
<name __type="str">リサイタル3級検定</name>
|
||||
<priority __type="s32">23</priority>
|
||||
<req_nos __type="s32">4500</req_nos>
|
||||
<mode_type __type="s32">2</mode_type>
|
||||
<req_grade __type="s32">525000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">18</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">40000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">39</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">84000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">60</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">132000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2020-01-21 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="19">
|
||||
<name __type="str">リサイタル2級検定</name>
|
||||
<priority __type="s32">22</priority>
|
||||
<req_nos __type="s32">5000</req_nos>
|
||||
<mode_type __type="s32">2</mode_type>
|
||||
<req_grade __type="s32">540000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">19</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">40000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">40</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">84000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">61</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">132000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2020-01-21 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="20">
|
||||
<name __type="str">リサイタル1級検定</name>
|
||||
<priority __type="s32">21</priority>
|
||||
<req_nos __type="s32">6000</req_nos>
|
||||
<mode_type __type="s32">2</mode_type>
|
||||
<req_grade __type="s32">550000</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">20</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">40000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">41</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">84000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">62</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">132000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">0</unlock_music>
|
||||
<unlock_item_list />
|
||||
<start_date __type="str">2020-01-21 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="21">
|
||||
<name __type="str">KACスペシャル検定(Normal)</name>
|
||||
<priority __type="s32">60</priority>
|
||||
<req_nos __type="s32">2000</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">0</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">261</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">900000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">262</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">1800000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">263</index>
|
||||
<difficulty __type="s32">0</difficulty>
|
||||
<clear_point __type="s32">2750000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">263</unlock_music>
|
||||
<unlock_item_list>
|
||||
<unlock_item unlock_item_no="0">
|
||||
<type __type="s32">1</type>
|
||||
<index __type="s32">263</index>
|
||||
<unlock_condition __type="s32">2</unlock_condition>
|
||||
</unlock_item>
|
||||
</unlock_item_list>
|
||||
<start_date __type="str">2019-02-28 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="22">
|
||||
<name __type="str">KACスペシャル検定(Hard)</name>
|
||||
<priority __type="s32">59</priority>
|
||||
<req_nos __type="s32">2000</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">0</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">261</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">925000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">262</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">1875000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">263</index>
|
||||
<difficulty __type="s32">1</difficulty>
|
||||
<clear_point __type="s32">2850000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">263</unlock_music>
|
||||
<unlock_item_list>
|
||||
<unlock_item unlock_item_no="0">
|
||||
<type __type="s32">1</type>
|
||||
<index __type="s32">263</index>
|
||||
<unlock_condition __type="s32">2</unlock_condition>
|
||||
</unlock_item>
|
||||
</unlock_item_list>
|
||||
<start_date __type="str">2019-02-28 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="23">
|
||||
<name __type="str">KACスペシャル検定(Expert)</name>
|
||||
<priority __type="s32">58</priority>
|
||||
<req_nos __type="s32">2000</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">0</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">261</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">925000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">262</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">1875000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">263</index>
|
||||
<difficulty __type="s32">2</difficulty>
|
||||
<clear_point __type="s32">2850000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">263</unlock_music>
|
||||
<unlock_item_list>
|
||||
<unlock_item unlock_item_no="0">
|
||||
<type __type="s32">1</type>
|
||||
<index __type="s32">263</index>
|
||||
<unlock_condition __type="s32">2</unlock_condition>
|
||||
</unlock_item>
|
||||
</unlock_item_list>
|
||||
<start_date __type="str">2019-02-28 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
<course_data index="24">
|
||||
<name __type="str">KACスペシャル検定(Real)</name>
|
||||
<priority __type="s32">57</priority>
|
||||
<req_nos __type="s32">2000</req_nos>
|
||||
<mode_type __type="s32">1</mode_type>
|
||||
<req_grade __type="s32">0</req_grade>
|
||||
<seq_list>
|
||||
<tune tune_no="0">
|
||||
<index __type="s32">261</index>
|
||||
<difficulty __type="s32">3</difficulty>
|
||||
<clear_point __type="s32">925000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="1">
|
||||
<index __type="s32">262</index>
|
||||
<difficulty __type="s32">3</difficulty>
|
||||
<clear_point __type="s32">1875000</clear_point>
|
||||
</tune>
|
||||
<tune tune_no="2">
|
||||
<index __type="s32">263</index>
|
||||
<difficulty __type="s32">3</difficulty>
|
||||
<clear_point __type="s32">2850000</clear_point>
|
||||
</tune>
|
||||
</seq_list>
|
||||
<unlock_music __type="s32">263</unlock_music>
|
||||
<unlock_item_list>
|
||||
<unlock_item unlock_item_no="0">
|
||||
<type __type="s32">1</type>
|
||||
<index __type="s32">263</index>
|
||||
<unlock_condition __type="s32">2</unlock_condition>
|
||||
</unlock_item>
|
||||
</unlock_item_list>
|
||||
<start_date __type="str">2019-02-28 10:00</start_date>
|
||||
<end_date __type="str">9999-01-01 00:00</end_date>
|
||||
</course_data>
|
||||
</course_data_list>
|
||||
1
nostalgia@asphyxia/data/forte_mdb.json.b64
Normal file
1
nostalgia@asphyxia/data/forte_mdb.json.b64
Normal file
File diff suppressed because one or more lines are too long
43
nostalgia@asphyxia/data/helper.ts
Normal file
43
nostalgia@asphyxia/data/helper.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
export interface CommonMusicDataField {
|
||||
basename: KITEM<"str">;
|
||||
title: KITEM<"str">;
|
||||
title_kana: KITEM<"str">;
|
||||
artist: KITEM<"str">;
|
||||
artist_kana: KITEM<"str">
|
||||
priority: KITEM<"s8">;
|
||||
category_flag: KARRAY<"s32">;
|
||||
primary_category: KITEM<"s8">;
|
||||
level_normal: KITEM<"s8">;
|
||||
level_hard: KITEM<"s8">;
|
||||
level_extreme: KITEM<"s8">;
|
||||
demo_popular: KITEM<"bool">;
|
||||
demo_bemani: KITEM<"bool">
|
||||
destination_j: KITEM<"bool">;
|
||||
destination_a: KITEM<"bool">;
|
||||
destination_y: KITEM<"bool">;
|
||||
destination_k: KITEM<"bool">;
|
||||
unlock_type: KITEM<"s8">;
|
||||
offline: KITEM<"bool">;
|
||||
volume_bgm: KITEM<"s8">;
|
||||
volume_key: KITEM<"s8">;
|
||||
start_date: KITEM<"str">;
|
||||
end_date: KITEM<"str">;
|
||||
description: KITEM<"str">;
|
||||
}
|
||||
|
||||
export async function readXML(path: string) {
|
||||
const xml = await IO.ReadFile(path, 'utf-8');
|
||||
const json = U.parseXML(xml, false)
|
||||
return json
|
||||
}
|
||||
|
||||
export async function readJSON(path: string) {
|
||||
const str = await IO.ReadFile(path, 'utf-8');
|
||||
const json = JSON.parse(str)
|
||||
return json
|
||||
}
|
||||
|
||||
export async function readB64JSON(b64path: string) {
|
||||
const buff = await IO.ReadFile(b64path, 'utf-8');
|
||||
return JSON.parse(Buffer.from(buff, 'base64').toString('utf-8'));
|
||||
}
|
||||
1
nostalgia@asphyxia/data/island.json.b64
Normal file
1
nostalgia@asphyxia/data/island.json.b64
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
|
@ -1,4 +1,6 @@
|
|||
import * as path from "path";
|
||||
import { processData } from "../data/ForteMusic";
|
||||
import { readB64JSON } from "../data/helper";
|
||||
|
||||
export const permitted_list = {
|
||||
flag: [
|
||||
|
|
@ -9,10 +11,22 @@ export const permitted_list = {
|
|||
],
|
||||
};
|
||||
|
||||
export const forte_permitted_list = {
|
||||
flag: [
|
||||
K.ARRAY('s32', Array(32).fill(-1), { sheet_type: '0' }),
|
||||
K.ARRAY('s32', Array(32).fill(-1), { sheet_type: '1' }),
|
||||
K.ARRAY('s32', Array(32).fill(-1), { sheet_type: '2' }),
|
||||
],
|
||||
}
|
||||
|
||||
async function ReadData(filename: string) {
|
||||
const xml = await IO.ReadFile(`data/${filename}.xml`, { encoding: 'utf-8'});
|
||||
if (!IO.Exists(`data/${filename}.xml`)) {
|
||||
const xml = await IO.ReadFile(`data/${filename}.xml`, 'utf-8');
|
||||
const json = U.parseXML(xml, false)
|
||||
// await IO.WriteFile(`data/${filename}.json.b64`, Buffer.from(JSON.stringify(json)).toString('base64'));
|
||||
return json
|
||||
}
|
||||
return readB64JSON(`data/${filename}.json.b64`)
|
||||
}
|
||||
|
||||
async function processIslandData() {
|
||||
|
|
@ -56,7 +70,7 @@ async function processCourseData() {
|
|||
return { course_data: courseData };
|
||||
}
|
||||
|
||||
export const get_common_info = async (req, data, send) => {
|
||||
export const get_common_info = async (info, data, send) => {
|
||||
send.object({
|
||||
permitted_list,
|
||||
olupdate: {
|
||||
|
|
@ -65,10 +79,12 @@ export const get_common_info = async (req, data, send) => {
|
|||
});
|
||||
};
|
||||
|
||||
export const get_music_info: EPR = async (req, data, send) => {
|
||||
export const get_music_info: EPR = async (info, data, send) => {
|
||||
const isForte = !info.module.includes("op")
|
||||
|
||||
const music_spec: any = [];
|
||||
for (let i = 1; i < 400; ++i) {
|
||||
music_spec.push(K.ATTR({ index: `${i}`}, {
|
||||
music_spec.push(K.ATTR({ index: `${i}` }, {
|
||||
jk_jpn: K.ITEM('bool', 1),
|
||||
jk_asia: K.ITEM('bool', 1),
|
||||
jk_kor: K.ITEM('bool', 1),
|
||||
|
|
@ -83,18 +99,25 @@ export const get_music_info: EPR = async (req, data, send) => {
|
|||
}));
|
||||
}
|
||||
|
||||
send.object({
|
||||
permitted_list,
|
||||
const versionObject = isForte
|
||||
? {
|
||||
permitted_list: forte_permitted_list,
|
||||
music_list: await processData()
|
||||
}
|
||||
: {
|
||||
permitted_list,
|
||||
island_data_list: await processIslandData(),
|
||||
course_data_list: await processCourseData(),
|
||||
|
||||
island_data_list: await processIslandData(),
|
||||
course_data_list: await processCourseData(),
|
||||
|
||||
overwrite_music_list: K.ATTR({
|
||||
overwrite_music_list: K.ATTR({
|
||||
revision: '16706',
|
||||
release_code: '2019100200',
|
||||
}, {
|
||||
music_spec: music_spec,
|
||||
}),
|
||||
music_spec: music_spec,
|
||||
}),
|
||||
};
|
||||
send.object({
|
||||
...versionObject,
|
||||
|
||||
gamedata_flag_list: {
|
||||
event: {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// import { Logger } from '../../util/Logger';
|
||||
import { Profile } from '../models/profile';
|
||||
import { Scores } from '../models/scores';
|
||||
import { permitted_list } from './common';
|
||||
import { permitted_list, forte_permitted_list } from './common';
|
||||
// import { getValue, getArray, getAttr, getStr, getBigInt } from '../../util/Helper';
|
||||
|
||||
|
||||
|
|
@ -18,9 +18,10 @@ import { permitted_list } from './common';
|
|||
// },
|
||||
// };
|
||||
|
||||
const getEventInfo = () => {
|
||||
const getEventInfo = (isForte: boolean) => {
|
||||
const event: any[] = [];
|
||||
for (let i = 1; i <= 17; ++i) {
|
||||
const event_num = isForte ? 10 : 17
|
||||
for (let i = 1; i <= event_num; ++i) {
|
||||
event.push({
|
||||
type: K.ITEM('s32', 4),
|
||||
index: K.ITEM('s32', i),
|
||||
|
|
@ -34,8 +35,9 @@ const getEventInfo = () => {
|
|||
return event;
|
||||
};
|
||||
|
||||
const getPlayerData = async (refid: string, name?: string) => {
|
||||
const getPlayerData = async (refid: string, info: EamuseInfo, name?: string) => {
|
||||
const p = await readProfile(refid);
|
||||
const isForte = !info.module.includes("op")
|
||||
|
||||
if (name && name.length > 0) {
|
||||
p.name = name;
|
||||
|
|
@ -45,7 +47,7 @@ const getPlayerData = async (refid: string, name?: string) => {
|
|||
const param: any[] = [];
|
||||
for (const t in p.params) {
|
||||
const para = p.params[t];
|
||||
param.push(K.ATTR({type: t}, {
|
||||
param.push(K.ATTR({ type: t }, {
|
||||
count: K.ITEM('s32', para.length),
|
||||
params_array: K.ARRAY('s32', para),
|
||||
}));
|
||||
|
|
@ -53,6 +55,7 @@ const getPlayerData = async (refid: string, name?: string) => {
|
|||
|
||||
const brooch: any[] = [];
|
||||
for (const b in p.brooches) {
|
||||
if (isForte && parseInt(b, 10) > 147) continue; // Forte Brooch is ~147.
|
||||
const bData = p.brooches[b];
|
||||
brooch.push(K.ATTR({ index: b }, {
|
||||
watch_count: K.ITEM('s32', bData.watch),
|
||||
|
|
@ -72,6 +75,20 @@ const getPlayerData = async (refid: string, name?: string) => {
|
|||
}));
|
||||
}
|
||||
|
||||
// Forte
|
||||
const stairs: any[] = [];
|
||||
for (const s in (p.cat_stairs || defaultProfile.cat_stairs)) {
|
||||
const stair = (p.cat_stairs || defaultProfile.cat_stairs)[s];
|
||||
|
||||
stairs.push(K.ATTR({ index: s }, {
|
||||
total_steps: K.ITEM("s32", stair.total),
|
||||
chapter_index: K.ITEM("s32", stair.index),
|
||||
chapter_steps: K.ITEM("s32", stair.steps),
|
||||
chapter_goal: K.ITEM("s32", stair.goal)
|
||||
}));
|
||||
}
|
||||
|
||||
// >= Op2
|
||||
const kentei_record: any[] = [];
|
||||
for (const k in p.kentei) {
|
||||
const kentei = p.kentei[k];
|
||||
|
|
@ -86,6 +103,7 @@ const getPlayerData = async (refid: string, name?: string) => {
|
|||
});
|
||||
}
|
||||
|
||||
// >= Op2
|
||||
const island_progress: any[] = [];
|
||||
for (const i in p.islands) {
|
||||
const island = p.islands[i];
|
||||
|
|
@ -119,40 +137,50 @@ const getPlayerData = async (refid: string, name?: string) => {
|
|||
}));
|
||||
}
|
||||
|
||||
const correct_permitted_list = !isForte ? permitted_list : forte_permitted_list
|
||||
const music_list = [
|
||||
K.ARRAY('s32', p.musicList.type_0, { sheet_type: '0' }),
|
||||
K.ARRAY('s32', p.musicList.type_1, { sheet_type: '1' }),
|
||||
K.ARRAY('s32', p.musicList.type_2, { sheet_type: '2' }),
|
||||
K.ARRAY('s32', p.musicList.type_3, { sheet_type: '3' }),
|
||||
];
|
||||
const music_list2 = [
|
||||
K.ARRAY('s32', p.musicList2.type_0, { sheet_type: '0' }),
|
||||
K.ARRAY('s32', p.musicList2.type_1, { sheet_type: '1' }),
|
||||
K.ARRAY('s32', p.musicList2.type_2, { sheet_type: '2' }),
|
||||
K.ARRAY('s32', p.musicList2.type_3, { sheet_type: '3' }),
|
||||
];
|
||||
|
||||
if(isForte) {
|
||||
music_list.pop();
|
||||
music_list2.pop();
|
||||
}
|
||||
|
||||
return {
|
||||
name: K.ITEM('str', p.name),
|
||||
play_count: K.ITEM('s32', p.playCount),
|
||||
today_play_count: K.ITEM('s32', p.todayPlayCount),
|
||||
permitted_list,
|
||||
event_info_list: { event: getEventInfo() },
|
||||
permitted_list: correct_permitted_list,
|
||||
event_info_list: { event: getEventInfo(isForte) }, // Op2
|
||||
event_control_list: { event: getEventInfo(isForte) }, // Forte
|
||||
music_list: {
|
||||
flag: [
|
||||
K.ARRAY('s32', p.musicList.type_0, { sheet_type: '0' }),
|
||||
K.ARRAY('s32', p.musicList.type_1, { sheet_type: '1' }),
|
||||
K.ARRAY('s32', p.musicList.type_2, { sheet_type: '2' }),
|
||||
K.ARRAY('s32', p.musicList.type_3, { sheet_type: '3' }),
|
||||
],
|
||||
flag: music_list,
|
||||
},
|
||||
free_for_play_music_list: {
|
||||
flag: [
|
||||
K.ARRAY('s32', p.musicList2.type_0, { sheet_type: '0' }),
|
||||
K.ARRAY('s32', p.musicList2.type_1, { sheet_type: '1' }),
|
||||
K.ARRAY('s32', p.musicList2.type_2, { sheet_type: '2' }),
|
||||
K.ARRAY('s32', p.musicList2.type_3, { sheet_type: '3' }),
|
||||
],
|
||||
flag: music_list2,
|
||||
},
|
||||
last: {
|
||||
music_index: K.ITEM('s32', p.music),
|
||||
sheet_type: K.ITEM('s8', p.sheet),
|
||||
brooch_index: K.ITEM('s32', p.brooch),
|
||||
music_index: K.ITEM('s32', forteNumericHandler(isForte, p.music, 195, 0)),
|
||||
sheet_type: K.ITEM('s8', forteNumericHandler(isForte, p.sheet, 3, 0)),
|
||||
brooch_index: K.ITEM('s32', forteNumericHandler(isForte, p.brooch, 147, 0)),
|
||||
hi_speed_level: K.ITEM('s32', p.hispeed),
|
||||
beat_guide: K.ITEM('s8', p.beatGuide),
|
||||
headphone_volume: K.ITEM('s8', p.headphone),
|
||||
judge_bar_pos: K.ITEM('s32', p.judgeBar),
|
||||
music_group: K.ITEM('s32', p.group),
|
||||
hands_mode: K.ITEM('s8', p.mode),
|
||||
hands_mode: isForte ? K.ITEM('s32', p.mode) : K.ITEM('s8', p.mode),
|
||||
near_setting: K.ITEM('s8', p.near),
|
||||
judge_delay_offset: K.ITEM('s8', p.offset),
|
||||
judge_delay_offset: isForte ? K.ITEM('s32', p.offset) : K.ITEM('s8', p.offset),
|
||||
bingo_index: K.ITEM('s32', p.bingo),
|
||||
total_skill_value: K.ITEM('u64', BigInt(p.skill)),
|
||||
key_beam_level: K.ITEM('s8', p.keyBeam),
|
||||
|
|
@ -169,14 +197,16 @@ const getPlayerData = async (refid: string, name?: string) => {
|
|||
judge_effect_adjust: K.ITEM('s8', p.judgeFX),
|
||||
simple_bg: K.ITEM('s8', p.simple),
|
||||
},
|
||||
brooch_list: {
|
||||
brooch,
|
||||
// TODO: Full unlock instead of saving?
|
||||
cat_progress: {
|
||||
stair: stairs
|
||||
},
|
||||
brooch_list: { brooch },
|
||||
extra_param: { param },
|
||||
present_list: {},
|
||||
various_music_list: {
|
||||
data: [
|
||||
K.ATTR({ list_type: '0' }, {
|
||||
K.ATTR({ list_type: '0' }, {
|
||||
cond_flag: K.ITEM('s32', 0),
|
||||
flag: K.ITEM('s32', 0, { sheet_type: '0' }),
|
||||
}),
|
||||
|
|
@ -202,14 +232,14 @@ export const regist_playdata: EPR = async (info, data, send) => {
|
|||
const name = $(data).str('name');
|
||||
console.debug(`nos op2 regist: ${name}`);
|
||||
|
||||
send.object(await getPlayerData(refid, name));
|
||||
send.object(await getPlayerData(refid, info, name));
|
||||
};
|
||||
|
||||
export const get_playdata: EPR = async (info, data, send) => {
|
||||
const refid = $(data).str('refid');
|
||||
if (!refid) return send.deny();
|
||||
|
||||
send.object(await getPlayerData(refid));
|
||||
send.object(await getPlayerData(refid, info));
|
||||
};
|
||||
|
||||
// export const set_stage_result: EPR = async (info, data, send) => {
|
||||
|
|
@ -220,6 +250,7 @@ export const set_total_result: EPR = async (info, data, send) => {
|
|||
const refid = $(data).str('refid');
|
||||
if (!refid) return send.deny();
|
||||
|
||||
const isForte = !info.module.includes("op")
|
||||
const p = await readProfile(refid);
|
||||
|
||||
p.playCount = $(data).number('play_count', p.playCount);
|
||||
|
|
@ -321,7 +352,7 @@ export const set_total_result: EPR = async (info, data, send) => {
|
|||
// BROOCHES
|
||||
let broochs = $(data).elements('brooch_list.brooch');
|
||||
for (const brooch of broochs) {
|
||||
const index = parseInt(_.get(brooch, '@attr.index', '-1'));
|
||||
const index = parseInt(brooch.attr().index || '-1', 10);
|
||||
if (index < 0) continue;
|
||||
|
||||
p.brooches[index] = {
|
||||
|
|
@ -335,7 +366,7 @@ export const set_total_result: EPR = async (info, data, send) => {
|
|||
// ISLAND
|
||||
let islands = $(data).elements('island_progress_list.island_progress');
|
||||
for (const island of islands) {
|
||||
const index = parseInt(_.get(island, '@attr.index', '-1'));
|
||||
const index = parseInt(island.attr().index || '-1', 10);
|
||||
if (index < 0) continue;
|
||||
|
||||
const containers: Profile['islands']['0']['containers'] = {};
|
||||
|
|
@ -366,6 +397,23 @@ export const set_total_result: EPR = async (info, data, send) => {
|
|||
};
|
||||
}
|
||||
|
||||
// CAT STAIR
|
||||
let stairs = $(data).elements('cat_progress.stair');
|
||||
if (!p.cat_stairs) {
|
||||
p.cat_stairs = defaultProfile.cat_stairs
|
||||
}
|
||||
for (const stair of stairs) {
|
||||
const index = parseInt(stair.attr().index || '-1', 10);
|
||||
if (index < 0) continue;
|
||||
|
||||
p.cat_stairs[index] = {
|
||||
total: stair.number('total_steps', 0),
|
||||
index: stair.number('chapter_index', 1),
|
||||
steps: stair.number('chapter_steps', 0),
|
||||
goal: stair.number('chapter_goal', 0),
|
||||
};
|
||||
}
|
||||
|
||||
await writeProfile(refid, p);
|
||||
|
||||
const scoreData = await readScores(refid);
|
||||
|
|
@ -376,12 +424,12 @@ export const set_total_result: EPR = async (info, data, send) => {
|
|||
const type = stage.attr().sheet_type
|
||||
|
||||
const key = `${mid}:${type}`;
|
||||
const c = stage.element('common');
|
||||
const c = isForte ? stage : stage.element('common');
|
||||
const o = _.get(scoreData, `scores.${key}`, {});
|
||||
const isHigh = c.number('score', 0) >= _.get(o, 'score', 0);
|
||||
scoreData.scores[key] = {
|
||||
score: Math.max(c.number('score', 0), _.get(o, 'score', 0)),
|
||||
grade: Math.max(c.number('grade_basic', 0), _.get(o, 'grade', 0)),
|
||||
grade: Math.max(Math.max(c.number('grade_basic', 0), c.number('evaluation', 0)), _.get(o, 'grade', 0)),
|
||||
recital: Math.max(c.number('grade_recital', 0), _.get(o, 'recital', 0)),
|
||||
mode: isHigh ? c.number('hands_mode', 0) : _.get(o, 'mode', 0),
|
||||
count: Math.max(c.number('play_count', 0), _.get(o, 'count', 1)),
|
||||
|
|
@ -393,7 +441,7 @@ export const set_total_result: EPR = async (info, data, send) => {
|
|||
|
||||
// Save Recitals
|
||||
const rInfo = $(data).element('recital_info.recital');
|
||||
if (rInfo){
|
||||
if (rInfo) {
|
||||
const rIndex = rInfo.number('recital_index', -1);
|
||||
if (rIndex >= 0) {
|
||||
const r = rInfo.element('result');
|
||||
|
|
@ -423,6 +471,7 @@ export const get_musicdata: EPR = async (info, data, send) => {
|
|||
const refid = $(data).str('refid');
|
||||
if (!refid) return send.deny();
|
||||
|
||||
const isForte = !info.module.includes("op")
|
||||
const scoreData = await readScores(refid);
|
||||
|
||||
const recital_record: any[] = [];
|
||||
|
|
@ -450,18 +499,21 @@ export const get_musicdata: EPR = async (info, data, send) => {
|
|||
const mdata = m.split(':');
|
||||
const musi = scoreData.scores[m];
|
||||
|
||||
if (isForte && parseInt(mdata[0], 10) > 195) continue;
|
||||
|
||||
music.push(K.ATTR({
|
||||
music_index: mdata[0],
|
||||
sheet_type: mdata[1],
|
||||
}, {
|
||||
'score': K.ITEM('s32', musi.score),
|
||||
'grade_basic': K.ITEM('u32', musi.grade),
|
||||
'grade_recital': K.ITEM('u32', musi.recital),
|
||||
'play_count': K.ITEM('s32', musi.count),
|
||||
'clear_count': K.ITEM('s32', musi.clear),
|
||||
'multi_count': K.ITEM('s32', musi.multi),
|
||||
'hands_mode': K.ITEM('s8', musi.mode),
|
||||
'clear_flag': K.ITEM('s32', musi.flag),
|
||||
music_index: mdata[0],
|
||||
sheet_type: mdata[1],
|
||||
}, {
|
||||
score: K.ITEM('s32', musi.score),
|
||||
evaluation: K.ITEM('u32', musi.grade), // Forte
|
||||
grade_basic: K.ITEM('u32', musi.grade),
|
||||
grade_recital: K.ITEM('u32', musi.recital),
|
||||
play_count: K.ITEM('s32', musi.count),
|
||||
clear_count: K.ITEM('s32', musi.clear),
|
||||
multi_count: K.ITEM('s32', musi.multi),
|
||||
hands_mode: K.ITEM('s8', musi.mode),
|
||||
clear_flag: K.ITEM('s32', musi.flag),
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -471,83 +523,95 @@ export const get_musicdata: EPR = async (info, data, send) => {
|
|||
});
|
||||
};
|
||||
|
||||
function forteNumericHandler(isForte: boolean, input: number, max: number, def: number = 0) {
|
||||
return isForte ? input > max ? def : input : input;
|
||||
}
|
||||
|
||||
async function readProfile(refid: string): Promise<Profile> {
|
||||
const profile = await DB.FindOne<Profile>(refid, { collection: 'profile'} )
|
||||
const profile = await DB.FindOne<Profile>(refid, { collection: 'profile' })
|
||||
return profile || defaultProfile
|
||||
}
|
||||
|
||||
async function writeProfile(refid: string, profile: Profile) {
|
||||
await DB.Upsert<Profile>(refid, { collection: 'profile'}, profile)
|
||||
await DB.Upsert<Profile>(refid, { collection: 'profile' }, profile)
|
||||
}
|
||||
|
||||
async function readScores(refid: string): Promise<Scores> {
|
||||
const score = await DB.FindOne<Scores>(refid, { collection: 'scores'} )
|
||||
return score || { collection: 'scores', recitals: {}, scores: {}}
|
||||
const score = await DB.FindOne<Scores>(refid, { collection: 'scores' })
|
||||
return score || { collection: 'scores', recitals: {}, scores: {} }
|
||||
}
|
||||
|
||||
async function writeScores(refid: string, scores: Scores) {
|
||||
await DB.Upsert<Scores>(refid, { collection: 'scores'}, scores)
|
||||
await DB.Upsert<Scores>(refid, { collection: 'scores' }, scores)
|
||||
}
|
||||
|
||||
const defaultProfile: Profile = {
|
||||
collection: 'profile',
|
||||
collection: 'profile',
|
||||
|
||||
name: 'GUEST',
|
||||
music: 0,
|
||||
sheet: 0,
|
||||
brooch: 0,
|
||||
hispeed: 0,
|
||||
beatGuide: 1,
|
||||
headphone: 0,
|
||||
judgeBar: 250,
|
||||
group: 0,
|
||||
mode: 0,
|
||||
near: 0,
|
||||
offset: 0,
|
||||
bingo: 0,
|
||||
skill: '0',
|
||||
playCount: 0,
|
||||
todayPlayCount: 0,
|
||||
keyBeam: 0,
|
||||
orbit: 0,
|
||||
noteHeight: 10,
|
||||
noteWidth: 0,
|
||||
judgeWidth: 0,
|
||||
beatVolume: 0,
|
||||
beatType: 0,
|
||||
keyVolume: 0,
|
||||
bgmVolume: 0,
|
||||
note: 0,
|
||||
sf: 0,
|
||||
judgeFX: 0,
|
||||
simple: 0,
|
||||
money: 0,
|
||||
fame: 0,
|
||||
fameId: 0,
|
||||
island: 0,
|
||||
brooches: {
|
||||
'1': {
|
||||
level: 1,
|
||||
watch: 0,
|
||||
steps: 0,
|
||||
new: 0,
|
||||
},
|
||||
},
|
||||
islands: {},
|
||||
kentei: {},
|
||||
params: {
|
||||
'1': [0],
|
||||
},
|
||||
musicList: {
|
||||
type_0: Array(32).fill(-1),
|
||||
type_1: Array(32).fill(-1),
|
||||
type_2: Array(32).fill(-1),
|
||||
type_3: Array(32).fill(-1),
|
||||
},
|
||||
musicList2: {
|
||||
type_0: Array(32).fill(-1),
|
||||
type_1: Array(32).fill(-1),
|
||||
type_2: Array(32).fill(-1),
|
||||
type_3: Array(32).fill(-1),
|
||||
name: 'GUEST',
|
||||
music: 0,
|
||||
sheet: 0,
|
||||
brooch: 0,
|
||||
hispeed: 0,
|
||||
beatGuide: 1,
|
||||
headphone: 0,
|
||||
judgeBar: 250,
|
||||
group: 0,
|
||||
mode: 0,
|
||||
near: 0,
|
||||
offset: 0,
|
||||
bingo: 0,
|
||||
skill: '0',
|
||||
playCount: 0,
|
||||
todayPlayCount: 0,
|
||||
keyBeam: 0,
|
||||
orbit: 0,
|
||||
noteHeight: 10,
|
||||
noteWidth: 0,
|
||||
judgeWidth: 0,
|
||||
beatVolume: 0,
|
||||
beatType: 0,
|
||||
keyVolume: 0,
|
||||
bgmVolume: 0,
|
||||
note: 0,
|
||||
sf: 0,
|
||||
judgeFX: 0,
|
||||
simple: 0,
|
||||
money: 0,
|
||||
fame: 0,
|
||||
fameId: 0,
|
||||
island: 0,
|
||||
brooches: {
|
||||
'1': {
|
||||
level: 1,
|
||||
watch: 0,
|
||||
steps: 0,
|
||||
new: 0,
|
||||
},
|
||||
},
|
||||
islands: {},
|
||||
kentei: {},
|
||||
cat_stairs: {
|
||||
'0': {
|
||||
total: 0,
|
||||
index: 0,
|
||||
steps: 0,
|
||||
goal: 0
|
||||
}
|
||||
},
|
||||
params: {
|
||||
'1': [0],
|
||||
},
|
||||
musicList: {
|
||||
type_0: Array(32).fill(-1),
|
||||
type_1: Array(32).fill(-1),
|
||||
type_2: Array(32).fill(-1),
|
||||
type_3: Array(32).fill(-1),
|
||||
},
|
||||
musicList2: {
|
||||
type_0: Array(32).fill(-1),
|
||||
type_1: Array(32).fill(-1),
|
||||
type_2: Array(32).fill(-1),
|
||||
type_3: Array(32).fill(-1),
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import { get_common_info, get_music_info } from "./handler/common";
|
||||
import { get_musicdata, get_playdata, regist_playdata, set_total_result} from "./handler/player"
|
||||
import { get_musicdata, get_playdata, regist_playdata, set_total_result } from "./handler/player"
|
||||
|
||||
export function register() {
|
||||
R.GameCode('PAN');
|
||||
|
||||
|
||||
const MultiRoute = (method: string, handler: EPR | boolean) => {
|
||||
// Helper for register multiple versions.
|
||||
// But.. only Opus 2 for now.
|
||||
R.Route(`op2_${method}`, handler);
|
||||
// Helper for register multiple versions.
|
||||
R.Route(method, handler); // First version and Forte.
|
||||
R.Route(`op2_${method}`, handler);
|
||||
};
|
||||
|
||||
const CommonRoute = (method: string, handler: EPR | boolean) =>
|
||||
const CommonRoute = (method: string, handler: EPR | boolean) =>
|
||||
MultiRoute(`common.${method}`, handler)
|
||||
|
||||
const PlayerRoute = (method: string, handler: EPR | boolean) =>
|
||||
const PlayerRoute = (method: string, handler: EPR | boolean) =>
|
||||
MultiRoute(`player.${method}`, handler)
|
||||
|
||||
|
||||
// Common
|
||||
CommonRoute('get_common_info', get_common_info);
|
||||
CommonRoute('get_music_info', get_music_info);
|
||||
|
|
@ -25,4 +25,13 @@ export function register() {
|
|||
PlayerRoute('get_playdata', get_playdata)
|
||||
PlayerRoute('regist_playdata', regist_playdata)
|
||||
PlayerRoute('set_total_result', set_total_result)
|
||||
|
||||
//TODO: Fix this things with actual working handler.
|
||||
PlayerRoute('set_stage_result', true)
|
||||
|
||||
R.Unhandled(async (info, data, send) => {
|
||||
if (["eventlog"].includes(info.module)) return;
|
||||
console.error(`Received Unhandled Response on ${info.method} by ${info.model}/${info.module}`)
|
||||
console.error(`Received Request: ${JSON.stringify(data, null, 4)}`)
|
||||
})
|
||||
}
|
||||
|
|
@ -1,82 +1,90 @@
|
|||
export interface Profile {
|
||||
collection: 'profile',
|
||||
|
||||
name: string;
|
||||
playCount: number;
|
||||
todayPlayCount: number;
|
||||
music: number;
|
||||
sheet: number;
|
||||
brooch: number;
|
||||
hispeed: number;
|
||||
beatGuide: number;
|
||||
headphone: number;
|
||||
judgeBar: number;
|
||||
group: number;
|
||||
mode: number;
|
||||
near: number;
|
||||
offset: number;
|
||||
bingo: number;
|
||||
skill: string;
|
||||
keyBeam: number;
|
||||
orbit: number;
|
||||
noteHeight: number;
|
||||
noteWidth: number;
|
||||
judgeWidth: number;
|
||||
beatVolume: number;
|
||||
beatType: number;
|
||||
keyVolume: number;
|
||||
bgmVolume: number;
|
||||
note: number;
|
||||
sf: number;
|
||||
judgeFX: number;
|
||||
simple: number;
|
||||
money: number;
|
||||
fame: number;
|
||||
fameId: number;
|
||||
island: number;
|
||||
params: {
|
||||
[key: string]: number[];
|
||||
collection: 'profile',
|
||||
|
||||
name: string;
|
||||
playCount: number;
|
||||
todayPlayCount: number;
|
||||
music: number;
|
||||
sheet: number;
|
||||
brooch: number;
|
||||
hispeed: number;
|
||||
beatGuide: number;
|
||||
headphone: number;
|
||||
judgeBar: number;
|
||||
group: number;
|
||||
mode: number;
|
||||
near: number;
|
||||
offset: number;
|
||||
bingo: number;
|
||||
skill: string;
|
||||
keyBeam: number;
|
||||
orbit: number;
|
||||
noteHeight: number;
|
||||
noteWidth: number;
|
||||
judgeWidth: number;
|
||||
beatVolume: number;
|
||||
beatType: number;
|
||||
keyVolume: number;
|
||||
bgmVolume: number;
|
||||
note: number;
|
||||
sf: number;
|
||||
judgeFX: number;
|
||||
simple: number;
|
||||
money: number;
|
||||
fame: number;
|
||||
fameId: number;
|
||||
island: number;
|
||||
params: {
|
||||
[key: string]: number[];
|
||||
};
|
||||
brooches: {
|
||||
[key: string]: {
|
||||
watch: number;
|
||||
level: number;
|
||||
steps: number;
|
||||
new: number;
|
||||
};
|
||||
brooches: {
|
||||
[key: string]: {
|
||||
watch: number;
|
||||
level: number;
|
||||
steps: number;
|
||||
new: number;
|
||||
};
|
||||
};
|
||||
islands: {
|
||||
[key: string]: {
|
||||
look: number;
|
||||
select: number;
|
||||
time: number;
|
||||
containers: {
|
||||
[key: string]: {
|
||||
prog: number;
|
||||
rewards: { [key: string]: number };
|
||||
};
|
||||
};
|
||||
islands: {
|
||||
[key: string]: {
|
||||
look: number;
|
||||
select: number;
|
||||
time: number;
|
||||
containers: {
|
||||
[key: string]: {
|
||||
prog: number;
|
||||
rewards: { [key: string]: number };
|
||||
};
|
||||
};
|
||||
};
|
||||
kentei: {
|
||||
[key: string]: {
|
||||
stage: number;
|
||||
score: number[];
|
||||
rate: number;
|
||||
flag: number;
|
||||
count: number;
|
||||
};
|
||||
};
|
||||
kentei: {
|
||||
[key: string]: {
|
||||
stage: number;
|
||||
score: number[];
|
||||
rate: number;
|
||||
flag: number;
|
||||
count: number;
|
||||
};
|
||||
musicList: {
|
||||
type_0: number[];
|
||||
type_1: number[];
|
||||
type_2: number[];
|
||||
type_3: number[];
|
||||
};
|
||||
musicList2: {
|
||||
type_0: number[];
|
||||
type_1: number[];
|
||||
type_2: number[];
|
||||
type_3: number[];
|
||||
};
|
||||
}
|
||||
};
|
||||
cat_stairs: {
|
||||
[key: string]: {
|
||||
total: number,
|
||||
index: number,
|
||||
steps: number,
|
||||
goal: number
|
||||
}
|
||||
};
|
||||
musicList: {
|
||||
type_0: number[];
|
||||
type_1: number[];
|
||||
type_2: number[];
|
||||
type_3: number[];
|
||||
};
|
||||
musicList2: {
|
||||
type_0: number[];
|
||||
type_1: number[];
|
||||
type_2: number[];
|
||||
type_3: number[];
|
||||
};
|
||||
}
|
||||
|
|
@ -1,30 +1,30 @@
|
|||
export interface Scores {
|
||||
collection: 'scores',
|
||||
|
||||
recitals: {
|
||||
[key: string]: {
|
||||
count: number;
|
||||
hall: number;
|
||||
cat: number[];
|
||||
audience: number;
|
||||
money: number;
|
||||
fame: number;
|
||||
player: number;
|
||||
score: number;
|
||||
start: string;
|
||||
end: string;
|
||||
};
|
||||
|
||||
recitals: {
|
||||
[key: string]: {
|
||||
count: number;
|
||||
hall: number;
|
||||
cat: number[];
|
||||
audience: number;
|
||||
money: number;
|
||||
fame: number;
|
||||
player: number;
|
||||
score: number;
|
||||
start: string;
|
||||
end: string;
|
||||
};
|
||||
scores: {
|
||||
[key: string]: {
|
||||
score: number;
|
||||
grade: number;
|
||||
recital: number;
|
||||
count: number;
|
||||
clear: number;
|
||||
multi: number;
|
||||
mode: number;
|
||||
flag: number;
|
||||
};
|
||||
};
|
||||
scores: {
|
||||
[key: string]: {
|
||||
score: number;
|
||||
grade: number;
|
||||
recital: number;
|
||||
count: number;
|
||||
clear: number;
|
||||
multi: number;
|
||||
mode: number;
|
||||
flag: number;
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user