Skip to content

Commit

Permalink
feat: support Fabric and FabricMod type (#5)
Browse files Browse the repository at this point in the history
* feat: support Fabric and FabricMod type

- rename loadForgeVersionJson to more generic name

* Refactor version json load slightly.

* Update fabric mod dir.

* Upgrade helios-distribution-types.

---------

Co-authored-by: Daniel Scalzi <[email protected]>
  • Loading branch information
jebibot and dscalzi authored Dec 3, 2023
1 parent c5bb9be commit 41417dc
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 45 deletions.
4 changes: 4 additions & 0 deletions lib/common/distribution/DistributionFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,15 @@ export class HeliosModule {
case Type.Library:
case Type.Forge:
case Type.ForgeHosted:
case Type.Fabric:
case Type.LiteLoader:
return join(commonDir, 'libraries', relativePath)
case Type.ForgeMod:
case Type.LiteMod:
// TODO Move to /mods/forge eventually..
return join(commonDir, 'modstore', relativePath)
case Type.FabricMod:
return join(commonDir, 'mods', 'fabric', relativePath)
case Type.File:
default:
return join(instanceDir, this.serverId, relativePath)
Expand Down
43 changes: 22 additions & 21 deletions lib/dl/distribution/DistributionIndexProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { mcVersionAtLeast } from '../../common/util/MojangUtils'
import { ensureDir, readJson, writeJson } from 'fs-extra'
import StreamZip from 'node-stream-zip'
import { dirname } from 'path'
import { VersionJsonBase } from '../mojang/MojangTypes'

export class DistributionIndexProcessor extends IndexProcessor {

Expand Down Expand Up @@ -43,7 +44,7 @@ export class DistributionIndexProcessor extends IndexProcessor {
}

public async postDownload(): Promise<void> {
await this.loadForgeVersionJson()
await this.loadModLoaderVersionJson()
}

private async validateModules(modules: HeliosModule[], accumulator: Asset[]): Promise<void> {
Expand All @@ -67,44 +68,35 @@ export class DistributionIndexProcessor extends IndexProcessor {
}
}

// TODO Type the return type.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public async loadForgeVersionJson(): Promise<any> {
public async loadModLoaderVersionJson(): Promise<VersionJsonBase> {

const server: HeliosServer = this.distribution.getServerById(this.serverId)!
if(server == null) {
throw new AssetGuardError(`Invalid server id ${this.serverId}`)
}

const forgeModule = server.modules.find(({ rawModule: { type } }) => type === Type.ForgeHosted || type === Type.Forge)
const modLoaderModule = server.modules.find(({ rawModule: { type } }) => type === Type.ForgeHosted || type === Type.Forge || type === Type.Fabric)

if(forgeModule == null) {
throw new AssetGuardError('No Forge module found!')
if(modLoaderModule == null) {
throw new AssetGuardError('No mod loader found!')
}

if(DistributionIndexProcessor.isForgeGradle3(server.rawServer.minecraftVersion, forgeModule.getMavenComponents().version)) {

const versionManifstModule = forgeModule.subModules.find(({ rawModule: { type }}) => type === Type.VersionManifest)
if(versionManifstModule == null) {
throw new AssetGuardError('No Forge version manifest module found!')
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return await readJson(versionManifstModule.getPath(), 'utf-8')

if(modLoaderModule.rawModule.type === Type.Fabric
|| DistributionIndexProcessor.isForgeGradle3(server.rawServer.minecraftVersion, modLoaderModule.getMavenComponents().version)) {
return await this.loadVersionManifest<VersionJsonBase>(modLoaderModule)
} else {

const zip = new StreamZip.async({ file: forgeModule.getPath() })
const zip = new StreamZip.async({ file: modLoaderModule.getPath() })

try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const data = JSON.parse((await zip.entryData('version.json')).toString('utf8'))
const writePath = getVersionJsonPath(this.commonDir, data.id as string)

const data = JSON.parse((await zip.entryData('version.json')).toString('utf8')) as VersionJsonBase
const writePath = getVersionJsonPath(this.commonDir, data.id)

await ensureDir(dirname(writePath))
await writeJson(writePath, data)

// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return data
}
finally {
Expand All @@ -114,6 +106,15 @@ export class DistributionIndexProcessor extends IndexProcessor {
}
}

public async loadVersionManifest<T>(modLoaderModule: HeliosModule): Promise<T> {
const versionManifstModule = modLoaderModule.subModules.find(({ rawModule: { type }}) => type === Type.VersionManifest)
if(versionManifstModule == null) {
throw new AssetGuardError('No mod loader version manifest module found!')
}

return await readJson(versionManifstModule.getPath(), 'utf-8') as T
}

// TODO Move this to a util maybe
public static isForgeGradle3(mcVersion: string, forgeVersion: string): boolean {

Expand Down
20 changes: 10 additions & 10 deletions lib/dl/mojang/MojangIndexProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ensureDir, pathExists, readFile, readJson, writeFile } from 'fs-extra'
import { Asset, HashAlgo } from '../Asset'
import { AssetGuardError } from '../AssetGuardError'
import { IndexProcessor } from '../IndexProcessor'
import { AssetIndex, LibraryArtifact, MojangVersionManifest, VersionJson } from './MojangTypes'
import { AssetIndex, LibraryArtifact, MojangVersionManifest, VersionJsonBase } from './MojangTypes'
import { calculateHashByBuffer, getLibraryDir, getVersionJarPath, getVersionJsonPath, validateLocalFile } from '../../common/util/FileUtils'
import { getMojangOS, isLibraryCompatible } from '../../common/util/MojangUtils'
import { LoggerUtil } from '../../util/LoggerUtil'
Expand All @@ -19,7 +19,7 @@ export class MojangIndexProcessor extends IndexProcessor {

private static readonly logger = LoggerUtil.getLogger('MojangIndexProcessor')

private versionJson!: VersionJson
private versionJson!: VersionJsonBase
private assetIndex!: AssetIndex
private client = got.extend({
responseType: 'json'
Expand Down Expand Up @@ -67,12 +67,12 @@ export class MojangIndexProcessor extends IndexProcessor {
}

// Can be called without init - needed for launch process.
public async getVersionJson(): Promise<VersionJson> {
public async getVersionJson(): Promise<VersionJsonBase> {
const versionManifest = await this.loadVersionManifest()
return await this.loadVersionJson(this.version, versionManifest)
}

private async loadAssetIndex(versionJson: VersionJson): Promise<AssetIndex> {
private async loadAssetIndex(versionJson: VersionJsonBase): Promise<AssetIndex> {
const assetIndexPath = this.getAssetIndexPath(versionJson.assetIndex.id)
const assetIndex = await this.loadContentWithRemoteFallback<AssetIndex>(versionJson.assetIndex.url, assetIndexPath, { algo: HashAlgo.SHA1, value: versionJson.assetIndex.sha1 })
if(assetIndex == null) {
Expand All @@ -81,14 +81,14 @@ export class MojangIndexProcessor extends IndexProcessor {
return assetIndex
}

private async loadVersionJson(version: string, versionManifest: MojangVersionManifest | null): Promise<VersionJson> {
private async loadVersionJson(version: string, versionManifest: MojangVersionManifest | null): Promise<VersionJsonBase> {
const versionJsonPath = getVersionJsonPath(this.commonDir, version)
if(versionManifest != null) {
const versionInfo = versionManifest.versions.find(({ id }) => id === version)
if(versionInfo == null) {
throw new AssetGuardError(`Invalid version: ${version}.`)
}
const versionJson = await this.loadContentWithRemoteFallback<VersionJson>(versionInfo.url, versionJsonPath, { algo: HashAlgo.SHA1, value: versionInfo.sha1 })
const versionJson = await this.loadContentWithRemoteFallback<VersionJsonBase>(versionInfo.url, versionJsonPath, { algo: HashAlgo.SHA1, value: versionInfo.sha1 })
if(versionJson == null) {
throw new AssetGuardError(`Failed to download ${version} json index.`)
}
Expand All @@ -98,7 +98,7 @@ export class MojangIndexProcessor extends IndexProcessor {
} else {
// Attempt to find local index.
if(await pathExists(versionJsonPath)) {
return await readJson(versionJsonPath) as VersionJson
return await readJson(versionJsonPath) as VersionJsonBase
} else {
throw new AssetGuardError(`Unable to load version manifest and ${version} json index does not exist locally.`)
}
Expand Down Expand Up @@ -204,7 +204,7 @@ export class MojangIndexProcessor extends IndexProcessor {

}

private async validateLibraries(versionJson: VersionJson): Promise<Asset[]> {
private async validateLibraries(versionJson: VersionJsonBase): Promise<Asset[]> {

const libDir = getLibraryDir(this.commonDir)
const notValid: Asset[] = []
Expand Down Expand Up @@ -241,7 +241,7 @@ export class MojangIndexProcessor extends IndexProcessor {
return notValid
}

private async validateClient(versionJson: VersionJson): Promise<Asset[]> {
private async validateClient(versionJson: VersionJsonBase): Promise<Asset[]> {

const version = versionJson.id
const versionJarPath = getVersionJarPath(this.commonDir, version)
Expand All @@ -262,7 +262,7 @@ export class MojangIndexProcessor extends IndexProcessor {

}

private async validateLogConfig(versionJson: VersionJson): Promise<Asset[]> {
private async validateLogConfig(versionJson: VersionJsonBase): Promise<Asset[]> {

const logFile = versionJson.logging.client.file
const path = join(this.assetPath, 'log_configs', logFile.id)
Expand Down
29 changes: 20 additions & 9 deletions lib/dl/mojang/MojangTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,8 @@ export interface Library {
rules?: Rule[]
}

export interface VersionJson {
export interface VersionJsonBase {

arguments: {
game: string[]
jvm: {
rules: Rule[]
value: string[]
}[]
}
assetIndex: {
id: string
sha1: string
Expand All @@ -70,6 +63,10 @@ export interface VersionJson {
server: BaseArtifact
}
id: string
/**
* Only on modloader version properties (extend and override base version)
*/
inheritsFrom?: string
libraries: Library[]
logging: {
client: {
Expand All @@ -84,11 +81,25 @@ export interface VersionJson {
}
}
mainClass: string
minimumLauncherVersion: number
releaseTime: string
time: string
type: string
}

export interface VersionJsonLegacy extends VersionJsonBase {
minecraftArguments: string
}

export interface VersionJsonNew extends VersionJsonBase {
arguments: {
game: (string | RuleBasedArgument)[]
jvm: (string | RuleBasedArgument)[]
}
}

export interface RuleBasedArgument {
rules: Rule[]
value: string | string[]
}

export interface AssetIndex {
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"chai-as-promised": "^7.1.1",
"cross-env": "^7.0.3",
"eslint": "^8.50.0",
"helios-distribution-types": "^1.2.0",
"helios-distribution-types": "^1.3.0",
"mocha": "^10.2.0",
"nock": "^13.3.8",
"rimraf": "^5.0.5",
Expand Down

0 comments on commit 41417dc

Please sign in to comment.