poi-plugin-kancolle-chs 1.1.0
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 +60 -0
- package/package.json +27 -0
- package/src/config.es +143 -0
- package/src/constants.es +83 -0
- package/src/core/api-merger.es +445 -0
- package/src/core/font-detector.es +72 -0
- package/src/core/git-manager.es +398 -0
- package/src/core/main-patcher.es +367 -0
- package/src/core/resource-manager.es +246 -0
- package/src/core/text-patcher.es +116 -0
- package/src/ja-maps.es +509 -0
- package/src/loaders/data-loader.es +391 -0
- package/src/loaders/json-cleaner.es +98 -0
- package/src/loaders/regex-validator.es +64 -0
- package/src/views/MainPanel.es +1458 -0
package/index.es
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { MainPanel } from './src/views/MainPanel'
|
|
2
|
+
import { configManager } from './src/config'
|
|
3
|
+
import { dataLoader } from './src/loaders/data-loader'
|
|
4
|
+
import { mainPatcher } from './src/core/main-patcher'
|
|
5
|
+
import { resourceManager } from './src/core/resource-manager'
|
|
6
|
+
|
|
7
|
+
// 导出插件在 POI 中展示的界面组件
|
|
8
|
+
export const reactClass = MainPanel
|
|
9
|
+
|
|
10
|
+
// 是否在 POI 标签栏显示控制台
|
|
11
|
+
export const show = true
|
|
12
|
+
|
|
13
|
+
// 窗口模式(false 为嵌入在 POI 主窗口 Tab 中)
|
|
14
|
+
export const windowMode = false
|
|
15
|
+
|
|
16
|
+
// 插件被启用时的生命周期钩子
|
|
17
|
+
export const pluginDidLoad = async () => {
|
|
18
|
+
console.log('[砍口垒汉化计划] POI 插件启动中...')
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
// 检查总开关
|
|
22
|
+
if (configManager.get('enabled', true)) {
|
|
23
|
+
// 1. 全量预加载汉化字典与正则
|
|
24
|
+
await dataLoader.loadAll()
|
|
25
|
+
|
|
26
|
+
// 2. 挂载静态贴图与中文字体 (.hack 细分控制)
|
|
27
|
+
await resourceManager.mountResources()
|
|
28
|
+
|
|
29
|
+
// 3. 自动编译并部署 main.hack.js 补丁
|
|
30
|
+
if (configManager.get('autoDeployOnStart', true)) {
|
|
31
|
+
await mainPatcher.buildAndDeploy()
|
|
32
|
+
}
|
|
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
|
+
|
|
41
|
+
console.log('[砍口垒汉化计划PLUS] 插件加载完毕,原生汉化模式已生效!')
|
|
42
|
+
} else {
|
|
43
|
+
console.log('[砍口垒汉化计划PLUS] 插件当前处于停用状态')
|
|
44
|
+
}
|
|
45
|
+
} catch (e) {
|
|
46
|
+
console.error('[砍口垒汉化计划PLUS] 插件启动阶段出现异常:', e)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 插件被禁用或卸载时的生命周期钩子
|
|
51
|
+
export const pluginWillUnload = async () => {
|
|
52
|
+
console.log('[砍口垒汉化计划] 插件卸载中,正在清理魔改补丁与挂载点...')
|
|
53
|
+
try {
|
|
54
|
+
await mainPatcher.undeploy()
|
|
55
|
+
await resourceManager.unmountResources()
|
|
56
|
+
console.log('[砍口垒汉化计划] 插件已安全卸载,原生环境已复原')
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.warn('[砍口垒汉化计划] 清理魔改挂载点时出错:', e)
|
|
59
|
+
}
|
|
60
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "poi-plugin-kancolle-chs",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "砍口垒汉化计划PLUS POI 原生独立插件:提供全界面文本替换、正则动态替换、KCSAPI 响应合流、中文字体与贴图魔改、自定义字体适配与官方资源更新",
|
|
5
|
+
"main": "index.es",
|
|
6
|
+
"files": [
|
|
7
|
+
"index.es",
|
|
8
|
+
"src/"
|
|
9
|
+
],
|
|
10
|
+
"author": "泉浅漪",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"poi",
|
|
14
|
+
"kancolle",
|
|
15
|
+
"poi-plugin",
|
|
16
|
+
"kancolle-chs",
|
|
17
|
+
"localization",
|
|
18
|
+
"translation"
|
|
19
|
+
],
|
|
20
|
+
"poiPlugin": {
|
|
21
|
+
"name": "砍口垒汉化PLUS",
|
|
22
|
+
"title": "砍口垒汉化计划PLUS",
|
|
23
|
+
"description": "原生集成《砍口垒汉化计划PLUS》,支持全界面文本翻译、任务/家具/海图/图鉴汉化、自定义字体优先适配、中文字体魔改与官方资源自动更新",
|
|
24
|
+
"icon": "fa/language",
|
|
25
|
+
"priority": 20
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/config.es
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import fs from 'fs-extra'
|
|
3
|
+
import { DEFAULT_CONFIG, RECOMMENDED_SOURCE_PATHS } from './constants'
|
|
4
|
+
|
|
5
|
+
class ConfigManager {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.pluginDir = path.resolve(__dirname, '..')
|
|
8
|
+
this.configFile = path.join(this.pluginDir, 'config.json')
|
|
9
|
+
this.config = { ...DEFAULT_CONFIG }
|
|
10
|
+
this.listeners = new Set()
|
|
11
|
+
this.loadConfig()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
loadConfig() {
|
|
15
|
+
try {
|
|
16
|
+
if (fs.existsSync(this.configFile)) {
|
|
17
|
+
const saved = fs.readJsonSync(this.configFile)
|
|
18
|
+
this.config = { ...DEFAULT_CONFIG, ...saved }
|
|
19
|
+
} else {
|
|
20
|
+
// 若首次启动且无配置,尝试查找推荐路径初始化
|
|
21
|
+
for (const candidate of RECOMMENDED_SOURCE_PATHS) {
|
|
22
|
+
if (fs.existsSync(candidate)) {
|
|
23
|
+
this.config.sourcePath = candidate
|
|
24
|
+
break
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
this.saveConfig()
|
|
28
|
+
}
|
|
29
|
+
} catch (e) {
|
|
30
|
+
console.error('[KancolleCHS] 加载配置文件失败:', e)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
saveConfig() {
|
|
35
|
+
try {
|
|
36
|
+
fs.writeJsonSync(this.configFile, this.config, { spaces: 2 })
|
|
37
|
+
} catch (e) {
|
|
38
|
+
console.error('[KancolleCHS] 保存配置文件失败:', e)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
update(newConfig) {
|
|
43
|
+
this.config = { ...this.config, ...newConfig }
|
|
44
|
+
this.saveConfig()
|
|
45
|
+
this.notify()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get(key, defaultValue = undefined) {
|
|
49
|
+
return this.config[key] !== undefined ? this.config[key] : defaultValue
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
set(key, value) {
|
|
53
|
+
this.config[key] = value
|
|
54
|
+
this.saveConfig()
|
|
55
|
+
this.notify()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
subscribe(listener) {
|
|
59
|
+
this.listeners.add(listener)
|
|
60
|
+
return () => this.listeners.delete(listener)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
notify() {
|
|
64
|
+
for (const fn of this.listeners) {
|
|
65
|
+
try {
|
|
66
|
+
fn(this.config)
|
|
67
|
+
} catch (e) {
|
|
68
|
+
console.error('[KancolleCHS] 配置更新通知失败:', e)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 检验指定路径是否为合法的 Kancolle_to_CHS 汉化资产目录
|
|
75
|
+
*/
|
|
76
|
+
validatePath(dirPath) {
|
|
77
|
+
if (!dirPath || typeof dirPath !== 'string' || dirPath.trim() === '') {
|
|
78
|
+
return {
|
|
79
|
+
valid: false,
|
|
80
|
+
error: '路径不能为空',
|
|
81
|
+
details: {},
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const resolved = path.resolve(dirPath.trim())
|
|
86
|
+
if (!fs.existsSync(resolved)) {
|
|
87
|
+
return {
|
|
88
|
+
valid: false,
|
|
89
|
+
error: '指定文件夹不存在',
|
|
90
|
+
details: {},
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const details = {
|
|
95
|
+
textDict: fs.existsSync(path.join(resolved, 'text', 'text')),
|
|
96
|
+
textRegex: fs.existsSync(path.join(resolved, 'text', 'text_regex')),
|
|
97
|
+
textApi: fs.existsSync(path.join(resolved, 'text', 'api')),
|
|
98
|
+
images: fs.existsSync(path.join(resolved, 'cache', 'kcs2', 'img')),
|
|
99
|
+
fonts: fs.existsSync(path.join(resolved, 'cache', 'kcs2', 'resources', 'font')),
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const missing = []
|
|
103
|
+
if (!details.textDict) missing.push('text/text (界面词条)')
|
|
104
|
+
if (!details.textRegex) missing.push('text/text_regex (正则规则)')
|
|
105
|
+
if (!details.textApi) missing.push('text/api (API补丁)')
|
|
106
|
+
if (!details.images) missing.push('cache/kcs2/img (贴图魔改)')
|
|
107
|
+
if (!details.fonts) missing.push('cache/kcs2/resources/font (中文字体)')
|
|
108
|
+
|
|
109
|
+
// 只要具备任一核心要素即视为主目录有效,但提供明细
|
|
110
|
+
const valid = details.textDict || details.textApi || details.images
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
valid,
|
|
114
|
+
path: resolved,
|
|
115
|
+
details,
|
|
116
|
+
missing,
|
|
117
|
+
error: valid ? null : `未在目录下找到有效的汉化包文件: 缺少 ${missing.join(', ')}`,
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 解析当前设定的汉化源目录 (以用户手动选择为绝对最高优先级)
|
|
123
|
+
*/
|
|
124
|
+
resolveSourcePath() {
|
|
125
|
+
if (this.config.sourcePath && this.config.sourcePath.trim() !== '') {
|
|
126
|
+
const p = this.config.sourcePath.trim()
|
|
127
|
+
if (fs.existsSync(p)) {
|
|
128
|
+
return path.resolve(p)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 次级备选:检查推荐目录
|
|
133
|
+
for (const candidate of RECOMMENDED_SOURCE_PATHS) {
|
|
134
|
+
if (fs.existsSync(candidate)) {
|
|
135
|
+
return path.resolve(candidate)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return null
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export const configManager = new ConfigManager()
|
package/src/constants.es
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
export * from './ja-maps'
|
|
3
|
+
|
|
4
|
+
export const API_PATHS = {
|
|
5
|
+
START2: '/kcsapi/api_start2/getData',
|
|
6
|
+
PICTURE_BOOK: '/kcsapi/api_get_member/picture_book',
|
|
7
|
+
QUESTLIST: '/kcsapi/api_get_member/questlist',
|
|
8
|
+
MAP_NEXT: '/kcsapi/api_req_map/next',
|
|
9
|
+
MAP_START: '/kcsapi/api_req_map/start',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// 官方汉化仓库与发布页地址
|
|
13
|
+
export const OFFICIAL_REPO_URL = 'https://github.com/asaico/Kancolle_to_CHS'
|
|
14
|
+
export const OFFICIAL_REPO_GIT = 'https://github.com/asaico/Kancolle_to_CHS.git'
|
|
15
|
+
export const OFFICIAL_REPO_RELEASES = 'https://github.com/asaico/Kancolle_to_CHS/releases'
|
|
16
|
+
|
|
17
|
+
// 常用推荐系统字体预设
|
|
18
|
+
export const PRESET_FONTS = [
|
|
19
|
+
{ label: '微软雅黑 (Microsoft YaHei)', value: 'Microsoft YaHei' },
|
|
20
|
+
{ label: '思源黑体 (Source Han Sans SC)', value: 'Source Han Sans SC' },
|
|
21
|
+
{ label: '苹方 / 苹方简体 (PingFang SC)', value: 'PingFang SC' },
|
|
22
|
+
{ label: '霞鹜文楷 (LXGW WenKai)', value: 'LXGW WenKai' },
|
|
23
|
+
{ label: '更纱黑体 (Sarasa Gothic SC)', value: 'Sarasa Gothic SC' },
|
|
24
|
+
{ label: '鸿蒙字体 (HarmonyOS Sans SC)', value: 'HarmonyOS Sans SC' },
|
|
25
|
+
{ label: '汉仪旗黑 (HYQiHei)', value: 'HYQiHei' },
|
|
26
|
+
{ label: '黑体 (SimHei)', value: 'SimHei' },
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
// 推荐备选路径(仅在用户未配置时智能查找标准目录,不包含任何私人硬编码)
|
|
30
|
+
export const RECOMMENDED_SOURCE_PATHS = [
|
|
31
|
+
path.join(process.env.APPDATA || '', 'poi', 'kancolle-chs-resources'),
|
|
32
|
+
path.join(process.env.USERPROFILE || '', 'Downloads', 'Kancolle_to_CHS'),
|
|
33
|
+
path.resolve(__dirname, '..', '..', 'Kancolle_to_CHS'),
|
|
34
|
+
path.resolve(__dirname, '..', 'resources'),
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
export const DEFAULT_CONFIG = {
|
|
38
|
+
// 插件全局总开关
|
|
39
|
+
enabled: true,
|
|
40
|
+
|
|
41
|
+
// 用户手动指定的汉化包根目录(包含 text 与 cache 文件夹)
|
|
42
|
+
sourcePath: '',
|
|
43
|
+
|
|
44
|
+
// --- 1. 界面文字翻译开关 ---
|
|
45
|
+
enableTextDict: true, // 界面精确词条匹配 (text/text/*.json)
|
|
46
|
+
enableTextRegex: true, // 界面动态正则替换 (text/text_regex/*.json)
|
|
47
|
+
|
|
48
|
+
// --- 2. KCSAPI 响应合流细分开关 ---
|
|
49
|
+
enableApiQuest: true, // 任务系统汉化 (questlist.json)
|
|
50
|
+
enableApiShip: true, // 舰船名称与初始形态入手台词 (start2.api_mst_ship.json)
|
|
51
|
+
enableApiMission: true, // 远征任务名称与详细说明 (start2.api_mst_mission.json)
|
|
52
|
+
enableApiFurniture: true, // 家具名称与背景描述 (start2.api_mst_furniture.json)
|
|
53
|
+
enableApiMapInfo: true, // 出击海区与作战行动说明 (start2.api_mst_mapinfo.json)
|
|
54
|
+
enableApiPictureBook: true, // 舰船与装备图鉴介绍 (picture_book.ship / slotitem)
|
|
55
|
+
enableApiFlavor: true, // 海域进点气象与深海台词 (battle.api_flavor_info.json)
|
|
56
|
+
|
|
57
|
+
// --- 3. 静态魔改资产细分开关 ---
|
|
58
|
+
enableFontHack: true, // 优美中文字体魔改 (A-OTF-UDShinGoPro*.hack.woff2)
|
|
59
|
+
enableImageHack: true, // 界面贴图与图标魔改 (.hack.png / .hack.jpg)
|
|
60
|
+
|
|
61
|
+
// --- 4. 自定义字体优先适配 ---
|
|
62
|
+
enableCustomFont: false, // 是否启用用户自定义字体优先适配
|
|
63
|
+
customFontSource: 'system', // 'system' (系统字体名) 或 'file' (本地字体文件)
|
|
64
|
+
customFontName: 'Microsoft YaHei', // 系统字体名称
|
|
65
|
+
customFontPath: '', // 本地字体文件绝对路径 (.woff2 / .ttf / .otf)
|
|
66
|
+
|
|
67
|
+
// --- 5. 官方资源与更新管理 ---
|
|
68
|
+
autoCheckUpdate: true, // 插件启动时是否在后台自动检查更新
|
|
69
|
+
|
|
70
|
+
// --- 6. 游戏运行帧率上限调节 ---
|
|
71
|
+
fpsLimit: 60, // 游戏帧率上限 (默认 60,可选 60, 120, 165, 240)
|
|
72
|
+
|
|
73
|
+
// 运行配置
|
|
74
|
+
autoDeployOnStart: true, // 插件启动时自动编译部署补丁
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 常用帧率预设
|
|
78
|
+
export const PRESET_FPS = [
|
|
79
|
+
{ label: '60 FPS', value: 60, tag: '原版默认', desc: '原版默认上限,省电稳定' },
|
|
80
|
+
{ label: '120 FPS', value: 120, tag: '双倍流畅', desc: '两倍丝滑,适合高刷显示器' },
|
|
81
|
+
{ label: '165 FPS', value: 165, tag: '电竞高刷', desc: '电竞级刷新率,极速响应' },
|
|
82
|
+
{ label: '240 FPS', value: 240, tag: '极致满血', desc: '满血超高刷,极致流畅动效' },
|
|
83
|
+
]
|