-
Notifications
You must be signed in to change notification settings - Fork 27
/
labymod.ts
148 lines (128 loc) · 5.11 KB
/
labymod.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import { MinecraftFolder, MinecraftLocation, LibraryInfo } from '@xmcl/core'
import { DownloadBaseOptions } from '@xmcl/file-transfer'
import { Task, task, AbortableTask, CancelledError } from '@xmcl/task'
import { writeFile } from 'fs/promises'
import { dirname } from 'path'
import { Dispatcher, request } from 'undici'
import { DownloadTask } from './downloadTask'
import { ensureDir } from './utils'
export interface LabyModManifest {
labyModVersion: string
commitReference: string
sha1: string
releaseTime: number
size: number
assets: {
shader: string
common: string
fonts: string
'vanilla-theme': string
'fancy-theme': string
i18n: string
}
minecraftVersions: MinecraftVersion[]
}
interface MinecraftVersion {
tag: string
version: string
index: number
type: string
runtime: {
name: string
version: number
}
customManifestUrl: string
}
export async function getLabyModManifest(env = 'production', options?: { dispatcher?: Dispatcher }): Promise<LabyModManifest> {
const url = `https://laby-releases.s3.de.io.cloud.ovh.net/api/v1/manifest/${env}/latest.json`
const res = await request(url, options)
return await res.body.json() as any
}
export interface InstallLabyModOptions extends DownloadBaseOptions {
dispatcher?: Dispatcher
environment?: string
}
class JsonTask extends AbortableTask<string> {
private controller = new AbortController()
constructor(private manifest: LabyModManifest, private tag: string, private folder: MinecraftFolder, private environment: string, private dispatcher?: Dispatcher) {
super()
this.name = 'json'
this.param = { version: tag }
}
protected async process(): Promise<string> {
this.controller = new AbortController()
const librariesUrl = `https://laby-releases.s3.de.io.cloud.ovh.net/api/v1/libraries/${this.environment}.json`
const versionInfo = this.manifest.minecraftVersions.find((v) => v.tag === this.tag)!
interface LibInfo {
name: string
url: string
minecraftVersion: string
sha1: string
size: number
natives: any[]
resolvedAt: number
}
// Get version json and merge with libraries
const libraries: LibInfo[] = await request(librariesUrl, { dispatcher: this.dispatcher, signal: this.controller.signal })
.then((res) => res.body.json() as any)
.then((res) => res.libraries as LibInfo[])
.then((libs) => libs.filter(lib => lib.minecraftVersion === 'all' || lib.minecraftVersion === this.tag))
const versionJson = await request(versionInfo.customManifestUrl, { dispatcher: this.dispatcher, signal: this.controller.signal }).then((res) => res.body.json() as any)
versionJson.libraries.push(...libraries.map((l) => ({
name: l.name,
downloads: {
artifact: {
path: LibraryInfo.resolve(l.name).path,
sha1: l.sha1,
size: l.size,
url: l.url,
},
},
})), {
name: `net.labymod:LabyMod:${this.manifest.labyModVersion}`,
downloads: {
artifact: {
path: `net/labymod/LabyMod/${this.manifest.labyModVersion}/LabyMod-${this.manifest.labyModVersion}.jar`,
sha1: this.manifest.sha1,
size: this.manifest.size,
url: `https://laby-releases.s3.de.io.cloud.ovh.net/api/v1/download/labymod4/${this.environment}/${this.manifest.commitReference}.jar`,
},
},
})
versionJson.id = `LabyMod-4-${this.tag}-${this.manifest.commitReference}`
// write json to file
const versionPath = this.folder.getPath('versions', versionJson.id, `${versionJson.id}.json`)
await ensureDir(dirname(versionPath))
await writeFile(versionPath, JSON.stringify(versionJson, null, 4))
return versionJson.id
}
protected abort(isCancelled: boolean): void {
this.controller.abort(new CancelledError())
}
protected isAbortedError(e: any): boolean {
return e instanceof CancelledError
}
}
export function installLabyMod4Task(manifest: LabyModManifest, tag: string, minecraft: MinecraftLocation, options?: InstallLabyModOptions): Task<string> {
return task('installLabyMod', async function () {
const folder = MinecraftFolder.from(minecraft)
const environment = options?.environment ?? 'production'
const versionId = await this.yield(new JsonTask(manifest, tag, folder, environment, options?.dispatcher))
// Download assets
for (const [name, hash] of Object.entries(manifest.assets)) {
const url = `https://laby-releases.s3.de.io.cloud.ovh.net/api/v1/download/assets/labymod4/${environment}/${manifest.commitReference}/${name}/${hash}.jar`
const destination = folder.getPath('labymod-neo', 'assets', `${name}.jar`)
await this.yield(new DownloadTask({
url,
destination,
validator: { algorithm: 'sha1', hash },
agent: options?.agent,
headers: options?.headers,
}).setName('asset', { name }))
}
return versionId
})
}
export function installLaby4Mod(manifest: LabyModManifest, tag: string, minecraft: MinecraftLocation, options?: InstallLabyModOptions): Promise<string> {
return installLabyMod4Task(manifest, tag, minecraft, options).startAndWait()
}