210 lines
7.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const { readFile, writeFile } = require("fs/promises");
const transform = require("./worker");
const fastly = process.env.OAFCHT_NO_ITER==='1';
const loadlist = async () => {
const datfile = await readFile("./serial.json");
const datas = JSON.parse(datfile.toString());
// 避免使用迭代器方法减少CPU已走过performance对比流程
// ---------------原来的代码在这里------------------
if( fastly === false ){
return Object.entries(datas).filter(n => n[1] != "????");
}
// ---------------修改的代码在这里------------------
const entries = Object.entries(datas);
const retval = new Array(entries.length);
let l = 0;
for( const data of entries ){
if( data[1] !== "????" ) retval[l++] = data;
}
retval.length = l;
return retval;
// ---------------修改的代码完结处------------------
}
const format = valid => {
valid.sort((a, b) => a.serial.localeCompare(b.serial));
console.info(`valid rom has ${valid.length}`);
const enc = new TextEncoder();
//const size = Symbol("length");
const concatUnit = 10240;
const align = (n, base) => base * Math.floor((n + base - 1) / base);
const size = new WeakMap()
const concat = (a, b) => {
const sizea = size.get(a);
let len = (sizea || 0) + b.length;
if (len > a.length) {
let n = new (Object.getPrototypeOf(a).constructor)(align(len, concatUnit) * 2);
n.set(a, 0);
n.set(b, sizea);
size.set(n, len);
return n;
}
else {
a.set(b, sizea);
size.set(a, len);
return a;
}
}
// 避免使用迭代器方法减少CPU已走过performance对比流程
// ---------------原来的代码在这里------------------
const getnametable = fastly === false ? list => list.reduce((r, { serial, cheat }, idx, arr) => {
const val = serial.slice(0, -1);
const size1 = size.get(r[1]);
if (val != r[4]) {
if (size1 > 0 && r[2] - r[1].at(size1 - 1) > r[3])
r[3] = r[2] - r[1].at(size1 - 1);
r[0] = concat(r[0], enc.encode(val))
r[1] = concat(r[1], [r[2]]);
r[4] = val;
}
r[2] = r[2] + cheat.length;
if (idx + 1 == arr.length) {
if (r[2] - r[1].at(size1 - 1) > r[3])
r[3] = r[2] - r[1].at(size1 - 1);
r[1] = concat(r[1], [r[2]]);
}
return r;
}, [concat(new Uint8Array(concatUnit), []), concat(new Uint16Array(concatUnit), []), 0, 0, ""])
// ---------------修改的代码在这里------------------
: list => {
const ret = [concat(new Uint8Array(concatUnit), []), concat(new Uint16Array(concatUnit), []), 0, 0, ""];
const {length} = list;
for( let idx=0; idx < length; ++idx ){
const { serial, cheat } = list[idx];
const val = serial.slice(0, -1);
const size1 = size.get(ret[1]);
if( val != ret[4] ){
if( size1 > 0 && ret[2] - ret[1].at(size1 - 1) > ret[3] )
ret[3] = ret[2] - ret[1].at(size1 - 1);
ret[0] = concat(ret[0], enc.encode(val))
ret[1] = concat(ret[1], [ret[2]]);
ret[4] = val;
}
ret[2] = ret[2] + cheat.length;
if( idx + 1 == length ){
if( ret[2] - ret[1].at(size1 - 1) > ret[3] )
ret[3] = ret[2] - ret[1].at(size1 - 1);
ret[1] = concat(ret[1], [ret[2]]);
}
}
return ret;
};
// ---------------修改的代码完结处------------------
// 避免使用迭代器方法减少CPU已走过performance对比流程
// ---------------原来的代码在这里------------------
const expandcheat = fastly === false ? (list, base) => list.reduce((r, { cheat, serial }) => {
const val = serial.charCodeAt(3);
return cheat.reduce((r, { id, bin }) => {
const off = r[2] + size.get(r[1]);
r[0] = concat(r[0], [val | (off << 3), id])
r[1] = concat(r[1], bin);
return r;
}, r);
}, [concat(new Uint32Array(concatUnit), []), concat(new Uint8Array(concatUnit), []), align(base, 32)])
// ---------------修改的代码在这里------------------
: (list, base) => {
const ret = [concat(new Uint32Array(concatUnit), []), concat(new Uint8Array(concatUnit), []), align(base, 32)];
const {length} = list;
for( let idx=0; idx < length; ++idx ){
const { cheat, serial } = list[idx];
const val = serial.charCodeAt(3);
for( const { id, bin } of cheat ){
const off = ret[2] + size.get(ret[1]);
ret[0] = concat(ret[0], [val | (off << 3), id])
ret[1] = concat(ret[1], bin);
}
}
return ret;
};
// ---------------修改的代码完结处------------------
const linkbuffer = (arr, ...l) => {
for (let i of l) {
const arrBa = arr[i];
arr[i] = arrBa.slice(0, size.get(arrBa));
}
return arr;
}
const [sers, offs, chtc, maxl] = linkbuffer(getnametable(valid), 0, 1);
const [cheats, expanded] = linkbuffer(expandcheat(valid, 8 + sers.length + offs.length * 2 + chtc * 8), 0, 1);
console.info(`name: ${sers.length} cheats: ${chtc} maxl: ${maxl}`);
const serialbase = 8;
const offsetbase = serialbase + sers.length;
const cheatbase = offsetbase + offs.length * 2;
const expandbase = align(cheatbase + cheats.length * 4, 32);
const total = expandbase + expanded.length;
const output = new ArrayBuffer(total);
// header: magic number: ACL\1-serial length(u32)
const writter = new DataView(output);
writter.setUint8(0, "A".charCodeAt());
writter.setUint8(1, "C".charCodeAt());
writter.setUint8(2, "L".charCodeAt());
writter.setUint8(3, 1);
const slen = sers.length / 3;
writter.setUint16(4, slen, true);
writter.setUint16(6, maxl, true);
let ret = new Uint8Array(output);
ret.set(sers, serialbase);
ret.set(new Uint8Array(offs.buffer), offsetbase);
ret.set(new Uint8Array(cheats.buffer), cheatbase);
ret.set(expanded, expandbase);
return ret;
}
const start = async () => {
let begin = performance.now();
let list = await loadlist();
let roms = await transform(list);
console.log(`all rom has ${roms.length} and time ${performance.now() - begin}`);
// 避免使用迭代器方法减少CPU已走过performance对比流程
// ---------------原来的代码在这里------------------
if( fastly === false ){
roms = Object.entries(roms.reduce((r, data) => {
if (!data) return r;
const { serial, cheat } = data;
if (!cheat || cheat.length == 0) return r;
if (serial in r) r[serial] = [...r[serial], ...cheat];
else r[serial] = cheat;
return r;
}, {})).map(([serial, cheat]) => ({ serial, cheat }));
}
// ---------------修改的代码在这里------------------
else
{
const res = new Array(10240), idx = {};
let l = 0;
for( const data of roms ){
if( !data ) continue;
const { serial, cheat } = data;
if( !cheat || cheat.length == 0 ) continue;
const cheats = idx[serial] ? idx[serial] : [];
cheats.push(...cheat);
if( !idx[serial] ){
idx[serial] = cheats;
res[l++] = { serial, cheat: cheats };
}
}
res.length = l;
roms = res;
}
// ---------------修改的代码完结处------------------
const content = await format( roms );
await writeFile( "gba.acl", content );
}
start()