|
|
@@ -14,72 +14,92 @@ const LEGACY_SMARTSHOOTER5 = {
|
|
|
controlPath: "C:\\Program Files\\Smart Shooter 5",
|
|
|
}
|
|
|
|
|
|
-function migrateLegacySmartShooter(config) {
|
|
|
- if (!config || config.smartShooter6Migrated) return { config, changed: false }
|
|
|
- const stillFactoryDefault = config.controlType === LEGACY_SMARTSHOOTER5.controlType
|
|
|
- && config.controlPath === LEGACY_SMARTSHOOTER5.controlPath
|
|
|
- config.smartShooter6Migrated = true
|
|
|
- if (!stillFactoryDefault) return { config, changed: true }
|
|
|
- config.controlType = defaultConfig.controlType
|
|
|
- config.controlPath = defaultConfig.controlPath
|
|
|
- config.SmartShooterPath = config.SmartShooterPath || LEGACY_SMARTSHOOTER5.controlPath
|
|
|
- config.SmartShooter6Path = defaultConfig.SmartShooter6Path
|
|
|
- return { config, changed: true }
|
|
|
+function sameValue(a, b) {
|
|
|
+ return JSON.stringify(a) === JSON.stringify(b)
|
|
|
+}
|
|
|
+
|
|
|
+// 用户目录只保留和 utils 默认值不同的项
|
|
|
+function stripDefaults(overrides) {
|
|
|
+ const next = { ...overrides }
|
|
|
+ for (const key of Object.keys(next)) {
|
|
|
+ if (Object.prototype.hasOwnProperty.call(defaultConfig, key) && sameValue(next[key], defaultConfig[key])) {
|
|
|
+ delete next[key]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return next
|
|
|
+}
|
|
|
+
|
|
|
+function overridesEqual(a, b) {
|
|
|
+ const keys = new Set([...Object.keys(a || {}), ...Object.keys(b || {})])
|
|
|
+ for (const key of keys) {
|
|
|
+ if (!sameValue(a[key], b[key])) return false
|
|
|
+ }
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+function readOverrides() {
|
|
|
+ if (!fs.existsSync(configPath)) return {}
|
|
|
+ const data = fs.readFileSync(configPath, 'utf8');
|
|
|
+ const parsed = JSON.parse(data);
|
|
|
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return {}
|
|
|
+ return parsed
|
|
|
+}
|
|
|
+
|
|
|
+function writeOverrides(overrides) {
|
|
|
+ fs.writeFileSync(configPath, JSON.stringify(overrides, null, 2), 'utf8');
|
|
|
+}
|
|
|
+
|
|
|
+function migrateLegacySmartShooter(overrides) {
|
|
|
+ if (!overrides || overrides.smartShooter6Migrated) return { overrides, changed: false }
|
|
|
+ const merged = { ...defaultConfig, ...overrides }
|
|
|
+ const stillFactoryDefault = merged.controlType === LEGACY_SMARTSHOOTER5.controlType
|
|
|
+ && merged.controlPath === LEGACY_SMARTSHOOTER5.controlPath
|
|
|
+ const next = { ...overrides, smartShooter6Migrated: true }
|
|
|
+ if (!stillFactoryDefault) return { overrides: next, changed: true }
|
|
|
+ next.controlType = defaultConfig.controlType
|
|
|
+ next.controlPath = defaultConfig.controlPath
|
|
|
+ next.SmartShooterPath = overrides.SmartShooterPath || LEGACY_SMARTSHOOTER5.controlPath
|
|
|
+ next.SmartShooter6Path = defaultConfig.SmartShooter6Path
|
|
|
+ return { overrides: next, changed: true }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 读取配置文件
|
|
|
+ * 读取配置:utils 里的默认值打底,用户目录里只覆盖改过的项
|
|
|
*/
|
|
|
function readConfigFile() {
|
|
|
|
|
|
try {
|
|
|
- if (fs.existsSync(configPath)) {
|
|
|
- const data = fs.readFileSync(configPath, 'utf8');
|
|
|
- const parsed = JSON.parse(data);
|
|
|
- const { config: merged, changed } = migrateLegacySmartShooter({
|
|
|
- ...defaultConfig,
|
|
|
- ...parsed,
|
|
|
- });
|
|
|
- if (changed) {
|
|
|
- fs.writeFileSync(configPath, JSON.stringify(merged, null, 2), 'utf8');
|
|
|
- }
|
|
|
-
|
|
|
- return merged;
|
|
|
- } else {
|
|
|
- console.log('配置文件不存在');
|
|
|
- // 创建空白JSON文件
|
|
|
- fs.writeFileSync(configPath, '{}', 'utf8');
|
|
|
- return {
|
|
|
- ...defaultConfig,
|
|
|
- };
|
|
|
+ const overrides = readOverrides()
|
|
|
+ const { overrides: migrated, changed } = migrateLegacySmartShooter(overrides)
|
|
|
+ const stored = stripDefaults(migrated)
|
|
|
+ if (changed || !overridesEqual(overrides, stored)) {
|
|
|
+ writeOverrides(stored)
|
|
|
}
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...defaultConfig,
|
|
|
+ ...stored,
|
|
|
+ };
|
|
|
} catch (error) {
|
|
|
console.error('读取配置文件出错:', error);
|
|
|
return null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function loadConfigFile() {
|
|
|
- if (!fs.existsSync(configPath)) {
|
|
|
- return { ...defaultConfig }
|
|
|
- }
|
|
|
- const data = fs.readFileSync(configPath, 'utf8');
|
|
|
- return {
|
|
|
- ...defaultConfig,
|
|
|
- ...JSON.parse(data),
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
- * 一次写入多项配置,避免 controlType 和安装目录被分成几次写入后互相覆盖
|
|
|
+ * 一次写入多项调整。和默认值相同的项不写进用户目录
|
|
|
*/
|
|
|
function updateConfigFile(partial) {
|
|
|
try {
|
|
|
- const config = {
|
|
|
- ...loadConfigFile(),
|
|
|
- ...partial,
|
|
|
+ const next = { ...readOverrides() }
|
|
|
+ for (const [key, value] of Object.entries(partial)) {
|
|
|
+ if (Object.prototype.hasOwnProperty.call(defaultConfig, key) && sameValue(value, defaultConfig[key])) {
|
|
|
+ delete next[key]
|
|
|
+ } else {
|
|
|
+ next[key] = value
|
|
|
+ }
|
|
|
}
|
|
|
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
|
+ writeOverrides(stripDefaults(next))
|
|
|
console.log(`成功写入配置项: ${Object.keys(partial).join(', ')}`);
|
|
|
} catch (error) {
|
|
|
console.error('写入配置文件出错:', error);
|