import { MinecraftConfig } from '../types'; import { FileUtils } from '../utils/FileUtils'; import { Logger } from '../utils/Logger'; import * as path from 'path'; import axios from 'axios'; import * as fs from 'fs-extra'; import * as stream from 'stream'; import * as util from 'util'; const pipeline = util.promisify(stream.pipeline); const finished = util.promisify(stream.finished); export class ViaVersionManager { private logger = Logger.getInstance(); private readonly VIAVERSION_URL = 'https://github.com/ViaVersion/ViaVersion/releases/download/5.7.2/ViaVersion-5.7.2.jar'; private readonly VIABACKWARDS_URL = 'https://github.com/ViaVersion/ViaBackwards/releases/download/5.7.2/ViaBackwards-5.7.2.jar'; private readonly VIAREWIND_URL = 'https://github.com/ViaVersion/ViaRewind/releases/download/4.0.15/ViaRewind-4.0.15.jar'; public async setup(config: MinecraftConfig): Promise { const pluginsDir = config.folders.plugins; await FileUtils.ensureDir(pluginsDir); this.logger.info('Setting up ViaVersion, ViaBackwards, ViaRewind...'); await this.cleanupRemappedFolders(pluginsDir); await this.downloadViaVersion(pluginsDir); await new Promise(resolve => setTimeout(resolve, 1000)); await this.downloadViaBackwards(pluginsDir); await this.downloadViaRewind(pluginsDir); this.logger.success('ViaVersion suite installed successfully'); } private async cleanupRemappedFolders(pluginsDir: string): Promise { try { const files = await fs.readdir(pluginsDir); for (const file of files) { if (file.includes('.paper-remapped')) { const remappedPath = path.join(pluginsDir, file); const stat = await fs.stat(remappedPath); if (stat.isDirectory()) { await fs.remove(remappedPath); } } } } catch (error) { } } private async downloadFile(url: string, destPath: string, fileName: string): Promise { if (await FileUtils.fileExists(destPath)) { await fs.remove(destPath); } this.logger.info(`Downloading ${fileName}...`); try { const response = await axios({ method: 'GET', url: url, responseType: 'stream', timeout: 60000, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } }); const writer = fs.createWriteStream(destPath); await pipeline(response.data, writer); await finished(writer); const stats = await fs.stat(destPath); if (stats.size < 100000) { throw new Error(`Downloaded file too small: ${stats.size} bytes`); } this.logger.success(`Downloaded ${fileName} (${(stats.size / 1024 / 1024).toFixed(2)} MB)`); } catch (error) { this.logger.error(`Failed to download ${fileName}:`, error); throw error; } } private async downloadViaVersion(pluginsDir: string): Promise { const destPath = path.join(pluginsDir, 'ViaVersion.jar'); await this.downloadFile(this.VIAVERSION_URL, destPath, 'ViaVersion.jar'); } private async downloadViaBackwards(pluginsDir: string): Promise { const destPath = path.join(pluginsDir, 'ViaBackwards.jar'); await this.downloadFile(this.VIABACKWARDS_URL, destPath, 'ViaBackwards.jar'); } private async downloadViaRewind(pluginsDir: string): Promise { const destPath = path.join(pluginsDir, 'ViaRewind.jar'); await this.downloadFile(this.VIAREWIND_URL, destPath, 'ViaRewind.jar'); } public async configureViaVersion(config: MinecraftConfig): Promise { const pluginsDir = config.folders.plugins; const viaConfigDir = path.join(pluginsDir, 'ViaVersion'); await FileUtils.ensureDir(viaConfigDir); const configFile = path.join(viaConfigDir, 'config.yml'); const configContent = `# ViaVersion Configuration enable-client-side-block-updates: true prevent-collision: true auto-team: true suppress-metadata-errors: false enable-legacy-server-ping: true block-connection-method: true nms-player-ticking: true debug: false max-pps: 800 max-pp-interval: 4 fix-self-rendering: true fix-low-level-collision: true shield-blocking: true fix-infested-block-breaking: true ignore-long-1_16-channel: true force-json-transform: false use-natives: true `; await FileUtils.writeFile(configFile, configContent); } }