use a proper logger

This commit is contained in:
beerpsi 2024-10-27 03:17:55 +07:00
parent cadee776ea
commit ecaec6d942
4 changed files with 40 additions and 13 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
.ruff_cache .ruff_cache
*.log

View File

@ -9,10 +9,10 @@ disk image.
## Patchers ## Patchers
- `patchers/b2spatch.ts`: Convert from BemaniPatcher to Spice2x JSON - `patchers/b2spatch.ts`: Convert from BemaniPatcher to Spice2x JSON
- Use Deno: `deno run -WNE b2spatch.ts ...` - Use Deno: `deno run -A b2spatch.ts ...`
- You will need to rename the resulting JSON manually so that they match the - You will need to rename the resulting JSON manually so that they match the
`{gameCode}-{timestamp}_{entrypoint}` format expected by Spice2x. `{gameCode}-{timestamp}_{entrypoint}` format expected by Spice2x.
- `patchers/b2mpatch.ts`: Convert from BemaniPatcher to [mempatch-hook](https://github.com/djhackersdev/bemanitools/blob/master/doc/tools/mempatch-hook.md) - `patchers/b2mpatch.ts`: Convert from BemaniPatcher to [mempatch-hook](https://github.com/djhackersdev/bemanitools/blob/master/doc/tools/mempatch-hook.md)/[mempatcher](https://github.com/aixxe/mempatcher)
- Use Deno: `deno run -A b2mpatch.ts ...` - Use Deno: `deno run -A b2mpatch.ts ...`
- You need to setup a folder of executables or DLLs you want to patch. They - You need to setup a folder of executables or DLLs you want to patch. They
can be named the patcher's description, or the patcher's filename. can be named the patcher's description, or the patcher's filename.

View File

@ -1,11 +1,15 @@
import { Buffer } from "node:buffer";
import { existsSync, readFileSync, writeFileSync } from "node:fs"; import { existsSync, readFileSync, writeFileSync } from "node:fs";
import process from "node:process"; import process from "node:process";
import path from "node:path"; import path from "node:path";
import { CreateLogger } from "npm:mei-logger";
import PE from "npm:pe-parser"; import PE from "npm:pe-parser";
import type { PEFile } from "npm:pe-parser/parser"; import type { PEFile } from "npm:pe-parser/parser";
import sanitize from "npm:sanitize-filename"; import sanitize from "npm:sanitize-filename";
import { bytesToHex, parsePatcherHtml } from "./_parser.ts"; import { bytesToHex, parsePatcherHtml } from "./_parser.ts";
const logger = CreateLogger("b2mpatch");
function fileOffsetToRVA(pe: PEFile, offset: number) { function fileOffsetToRVA(pe: PEFile, offset: number) {
for (const section of pe.sections) { for (const section of pe.sections) {
if ( if (
@ -45,32 +49,46 @@ async function main() {
executableDir, executableDir,
sanitize(patcher.description) + path.extname(patcher.fname), sanitize(patcher.description) + path.extname(patcher.fname),
); );
let useFileOffsets = false;
if (!existsSync(exePath)) { if (!existsSync(exePath)) {
console.warn( logger.warn(
`Target file ${exePath} does not exist, falling back to ${patcher.fname}.`, `Target file ${exePath} does not exist, falling back to ${patcher.fname}.`,
); );
exePath = path.join(executableDir, patcher.fname); exePath = path.join(executableDir, patcher.fname);
} }
if (!existsSync(exePath)) { if (!existsSync(exePath)) {
console.warn(`Target file ${exePath} does not exist, skipping.`); logger.warn(`Target file ${exePath} does not exist, using file offsets instead (requires gh:aixxe/mempatcher).`);
continue; useFileOffsets = true;
}
let data: Buffer | null = null;
let pe: PEFile | null = null;
if (!useFileOffsets) {
data = readFileSync(exePath);
pe = await PE.Parse(data);
} }
const data = readFileSync(exePath);
const pe = await PE.Parse(data);
let mempatch = `# ${patcher.fname} ${patcher.description}\n\n`; let mempatch = `# ${patcher.fname} ${patcher.description}\n\n`;
for (const patch of patcher.patches) { for (const patch of patcher.patches) {
if (patch.type !== undefined && patch.type !== "union") { if (patch.type !== undefined && patch.type !== "union") {
console.warn( logger.warn(
`Unsupported BemaniPatcher patch type ${patch.type}`, `Unsupported BemaniPatcher patch type ${patch.type}`,
patch, patch,
); );
continue; continue;
} }
if (patch.type === "union" && !data) {
logger.warn(
`Union patch requires file data, skipping.`, patch,
);
continue;
}
mempatch += `# ${patch.name}\n`; mempatch += `# ${patch.name}\n`;
if (patch.tooltip) { if (patch.tooltip) {
@ -90,7 +108,7 @@ async function main() {
const up = p as { name: string; patch: number[] }; const up = p as { name: string; patch: number[] };
on = bytesToHex(up.patch); on = bytesToHex(up.patch);
off = data off = data!
.subarray( .subarray(
patch.offset, patch.offset,
patch.offset + up.patch.length, patch.offset + up.patch.length,
@ -111,8 +129,13 @@ async function main() {
on = bytesToHex(sp.on); on = bytesToHex(sp.on);
off = bytesToHex(sp.off); off = bytesToHex(sp.off);
offset = fileOffsetToRVA(pe, sp.offset).toString(16)
.toUpperCase(); if (useFileOffsets) {
offset = "F+" + sp.offset.toString(16).toUpperCase();
} else {
offset = fileOffsetToRVA(pe, sp.offset).toString(16)
.toUpperCase();
}
} }
if (patch.type === "union" && on === off) { if (patch.type === "union" && on === off) {

View File

@ -8,6 +8,7 @@
import { readFileSync, writeFileSync } from "node:fs"; import { readFileSync, writeFileSync } from "node:fs";
import path from "node:path"; import path from "node:path";
import process from "node:process"; import process from "node:process";
import { CreateLogger } from "npm:mei-logger";
import { bytesToHex, parsePatcherHtml } from "./_parser.ts"; import { bytesToHex, parsePatcherHtml } from "./_parser.ts";
import type { import type {
BemaniPatch, BemaniPatch,
@ -19,6 +20,8 @@ import type {
SpiceUnionPatch, SpiceUnionPatch,
} from "./_types.ts"; } from "./_types.ts";
const logger = CreateLogger("b2spatch");
function convertToSpicePatch( function convertToSpicePatch(
bmPatch: BemaniPatch, bmPatch: BemaniPatch,
gameCode: string, gameCode: string,
@ -69,7 +72,7 @@ function convertToSpicePatch(
// Technically you can match BemaniPatcher's DynamicPatch type to // Technically you can match BemaniPatcher's DynamicPatch type to
// Spice's signature patch, but one DynamicPatch can have multiple signatures, // Spice's signature patch, but one DynamicPatch can have multiple signatures,
// while Spice only supports one signature per patch. // while Spice only supports one signature per patch.
console.warn( logger.warn(
`Unsupported BemaniPatcher patch type ${bmPatch.type}`, `Unsupported BemaniPatcher patch type ${bmPatch.type}`,
bmPatch, bmPatch,
); );
@ -90,7 +93,7 @@ function convertToSpicePatch(
async function main() { async function main() {
if (process.argv.length < 4) { if (process.argv.length < 4) {
console.log( console.log(
"Usage: deno run -WNE b2spatch.ts <patcher URL | local patcher HTML> <gameCode> [output dir]", "Usage: deno run -A b2spatch.ts <patcher URL | local patcher HTML> <gameCode> [output dir]",
); );
process.exit(1); process.exit(1);
} }