From aeef30e3c8af4f6d822286aeb226a47692a2ee2c Mon Sep 17 00:00:00 2001 From: Daniel Scalzi Date: Sat, 18 Jan 2020 10:50:28 -0500 Subject: [PATCH] Initial work on 1.13 forge resolver, fixes. Moved java executable to its own util class. Fixed artifact resolution links for older versions of forge. 1.13 support is going to be difficult because forge does not make anything developer friendly. --- .vscode/launch.json | 5 +- src/index.ts | 3 +- src/model/forge/versionmanifest.ts | 3 +- src/model/struct/model/server.struct.ts | 2 +- src/model/struct/repo/repo.struct.ts | 4 ++ .../forge/adapter/forge113.resolver.ts | 58 ++++++++++++++++++- .../forge/adapter/forge18.resolver.ts | 11 ++-- src/resolver/forge/forge.resolver.ts | 50 ++++++++++++++++ src/util/PackXZExtractWrapper.ts | 7 +-- src/util/javautil.ts | 7 +++ src/util/versionutil.ts | 2 +- 11 files changed, 133 insertions(+), 19 deletions(-) create mode 100644 src/util/javautil.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 4d659ac..3639121 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,9 +10,8 @@ "name": "Launch Program", "program": "${workspaceFolder}\\src\\index.ts", "args": [ - "test", - "1.12.2", - "14.23.5.2847" + "g", + "distro" ], "preLaunchTask": "compile", "outFiles": [ diff --git a/src/index.ts b/src/index.ts index 33d860f..387b525 100644 --- a/src/index.ts +++ b/src/index.ts @@ -217,7 +217,8 @@ const testCommand: yargs.CommandModule = { handler: async (argv) => { console.debug(`Invoked test with mcVer ${argv.mcVer} forgeVer ${argv.forgeVer}`) console.log(process.cwd()) - const resolver = ResolverRegistry.getForgeResolver('1.12.2', '14.23.5.2847', getRoot(), '', getBaseURL()) + const resolver = ResolverRegistry.getForgeResolver(argv.mcVer as string, + argv.forgeVer as string, getRoot(), '', getBaseURL()) if (resolver != null) { const mdl = await resolver.getModule() console.log(inspect(mdl, false, null, true)) diff --git a/src/model/forge/versionmanifest.ts b/src/model/forge/versionmanifest.ts index bbf54f3..b029c16 100644 --- a/src/model/forge/versionmanifest.ts +++ b/src/model/forge/versionmanifest.ts @@ -14,7 +14,8 @@ export interface VersionManifest { url?: string, checksums?: string[], serverreq?: boolean, - clientreq?: boolean + clientreq?: boolean, + comment?: string }> } diff --git a/src/model/struct/model/server.struct.ts b/src/model/struct/model/server.struct.ts index 73b4687..b767f3f 100644 --- a/src/model/struct/model/server.struct.ts +++ b/src/model/struct/model/server.struct.ts @@ -103,7 +103,7 @@ export class ServerStructure extends BaseModelStructure { const forgeResolver = ResolverRegistry.getForgeResolver( match[2], serverMeta.forgeVersion, - dirname(this.absoluteRoot), + dirname(this.containerDirectory), '', this.baseUrl ) diff --git a/src/model/struct/repo/repo.struct.ts b/src/model/struct/repo/repo.struct.ts index 954f98a..eb6d5c4 100644 --- a/src/model/struct/repo/repo.struct.ts +++ b/src/model/struct/repo/repo.struct.ts @@ -43,4 +43,8 @@ export class RepoStructure extends BaseFileStructure { return join(this.absoluteRoot, 'temp') } + public getWorkDirectory() { + return join(this.absoluteRoot, 'work') + } + } diff --git a/src/resolver/forge/adapter/forge113.resolver.ts b/src/resolver/forge/adapter/forge113.resolver.ts index 9e59f1f..fc8abc4 100644 --- a/src/resolver/forge/adapter/forge113.resolver.ts +++ b/src/resolver/forge/adapter/forge113.resolver.ts @@ -1,4 +1,9 @@ +import { spawn } from 'child_process' +import { copy, mkdirs, pathExists, remove, writeFile } from 'fs-extra' +import { basename, join } from 'path' import { Module } from '../../../model/spec/module' +import { ForgeRepoStructure } from '../../../model/struct/repo/forgerepo.struct' +import { JavaUtil } from '../../../util/javautil' import { ForgeResolver } from '../forge.resolver' export class Forge113Adapter extends ForgeResolver { @@ -18,11 +23,62 @@ export class Forge113Adapter extends ForgeResolver { } public async getModule(): Promise { - return null as unknown as Module + await this.process() + return {} as unknown as Module } public isForVersion(version: string): boolean { return Forge113Adapter.isForVersion(version) } + private async process() { + const forgeRepo = this.repoStructure.getForgeRepoStruct() + const installerPath = forgeRepo.getLocalForge(this.artifactVersion, 'installer') + console.debug(`Checking for forge installer at ${installerPath}..`) + if (!await forgeRepo.artifactExists(installerPath)) { + console.debug(`Forge installer not found locally, initializing download..`) + await forgeRepo.downloadArtifactByComponents( + this.REMOTE_REPOSITORY, + ForgeRepoStructure.FORGE_GROUP, + ForgeRepoStructure.FORGE_ARTIFACT, + this.artifactVersion, 'installer', 'jar' + ) + } else { + console.debug('Using locally discovered forge installer.') + } + console.debug(`Beginning processing of Forge v${this.forgeVersion} (Minecraft ${this.minecraftVersion})`) + + const workDir = this.repoStructure.getWorkDirectory() + if (await pathExists(workDir)) { + await remove(workDir) + } + + await mkdirs(workDir) + + const workingInstaller = join(workDir, basename(installerPath)) + + await copy(installerPath, workingInstaller) + + // Required for the installer to function. + await writeFile(join(workDir, 'launcher_profiles.json'), JSON.stringify({})) + + console.debug(`Spawning forge installer`) + + } + + private executeInstaller(installerExec: string) { + return new Promise((resolve, reject) => { + const child = spawn(JavaUtil.getJavaExecutable(), [ + '-jar', + installerExec + ]) + child.stdout.on('data', (data) => console.log('[Forge Installer]', data.toString('utf8'))) + child.stderr.on('data', (data) => console.error('[Forge Installer]', data.toString('utf8'))) + child.on('close', (code, signal) => { + console.log('[Forge Installer]', 'Exited with code', code) + resolve() + }) + }) + } + } diff --git a/src/resolver/forge/adapter/forge18.resolver.ts b/src/resolver/forge/adapter/forge18.resolver.ts index 8019609..37adbd9 100644 --- a/src/resolver/forge/adapter/forge18.resolver.ts +++ b/src/resolver/forge/adapter/forge18.resolver.ts @@ -14,7 +14,7 @@ import { ForgeResolver } from '../forge.resolver' export class Forge18Adapter extends ForgeResolver { public static isForVersion(version: string) { - return Forge18Adapter.isVersionAcceptable(version, [8, 9, 10, 11, 12]) + return Forge18Adapter.isVersionAcceptable(version, [7, 8, 9, 10, 11, 12]) } constructor( @@ -37,8 +37,7 @@ export class Forge18Adapter extends ForgeResolver { public async getForgeByVersion() { const forgeRepo = this.repoStructure.getForgeRepoStruct() - const artifactVersion = `${this.minecraftVersion}-${this.forgeVersion}` - const targetLocalPath = forgeRepo.getLocalForge(artifactVersion, 'universal') + const targetLocalPath = forgeRepo.getLocalForge(this.artifactVersion, 'universal') console.debug(`Checking for forge version at ${targetLocalPath}..`) if (!await forgeRepo.artifactExists(targetLocalPath)) { console.debug(`Forge not found locally, initializing download..`) @@ -46,7 +45,7 @@ export class Forge18Adapter extends ForgeResolver { this.REMOTE_REPOSITORY, ForgeRepoStructure.FORGE_GROUP, ForgeRepoStructure.FORGE_ARTIFACT, - artifactVersion, 'universal', 'jar') + this.artifactVersion, 'universal', 'jar') } else { console.debug('Using locally discovered forge.') } @@ -75,7 +74,7 @@ export class Forge18Adapter extends ForgeResolver { id: MavenUtil.mavenComponentsToIdentifier( ForgeRepoStructure.FORGE_GROUP, ForgeRepoStructure.FORGE_ARTIFACT, - artifactVersion, 'universal' + this.artifactVersion, 'universal' ), name: 'Minecraft Forge', type: Type.ForgeHosted, @@ -86,7 +85,7 @@ export class Forge18Adapter extends ForgeResolver { this.baseUrl, ForgeRepoStructure.FORGE_GROUP, ForgeRepoStructure.FORGE_ARTIFACT, - artifactVersion, 'universal' + this.artifactVersion, 'universal' ) ), subModules: [] diff --git a/src/resolver/forge/forge.resolver.ts b/src/resolver/forge/forge.resolver.ts index 49f99ba..41343c5 100644 --- a/src/resolver/forge/forge.resolver.ts +++ b/src/resolver/forge/forge.resolver.ts @@ -6,6 +6,7 @@ export abstract class ForgeResolver extends BaseResolver { protected readonly REMOTE_REPOSITORY = 'https://files.minecraftforge.net/maven/' protected repoStructure: RepoStructure + protected artifactVersion: string constructor( absoluteRoot: string, @@ -16,6 +17,55 @@ export abstract class ForgeResolver extends BaseResolver { ) { super(absoluteRoot, relativeRoot, baseUrl) this.repoStructure = new RepoStructure(absoluteRoot, relativeRoot) + this.artifactVersion = this.inferArtifactVersion() + } + + // Coverage is not 100% but that doesnt matter. + // It's enough and you should always use the latest version anyway. + public inferArtifactVersion() { + const version = `${this.minecraftVersion}-${this.forgeVersion}` + + const ver = this.forgeVersion.split('.') + const major = Number(ver[0]) + if ([12, 11, 10].indexOf(major) > -1) { + const minor = Number(ver[1]) + const revision = Number(ver[2]) + const extra = Number(ver[3]) + + if (major === 10) { + if (minor === 13 && revision >= 2 && extra >= 1300) { + return `${version}-1.7.10` + } + } else + if (major === 11) { + if (minor === 15) { + if (revision === 1 && extra >= 1890) { + return `${version}-1.8.9` + } else + if (revision === 0 && extra <= 1654) { + return `${version}-1.8.8` + } + } else + if (minor === 14 && revision === 0 && extra <= 1295) { + return `${version}-1.8` + } + } else + if (major === 12) { + if (minor === 17 && revision === 0 && extra <= 1936) { + return `${version}-1.9.4` + } else + if (minor === 16) { + if (revision === 0 && extra <= 1885) { + return `${version}-1.9` + } else + if (revision === 1 && extra === 1938) { + return `${version}-1.9.0` + } + } + } + + } + return version } } diff --git a/src/util/PackXZExtractWrapper.ts b/src/util/PackXZExtractWrapper.ts index 273874f..69164fb 100644 --- a/src/util/PackXZExtractWrapper.ts +++ b/src/util/PackXZExtractWrapper.ts @@ -1,12 +1,9 @@ import { spawn } from 'child_process' import { join } from 'path' +import { JavaUtil } from './javautil' export class PackXZExtractWrapper { - public static getJavaExecutable() { - return process.env.JAVA_EXECUTABLE as string - } - public static getPackXZExtract() { return join(process.cwd(), 'libraries', 'java', 'PackXZExtract.jar') } @@ -25,7 +22,7 @@ export class PackXZExtractWrapper { private static execute(command: string, paths: string[]) { return new Promise((resolve, reject) => { - const child = spawn(PackXZExtractWrapper.getJavaExecutable(), [ + const child = spawn(JavaUtil.getJavaExecutable(), [ '-jar', PackXZExtractWrapper.getPackXZExtract(), command, diff --git a/src/util/javautil.ts b/src/util/javautil.ts new file mode 100644 index 0000000..a6bef2d --- /dev/null +++ b/src/util/javautil.ts @@ -0,0 +1,7 @@ +export class JavaUtil { + + public static getJavaExecutable() { + return process.env.JAVA_EXECUTABLE as string + } + +} diff --git a/src/util/versionutil.ts b/src/util/versionutil.ts index efb2c06..4cdcf5a 100644 --- a/src/util/versionutil.ts +++ b/src/util/versionutil.ts @@ -17,7 +17,7 @@ export class VersionUtil { } } } - return null + throw new Error(`${version} is not a valid minecraft version!`) } }