first commit
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import { spawn } from 'child_process'
|
||||
import { parse as parseToml } from 'smol-toml'
|
||||
import { paths } from './paths'
|
||||
import { config } from '../shared/config'
|
||||
import { fetchText } from './download'
|
||||
import { emit } from './events'
|
||||
|
||||
/**
|
||||
* Gestion du modpack côté launcher :
|
||||
* - lecture du pack.toml packwiz distant (versions MC/NeoForge = source de vérité)
|
||||
* - sync incrémentale des mods/configs via packwiz-installer-bootstrap.
|
||||
*
|
||||
* packwiz-installer garde un manifeste local (packwiz.json dans l'instance) et
|
||||
* ne re-télécharge QUE les fichiers dont le hash a changé — c'est exactement le
|
||||
* comportement "pas de re-download complet à chaque update" recherché.
|
||||
*/
|
||||
|
||||
export interface PackMeta {
|
||||
name: string
|
||||
version: string
|
||||
minecraft: string
|
||||
neoforge: string
|
||||
}
|
||||
|
||||
/** Télécharge et parse le pack.toml distant. */
|
||||
export async function fetchPackMeta(): Promise<PackMeta> {
|
||||
emit.progress({ phase: 'pack-meta', message: 'Lecture du modpack…', progress: undefined })
|
||||
|
||||
if (!config.packTomlUrl || config.packTomlUrl.includes('CHANGE_ME')) {
|
||||
throw new Error(
|
||||
'URL du pack.toml non configurée. Renseigne packTomlUrl dans src/shared/config.ts.'
|
||||
)
|
||||
}
|
||||
|
||||
const raw = await fetchText(config.packTomlUrl)
|
||||
const data = parseToml(raw) as {
|
||||
name?: string
|
||||
version?: string
|
||||
versions?: { minecraft?: string; neoforge?: string }
|
||||
}
|
||||
|
||||
const minecraft = data.versions?.minecraft
|
||||
const neoforge = data.versions?.neoforge
|
||||
if (!minecraft || !neoforge) {
|
||||
throw new Error(
|
||||
'pack.toml invalide : [versions] doit contenir "minecraft" et "neoforge".'
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
name: data.name ?? 'Modpack',
|
||||
version: data.version ?? '0',
|
||||
minecraft,
|
||||
neoforge
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lance packwiz-installer-bootstrap pour synchroniser l'instance.
|
||||
* `java` = chemin du binaire Java 21 géré (réutilisé pour faire tourner le jar).
|
||||
*/
|
||||
export async function syncModpack(javaPath: string): Promise<void> {
|
||||
emit.progress({ phase: 'modpack', message: 'Synchronisation du modpack…', progress: undefined })
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const child = spawn(
|
||||
javaPath,
|
||||
['-jar', paths.packwizBootstrapJar, '-g', '-s', 'client', config.packTomlUrl],
|
||||
{ cwd: paths.instanceDir }
|
||||
)
|
||||
|
||||
// On garde les dernières lignes de sortie pour pouvoir afficher la VRAIE
|
||||
// erreur de packwiz si le process échoue.
|
||||
const recent: string[] = []
|
||||
const onLine = (buf: Buffer): void => {
|
||||
for (const line of buf.toString().split(/\r?\n/)) {
|
||||
const text = line.trim()
|
||||
if (!text) continue
|
||||
recent.push(text)
|
||||
if (recent.length > 25) recent.shift()
|
||||
emit.progress({ phase: 'modpack', message: text, progress: undefined })
|
||||
// Visible aussi dans la console du launcher.
|
||||
emit.gameLog({ stream: 'stdout', line: `[packwiz] ${text}` })
|
||||
}
|
||||
}
|
||||
child.stdout.on('data', onLine)
|
||||
child.stderr.on('data', onLine)
|
||||
|
||||
child.on('error', reject)
|
||||
child.on('close', (code) => {
|
||||
if (code === 0) return resolve()
|
||||
const tail = recent.slice(-12).join('\n')
|
||||
reject(
|
||||
new Error(
|
||||
`packwiz-installer a échoué (code ${code}).` +
|
||||
(tail ? `\nDernières lignes :\n${tail}` : '')
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
emit.progress({ phase: 'modpack', message: 'Modpack à jour.', progress: 1 })
|
||||
}
|
||||
Reference in New Issue
Block a user