fix: fix auth problem
This commit is contained in:
+4
-2
@@ -46,9 +46,11 @@ class LauncherPaths {
|
|||||||
return this.ensure(join(this.root, 'java'))
|
return this.ensure(join(this.root, 'java'))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Cache des tokens d'auth (prismarine-auth). */
|
/** Cache des tokens d'auth (prismarine-auth). Toujours dans userData,
|
||||||
|
* indépendamment de dataDir — les tokens survivent ainsi aux changements
|
||||||
|
* de dossier de données et aux mises à jour du launcher. */
|
||||||
get authCache(): string {
|
get authCache(): string {
|
||||||
return this.ensure(join(this.root, 'auth-cache'))
|
return this.ensure(join(app.getPath('userData'), 'auth-cache'))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fichier de réglages utilisateur. */
|
/** Fichier de réglages utilisateur. */
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { fetchPackMeta } from './modpack'
|
|||||||
import { ensureJava } from './java'
|
import { ensureJava } from './java'
|
||||||
import { installMinecraft, installNeoForge } from './install'
|
import { installMinecraft, installNeoForge } from './install'
|
||||||
import { syncModpack } from './modpack'
|
import { syncModpack } from './modpack'
|
||||||
|
import { ensureServerInList } from './server-list'
|
||||||
import { launchGame } from './launch'
|
import { launchGame } from './launch'
|
||||||
import { getSettings } from './settings'
|
import { getSettings } from './settings'
|
||||||
import { emit } from './events'
|
import { emit } from './events'
|
||||||
@@ -42,6 +43,7 @@ export async function play(opts?: PlayOptions): Promise<void> {
|
|||||||
await installMinecraft(meta.minecraft, repair)
|
await installMinecraft(meta.minecraft, repair)
|
||||||
const versionId = await installNeoForge(meta.neoforge, meta.minecraft, javaPath, repair)
|
const versionId = await installNeoForge(meta.neoforge, meta.minecraft, javaPath, repair)
|
||||||
await syncModpack(javaPath)
|
await syncModpack(javaPath)
|
||||||
|
await ensureServerInList()
|
||||||
|
|
||||||
const settings = await getSettings()
|
const settings = await getSettings()
|
||||||
const proc = await launchGame(versionId, auth, javaPath, settings)
|
const proc = await launchGame(versionId, auth, javaPath, settings)
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
import { readFile, writeFile } from 'fs/promises'
|
||||||
|
import { join } from 'path'
|
||||||
|
import { paths } from './paths'
|
||||||
|
import { config } from '../shared/config'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assure que le serveur configuré est présent dans servers.dat de l'instance.
|
||||||
|
* Si le fichier n'existe pas, il est créé. Si le serveur est déjà listé (même
|
||||||
|
* IP), rien n'est modifié pour ne pas écraser les préférences utilisateur.
|
||||||
|
*
|
||||||
|
* servers.dat : NBT non compressé (contrairement à level.dat).
|
||||||
|
* Structure : TAG_Compound root -> TAG_List "servers" -> TAG_Compound[] serveurs.
|
||||||
|
*/
|
||||||
|
export async function ensureServerInList(): Promise<void> {
|
||||||
|
if (!config.serverAddress?.trim()) return
|
||||||
|
|
||||||
|
const ip = config.serverAddress.trim()
|
||||||
|
const serversDat = join(paths.instanceDir, 'servers.dat')
|
||||||
|
|
||||||
|
let servers: ServerEntry[] = []
|
||||||
|
|
||||||
|
try {
|
||||||
|
const buf = await readFile(serversDat)
|
||||||
|
servers = decodeServersDat(buf)
|
||||||
|
} catch {
|
||||||
|
// Fichier absent ou illisible : on part d'une liste vide.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (servers.some((s) => s.ip === ip)) return
|
||||||
|
|
||||||
|
// Notre serveur en tête de liste.
|
||||||
|
servers = [{ name: config.appName, ip }, ...servers]
|
||||||
|
await writeFile(serversDat, encodeServersDat(servers))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Types internes
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
interface ServerEntry {
|
||||||
|
name: string
|
||||||
|
ip: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Encodeur NBT minimal
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function b1(n: number): Buffer {
|
||||||
|
return Buffer.from([n])
|
||||||
|
}
|
||||||
|
function b2(n: number): Buffer {
|
||||||
|
const b = Buffer.allocUnsafe(2)
|
||||||
|
b.writeUInt16BE(n)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
function b4(n: number): Buffer {
|
||||||
|
const b = Buffer.allocUnsafe(4)
|
||||||
|
b.writeInt32BE(n)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
function encStr(s: string): Buffer {
|
||||||
|
const d = Buffer.from(s, 'utf8')
|
||||||
|
return Buffer.concat([b2(d.length), d])
|
||||||
|
}
|
||||||
|
function encTag(type: number, name: string, payload: Buffer): Buffer {
|
||||||
|
return Buffer.concat([b1(type), encStr(name), payload])
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeServersDat(servers: ServerEntry[]): Buffer {
|
||||||
|
const entries = servers.flatMap((s) => [
|
||||||
|
encTag(8, 'name', encStr(s.name)),
|
||||||
|
encTag(8, 'ip', encStr(s.ip)),
|
||||||
|
encTag(1, 'acceptTextures', b1(1)),
|
||||||
|
b1(0) // TAG_End clôture le compound dans la liste
|
||||||
|
])
|
||||||
|
|
||||||
|
const listPayload = Buffer.concat([b1(10), b4(servers.length), ...entries])
|
||||||
|
const rootPayload = Buffer.concat([encTag(9, 'servers', listPayload), b1(0)])
|
||||||
|
return Buffer.concat([b1(10), encStr(''), rootPayload])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Décodeur NBT minimal
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
interface Reader {
|
||||||
|
buf: Buffer
|
||||||
|
pos: number
|
||||||
|
}
|
||||||
|
|
||||||
|
function ru8(r: Reader): number {
|
||||||
|
return r.buf[r.pos++]
|
||||||
|
}
|
||||||
|
function ru16(r: Reader): number {
|
||||||
|
const v = r.buf.readUInt16BE(r.pos)
|
||||||
|
r.pos += 2
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
function ri32(r: Reader): number {
|
||||||
|
const v = r.buf.readInt32BE(r.pos)
|
||||||
|
r.pos += 4
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
function rstr(r: Reader): string {
|
||||||
|
const len = ru16(r)
|
||||||
|
const s = r.buf.subarray(r.pos, r.pos + len).toString('utf8')
|
||||||
|
r.pos += len
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
function skipPayload(r: Reader, type: number): void {
|
||||||
|
switch (type) {
|
||||||
|
case 1: r.pos++; return // TAG_Byte
|
||||||
|
case 2: r.pos += 2; return // TAG_Short
|
||||||
|
case 3: r.pos += 4; return // TAG_Int
|
||||||
|
case 4: r.pos += 8; return // TAG_Long
|
||||||
|
case 5: r.pos += 4; return // TAG_Float
|
||||||
|
case 6: r.pos += 8; return // TAG_Double
|
||||||
|
case 7: r.pos += ri32(r); return // TAG_Byte_Array
|
||||||
|
case 8: r.pos += ru16(r); return // TAG_String
|
||||||
|
case 9: { // TAG_List
|
||||||
|
const et = ru8(r)
|
||||||
|
const n = ri32(r)
|
||||||
|
for (let i = 0; i < n; i++) skipPayload(r, et)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case 10: { // TAG_Compound
|
||||||
|
while (r.pos < r.buf.length) {
|
||||||
|
const t = ru8(r)
|
||||||
|
if (t === 0) return
|
||||||
|
r.pos += ru16(r) // skip name
|
||||||
|
skipPayload(r, t)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case 11: r.pos += ri32(r) * 4; return // TAG_Int_Array
|
||||||
|
case 12: r.pos += ri32(r) * 8; return // TAG_Long_Array
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeServersDat(buf: Buffer): ServerEntry[] {
|
||||||
|
const r: Reader = { buf, pos: 0 }
|
||||||
|
|
||||||
|
if (ru8(r) !== 10) return [] // root doit être TAG_Compound
|
||||||
|
rstr(r) // nom de la racine (vide)
|
||||||
|
|
||||||
|
const servers: ServerEntry[] = []
|
||||||
|
|
||||||
|
while (r.pos < buf.length) {
|
||||||
|
const type = ru8(r)
|
||||||
|
if (type === 0) break
|
||||||
|
|
||||||
|
const key = rstr(r)
|
||||||
|
|
||||||
|
if (type === 9 && key === 'servers') {
|
||||||
|
const elemType = ru8(r)
|
||||||
|
const count = ri32(r)
|
||||||
|
|
||||||
|
if (elemType !== 10) {
|
||||||
|
// Type inattendu : skip
|
||||||
|
for (let i = 0; i < count; i++) skipPayload(r, elemType)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
const entry: Partial<ServerEntry> = {}
|
||||||
|
while (r.pos < buf.length) {
|
||||||
|
const t = ru8(r)
|
||||||
|
if (t === 0) break
|
||||||
|
const k = rstr(r)
|
||||||
|
if (t === 8) {
|
||||||
|
const val = rstr(r)
|
||||||
|
if (k === 'name') entry.name = val
|
||||||
|
else if (k === 'ip') entry.ip = val
|
||||||
|
} else {
|
||||||
|
skipPayload(r, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entry.ip) servers.push({ name: entry.name ?? '', ip: entry.ip })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
skipPayload(r, type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return servers
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user