plugins/nostalgia@asphyxia/handler/common.ts
2026-06-28 16:13:47 +07:00

208 lines
6.3 KiB
TypeScript

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),
},
});
};