diff --git a/backend/managers/gameLauncher.js b/backend/managers/gameLauncher.js index 9a8a317..bcbe784 100644 --- a/backend/managers/gameLauncher.js +++ b/backend/managers/gameLauncher.js @@ -285,12 +285,30 @@ exec "$REAL_JAVA" "\${ARGS[@]}" const gpuEnv = setupGpuEnvironment(gpuPreference); Object.assign(env, gpuEnv); - // Disable glibc heap validation on Linux to prevent false positive - // "free(): invalid pointer" crashes on Steam Deck and Ubuntu LTS - // This doesn't hide real bugs - the same binary works on other systems + // Linux memory allocator fixes for "free(): invalid pointer" crashes + // on Steam Deck (glibc 2.41) and Ubuntu LTS if (process.platform === 'linux') { + // Option 1: Disable glibc heap validation env.MALLOC_CHECK_ = '0'; - console.log('Linux detected: Setting MALLOC_CHECK_=0 to disable glibc heap validation'); + + // Option 2: Try to use jemalloc if available (more robust allocator) + // User can set HYTALE_USE_JEMALLOC=1 to enable + if (process.env.HYTALE_USE_JEMALLOC === '1') { + const jemalloc = require('fs').existsSync('/usr/lib/libjemalloc.so.2') + ? '/usr/lib/libjemalloc.so.2' + : require('fs').existsSync('/usr/lib/x86_64-linux-gnu/libjemalloc.so.2') + ? '/usr/lib/x86_64-linux-gnu/libjemalloc.so.2' + : null; + + if (jemalloc) { + env.LD_PRELOAD = jemalloc + (env.LD_PRELOAD ? ':' + env.LD_PRELOAD : ''); + console.log(`Linux: Using jemalloc allocator (${jemalloc})`); + } else { + console.log('Linux: jemalloc not found, using glibc with MALLOC_CHECK_=0'); + } + } else { + console.log('Linux: Using glibc with MALLOC_CHECK_=0 (set HYTALE_USE_JEMALLOC=1 to try jemalloc)'); + } } try { diff --git a/backend/utils/clientPatcher.js b/backend/utils/clientPatcher.js index 332a7a4..21f6116 100644 --- a/backend/utils/clientPatcher.js +++ b/backend/utils/clientPatcher.js @@ -245,6 +245,10 @@ class ClientPatcher { /** * Apply all domain patches using length-prefixed format * This is the main patching method for variable-length domains + * + * Debug env vars: + * HYTALE_SKIP_SENTRY_PATCH=1 - Skip sentry URL patch (biggest size change) + * HYTALE_SKIP_SUBDOMAIN_PATCH=1 - Skip subdomain prefix patches */ applyDomainPatches(data, domain, protocol = 'https://') { let result = Buffer.from(data); @@ -253,20 +257,24 @@ class ClientPatcher { console.log(` Patching strategy: ${strategy.description}`); - // 1. Patch telemetry/sentry URL - const oldSentry = 'https://ca900df42fcf57d4dd8401a86ddd7da2@sentry.hytale.com/2'; - const newSentry = `${protocol}t@${domain}/2`; + // 1. Patch telemetry/sentry URL (skip if debugging) + if (process.env.HYTALE_SKIP_SENTRY_PATCH === '1') { + console.log(` Skipping sentry patch (HYTALE_SKIP_SENTRY_PATCH=1)`); + } else { + const oldSentry = 'https://ca900df42fcf57d4dd8401a86ddd7da2@sentry.hytale.com/2'; + const newSentry = `${protocol}t@${domain}/2`; - console.log(` Patching sentry: ${oldSentry.slice(0, 30)}... -> ${newSentry}`); - const sentryResult = this.replaceBytes( - result, - this.stringToLengthPrefixed(oldSentry), - this.stringToLengthPrefixed(newSentry) - ); - result = sentryResult.buffer; - if (sentryResult.count > 0) { - console.log(` Replaced ${sentryResult.count} sentry occurrence(s)`); - totalCount += sentryResult.count; + console.log(` Patching sentry: ${oldSentry.slice(0, 30)}... -> ${newSentry}`); + const sentryResult = this.replaceBytes( + result, + this.stringToLengthPrefixed(oldSentry), + this.stringToLengthPrefixed(newSentry) + ); + result = sentryResult.buffer; + if (sentryResult.count > 0) { + console.log(` Replaced ${sentryResult.count} sentry occurrence(s)`); + totalCount += sentryResult.count; + } } // 2. Patch main domain (hytale.com -> mainDomain) @@ -282,21 +290,25 @@ class ClientPatcher { totalCount += domainResult.count; } - // 3. Patch subdomain prefixes - const subdomains = ['https://tools.', 'https://sessions.', 'https://account-data.', 'https://telemetry.']; - const newSubdomainPrefix = protocol + strategy.subdomainPrefix; + // 3. Patch subdomain prefixes (skip if debugging) + if (process.env.HYTALE_SKIP_SUBDOMAIN_PATCH === '1') { + console.log(` Skipping subdomain patches (HYTALE_SKIP_SUBDOMAIN_PATCH=1)`); + } else { + const subdomains = ['https://tools.', 'https://sessions.', 'https://account-data.', 'https://telemetry.']; + const newSubdomainPrefix = protocol + strategy.subdomainPrefix; - for (const sub of subdomains) { - console.log(` Patching subdomain: ${sub} -> ${newSubdomainPrefix}`); - const subResult = this.replaceBytes( - result, - this.stringToLengthPrefixed(sub), - this.stringToLengthPrefixed(newSubdomainPrefix) - ); - result = subResult.buffer; - if (subResult.count > 0) { - console.log(` Replaced ${subResult.count} occurrence(s)`); - totalCount += subResult.count; + for (const sub of subdomains) { + console.log(` Patching subdomain: ${sub} -> ${newSubdomainPrefix}`); + const subResult = this.replaceBytes( + result, + this.stringToLengthPrefixed(sub), + this.stringToLengthPrefixed(newSubdomainPrefix) + ); + result = subResult.buffer; + if (subResult.count > 0) { + console.log(` Replaced ${subResult.count} occurrence(s)`); + totalCount += subResult.count; + } } }