Files
Starlight_Lancher/apps/app-frontend/src/helpers/game-options.ts
T
AxTps 83ee962c16
Sync source to CNB / Sync Git ref (push) Has been cancelled
feat: 跨实例同步移植第8轮(前端 helpers + 同步设置 UI)
新增同步 helpers(synced-options / synced-packs / game-options),在 instance helper 中补充同步类型与 API。新增实例设置「同步」标签页(SyncSettings)及 SyncSource / SyncedPacks / servers / command-history 四个弹窗,并把 CheckCircleButton、TeleportOverflowMenu 从 ui 包导出。同步相关的 en-US / zh-CN 文案已补齐(各 62 条)。game-settings-modal 留待下一轮。
2026-10-04 08:51:45 +08:00

245 lines
6.3 KiB
TypeScript

import { queryOptions } from '@tanstack/vue-query'
import { invoke } from '@tauri-apps/api/core'
export type GameOptionCanonicalValue =
| { type: 'bool'; value: boolean }
| { type: 'integer'; value: number }
| { type: 'decimal'; value: string }
| { type: 'enum'; value: string }
| { type: 'text'; value: string }
| { type: 'string_list'; value: string[] }
| { type: 'key_binding'; value: string }
| { type: 'external_raw'; value: string }
export type GameOptionValueState = 'canonical' | 'uniform_local' | 'mixed' | 'unset' | 'invalid'
export type GameOptionCompatibilityStatus =
| 'ready'
| 'deferred'
| 'waiting_for_file'
| 'waiting_for_base'
| 'not_available'
| 'unsupported_value'
| 'unmappable'
| 'catalog_uncovered'
| 'controlled'
| 'degraded'
export type GameOptionMappingKind = 'direct' | 'legacy' | 'migrated' | 'lossless' | 'lossy'
export type GameOptionCompatibilityReason =
| 'launcher_controlled'
| 'catalog_uncovered'
| 'inspection_failed'
| 'waiting_for_options_file'
| 'unsupported_value'
| 'migrates_on_write'
| 'waiting_for_compatible_base'
| 'missing_setting'
export type GameOptionCompatibilityBucket = {
instance_count: number
write_keys: string[]
eventual_keys: string[]
game_versions: string[]
status: GameOptionCompatibilityStatus
mapping?: GameOptionMappingKind | null
reason?: GameOptionCompatibilityReason | null
}
export type GameOptionCompatibilitySummary = {
total_participating: number
will_receive: number
write_now: number
left_local: number
buckets: GameOptionCompatibilityBucket[]
}
export type GameOptionEditorChoice = {
value: string
}
export type GameOptionEditor = {
type:
| 'bool'
| 'integer'
| 'decimal'
| 'enum'
| 'text'
| 'string_list'
| 'key_binding'
| 'external_raw'
min?: number | null
max?: number | null
step?: number | null
unit?: string | null
choices?: GameOptionEditorChoice[]
}
export type GameSettingCategory = {
id: string
is_custom?: boolean
}
export type GameOptionValidationError =
'missing_value' | 'no_compatible_instances' | 'invalid_value' | 'changed_since_opened'
export type EditableGameSetting = {
option_id: string
category_id: string
kind: 'vanilla' | 'external'
raw_key?: string | null
sync_enabled: boolean
canonical_value?: GameOptionCanonicalValue | null
value_state: GameOptionValueState
option_revision: number
editor: GameOptionEditor
compatibility: GameOptionCompatibilitySummary
validation_error?: GameOptionValidationError | null
controlled?: boolean
}
export type GameSettingsEditorState = {
summary_revision: string
canonical_revision: number
catalog_revision: number
total_participating: number
categories: GameSettingCategory[]
settings: EditableGameSetting[]
}
export type GameSettingChange = {
option_id: string
base_option_revision: number
sync_enabled?: boolean
canonical_value?: GameOptionCanonicalValue | null
}
export type UpdateGameSettingsRequest = {
expected_summary_revision: string
expected_canonical_revision: number
expected_catalog_revision: number
changes: GameSettingChange[]
}
export type GameOptionsSourceCandidate = {
source_id: string
instance_id: string
name: string
icon_path?: string | null
game_version?: string | null
eligible: boolean
disabled_reason?: GameOptionsSourceDisabledReason | null
recognized_setting_count: number
custom_setting_count: number
}
export type GameOptionsSourceDisabledReason =
| 'installing_or_updating'
| 'unsupported_version'
| 'missing_options_file'
| 'no_syncable_settings'
| 'unreadable_options_file'
export type SaveGameSettingsResult = {
state?: GameSettingsEditorState
applied: number
migrated: number
deferred: number
unsupported: number
failed: number
conflicts?: string[]
}
export type GameSettingLocaleLabel = {
label: string
choices: Record<string, string>
source?: GameSettingSource | null
}
export type GameSettingSource = {
instance_id: string
file_name: string
file_path: string
project: {
id: string
title: string
icon_url: string | null
} | null
}
export async function get_game_setting_locale_labels(
instanceId: string | undefined,
locale: string,
optionIds: string[],
refreshSources = false,
): Promise<{ settings: Record<string, GameSettingLocaleLabel> }> {
return await invoke('plugin:instance|instance_get_game_setting_locale_labels', {
instanceId,
locale,
optionIds,
refreshSources,
})
}
export async function list_game_options_sync_sources(): Promise<GameOptionsSourceCandidate[]> {
return await invoke('plugin:instance|instance_list_game_options_sync_sources')
}
export async function get_synced_game_options_config(): Promise<GameSettingsEditorState> {
return await invoke('plugin:instance|instance_get_synced_game_options_config')
}
export const gameSettingsKeys = {
synced: ['game-settings', 'synced'] as const,
local: (instanceId: string) => ['game-settings', 'local', instanceId] as const,
}
export function gameSettingsQueryOptions(instanceId?: string) {
return queryOptions({
queryKey: instanceId ? gameSettingsKeys.local(instanceId) : gameSettingsKeys.synced,
queryFn: () =>
instanceId ? get_local_game_options_config(instanceId) : get_synced_game_options_config(),
staleTime: 30_000,
retry: false,
})
}
export async function preview_synced_game_option_changes(
request: UpdateGameSettingsRequest,
): Promise<GameSettingsEditorState> {
return await invoke('plugin:instance|instance_preview_synced_game_option_changes', { request })
}
export async function save_synced_game_option_changes(
request: UpdateGameSettingsRequest,
): Promise<SaveGameSettingsResult> {
return await invoke('plugin:instance|instance_save_synced_game_option_changes', { request })
}
export async function get_local_game_options_config(
instanceId: string,
): Promise<GameSettingsEditorState> {
return await invoke('plugin:instance|instance_get_local_game_options_config', { instanceId })
}
export async function preview_local_game_option_changes(
instanceId: string,
request: UpdateGameSettingsRequest,
): Promise<GameSettingsEditorState> {
return await invoke('plugin:instance|instance_preview_local_game_option_changes', {
instanceId,
request,
})
}
export async function save_local_game_option_changes(
instanceId: string,
request: UpdateGameSettingsRequest,
): Promise<SaveGameSettingsResult> {
return await invoke('plugin:instance|instance_save_local_game_option_changes', {
instanceId,
request,
})
}