diff --git a/package.json b/package.json index 50bc6cb1..51c5b508 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "date-fns": "^4.1.0", "echarts": "^6.0.0", "html2canvas": "^1.4.1", + "ini": "^6.0.0", "js-md5": "^0.8.3", "jsencrypt": "^3.5.4", "json-bigint": "^1.0.0", @@ -118,6 +119,7 @@ "@microsoft/tsdoc": "^0.16.0", "@tauri-apps/cli": "2.10.1", "@types/fs-extra": "^11.0.4", + "@types/ini": "^4.1.1", "@types/js-md5": "^0.8.0", "@types/json-bigint": "^1.0.4", "@types/node": "^25.5.0", @@ -126,7 +128,7 @@ "app-root-path": "^3.1.0", "concurrently": "^9.2.1", "envfile": "^7.1.0", - "eslint": "10.1.0", + "eslint": "^9.22.0", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsonc": "^3.1.2", "eslint-plugin-prettier": "^5.5.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 435bcf1f..ebbddc14 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -80,6 +80,9 @@ importers: html2canvas: specifier: ^1.4.1 version: 1.4.1 + ini: + specifier: ^6.0.0 + version: 6.0.0 js-md5: specifier: ^0.8.3 version: 0.8.3 @@ -147,6 +150,9 @@ importers: '@types/fs-extra': specifier: ^11.0.4 version: 11.0.4 + '@types/ini': + specifier: ^4.1.1 + version: 4.1.1 '@types/js-md5': specifier: ^0.8.0 version: 0.8.0 @@ -1735,6 +1741,9 @@ packages: '@types/fs-extra@11.0.4': resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + '@types/ini@4.1.1': + resolution: {integrity: sha512-MIyNUZipBTbyUNnhvuXJTY7B6qNI78meck9Jbv3wk0OgNwRyOOVEKDutAkOs1snB/tx0FafyR6/SN4Ps0hZPeg==} + '@types/js-md5@0.8.0': resolution: {integrity: sha512-gQkc1Felhyj+aB9jmz/ICLm1fDPQx7l/60JIBSSEC+j09JeaINlzd0Wj9LZlQkHnV5rJYkroOHE5wdbDgADJrw==} @@ -2865,6 +2874,10 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + ini@6.0.0: + resolution: {integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==} + engines: {node: ^20.17.0 || >=22.9.0} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -5849,6 +5862,8 @@ snapshots: '@types/jsonfile': 6.1.4 '@types/node': 25.5.0 + '@types/ini@4.1.1': {} + '@types/js-md5@0.8.0': {} '@types/json-bigint@1.0.4': {} @@ -7212,6 +7227,8 @@ snapshots: ini@1.3.8: {} + ini@6.0.0: {} + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 diff --git a/src/types/Game/Config.d.ts b/src/types/Game/Config.d.ts new file mode 100644 index 00000000..f55244d0 --- /dev/null +++ b/src/types/Game/Config.d.ts @@ -0,0 +1,41 @@ +/** + * 游戏配置文件相关 + * @since Beta v0.9.9 + */ + +declare namespace TGApp.Game.Config { + /** + * Config.ini 文件 + * @since Beta v0.9.9 + */ + type GameConf = { + /** 通用配置 */ + general: GeneralConf; + }; + + /** + * Config.ini 配置 + * @since Beta v0.9.9 + */ + type GeneralConf = { + /** channel */ + channel: string; + /** cps */ + cps: string; + /** downloading_mode */ + downloading_mode: string; + /** game_version */ + game_version: string; + /** plugin_sdk_version */ + plugin_sdk_version: string; + /** sub_channel */ + sub_channel: string; + /** + * uapc + * @remarks 序列化的JSON字符串 + */ + uapc: string; + /** wpf_version */ + wpf_version: string; + }; +} diff --git a/src/utils/TGGame.ts b/src/utils/TGGame.ts index 371ac0ab..f5e13011 100644 --- a/src/utils/TGGame.ts +++ b/src/utils/TGGame.ts @@ -1,26 +1,33 @@ /** * 游戏文件相关功能 - * @since Beta v0.9.8 + * @since Beta v0.9.9 */ import showDialog from "@comp/func/dialog.js"; import showSnackbar from "@comp/func/snackbar.js"; +import { parse } from "ini"; import { invoke } from "@tauri-apps/api/core"; import { documentDir, resourceDir, sep } from "@tauri-apps/api/path"; -import { - copyFile, - exists, - mkdir, - readDir, - readTextFile, - readTextFileLines, -} from "@tauri-apps/plugin-fs"; +import { copyFile, exists, mkdir, readDir, readTextFile } from "@tauri-apps/plugin-fs"; import { platform } from "@tauri-apps/plugin-os"; import TGLogger from "@utils/TGLogger.js"; // YAE支持的游戏版本 export const YAE_GAME_VER: Readonly = "6.4.0"; +/** + * 验证游戏格式 + * @since Beta v0.9.9 + * @param data - ini数据 + * @returns 类型收束 + */ +function verifyConfigIni(data: object): data is TGApp.Game.Config.GameConf { + if (!("general" in data) || typeof data.general !== "object" || data.general === null) return false; + if (!("game_version" in data.general) || typeof data.general.game_version !== "string") return false; + // 简单验证general跟game_version + return true; +} + /** * 尝试获取游戏版本 * @since Beta v0.9.1 @@ -37,14 +44,12 @@ export async function tryReadGameVer(gameDir: string): Promise { } const iniPath = `${gameDir}${sep()}config.ini`; if (await exists(iniPath)) { - const iniRead = await readTextFileLines(iniPath); - while (true) { - const line = await iniRead.next(); - const lineRead = line.value; - if (typeof lineRead === "string" && lineRead.startsWith("game_version=")) { - return lineRead.split("=")[1]; - } - if (line.done) break; + const iniRead = await readTextFile(iniPath); + try { + const iniParse = parse(iniRead); + if (verifyConfigIni(iniParse)) return iniParse.general.game_version; + } catch (e) { + showSnackbar.warn("config.ini 配置格式异常"); } } const scriptPath = `${gameDir}${sep()}YuanShen_Data${sep()}Persistent${sep()}ScriptVersion`; @@ -56,12 +61,11 @@ export async function tryReadGameVer(gameDir: string): Promise { /** * 判断是否是管理员模式 - * @since Beta v0.9.1 + * @since Beta v0.9.9 */ export async function isRunInAdmin(): Promise { try { - const isAdmin = await invoke("is_in_admin"); - return isAdmin; + return await invoke("is_in_admin"); } catch (err) { showSnackbar.error(`检测管理员权限失败:${err}`); await TGLogger.Error(`[TGGame][isRunInAdmin]检测管理员权限失败:${err}`);