poi-plugin-kancolle-chs 1.2.1 → 1.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.es +1 -7
- package/package.json +6 -1
- package/src/config.es +3 -0
- package/src/constants.es +21 -6
- package/src/core/api-merger.es +227 -14
- package/src/core/main-patcher.es +1 -0
- package/src/core/resource-manager.es +88 -17
- package/src/core/resource-updater.es +807 -0
- package/src/core/text-patcher.es +3 -0
- package/src/loaders/data-loader.es +129 -13
- package/src/views/MainPanel.es +1320 -468
package/index.es
CHANGED
|
@@ -31,13 +31,7 @@ export const pluginDidLoad = async () => {
|
|
|
31
31
|
await mainPatcher.buildAndDeploy()
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// 4.
|
|
35
|
-
if (configManager.get('autoCheckUpdate', true)) {
|
|
36
|
-
import('./src/core/git-manager').then(({ gitManager }) => {
|
|
37
|
-
gitManager.checkForUpdates().catch(() => {})
|
|
38
|
-
}).catch(() => {})
|
|
39
|
-
}
|
|
40
|
-
|
|
34
|
+
// 4. 若开启了启动自动检查更新,由 MainPanel 在渲染时自动检测并在有更新时弹窗提醒
|
|
41
35
|
console.log('[砍口垒汉化计划PLUS] 插件加载完毕,原生汉化模式已生效!')
|
|
42
36
|
} else {
|
|
43
37
|
console.log('[砍口垒汉化计划PLUS] 插件当前处于停用状态,确保环境纯净官方原版...')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poi-plugin-kancolle-chs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.8",
|
|
4
4
|
"description": "砍口垒汉化计划PLUS POI 原生独立插件:提供全界面文本替换、正则动态替换、KCSAPI 响应合流、中文字体与贴图魔改、自定义字体适配与官方资源更新",
|
|
5
5
|
"main": "index.es",
|
|
6
6
|
"files": [
|
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
"assets/",
|
|
10
10
|
"generated/"
|
|
11
11
|
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"pub": "node scripts/publish-to-npm.js",
|
|
14
|
+
"publish-plugin": "node scripts/publish-to-npm.js",
|
|
15
|
+
"pub:dry": "node scripts/publish-to-npm.js --dry-run"
|
|
16
|
+
},
|
|
12
17
|
"author": {
|
|
13
18
|
"name": "泉浅漪",
|
|
14
19
|
"link": "https://github.com/asaico",
|
package/src/config.es
CHANGED
|
@@ -93,6 +93,9 @@ class ConfigManager {
|
|
|
93
93
|
|
|
94
94
|
if (saved && typeof saved === 'object') {
|
|
95
95
|
this.config = { ...DEFAULT_CONFIG, ...saved }
|
|
96
|
+
if (saved.autoCheckResourceUpdate === undefined && saved.autoCheckUpdate !== undefined) {
|
|
97
|
+
this.config.autoCheckResourceUpdate = saved.autoCheckUpdate
|
|
98
|
+
}
|
|
96
99
|
} else {
|
|
97
100
|
// 若首次启动且无配置,尝试全平台推荐路径初始化
|
|
98
101
|
for (const candidate of RECOMMENDED_SOURCE_PATHS) {
|
package/src/constants.es
CHANGED
|
@@ -15,7 +15,7 @@ export const OFFICIAL_REPO_GIT = 'https://github.com/asaico/Kancolle_to_CHS.git'
|
|
|
15
15
|
export const OFFICIAL_REPO_RELEASES = 'https://github.com/asaico/Kancolle_to_CHS/releases'
|
|
16
16
|
|
|
17
17
|
// 插件版本与 npm 元信息
|
|
18
|
-
let pkgVersion = '1.
|
|
18
|
+
let pkgVersion = '1.3.8'
|
|
19
19
|
try {
|
|
20
20
|
const pkg = require('../package.json')
|
|
21
21
|
if (pkg && pkg.version) pkgVersion = pkg.version
|
|
@@ -70,9 +70,10 @@ export const DEFAULT_CONFIG = {
|
|
|
70
70
|
enableApiMapInfo: true, // 出击海区与作战行动说明 (start2.api_mst_mapinfo.json)
|
|
71
71
|
enableApiPictureBook: true, // 舰船与装备图鉴介绍 (picture_book.ship / slotitem)
|
|
72
72
|
enableApiFlavor: true, // 海域进点气象与深海台词 (battle.api_flavor_info.json)
|
|
73
|
+
enableApiItem: true, // 消耗道具与商城道具汉化 (useitem / payitem.json)
|
|
73
74
|
|
|
74
75
|
// --- 3. 静态魔改资产细分开关 ---
|
|
75
|
-
enableFontHack: true, //
|
|
76
|
+
enableFontHack: true, // 默认中文字体替换(思源黑体)
|
|
76
77
|
enableImageHack: true, // 界面贴图与图标魔改 (.hack.png / .hack.jpg)
|
|
77
78
|
|
|
78
79
|
// --- 4. 自定义字体优先适配 ---
|
|
@@ -82,14 +83,17 @@ export const DEFAULT_CONFIG = {
|
|
|
82
83
|
customFontPath: '', // 本地字体文件绝对路径 (.woff2 / .ttf / .otf)
|
|
83
84
|
|
|
84
85
|
// --- 5. 官方资源与更新管理 ---
|
|
85
|
-
autoCheckUpdate: true,
|
|
86
|
+
autoCheckUpdate: true, // 插件启动时是否在后台自动检查更新
|
|
87
|
+
autoCheckResourceUpdate: true, // 启动 POI 时自动检查本地汉化资源更新并在面板提示
|
|
88
|
+
downloadMirror: 'direct', // 资源下载加速镜像,默认 'direct' (GitHub 官方直连)
|
|
86
89
|
|
|
87
90
|
// --- 6. 游戏运行帧率上限调节 ---
|
|
88
91
|
fpsLimit: 60, // 游戏帧率上限 (默认 60,可选 60, 120, 165, 240)
|
|
89
92
|
|
|
90
|
-
// --- 7.
|
|
93
|
+
// --- 7. 综合设置与界面布局模式 ---
|
|
91
94
|
layoutDensity: 'auto', // 'auto'(自适应), 'compact'(紧凑模式), 'spacious'(宽屏模式)
|
|
92
95
|
panelMaxWidth: '100%', // 面板最大宽度: '100%', '880px', '1080px'
|
|
96
|
+
noticeAutoCloseSeconds: 20, // 提示与通知默认自动向上折叠关闭时间 (秒,0 为不自动关闭)
|
|
93
97
|
|
|
94
98
|
// --- 8. 其他魔改功能 (独立路径优先加载第三方魔改资源) ---
|
|
95
99
|
enableCustomHack: false, // 是否启用其他第三方魔改功能
|
|
@@ -116,7 +120,18 @@ export const PRESET_LAYOUT_DENSITY = [
|
|
|
116
120
|
|
|
117
121
|
// 界面最大宽度预设
|
|
118
122
|
export const PRESET_MAX_WIDTH = [
|
|
119
|
-
{ label: '
|
|
123
|
+
{ label: '500px 窄屏', value: '500px' },
|
|
120
124
|
{ label: '880px 适中', value: '880px' },
|
|
121
|
-
{ label: '
|
|
125
|
+
{ label: '1200px 宽屏', value: '1200px' },
|
|
126
|
+
{ label: '1600px 超宽', value: '1600px' },
|
|
127
|
+
{ label: '100% 铺满', value: '100%' },
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
// 提示自动折叠关闭时间预设
|
|
131
|
+
export const PRESET_NOTICE_AUTOCLOSE = [
|
|
132
|
+
{ label: '5秒 极速', value: 5 },
|
|
133
|
+
{ label: '10秒 适中', value: 10 },
|
|
134
|
+
{ label: '20秒 默认', value: 20 },
|
|
135
|
+
{ label: '30秒 宽裕', value: 30 },
|
|
136
|
+
{ label: '从不自动折叠', value: 0 },
|
|
122
137
|
]
|
package/src/core/api-merger.es
CHANGED
|
@@ -11,6 +11,7 @@ export function generateApiPatcherScript(apiData, options = {}) {
|
|
|
11
11
|
enableApiMapInfo = true,
|
|
12
12
|
enableApiPictureBook = true,
|
|
13
13
|
enableApiFlavor = true,
|
|
14
|
+
enableApiItem = true,
|
|
14
15
|
} = options
|
|
15
16
|
|
|
16
17
|
// 若所有 API 模块均未启用,则不注入 XHR 拦截代码
|
|
@@ -21,7 +22,8 @@ export function generateApiPatcherScript(apiData, options = {}) {
|
|
|
21
22
|
enableApiFurniture ||
|
|
22
23
|
enableApiMapInfo ||
|
|
23
24
|
enableApiPictureBook ||
|
|
24
|
-
enableApiFlavor
|
|
25
|
+
enableApiFlavor ||
|
|
26
|
+
enableApiItem
|
|
25
27
|
|
|
26
28
|
if (!anyApiEnabled) {
|
|
27
29
|
return ''
|
|
@@ -33,6 +35,10 @@ export function generateApiPatcherScript(apiData, options = {}) {
|
|
|
33
35
|
furniture = {},
|
|
34
36
|
mapinfo = {},
|
|
35
37
|
slotitem = {},
|
|
38
|
+
slotitemEquiptype = {},
|
|
39
|
+
stype = {},
|
|
40
|
+
useitem = {},
|
|
41
|
+
payitem = {},
|
|
36
42
|
pictureBookShip = {},
|
|
37
43
|
pictureBookSlot = {},
|
|
38
44
|
questlist = {},
|
|
@@ -45,6 +51,10 @@ export function generateApiPatcherScript(apiData, options = {}) {
|
|
|
45
51
|
const activeFurniture = enableApiFurniture ? furniture : {}
|
|
46
52
|
const activeMapInfo = enableApiMapInfo ? mapinfo : {}
|
|
47
53
|
const activeSlot = enableApiShip ? slotitem : {}
|
|
54
|
+
const activeEquiptype = enableApiShip ? slotitemEquiptype : {}
|
|
55
|
+
const activeStype = enableApiShip ? stype : {}
|
|
56
|
+
const activeUseitem = enableApiItem ? useitem : {}
|
|
57
|
+
const activePayitem = enableApiItem ? payitem : {}
|
|
48
58
|
const activePBShip = enableApiPictureBook ? pictureBookShip : {}
|
|
49
59
|
const activePBSlot = enableApiPictureBook ? pictureBookSlot : {}
|
|
50
60
|
const activeQuest = enableApiQuest ? questlist : {}
|
|
@@ -61,6 +71,7 @@ export function generateApiPatcherScript(apiData, options = {}) {
|
|
|
61
71
|
enableApiMapInfo: ${enableApiMapInfo ? 'true' : 'false'},
|
|
62
72
|
enableApiPictureBook: ${enableApiPictureBook ? 'true' : 'false'},
|
|
63
73
|
enableApiFlavor: ${enableApiFlavor ? 'true' : 'false'},
|
|
74
|
+
enableApiItem: ${enableApiItem ? 'true' : 'false'},
|
|
64
75
|
}, window.__kanchs_api_options || {});
|
|
65
76
|
|
|
66
77
|
window.__kanchs_api_data = Object.assign({
|
|
@@ -69,6 +80,10 @@ export function generateApiPatcherScript(apiData, options = {}) {
|
|
|
69
80
|
furniture: ${JSON.stringify(activeFurniture)},
|
|
70
81
|
mapinfo: ${JSON.stringify(activeMapInfo)},
|
|
71
82
|
slotitem: ${JSON.stringify(activeSlot)},
|
|
83
|
+
slotitemEquiptype: ${JSON.stringify(activeEquiptype)},
|
|
84
|
+
stype: ${JSON.stringify(activeStype)},
|
|
85
|
+
useitem: ${JSON.stringify(activeUseitem)},
|
|
86
|
+
payitem: ${JSON.stringify(activePayitem)},
|
|
72
87
|
pictureBookShip: ${JSON.stringify(activePBShip)},
|
|
73
88
|
pictureBookSlot: ${JSON.stringify(activePBSlot)},
|
|
74
89
|
questlist: ${JSON.stringify(activeQuest)},
|
|
@@ -198,6 +213,105 @@ export function generateApiPatcherScript(apiData, options = {}) {
|
|
|
198
213
|
}
|
|
199
214
|
}
|
|
200
215
|
|
|
216
|
+
// 6. 装备类型分类母表 (start2.api_mst_slotitem_equiptype.json)
|
|
217
|
+
if (getOpt('enableApiShip') && Array.isArray(data.api_mst_slotitem_equiptype)) {
|
|
218
|
+
const EQUIPTYPE_DATA = getData('slotitemEquiptype');
|
|
219
|
+
for (let i = 0; i < data.api_mst_slotitem_equiptype.length; i++) {
|
|
220
|
+
const eq = data.api_mst_slotitem_equiptype[i];
|
|
221
|
+
if (!eq || eq.api_id === undefined) continue;
|
|
222
|
+
const patch = EQUIPTYPE_DATA[eq.api_id] || EQUIPTYPE_DATA[String(eq.api_id)];
|
|
223
|
+
if (patch && patch.api_name) {
|
|
224
|
+
const origName = eq.api_name;
|
|
225
|
+
eq.api_name = patch.api_name;
|
|
226
|
+
if (typeof window !== 'undefined' && window.__kanchs_dynamic_dict && origName) {
|
|
227
|
+
window.__kanchs_dynamic_dict[origName] = patch.api_name;
|
|
228
|
+
}
|
|
229
|
+
modified = true;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 7. 基础舰种母表 (start2.api_mst_stype.json)
|
|
235
|
+
if (getOpt('enableApiShip') && Array.isArray(data.api_mst_stype)) {
|
|
236
|
+
const STYPE_DATA = getData('stype');
|
|
237
|
+
for (let i = 0; i < data.api_mst_stype.length; i++) {
|
|
238
|
+
const st = data.api_mst_stype[i];
|
|
239
|
+
if (!st || st.api_id === undefined) continue;
|
|
240
|
+
const patch = STYPE_DATA[st.api_id] || STYPE_DATA[String(st.api_id)];
|
|
241
|
+
if (patch && patch.api_name) {
|
|
242
|
+
const origName = st.api_name;
|
|
243
|
+
st.api_name = patch.api_name;
|
|
244
|
+
if (typeof window !== 'undefined' && window.__kanchs_dynamic_dict && origName) {
|
|
245
|
+
window.__kanchs_dynamic_dict[origName] = patch.api_name;
|
|
246
|
+
}
|
|
247
|
+
modified = true;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// 8. 消耗道具母表 (start2.api_mst_useitem.json)
|
|
253
|
+
if (getOpt('enableApiItem') && Array.isArray(data.api_mst_useitem)) {
|
|
254
|
+
const USEITEM_DATA = getData('useitem');
|
|
255
|
+
for (let i = 0; i < data.api_mst_useitem.length; i++) {
|
|
256
|
+
const u = data.api_mst_useitem[i];
|
|
257
|
+
if (!u || u.api_id === undefined) continue;
|
|
258
|
+
const patch = USEITEM_DATA[u.api_id] || USEITEM_DATA[String(u.api_id)];
|
|
259
|
+
if (patch) {
|
|
260
|
+
if (patch.api_name) {
|
|
261
|
+
const origName = u.api_name;
|
|
262
|
+
u.api_name = patch.api_name;
|
|
263
|
+
if (typeof window !== 'undefined' && window.__kanchs_dynamic_dict && origName) {
|
|
264
|
+
window.__kanchs_dynamic_dict[origName] = patch.api_name;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (patch.api_description) {
|
|
268
|
+
u.api_description = patch.api_description;
|
|
269
|
+
if (Array.isArray(patch.api_description)) {
|
|
270
|
+
for (let dIdx = 0; dIdx < patch.api_description.length; dIdx++) {
|
|
271
|
+
const line = patch.api_description[dIdx];
|
|
272
|
+
if (typeof line === 'string' && line.trim()) {
|
|
273
|
+
registerBrVariants(line, line);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
} else if (typeof patch.api_description === 'string') {
|
|
277
|
+
registerBrVariants(patch.api_description, patch.api_description);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
modified = true;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// 9. 商城与点券道具母表 (start2.api_mst_payitem.json)
|
|
286
|
+
if (getOpt('enableApiItem') && Array.isArray(data.api_mst_payitem)) {
|
|
287
|
+
const PAYITEM_DATA = getData('payitem');
|
|
288
|
+
for (let i = 0; i < data.api_mst_payitem.length; i++) {
|
|
289
|
+
const p = data.api_mst_payitem[i];
|
|
290
|
+
if (!p || p.api_id === undefined) continue;
|
|
291
|
+
const patch = PAYITEM_DATA[p.api_id] || PAYITEM_DATA[String(p.api_id)];
|
|
292
|
+
if (patch) {
|
|
293
|
+
if (patch.api_name) {
|
|
294
|
+
const origName = p.api_name;
|
|
295
|
+
p.api_name = patch.api_name;
|
|
296
|
+
if (typeof window !== 'undefined' && window.__kanchs_dynamic_dict && origName) {
|
|
297
|
+
window.__kanchs_dynamic_dict[origName] = patch.api_name;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (patch.api_description) {
|
|
301
|
+
const origDesc = p.api_description;
|
|
302
|
+
p.api_description = patch.api_description;
|
|
303
|
+
registerBrVariants(origDesc, patch.api_description);
|
|
304
|
+
}
|
|
305
|
+
if (patch.api_shop_description) {
|
|
306
|
+
const origShop = p.api_shop_description;
|
|
307
|
+
p.api_shop_description = patch.api_shop_description;
|
|
308
|
+
registerBrVariants(origShop, patch.api_shop_description);
|
|
309
|
+
}
|
|
310
|
+
modified = true;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
201
315
|
return modified;
|
|
202
316
|
}
|
|
203
317
|
|
|
@@ -298,19 +412,102 @@ export function generateApiPatcherScript(apiData, options = {}) {
|
|
|
298
412
|
}
|
|
299
413
|
|
|
300
414
|
function patchFlavor(data) {
|
|
301
|
-
if (!getOpt('enableApiFlavor') || !data ||
|
|
415
|
+
if (!getOpt('enableApiFlavor') || !data || typeof data !== 'object') return false;
|
|
302
416
|
let modified = false;
|
|
303
417
|
const FLAVOR_DATA = getData('flavorInfo');
|
|
418
|
+
const SHIP_DATA = getData('ship');
|
|
419
|
+
const dynamicDict = window.__kanchs_dynamic_dict || {};
|
|
420
|
+
|
|
421
|
+
// 1. 处理战斗台词与深海入场 (api_flavor_info 数组或单个对象)
|
|
422
|
+
if (data.api_flavor_info) {
|
|
423
|
+
const list = Array.isArray(data.api_flavor_info) ? data.api_flavor_info : [data.api_flavor_info];
|
|
424
|
+
for (let i = 0; i < list.length; i++) {
|
|
425
|
+
const f = list[i];
|
|
426
|
+
if (!f || typeof f !== 'object') continue;
|
|
427
|
+
|
|
428
|
+
// 尝试通过 api_voice_id 或 api_boss_ship_id 匹配汉化补丁
|
|
429
|
+
let patch = null;
|
|
430
|
+
if (f.api_voice_id !== undefined && f.api_voice_id !== null) {
|
|
431
|
+
patch = FLAVOR_DATA[f.api_voice_id] || FLAVOR_DATA[String(f.api_voice_id)];
|
|
432
|
+
}
|
|
433
|
+
if (!patch && f.api_boss_ship_id !== undefined && f.api_boss_ship_id !== null) {
|
|
434
|
+
patch = FLAVOR_DATA['ship_' + f.api_boss_ship_id] || FLAVOR_DATA[f.api_boss_ship_id];
|
|
435
|
+
}
|
|
304
436
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
437
|
+
const origMsg = f.api_message || '';
|
|
438
|
+
const origShip = f.api_ship_name || '';
|
|
439
|
+
const origClass = f.api_class_name || '';
|
|
440
|
+
|
|
441
|
+
if (patch) {
|
|
442
|
+
if (patch.api_message) {
|
|
443
|
+
f.api_message = patch.api_message;
|
|
444
|
+
registerBrVariants(origMsg, patch.api_message);
|
|
445
|
+
modified = true;
|
|
446
|
+
}
|
|
447
|
+
if (patch.api_class_name) {
|
|
448
|
+
f.api_class_name = patch.api_class_name;
|
|
449
|
+
if (origClass) dynamicDict[origClass] = patch.api_class_name;
|
|
450
|
+
modified = true;
|
|
451
|
+
}
|
|
452
|
+
if (patch.api_ship_name) {
|
|
453
|
+
f.api_ship_name = patch.api_ship_name;
|
|
454
|
+
if (origShip) dynamicDict[origShip] = patch.api_ship_name;
|
|
455
|
+
modified = true;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// 兜底 1: 若未由 patch 提供 ship_name 或 class_name,尝试通过舰船表与动态字典补全汉化
|
|
460
|
+
if (f.api_boss_ship_id && SHIP_DATA && SHIP_DATA[f.api_boss_ship_id] && SHIP_DATA[f.api_boss_ship_id].api_name) {
|
|
461
|
+
if (!patch || !patch.api_ship_name) {
|
|
462
|
+
f.api_ship_name = SHIP_DATA[f.api_boss_ship_id].api_name;
|
|
463
|
+
if (origShip) dynamicDict[origShip] = f.api_ship_name;
|
|
464
|
+
modified = true;
|
|
465
|
+
}
|
|
466
|
+
} else if (f.api_ship_name && dynamicDict[f.api_ship_name]) {
|
|
467
|
+
f.api_ship_name = dynamicDict[f.api_ship_name];
|
|
468
|
+
modified = true;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (f.api_class_name && dynamicDict[f.api_class_name]) {
|
|
472
|
+
f.api_class_name = dynamicDict[f.api_class_name];
|
|
473
|
+
modified = true;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// 兜底 2: 若 api_message 未被 voice_id 补丁命中,尝试字典直接替换
|
|
477
|
+
if ((!patch || !patch.api_message) && f.api_message) {
|
|
478
|
+
if (dynamicDict[f.api_message]) {
|
|
479
|
+
f.api_message = dynamicDict[f.api_message];
|
|
480
|
+
registerBrVariants(origMsg, f.api_message);
|
|
481
|
+
modified = true;
|
|
482
|
+
} else {
|
|
483
|
+
const clean = f.api_message.replace(/<br\\s*\\/?>/gi, '');
|
|
484
|
+
if (dynamicDict[clean]) {
|
|
485
|
+
f.api_message = dynamicDict[clean];
|
|
486
|
+
registerBrVariants(origMsg, f.api_message);
|
|
487
|
+
modified = true;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// 2. 处理海图进点气象/剧情提示 (api_cell_flavor 对象)
|
|
495
|
+
if (data.api_cell_flavor && typeof data.api_cell_flavor === 'object') {
|
|
496
|
+
const cf = data.api_cell_flavor;
|
|
497
|
+
if (cf.api_message) {
|
|
498
|
+
const orig = cf.api_message;
|
|
499
|
+
if (dynamicDict[orig]) {
|
|
500
|
+
cf.api_message = dynamicDict[orig];
|
|
501
|
+
registerBrVariants(orig, cf.api_message);
|
|
502
|
+
modified = true;
|
|
503
|
+
} else {
|
|
504
|
+
const clean = orig.replace(/<br\\s*\\/?>/gi, '');
|
|
505
|
+
if (dynamicDict[clean]) {
|
|
506
|
+
cf.api_message = dynamicDict[clean];
|
|
507
|
+
registerBrVariants(orig, cf.api_message);
|
|
508
|
+
modified = true;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
314
511
|
}
|
|
315
512
|
}
|
|
316
513
|
|
|
@@ -327,7 +524,12 @@ export function generateApiPatcherScript(apiData, options = {}) {
|
|
|
327
524
|
return url.indexOf('/api_start2/getData') !== -1 ||
|
|
328
525
|
url.indexOf('/api_get_member/picture_book') !== -1 ||
|
|
329
526
|
url.indexOf('/api_get_member/questlist') !== -1 ||
|
|
330
|
-
url.indexOf('/api_req_map/') !== -1
|
|
527
|
+
url.indexOf('/api_req_map/') !== -1 ||
|
|
528
|
+
url.indexOf('/api_req_sortie/') !== -1 ||
|
|
529
|
+
url.indexOf('/api_req_combined_battle/') !== -1 ||
|
|
530
|
+
url.indexOf('/api_req_battle_midnight/') !== -1 ||
|
|
531
|
+
url.indexOf('/api_req_practice/') !== -1 ||
|
|
532
|
+
url.indexOf('battle') !== -1;
|
|
331
533
|
}
|
|
332
534
|
|
|
333
535
|
function handleIntercept(target) {
|
|
@@ -363,8 +565,19 @@ export function generateApiPatcherScript(apiData, options = {}) {
|
|
|
363
565
|
modified = patchPictureBook(json.api_data, target._kanchs_body);
|
|
364
566
|
} else if (url.includes('/api_get_member/questlist')) {
|
|
365
567
|
modified = patchQuestlist(json.api_data);
|
|
366
|
-
}
|
|
367
|
-
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// 战斗、夜战、联合舰队或海图进点:检查并合流深海台词 (api_flavor_info) 与海况剧情 (api_cell_flavor)
|
|
571
|
+
if (
|
|
572
|
+
url.includes('/api_req_sortie/') ||
|
|
573
|
+
url.includes('/api_req_combined_battle/') ||
|
|
574
|
+
url.includes('/api_req_battle_midnight/') ||
|
|
575
|
+
url.includes('/api_req_practice/') ||
|
|
576
|
+
url.includes('/api_req_map/') ||
|
|
577
|
+
(json.api_data && (json.api_data.api_flavor_info || json.api_data.api_cell_flavor))
|
|
578
|
+
) {
|
|
579
|
+
const flavorModified = patchFlavor(json.api_data);
|
|
580
|
+
modified = modified || flavorModified;
|
|
368
581
|
}
|
|
369
582
|
|
|
370
583
|
if (modified) {
|
package/src/core/main-patcher.es
CHANGED
|
@@ -255,6 +255,7 @@ class MainPatcher {
|
|
|
255
255
|
enableApiMapInfo: configManager.get('enableApiMapInfo', true),
|
|
256
256
|
enableApiPictureBook: configManager.get('enableApiPictureBook', true),
|
|
257
257
|
enableApiFlavor: configManager.get('enableApiFlavor', true),
|
|
258
|
+
enableApiItem: configManager.get('enableApiItem', true),
|
|
258
259
|
}
|
|
259
260
|
const apiScript = generateApiPatcherScript(dataLoader.apiData, apiOptions)
|
|
260
261
|
if (apiScript) {
|
|
@@ -16,10 +16,61 @@ class ResourceManager {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* 判断指定路径是否位于用户系统的 Downloads (下载) 目录中
|
|
20
|
+
*/
|
|
21
|
+
isDownloadsPath(targetPath) {
|
|
22
|
+
if (!targetPath || typeof targetPath !== 'string') return false
|
|
23
|
+
try {
|
|
24
|
+
const home = process.env.HOME || process.env.USERPROFILE || ''
|
|
25
|
+
if (!home) return false
|
|
26
|
+
const downloads = path.resolve(path.join(home, 'Downloads')).toLowerCase()
|
|
27
|
+
const resolved = path.resolve(targetPath.trim()).toLowerCase()
|
|
28
|
+
return resolved === downloads || resolved.startsWith(downloads + path.sep)
|
|
29
|
+
} catch (_) {
|
|
30
|
+
return false
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 自动清理可能错误创建在 Downloads 目录下的 KanColle 临时挂载点
|
|
36
|
+
*/
|
|
37
|
+
cleanSpuriousDownloadsKanColle() {
|
|
38
|
+
try {
|
|
39
|
+
const home = process.env.HOME || process.env.USERPROFILE || ''
|
|
40
|
+
if (!home) return
|
|
41
|
+
const dlKc = path.join(home, 'Downloads', 'KanColle')
|
|
42
|
+
if (fs.existsSync(dlKc)) {
|
|
43
|
+
const cleanRec = (dir) => {
|
|
44
|
+
if (!fs.existsSync(dir)) return
|
|
45
|
+
const items = fs.readdirSync(dir)
|
|
46
|
+
for (const item of items) {
|
|
47
|
+
const full = path.join(dir, item)
|
|
48
|
+
try {
|
|
49
|
+
const st = fs.lstatSync(full)
|
|
50
|
+
if (st.isSymbolicLink()) {
|
|
51
|
+
fs.unlinkSync(full)
|
|
52
|
+
} else if (st.isDirectory()) {
|
|
53
|
+
cleanRec(full)
|
|
54
|
+
fs.rmdirSync(full)
|
|
55
|
+
} else {
|
|
56
|
+
fs.unlinkSync(full)
|
|
57
|
+
}
|
|
58
|
+
} catch (_) {}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
cleanRec(dlKc)
|
|
62
|
+
if (fs.existsSync(dlKc)) fs.rmdirSync(dlKc)
|
|
63
|
+
console.log('[KancolleCHS] 已安全清理 Downloads 目录下的 KanColle 临时挂载点')
|
|
64
|
+
}
|
|
65
|
+
} catch (_e) {}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 获取系统中所有可能存在的 POI 缓存目录路径 (包括用户自定义缓存路径、默认 MyCache 等,严格排除 Downloads)
|
|
20
70
|
*/
|
|
21
71
|
getAllPoiCacheDirs() {
|
|
22
72
|
const dirs = new Set()
|
|
73
|
+
this.cleanSpuriousDownloadsKanColle()
|
|
23
74
|
|
|
24
75
|
// 1. 若运行于 POI 渲染进程,优先从 POI 配置读取
|
|
25
76
|
try {
|
|
@@ -35,7 +86,9 @@ class ResourceManager {
|
|
|
35
86
|
} catch (_) {}
|
|
36
87
|
}
|
|
37
88
|
if (p && typeof p === 'string' && p.trim() && p !== 'null' && p !== 'undefined' && fs.existsSync(p)) {
|
|
38
|
-
|
|
89
|
+
if (!this.isDownloadsPath(p)) {
|
|
90
|
+
dirs.add(path.resolve(p))
|
|
91
|
+
}
|
|
39
92
|
}
|
|
40
93
|
|
|
41
94
|
// 检查 POI 全局默认缓存路径 (POI 源码: global.DEFAULT_CACHE_PATH)
|
|
@@ -43,7 +96,9 @@ class ResourceManager {
|
|
|
43
96
|
try {
|
|
44
97
|
const defaultCacheGlobal = window.remote.getGlobal('DEFAULT_CACHE_PATH')
|
|
45
98
|
if (defaultCacheGlobal && typeof defaultCacheGlobal === 'string' && fs.existsSync(defaultCacheGlobal)) {
|
|
46
|
-
|
|
99
|
+
if (!this.isDownloadsPath(defaultCacheGlobal)) {
|
|
100
|
+
dirs.add(path.resolve(defaultCacheGlobal))
|
|
101
|
+
}
|
|
47
102
|
}
|
|
48
103
|
} catch (_) {}
|
|
49
104
|
try {
|
|
@@ -75,7 +130,9 @@ class ResourceManager {
|
|
|
75
130
|
let cleaned = line.replace(/^\s*path:\s*/, '').trim()
|
|
76
131
|
cleaned = cleaned.replace(/^['"]|['"]$/g, '').replace(/\\\\/g, '\\').trim()
|
|
77
132
|
if (cleaned && cleaned !== 'null' && cleaned !== 'undefined' && fs.existsSync(cleaned)) {
|
|
78
|
-
|
|
133
|
+
if (!this.isDownloadsPath(cleaned)) {
|
|
134
|
+
dirs.add(path.resolve(cleaned))
|
|
135
|
+
}
|
|
79
136
|
}
|
|
80
137
|
break
|
|
81
138
|
} else if (!line.startsWith(' ') && !line.startsWith('\t')) {
|
|
@@ -91,7 +148,10 @@ class ResourceManager {
|
|
|
91
148
|
if (fs.existsSync(cacheDir)) dirs.add(path.resolve(cacheDir))
|
|
92
149
|
}
|
|
93
150
|
|
|
94
|
-
const list = Array.from(dirs)
|
|
151
|
+
const list = Array.from(dirs)
|
|
152
|
+
.filter((d) => typeof d === 'string' && d.trim() && d !== 'null' && d !== 'undefined')
|
|
153
|
+
.filter((d) => !this.isDownloadsPath(d))
|
|
154
|
+
|
|
95
155
|
if (list.length === 0) {
|
|
96
156
|
if (userDataDir) {
|
|
97
157
|
list.push(path.resolve(path.join(userDataDir, 'MyCache')))
|
|
@@ -105,6 +165,12 @@ class ResourceManager {
|
|
|
105
165
|
}
|
|
106
166
|
|
|
107
167
|
getPoiCacheDir() {
|
|
168
|
+
this.cleanSpuriousDownloadsKanColle()
|
|
169
|
+
const userDataDir = getPoiUserDataDir()
|
|
170
|
+
const defaultSafePath = userDataDir
|
|
171
|
+
? path.resolve(path.join(userDataDir, 'MyCache'))
|
|
172
|
+
: path.resolve(path.join(process.env.USERPROFILE || process.env.HOME || '.', '.poi', 'MyCache'))
|
|
173
|
+
|
|
108
174
|
try {
|
|
109
175
|
if (typeof window !== 'undefined') {
|
|
110
176
|
let val = null
|
|
@@ -118,6 +184,15 @@ class ResourceManager {
|
|
|
118
184
|
} catch (_) {}
|
|
119
185
|
}
|
|
120
186
|
if (val && typeof val === 'string' && val.trim() && val !== 'null' && val !== 'undefined') {
|
|
187
|
+
if (this.isDownloadsPath(val)) {
|
|
188
|
+
console.warn('[KancolleCHS] 检测到 POI 缓存路径指向 Downloads,强制重置为 MyCache 以保护下载目录')
|
|
189
|
+
try {
|
|
190
|
+
if (window.config && typeof window.config.set === 'function') {
|
|
191
|
+
window.config.set('poi.misc.cache.path', defaultSafePath)
|
|
192
|
+
}
|
|
193
|
+
} catch (_) {}
|
|
194
|
+
return defaultSafePath
|
|
195
|
+
}
|
|
121
196
|
return path.resolve(val)
|
|
122
197
|
}
|
|
123
198
|
|
|
@@ -125,7 +200,9 @@ class ResourceManager {
|
|
|
125
200
|
try {
|
|
126
201
|
const defaultCacheGlobal = window.remote.getGlobal('DEFAULT_CACHE_PATH')
|
|
127
202
|
if (defaultCacheGlobal && typeof defaultCacheGlobal === 'string' && defaultCacheGlobal.trim()) {
|
|
128
|
-
|
|
203
|
+
if (!this.isDownloadsPath(defaultCacheGlobal)) {
|
|
204
|
+
return path.resolve(defaultCacheGlobal)
|
|
205
|
+
}
|
|
129
206
|
}
|
|
130
207
|
} catch (_) {}
|
|
131
208
|
try {
|
|
@@ -139,19 +216,13 @@ class ResourceManager {
|
|
|
139
216
|
} catch (_e) {}
|
|
140
217
|
|
|
141
218
|
const allDirs = this.getAllPoiCacheDirs()
|
|
142
|
-
|
|
143
|
-
|
|
219
|
+
for (const d of allDirs) {
|
|
220
|
+
if (d && typeof d === 'string' && d.trim() && !this.isDownloadsPath(d)) {
|
|
221
|
+
return path.resolve(d)
|
|
222
|
+
}
|
|
144
223
|
}
|
|
145
224
|
|
|
146
|
-
|
|
147
|
-
if (userDataDir) {
|
|
148
|
-
return path.resolve(path.join(userDataDir, 'MyCache'))
|
|
149
|
-
}
|
|
150
|
-
const home = process.env.HOME || process.env.USERPROFILE || ''
|
|
151
|
-
if (home) {
|
|
152
|
-
return path.resolve(path.join(home, '.poi', 'MyCache'))
|
|
153
|
-
}
|
|
154
|
-
return path.resolve('.')
|
|
225
|
+
return defaultSafePath
|
|
155
226
|
}
|
|
156
227
|
|
|
157
228
|
/**
|