Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
StarLight 实例一键安装此前固定落到启动器默认目录,无法选择游戏数据位置。 现复用创建流程的外部游戏目录能力:点击一键安装后弹出目录选择框, 只允许修改游戏目录,其余参数仍由服务器整合包决定。 - hosted::create 接受 game_dir_root,拼为 <root>/<包名> 作为 game_dir_override (刻意避开 versions/ 布局,该结构被外部直链实例检测占用) - 新增顶层命令 get_launcher_root_dir,作为弹窗默认值(可执行文件所在目录) - 新增 HostedGameDirModal 弹窗:只读路径框 + 浏览 + 默认位置 + 安装预览 - 补齐 en-US / zh-CN / zh-TW 三语文案 hosted_create 增加 game_dir_root 参数,前端 hostedCreate/install 同步透传。
112 lines
3.4 KiB
TypeScript
112 lines
3.4 KiB
TypeScript
import { invoke } from '@tauri-apps/api/core'
|
|
import {
|
|
requestSkinSiteDownloadToken,
|
|
skinSiteStatus,
|
|
skinSiteUser,
|
|
waitForSkinSiteSession,
|
|
} from '../composables/skin-site-session.ts'
|
|
|
|
let sessionUpdate: Promise<void> = Promise.resolve()
|
|
const attemptListeners = new Set<(instanceId: string) => void>()
|
|
|
|
export function onHostedPackAttemptStarted(listener: (instanceId: string) => void) {
|
|
attemptListeners.add(listener)
|
|
return () => {
|
|
attemptListeners.delete(listener)
|
|
}
|
|
}
|
|
|
|
function startHostedPackAttempt(instanceId: string) {
|
|
for (const listener of attemptListeners) listener(instanceId)
|
|
}
|
|
|
|
export function clearHostedSession(): Promise<void> {
|
|
const update = sessionUpdate
|
|
.catch(() => {})
|
|
.then(() => invokeHosted<void>('plugin:install|hosted_set_session', { token: null }))
|
|
sessionUpdate = update
|
|
return update
|
|
}
|
|
|
|
export async function prepareHostedSession(): Promise<void> {
|
|
await waitForSkinSiteSession()
|
|
const userId = skinSiteUser.value?.uuid
|
|
const token = await requestSkinSiteDownloadToken()
|
|
const update = sessionUpdate
|
|
.catch(() => {})
|
|
.then(async () => {
|
|
if (skinSiteStatus.value !== 'signed-in' || skinSiteUser.value?.uuid !== userId) {
|
|
throw new Error('StarLight 登录状态已变化,请重试。')
|
|
}
|
|
await invokeHosted<void>('plugin:install|hosted_set_session', { token })
|
|
})
|
|
sessionUpdate = update
|
|
await update
|
|
}
|
|
|
|
async function invokeWithSession<T>(command: string, args?: Record<string, unknown>): Promise<T> {
|
|
await prepareHostedSession()
|
|
return invokeHosted<T>(command, args)
|
|
}
|
|
|
|
async function invokeHosted<T>(command: string, args?: Record<string, unknown>): Promise<T> {
|
|
try {
|
|
return await invoke<T>(command, args)
|
|
} catch (cause) {
|
|
if (
|
|
!(cause instanceof Error) &&
|
|
typeof cause === 'object' &&
|
|
cause !== null &&
|
|
'message' in cause &&
|
|
typeof cause.message === 'string'
|
|
) {
|
|
throw new Error(cause.message, { cause })
|
|
}
|
|
throw cause
|
|
}
|
|
}
|
|
|
|
export type InstanceMode = 'starlight' | 'local'
|
|
export const getInstanceMode = (instanceId: string) =>
|
|
invokeHosted<InstanceMode>('plugin:install|hosted_instance_mode', { instanceId })
|
|
export const setInstanceMode = (instanceId: string, mode: InstanceMode) => {
|
|
if (mode === 'starlight') startHostedPackAttempt(instanceId)
|
|
return (mode === 'starlight' ? invokeWithSession<void> : invokeHosted<void>)(
|
|
'plugin:install|hosted_set_instance_mode',
|
|
{ instanceId, mode },
|
|
)
|
|
}
|
|
|
|
export interface HostedPublication {
|
|
packId: string
|
|
releaseId: number
|
|
manifest: {
|
|
name: string
|
|
version: string
|
|
format: string
|
|
runtime: { gameVersion: string; loader: string; loaderVersion: string | null }
|
|
files: { path: string; size: number; sha256: string }[]
|
|
}
|
|
}
|
|
export interface HostedBinding {
|
|
publication: HostedPublication
|
|
}
|
|
export interface HostedSyncResult {
|
|
version: string
|
|
downloadedBytes: number
|
|
changedFiles: number
|
|
preservedFiles: string[]
|
|
}
|
|
export const hostedDefault = () =>
|
|
invokeWithSession<HostedPublication>('plugin:install|hosted_default')
|
|
export const hostedCreate = (gameDirRoot?: string | null) =>
|
|
invokeWithSession<string>('plugin:install|hosted_create', {
|
|
gameDirRoot: gameDirRoot ?? null,
|
|
})
|
|
export const hostedBinding = (instanceId: string) =>
|
|
invokeHosted<HostedBinding | null>('plugin:install|hosted_binding', { instanceId })
|
|
export const hostedSync = (instanceId: string) => {
|
|
startHostedPackAttempt(instanceId)
|
|
return invokeWithSession<HostedSyncResult>('plugin:install|hosted_sync', { instanceId })
|
|
}
|