mirror of
https://git.sanhost.net/sanasol/hytale-f2p
synced 2026-02-26 14:01:48 -03:00
Fix community link order: TG Group > TG Channel > Chat
Consistent order across all files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
405
backend/utils/clientPatcher.localhost.js.bak
Normal file
405
backend/utils/clientPatcher.localhost.js.bak
Normal file
@@ -0,0 +1,405 @@
|
||||
/**
|
||||
* Localhost/Local Development Code Backup
|
||||
*
|
||||
* This file contains code removed from clientPatcher.js that was used for local development.
|
||||
* To re-enable local dev mode, merge this code back into clientPatcher.js.
|
||||
*
|
||||
* Backed up: 2026-01-28
|
||||
*/
|
||||
|
||||
// =============================================================================
|
||||
// LOCAL PATCHER PATHS (was in ensurePatcherDownloaded method)
|
||||
// =============================================================================
|
||||
|
||||
// Check for local patcher (for local development)
|
||||
const localPatcherPaths = [
|
||||
path.join(__dirname, '..', '..', '..', 'hytale-auth-server', 'patcher', 'DualAuthPatcher.java'),
|
||||
path.join(__dirname, '..', '..', '..', '..', 'hytale-auth-server', 'patcher', 'DualAuthPatcher.java'),
|
||||
'/Users/sanasol/code/pterodactyl-hytale/hytale-auth-server/patcher/DualAuthPatcher.java'
|
||||
];
|
||||
|
||||
// Check if we should use local patcher (localhost domain = local dev)
|
||||
const domain = getTargetDomain();
|
||||
const isLocalDev = domain.startsWith('localhost') || domain.startsWith('127.0.0.1');
|
||||
|
||||
if (isLocalDev) {
|
||||
for (const localPath of localPatcherPaths) {
|
||||
if (fs.existsSync(localPath)) {
|
||||
console.log(`Using local DualAuthPatcher: ${localPath}`);
|
||||
// Always copy fresh for local dev to pick up changes
|
||||
fs.copyFileSync(localPath, patcherJava);
|
||||
// Delete compiled class to force recompile
|
||||
const patcherClass = path.join(patcherDir, 'DualAuthPatcher.class');
|
||||
if (fs.existsSync(patcherClass)) {
|
||||
fs.unlinkSync(patcherClass);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
console.log('Local patcher not found, falling back to download...');
|
||||
}
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// LEGACY SERVER PATCHER (was patchServerLegacy method)
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Legacy server patcher (simple domain replacement, no dual auth)
|
||||
* Use patchServer() for full dual auth support
|
||||
*/
|
||||
async patchServerLegacy(serverPath, progressCallback) {
|
||||
const newDomain = this.getNewDomain();
|
||||
const strategy = this.getDomainStrategy(newDomain);
|
||||
|
||||
console.log('=== Legacy Server Patcher ===');
|
||||
console.log(`Target: ${serverPath}`);
|
||||
console.log(`Domain: ${newDomain} (${newDomain.length} chars)`);
|
||||
|
||||
if (!fs.existsSync(serverPath)) {
|
||||
return { success: false, error: `Server JAR not found: ${serverPath}` };
|
||||
}
|
||||
|
||||
if (progressCallback) progressCallback('Patching server...', 20);
|
||||
|
||||
console.log('Opening server JAR...');
|
||||
const zip = new AdmZip(serverPath);
|
||||
const entries = zip.getEntries();
|
||||
|
||||
let totalCount = 0;
|
||||
const oldUtf8 = this.stringToUtf8(ORIGINAL_DOMAIN);
|
||||
|
||||
for (const entry of entries) {
|
||||
const name = entry.entryName;
|
||||
if (name.endsWith('.class') || name.endsWith('.properties') ||
|
||||
name.endsWith('.json') || name.endsWith('.xml') || name.endsWith('.yml')) {
|
||||
const data = entry.getData();
|
||||
if (data.includes(oldUtf8)) {
|
||||
const { buffer: patchedData, count } = this.findAndReplaceDomainUtf8(data, ORIGINAL_DOMAIN, strategy.mainDomain);
|
||||
if (count > 0) {
|
||||
zip.updateFile(entry.entryName, patchedData);
|
||||
totalCount += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (totalCount > 0) {
|
||||
zip.writeZip(serverPath);
|
||||
}
|
||||
|
||||
if (progressCallback) progressCallback('Complete', 100);
|
||||
return { success: true, patchCount: totalCount };
|
||||
}
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// DUALAUTHPATCHER FLOW FOR NON-STANDARD DOMAINS (was in patchServer method)
|
||||
// =============================================================================
|
||||
|
||||
// For non-standard domains, use DualAuthPatcher for proper bytecode patching
|
||||
const isStandardDomain = newDomain === 'auth.sanasol.ws' || newDomain === 'sanasol.ws';
|
||||
|
||||
if (!isStandardDomain) {
|
||||
console.log(`Non-standard domain "${newDomain}" - using DualAuthPatcher`);
|
||||
|
||||
// Find Java
|
||||
const java = this.findJava();
|
||||
if (!java) {
|
||||
console.error('Java not found - cannot run DualAuthPatcher');
|
||||
console.error('Please install Java or use the bundled JRE');
|
||||
return { success: false, error: 'Java not found for DualAuthPatcher' };
|
||||
}
|
||||
console.log(` Using Java: ${java}`);
|
||||
|
||||
// Setup patcher directory
|
||||
const patcherDir = path.join(path.dirname(serverPath), '.patcher');
|
||||
const libDir = path.join(patcherDir, 'lib');
|
||||
|
||||
try {
|
||||
// Download patcher and libraries
|
||||
if (progressCallback) progressCallback('Downloading DualAuthPatcher...', 20);
|
||||
await this.ensurePatcherDownloaded(patcherDir);
|
||||
|
||||
if (progressCallback) progressCallback('Downloading ASM libraries...', 30);
|
||||
await this.ensureAsmLibraries(libDir);
|
||||
|
||||
// Compile patcher
|
||||
if (progressCallback) progressCallback('Compiling patcher...', 40);
|
||||
const compileResult = await this.compileDualAuthPatcher(java, patcherDir, libDir);
|
||||
if (!compileResult.success) {
|
||||
return { success: false, error: compileResult.error };
|
||||
}
|
||||
|
||||
// Build classpath
|
||||
const classpath = [
|
||||
patcherDir,
|
||||
path.join(libDir, 'asm-9.6.jar'),
|
||||
path.join(libDir, 'asm-tree-9.6.jar'),
|
||||
path.join(libDir, 'asm-util-9.6.jar')
|
||||
].join(process.platform === 'win32' ? ';' : ':');
|
||||
|
||||
// Run DualAuthPatcher with custom domain
|
||||
if (progressCallback) progressCallback('Running DualAuthPatcher...', 60);
|
||||
console.log(` Running DualAuthPatcher with domain: ${newDomain}`);
|
||||
|
||||
const patchResult = await this.runDualAuthPatcher(java, classpath, serverPath, newDomain);
|
||||
|
||||
if (patchResult.success) {
|
||||
// Mark as patched
|
||||
fs.writeFileSync(patchFlagFile, JSON.stringify({
|
||||
domain: newDomain,
|
||||
patchedAt: new Date().toISOString(),
|
||||
patcher: 'DualAuthPatcher',
|
||||
output: patchResult.stdout
|
||||
}, null, 2));
|
||||
|
||||
if (progressCallback) progressCallback('Server patching complete', 100);
|
||||
console.log('=== Server Patching Complete (DualAuthPatcher) ===');
|
||||
return { success: true, patchCount: 1 };
|
||||
} else {
|
||||
console.error('DualAuthPatcher failed:', patchResult.error);
|
||||
return { success: false, error: patchResult.error };
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error('Failed to run DualAuthPatcher:', err.message);
|
||||
return { success: false, error: err.message };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// HELPER METHODS FOR DUALAUTHPATCHER (keep if re-enabling non-standard domains)
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Find Java executable - uses bundled JRE first (same as game uses)
|
||||
* Falls back to system Java if bundled not available
|
||||
*/
|
||||
findJava() {
|
||||
// 1. Try bundled JRE first (comes with the game)
|
||||
try {
|
||||
const bundled = getBundledJavaPath(JRE_DIR);
|
||||
if (bundled && fs.existsSync(bundled)) {
|
||||
console.log(`Using bundled Java: ${bundled}`);
|
||||
return bundled;
|
||||
}
|
||||
} catch (e) {
|
||||
// Bundled not available
|
||||
}
|
||||
|
||||
// 2. Try javaManager's getJavaExec (handles all fallbacks)
|
||||
try {
|
||||
const javaExec = getJavaExec(JRE_DIR);
|
||||
if (javaExec && fs.existsSync(javaExec)) {
|
||||
console.log(`Using Java from javaManager: ${javaExec}`);
|
||||
return javaExec;
|
||||
}
|
||||
} catch (e) {
|
||||
// Not available
|
||||
}
|
||||
|
||||
// 3. Check JAVA_HOME
|
||||
if (process.env.JAVA_HOME) {
|
||||
const javaHome = process.env.JAVA_HOME;
|
||||
const javaBin = path.join(javaHome, 'bin', process.platform === 'win32' ? 'java.exe' : 'java');
|
||||
if (fs.existsSync(javaBin)) {
|
||||
console.log(`Using Java from JAVA_HOME: ${javaBin}`);
|
||||
return javaBin;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Try 'java' from PATH
|
||||
try {
|
||||
execSync('java -version 2>&1', { encoding: 'utf8' });
|
||||
console.log('Using Java from PATH');
|
||||
return 'java';
|
||||
} catch (e) {
|
||||
// Not in PATH
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DualAuthPatcher - downloads from GitHub
|
||||
*/
|
||||
async ensurePatcherDownloaded(patcherDir) {
|
||||
const patcherJava = path.join(patcherDir, 'DualAuthPatcher.java');
|
||||
const patcherUrl = 'https://raw.githubusercontent.com/sanasol/hytale-auth-server/master/patcher/DualAuthPatcher.java';
|
||||
|
||||
if (!fs.existsSync(patcherDir)) {
|
||||
fs.mkdirSync(patcherDir, { recursive: true });
|
||||
}
|
||||
|
||||
if (!fs.existsSync(patcherJava)) {
|
||||
console.log('Downloading DualAuthPatcher from hytale-auth-server...');
|
||||
try {
|
||||
const https = require('https');
|
||||
await new Promise((resolve, reject) => {
|
||||
const file = fs.createWriteStream(patcherJava);
|
||||
https.get(patcherUrl, (response) => {
|
||||
if (response.statusCode === 302 || response.statusCode === 301) {
|
||||
https.get(response.headers.location, (redirectResponse) => {
|
||||
redirectResponse.pipe(file);
|
||||
file.on('finish', () => {
|
||||
file.close();
|
||||
resolve();
|
||||
});
|
||||
}).on('error', reject);
|
||||
} else {
|
||||
response.pipe(file);
|
||||
file.on('finish', () => {
|
||||
file.close();
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
}).on('error', (err) => {
|
||||
fs.unlink(patcherJava, () => {});
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
console.log(' Downloaded DualAuthPatcher.java');
|
||||
} catch (e) {
|
||||
console.error(` Failed to download DualAuthPatcher: ${e.message}`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download ASM libraries if not present
|
||||
*/
|
||||
async ensureAsmLibraries(libDir) {
|
||||
if (!fs.existsSync(libDir)) {
|
||||
fs.mkdirSync(libDir, { recursive: true });
|
||||
}
|
||||
|
||||
const libs = [
|
||||
{ name: 'asm-9.6.jar', url: 'https://repo1.maven.org/maven2/org/ow2/asm/asm/9.6/asm-9.6.jar' },
|
||||
{ name: 'asm-tree-9.6.jar', url: 'https://repo1.maven.org/maven2/org/ow2/asm/asm-tree/9.6/asm-tree-9.6.jar' },
|
||||
{ name: 'asm-util-9.6.jar', url: 'https://repo1.maven.org/maven2/org/ow2/asm/asm-util/9.6/asm-util-9.6.jar' }
|
||||
];
|
||||
|
||||
for (const lib of libs) {
|
||||
const libPath = path.join(libDir, lib.name);
|
||||
if (!fs.existsSync(libPath)) {
|
||||
console.log(`Downloading ${lib.name}...`);
|
||||
try {
|
||||
const https = require('https');
|
||||
await new Promise((resolve, reject) => {
|
||||
const file = fs.createWriteStream(libPath);
|
||||
https.get(lib.url, (response) => {
|
||||
response.pipe(file);
|
||||
file.on('finish', () => {
|
||||
file.close();
|
||||
resolve();
|
||||
});
|
||||
}).on('error', (err) => {
|
||||
fs.unlink(libPath, () => {});
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
console.log(` Downloaded ${lib.name}`);
|
||||
} catch (e) {
|
||||
console.error(` Failed to download ${lib.name}: ${e.message}`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile DualAuthPatcher if needed
|
||||
*/
|
||||
async compileDualAuthPatcher(java, patcherDir, libDir) {
|
||||
const patcherClass = path.join(patcherDir, 'DualAuthPatcher.class');
|
||||
const patcherJava = path.join(patcherDir, 'DualAuthPatcher.java');
|
||||
|
||||
if (fs.existsSync(patcherClass)) {
|
||||
const classTime = fs.statSync(patcherClass).mtime;
|
||||
const javaTime = fs.statSync(patcherJava).mtime;
|
||||
if (classTime > javaTime) {
|
||||
console.log('DualAuthPatcher already compiled');
|
||||
return { success: true };
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Compiling DualAuthPatcher...');
|
||||
|
||||
const javac = java.replace(/java(\.exe)?$/, 'javac$1');
|
||||
const classpath = [
|
||||
path.join(libDir, 'asm-9.6.jar'),
|
||||
path.join(libDir, 'asm-tree-9.6.jar'),
|
||||
path.join(libDir, 'asm-util-9.6.jar')
|
||||
].join(process.platform === 'win32' ? ';' : ':');
|
||||
|
||||
try {
|
||||
const execOptions = {
|
||||
stdio: 'pipe',
|
||||
cwd: patcherDir,
|
||||
env: { ...process.env }
|
||||
};
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
const systemRoot = process.env.SystemRoot || 'C:\\WINDOWS';
|
||||
const systemPath = `${systemRoot}\\system32;${systemRoot};${systemRoot}\\System32\\Wbem`;
|
||||
execOptions.env.PATH = execOptions.env.PATH
|
||||
? `${systemPath};${execOptions.env.PATH}`
|
||||
: systemPath;
|
||||
execOptions.shell = true;
|
||||
}
|
||||
|
||||
execSync(`"${javac}" -cp "${classpath}" -d "${patcherDir}" "${patcherJava}"`, execOptions);
|
||||
console.log(' Compilation successful');
|
||||
return { success: true };
|
||||
} catch (e) {
|
||||
const error = `Failed to compile DualAuthPatcher: ${e.message}`;
|
||||
console.error(error);
|
||||
if (e.stderr) console.error(e.stderr.toString());
|
||||
return { success: false, error };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run DualAuthPatcher on the server JAR
|
||||
*/
|
||||
async runDualAuthPatcher(java, classpath, serverPath, domain) {
|
||||
return new Promise((resolve) => {
|
||||
const args = ['-cp', classpath, 'DualAuthPatcher', serverPath];
|
||||
const env = { ...process.env, HYTALE_AUTH_DOMAIN: domain };
|
||||
|
||||
console.log(`Running: java ${args.join(' ')}`);
|
||||
console.log(` HYTALE_AUTH_DOMAIN=${domain}`);
|
||||
|
||||
const proc = spawn(java, args, { env, stdio: ['pipe', 'pipe', 'pipe'] });
|
||||
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
|
||||
proc.stdout.on('data', (data) => {
|
||||
const str = data.toString();
|
||||
stdout += str;
|
||||
console.log(str.trim());
|
||||
});
|
||||
|
||||
proc.stderr.on('data', (data) => {
|
||||
const str = data.toString();
|
||||
stderr += str;
|
||||
console.error(str.trim());
|
||||
});
|
||||
|
||||
proc.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve({ success: true, stdout });
|
||||
} else {
|
||||
resolve({ success: false, error: `Patcher exited with code ${code}: ${stderr}` });
|
||||
}
|
||||
});
|
||||
|
||||
proc.on('error', (err) => {
|
||||
resolve({ success: false, error: `Failed to run patcher: ${err.message}` });
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user