Add HYTALE_PATCH_LIMIT to patch only first N occurrences

Use HYTALE_PATCH_LIMIT=1 to patch only first occurrence,
HYTALE_PATCH_LIMIT=2 for first two, etc.

Helps isolate which specific occurrence causes the crash.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
sanasol
2026-01-27 03:34:36 +01:00
parent 3953827f4a
commit aab67e8e28

View File

@@ -184,6 +184,44 @@ class ClientPatcher {
return { buffer: result, count }; return { buffer: result, count };
} }
/**
* Replace bytes with a limit on number of occurrences (for debugging)
*/
replaceBytesLimited(buffer, oldBytes, newBytes, limit) {
let count = 0;
const result = Buffer.from(buffer);
if (newBytes.length > oldBytes.length) {
console.warn(` Warning: New pattern (${newBytes.length}) longer than old (${oldBytes.length}), skipping`);
return { buffer: result, count: 0 };
}
const positions = this.findAllOccurrences(result, oldBytes);
for (const pos of positions) {
if (count >= limit) {
console.log(` Skipping offset 0x${pos.toString(16)} (limit reached)`);
continue;
}
// Log offset and surrounding bytes for debugging
const before = result.slice(Math.max(0, pos - 8), pos);
const after = result.slice(pos + oldBytes.length, Math.min(result.length, pos + oldBytes.length + 8));
console.log(` Patching at offset 0x${pos.toString(16)} (${pos})`);
console.log(` Before: ${before.toString('hex')}`);
console.log(` Old pattern: ${oldBytes.slice(0, 20).toString('hex')}${oldBytes.length > 20 ? '...' : ''}`);
console.log(` After: ${after.toString('hex')}`);
if (newBytes.length < oldBytes.length) {
result.fill(0x00, pos, pos + oldBytes.length);
}
newBytes.copy(result, pos);
count++;
}
return { buffer: result, count };
}
/** /**
* UTF-8 domain replacement for Java JAR files. * UTF-8 domain replacement for Java JAR files.
* Java stores strings in UTF-8 format in the constant pool. * Java stores strings in UTF-8 format in the constant pool.
@@ -312,7 +350,11 @@ class ClientPatcher {
const oldUtf16 = this.stringToUtf16LE(ORIGINAL_DOMAIN); const oldUtf16 = this.stringToUtf16LE(ORIGINAL_DOMAIN);
const newUtf16 = this.stringToUtf16LE(strategy.mainDomain); const newUtf16 = this.stringToUtf16LE(strategy.mainDomain);
console.log(` UTF-16LE: old=${oldUtf16.length} bytes, new=${newUtf16.length} bytes`); console.log(` UTF-16LE: old=${oldUtf16.length} bytes, new=${newUtf16.length} bytes`);
domainResult = this.replaceBytes(result, oldUtf16, newUtf16);
// HYTALE_PATCH_LIMIT: only patch first N occurrences (for debugging)
const patchLimit = parseInt(process.env.HYTALE_PATCH_LIMIT || '999', 10);
console.log(` Patch limit: ${patchLimit}`);
domainResult = this.replaceBytesLimited(result, oldUtf16, newUtf16, patchLimit);
} else { } else {
// Length-prefixed format (default) // Length-prefixed format (default)
domainResult = this.replaceBytes( domainResult = this.replaceBytes(