import { processData as firstData } from "../data/FirstMusic"; import { processData as forteData } from "../data/ForteMusic"; import { processOp3MusicData } from "../data/Op3Music"; import { readB64JSON } from "../data/helper"; import { NosVersionHelper } from "../utils"; export const 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' }), K.ARRAY('s32', Array(32).fill(-1), { sheet_type: '3' }), ], }; 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) { if (!IO.Exists(`data/${filename}.json.b64`)) { 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() { const islandData = (await ReadData('island')).island_data_list.island_data; for (const island of islandData) { island.flag_permitted = K.ITEM('bool', 1); island.cost['@content'][0] = ~~(island.cost['@content'][0] / 10); let containers = island.get_music_index_list.container; if (!_.isArray(containers)) { containers = [containers]; } for (const cont of containers) { cont['@attr'].no = cont['@attr'].container_no; delete cont['@attr'].container_no; if (!_.isArray(cont.music)) { cont.music = [cont.music]; } for (const m of cont.music) { m.get_point['@content'][0] = ~~(m.get_point['@content'][0] / 6); } } island.get_music_index_list.container = containers; }; return { island_data: islandData }; } async function processCourseData() { const courseData = (await ReadData('course')).course_data_list.course_data; for (const course of courseData) { course.req_nos['@content'][0] = ~~(course.req_nos['@content'][0] / 10); if (course.seq_list && course.seq_list.tune) { course.seq_list = course.seq_list.tune; course.is_open = K.ITEM('bool', 1); } } return { course_data: courseData }; } export const get_common_info = async (info, data, send) => { send.object({ permitted_list, olupdate: { delete_flag: K.ITEM('bool', 0), }, }); }; let op3MusicInfoByteCache: { data: any; xCompress: any; xCorePlugin: any } | null = null; export const get_music_info: EPR = async (info, data, send) => { const version = new NosVersionHelper(info) if (version.isOp3()) { const t0 = Date.now(); const op3 = await processOp3MusicData(); console.log( `[nostalgia@asphyxia] op3_common.get_music_info ${Date.now() - t0}ms (songs=${op3.max_index}, cache=${op3.fromCache ? 'hit' : 'miss'})` ); try { const inst: any = send as any; const res: any = inst?.res; if (!inst?.body?.encrypted && res && typeof res.send === 'function' && typeof res.setHeader === 'function') { if (op3MusicInfoByteCache) { res.setHeader('X-Compress', op3MusicInfoByteCache.xCompress ?? 'none'); if (op3MusicInfoByteCache.xCorePlugin != null) { res.setHeader('X-CORE-Plugin', op3MusicInfoByteCache.xCorePlugin); } res.send(op3MusicInfoByteCache.data); inst.sent = true; console.log(`[nostalgia@asphyxia] op3_common.get_music_info byte-cache HIT (songs=${op3.max_index})`); return; } const realSend = res.send.bind(res); res.send = (d: any) => { res.send = realSend; try { if (Buffer.isBuffer(d) || typeof d === 'string') { op3MusicInfoByteCache = { data: d, xCompress: res.getHeader('X-Compress'), xCorePlugin: res.getHeader('X-CORE-Plugin'), }; } } catch (_e) { /* ignore capture failure */ } return realSend(d); }; } } catch (_e) { /* fall back to normal send.object */ } send.object({ permitted_list, music_list: K.ATTR({ revision: op3.revision, release_code: op3.release_code, }, { music_spec: op3.music_spec, }), overwrite_music_list: K.ATTR({ revision: op3.revision, release_code: op3.release_code, }, { music_spec: op3.overwrite_spec, }), gamedata_flag_list: {}, trend_music_list: { trend_music: K.ATTR({ music_index: '1', rank: '1' }, {}), }, olupdate: { delete_flag: K.ITEM('bool', 0), }, }); return; } const music_spec: any = []; for (let i = 1; i < 400; ++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), jk_idn: K.ITEM('bool', 1), start_date: K.ITEM('str', '2017-01-11 10:00'), end_date: K.ITEM('str', '9999-12-31 23:59'), expiration_date: K.ITEM('str', '9999-12-31 23:59'), real_start_date: K.ITEM('str', '2017-01-11 10:00'), real_end_date: K.ITEM('str', '9999-12-31 23:59'), real_once_price: K.ITEM('s32', 300), real_forever_price: K.ITEM('s32', 7500), })); } const music_list = async () => version.version === 'Forte' ? await forteData() : await firstData() const versionObject = version.isFirstOrForte() ? { permitted_list: forte_permitted_list, music_list: await music_list() } : { permitted_list, island_data_list: await processIslandData(), course_data_list: await processCourseData(), overwrite_music_list: K.ATTR({ revision: '16706', release_code: '2019100200', }, { music_spec: music_spec, }), }; send.object({ ...versionObject, gamedata_flag_list: { event: { index: K.ITEM('s32', 0), status: K.ITEM('s8', 1), start_time: K.ITEM('u64', BigInt(0)), end_time: K.ITEM('u64', BigInt(0)), param1: K.ITEM('u64', BigInt(0)), param2: K.ITEM('u64', BigInt(0)), }, }, olupdate: { delete_flag: K.ITEM('bool', 0), }, }); };