From 19ce7dd24ab999267da004994b01a8629ed90151 Mon Sep 17 00:00:00 2001 From: a92126 <182859762@qq.com> Date: Tue, 8 Oct 2024 15:41:54 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BA=E4=BA=86=E6=8F=90=E9=AB=98=E6=89=93?= =?UTF-8?q?=E5=8C=85=E9=87=91=E6=89=8B=E6=8C=87=E7=9A=84=E9=80=9F=E5=BA=A6?= =?UTF-8?q?=EF=BC=8C=E8=BF=9B=E8=A1=8C=E4=BA=86=E5=A4=9A=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=8C=E4=BD=86=E6=98=AF=E5=8F=91=E7=8E=B0?= =?UTF-8?q?=E5=9C=A8cpu=E4=B8=8D=E5=A4=9A=E7=9A=84=E6=83=85=E5=86=B5?= =?UTF-8?q?=E4=B8=8B=EF=BC=8C=E5=85=B6=E5=AE=9E=E6=AF=94=E8=B5=B7=E5=8D=95?= =?UTF-8?q?=E6=A0=B8=E5=B9=B6=E4=B8=8D=E4=BC=9A=E5=BF=AB=E5=BE=88=E5=A4=9A?= =?UTF-8?q?=EF=BC=88=E6=AF=95=E7=AB=9F=20=E9=9C=80=E8=A6=81=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E5=BA=8F=E5=88=97=E5=8C=96=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/cheat-builder/build.js | 64 +++------------------------- tools/cheat-builder/worker.js | 78 +++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 59 deletions(-) create mode 100644 tools/cheat-builder/worker.js diff --git a/tools/cheat-builder/build.js b/tools/cheat-builder/build.js index 0db2505..d9b412a 100644 --- a/tools/cheat-builder/build.js +++ b/tools/cheat-builder/build.js @@ -1,6 +1,7 @@ const readCht = require("./cht"); const fs = require("fs"); -const { readFile, writeFile, access } = require("fs/promises"); +const { readFile, writeFile } = require("fs/promises"); +const transform = require("./worker"); const loadlist = async () => { const datfile = await readFile("./serial.json"); @@ -8,45 +9,6 @@ const loadlist = async () => { return Object.entries(datas).filter(n => n[1] != "????"); } -const trimcheat = (dat, info, order) => { - let parts = [], start = 0, done = false; - while (!done) { - let pos = dat.indexOf("[GameInfo]", start); - if (pos > 0) { - pos = dat.indexOf("[", pos + "[GameInfo]".length); - if (pos > 0) { - parts.push(dat.slice(start, pos)); - start = pos; - } - else { - parts.push(dat.slice(start, dat.length)); - done = true; - } - } - else { - parts.push(dat.slice(start, dat.length)); - done = true; - } - } - return parts.map(tr => readCht(tr, info, order)); -} - -const loadcheat = async (order, serial, title, file) => { - try { - const chtfile = await readFile(file); - const cheats = chtfile.toString("utf-8"); - let cheat = null; - if (cheats.indexOf("[GameInfo]") != cheats.lastIndexOf("[GameInfo]")) - cheat = trimcheat(cheats, { serial }, order); - else cheat = [readCht(cheats, { serial }, order)]; - return { serial, cheat } - } - catch (e) { - console.log("bad cheat: %s[order=%d]\n%s", title, order, e.stack) - return { serial } - }; -} - const format = valid => { valid.sort((a, b) => a.serial.localeCompare(b.serial)); console.info(`valid rom has ${valid.length}`); @@ -137,27 +99,11 @@ const format = valid => { return ret; } -const hasfile = f => { - try { - fs.accessSync(f); - return true; - } - catch (e) { - console.error(e.stack) - return false; - } -} - const start = async () => { + let begin = Date.now(); let list = await loadlist(); - let roms = await Promise.all(list.map(game => { - const [order, serial, title] = game; - const file = `./gba/${order}.u8`; - if (hasfile(file)) - return loadcheat(order, serial, title ?? order, file); - else return Promise.resolve(); - })); - console.log(`all rom has ${roms.length}`); + let roms = await transform(list); + console.log(`all rom has ${roms.length} and time ${Date.now() - begin}`); roms = Object.entries(roms.reduce((r, data) => { if (!data) return r; diff --git a/tools/cheat-builder/worker.js b/tools/cheat-builder/worker.js new file mode 100644 index 0000000..3339bb9 --- /dev/null +++ b/tools/cheat-builder/worker.js @@ -0,0 +1,78 @@ +const {Worker, isMainThread, parentPort, workerData} = require("worker_threads"); +const readCht = require("./cht"); +const { readFile, access } = require("fs/promises"); +const ncpu = require("os").availableParallelism(); + +const trimcheat = (dat, info, order) => { + let parts = [], start = 0, done = false; + while (!done) { + let pos = dat.indexOf("[GameInfo]", start); + if (pos > 0) { + pos = dat.indexOf("[", pos + "[GameInfo]".length); + if (pos > 0) { + parts.push(dat.slice(start, pos)); + start = pos; + } + else { + parts.push(dat.slice(start, dat.length)); + done = true; + } + } + else { + parts.push(dat.slice(start, dat.length)); + done = true; + } + } + return parts.map(tr => readCht(tr, info, order)); +} + +const loadcheat = async (order, serial, title, file) => { + if( false == await access(file).catch( e => false ) ) { + return Promise.resolve(); + } + + try { + const chtfile = await readFile(file); + const cheats = chtfile.toString("utf-8"); + let cheat = null; + if (cheats.indexOf("[GameInfo]") != cheats.lastIndexOf("[GameInfo]")) + cheat = trimcheat(cheats, { serial }, order); + else cheat = [readCht(cheats, { serial }, order)]; + return { serial, cheat } + } + catch (e) { + console.log("bad cheat: %s[order=%d]\n%s", title, order, e.stack) + return { serial } + }; +} + +if( isMainThread ) { + module.exports = ncpu > 3 ? function(list) { + const nPerThread = Math.ceil(list.length / ncpu); + const results = new Array(ncpu); + let n = 0; + return new Promise( ok => { + const workers = new Array(ncpu).fill(0).map( (_,i) => { + const sublist = list.slice(i * nPerThread, (i+1) * nPerThread); + const worker = new Worker(__filename, { workerData: sublist }); + worker.once("message", msg => { + results[i] = msg; + worker.unref(); + if( ++n == ncpu ) ok(results.flat()); + }); + } ); + }); + } : list => Promise.all( list.map( game => { + const [order, serial, title] = game; + const file = `./gba/${order}.u8`; + return loadcheat(order, serial, title ?? order, file); + } ) ); +} +else { + const list = workerData; + Promise.all( list.map( game => { + const [order, serial, title] = game; + const file = `./gba/${order}.u8`; + return loadcheat(order, serial, title ?? order, file); + } ) ).then( res => parentPort.postMessage(res) ); +}