diff --git a/backend/utils/clientPatcher.js b/backend/utils/clientPatcher.js index 1922725..46d8fde 100644 --- a/backend/utils/clientPatcher.js +++ b/backend/utils/clientPatcher.js @@ -184,6 +184,44 @@ class ClientPatcher { 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. * Java stores strings in UTF-8 format in the constant pool. @@ -312,7 +350,11 @@ class ClientPatcher { const oldUtf16 = this.stringToUtf16LE(ORIGINAL_DOMAIN); const newUtf16 = this.stringToUtf16LE(strategy.mainDomain); 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 { // Length-prefixed format (default) domainResult = this.replaceBytes(