poi-plugin-kai-planner 1.0.18 → 1.0.20
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/README.md +3 -3
- package/index.js +24 -23
- package/package.json +1 -1
- package/src/app/KaiPlannerApp.js +58 -11
- package/src/app/tabs/acquisition/AcquisitionTab.js +16 -5
- package/src/app/tabs/daily/DailyTabV2.js +4 -0
- package/src/app/tabs/debug/debugDiagnostics.js +1 -0
- package/src/app/tabs/wishlist/WishlistTabV2.js +19 -8
- package/src/core/poi/ensurePluginWindowVisible.js +54 -0
- package/src/data/static/data_manifest.json +48 -31
- package/src/data/static/equip_base_cost.json +28 -0
- package/src/data/static/improvement_arrangement.json +708 -276
- package/src/data/static/improvement_consume_item.json +234 -0
- package/src/data/static/improvement_consume_step.json +75 -3
- package/src/data/static/improvement_upgrade_target.json +8 -8
- package/src/services/player/getReduxStateFromEnvWindow.js +10 -6
- package/src/services/static/version/dataUpdateManager.js +75 -40
- package/src/services/static/version/requestText.js +81 -0
package/README.md
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
- 在`每日改修`页面查看当天可改修装备、基础消耗、秘书舰要求与可进化状态。
|
|
8
8
|
- 在`每日改修`页面把常看的装备标记为收藏,收藏项会优先排序并长期保存在本地。
|
|
9
|
-
-
|
|
9
|
+
- 在`改修规划`页面创建、编辑、刷新和追踪个人改修计划,查看实时完成进度与资源缺口。
|
|
10
10
|
- 在`装备获取规划`页面管理想提前准备的装备,查看它们与未完成改修计划之间的待消耗关联。
|
|
11
|
-
-
|
|
12
|
-
-
|
|
11
|
+
- 按需开启 `poiPlugin.enableDebug` 后,在 `Debug` 页面查看运行时数据;默认隐藏。
|
|
12
|
+
- 静态数据在页面挂载时检查:成功后间隔 2 个 UTC 自然日,失败后间隔 15 分钟;可手动“检查更新”。下载有超时和有限重试,成功后页面自动刷新并保留编辑草稿。
|
|
13
13
|
- 改修规划的待消耗道具会区分 useitem 与 `api_material` 资源类材料,例如高速建造材、高速修复材、开发资材、改修资材。
|
|
14
14
|
|
|
15
15
|
## 技术文档
|
package/index.js
CHANGED
|
@@ -7,6 +7,8 @@ const { WindowEnv } = require("views/components/etc/window-env");
|
|
|
7
7
|
const { KaiPlannerApp } = require("./src/app/KaiPlannerApp");
|
|
8
8
|
const { subscribeMaterialResourceUpdates } = require("./src/services/player/materialResourceCounts");
|
|
9
9
|
|
|
10
|
+
const { enableDataUpdates, disposeDataUpdates } = require("./src/services/static/version/dataUpdateManager");
|
|
11
|
+
|
|
10
12
|
let unsubscribeMaterialResourceUpdates = null;
|
|
11
13
|
|
|
12
14
|
function KaiPlannerAppWithEnv() {
|
|
@@ -21,27 +23,26 @@ function KaiPlannerAppWithEnv() {
|
|
|
21
23
|
});
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
},
|
|
26
|
+
exports.reactClass = KaiPlannerAppWithEnv;
|
|
27
|
+
exports.windowMode = true;
|
|
28
|
+
exports.pluginDidLoad = function pluginDidLoad() {
|
|
29
|
+
enableDataUpdates();
|
|
30
|
+
if (!unsubscribeMaterialResourceUpdates) {
|
|
31
|
+
unsubscribeMaterialResourceUpdates = subscribeMaterialResourceUpdates(
|
|
32
|
+
typeof window !== "undefined" ? window : null
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
if (typeof window !== "undefined" && window.log) {
|
|
36
|
+
window.log("[kai-planner] loaded");
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
exports.pluginWillUnload = function pluginWillUnload() {
|
|
40
|
+
disposeDataUpdates();
|
|
41
|
+
if (unsubscribeMaterialResourceUpdates) {
|
|
42
|
+
unsubscribeMaterialResourceUpdates();
|
|
43
|
+
unsubscribeMaterialResourceUpdates = null;
|
|
44
|
+
}
|
|
45
|
+
if (typeof window !== "undefined" && window.log) {
|
|
46
|
+
window.log("[kai-planner] unloaded");
|
|
47
|
+
}
|
|
47
48
|
};
|
package/package.json
CHANGED
package/src/app/KaiPlannerApp.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const React = require("react");
|
|
2
2
|
const { DailyTabV2 } = require("./tabs/daily/DailyTabV2");
|
|
3
|
-
const { checkAndUpdateData } = require("../services/static/version/dataUpdateManager");
|
|
3
|
+
const { checkAndUpdateData, getUpdateState, subscribeDataUpdates } = require("../services/static/version/dataUpdateManager");
|
|
4
4
|
const { readMeta } = require("../services/static/version/versionStore");
|
|
5
|
+
const { ensurePluginWindowVisible } = require("../core/poi/ensurePluginWindowVisible");
|
|
5
6
|
const {
|
|
6
7
|
DEFAULT_THEME_TOKENS,
|
|
7
8
|
readPoiTheme,
|
|
@@ -66,7 +67,7 @@ function getUpdateFailureTip(result) {
|
|
|
66
67
|
data_source_not_configured: "未配置远端数据源",
|
|
67
68
|
};
|
|
68
69
|
const label = labels[reason] || "检查失败";
|
|
69
|
-
return
|
|
70
|
+
return reason === "update_cancelled" ? "更新已取消。" : `${label},可点击检查更新重试。`;
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
class KaiPlannerApp extends React.Component {
|
|
@@ -77,7 +78,10 @@ class KaiPlannerApp extends React.Component {
|
|
|
77
78
|
wishlistLoadError: null,
|
|
78
79
|
acquisitionLoadError: null,
|
|
79
80
|
debugLoadError: null,
|
|
80
|
-
checkingUpdate:
|
|
81
|
+
checkingUpdate: getUpdateState().checking,
|
|
82
|
+
dataRevision: getUpdateState().dataRevision,
|
|
83
|
+
updateDiagnostic: "",
|
|
84
|
+
copyTip: "",
|
|
81
85
|
lastUpdateAtText: "-",
|
|
82
86
|
updateTip: "",
|
|
83
87
|
materialResourceVersion: 0,
|
|
@@ -89,12 +93,17 @@ class KaiPlannerApp extends React.Component {
|
|
|
89
93
|
this._unsubscribeTheme = null;
|
|
90
94
|
this._unsubscribeMaterialResources = null;
|
|
91
95
|
this._themeWarmupTimer = null;
|
|
96
|
+
this._cancelWindowVisibility = null;
|
|
92
97
|
this.enableDebug = readEnableDebugFlag();
|
|
93
98
|
this.handleCheckUpdate = this.handleCheckUpdate.bind(this);
|
|
94
99
|
this.syncTheme = this.syncTheme.bind(this);
|
|
95
100
|
}
|
|
96
101
|
|
|
97
102
|
componentDidMount() {
|
|
103
|
+
this._mounted = true;
|
|
104
|
+
this._unsubscribeDataUpdates = subscribeDataUpdates(() => this.syncDataUpdateState());
|
|
105
|
+
this.syncDataUpdateState();
|
|
106
|
+
this._cancelWindowVisibility = ensurePluginWindowVisible(this.props.envWindow, this.props.envCtx);
|
|
98
107
|
this.syncTheme();
|
|
99
108
|
this._unsubscribeTheme = subscribePoiTheme(this.props.envWindow, (hostTheme) => {
|
|
100
109
|
this.setState({ themeTokens: buildPlannerThemeTokens(hostTheme) });
|
|
@@ -109,6 +118,10 @@ class KaiPlannerApp extends React.Component {
|
|
|
109
118
|
}
|
|
110
119
|
|
|
111
120
|
componentWillUnmount() {
|
|
121
|
+
this._mounted = false;
|
|
122
|
+
if (this._unsubscribeDataUpdates) this._unsubscribeDataUpdates();
|
|
123
|
+
if (this._cancelWindowVisibility) this._cancelWindowVisibility();
|
|
124
|
+
this._cancelWindowVisibility = null;
|
|
112
125
|
if (typeof this._unsubscribeTheme === "function") this._unsubscribeTheme();
|
|
113
126
|
if (typeof this._unsubscribeMaterialResources === "function") this._unsubscribeMaterialResources();
|
|
114
127
|
if (this._themeWarmupTimer != null) {
|
|
@@ -133,21 +146,44 @@ class KaiPlannerApp extends React.Component {
|
|
|
133
146
|
} catch {}
|
|
134
147
|
}
|
|
135
148
|
|
|
149
|
+
syncDataUpdateState() {
|
|
150
|
+
if (!this._mounted) return;
|
|
151
|
+
const update = getUpdateState();
|
|
152
|
+
const meta = readMeta();
|
|
153
|
+
const result = update.result;
|
|
154
|
+
const failure = result && !result.ok ? result : ((!result || result.skipped) && meta.lastCheckOk === false ? {
|
|
155
|
+
reason: meta.lastCheckReason, error: meta.lastCheckError, diagnostic: meta.lastCheckDiagnostic,
|
|
156
|
+
} : null);
|
|
157
|
+
this.setState({
|
|
158
|
+
checkingUpdate: update.checking,
|
|
159
|
+
dataRevision: update.dataRevision,
|
|
160
|
+
updateDiagnostic: failure ? JSON.stringify({ checkedAt: meta.lastCheckAt, reason: failure.reason, diagnostic: failure.diagnostic, error: failure.error }, null, 2) : "",
|
|
161
|
+
});
|
|
162
|
+
this.syncUpdateMeta();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async copyUpdateDiagnostic() {
|
|
166
|
+
try {
|
|
167
|
+
await require("views/services/clipboard").writeClipboardText(this.state.updateDiagnostic);
|
|
168
|
+
if (this._mounted) this.setState({ copyTip: "已复制" });
|
|
169
|
+
} catch {
|
|
170
|
+
if (this._mounted) this.setState({ copyTip: "复制失败,请选中下方详情手动复制。" });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
136
174
|
async handleCheckUpdate(force) {
|
|
137
|
-
if (this.
|
|
138
|
-
this.setState({
|
|
175
|
+
if (!this._mounted) return;
|
|
176
|
+
this.setState({ updateTip: force ? "正在检查..." : "", copyTip: "" });
|
|
139
177
|
try {
|
|
140
178
|
const result = await checkAndUpdateData({ force: !!force });
|
|
141
|
-
this.
|
|
179
|
+
if (!this._mounted) return;
|
|
142
180
|
if (force) {
|
|
143
|
-
if (result
|
|
144
|
-
else if (result
|
|
181
|
+
if (result.ok && result.updated) this.setState({ updateTip: `已更新到数据版本 ${result.remoteVersion}` });
|
|
182
|
+
else if (result.ok) this.setState({ updateTip: "当前已是最新数据。" });
|
|
145
183
|
else this.setState({ updateTip: getUpdateFailureTip(result) });
|
|
146
184
|
}
|
|
147
185
|
} catch (error) {
|
|
148
|
-
if (
|
|
149
|
-
} finally {
|
|
150
|
-
this.setState({ checkingUpdate: false });
|
|
186
|
+
if (this._mounted) this.setState({ updateTip: "检查失败,可重试。", updateDiagnostic: String(error.stack || error) });
|
|
151
187
|
}
|
|
152
188
|
}
|
|
153
189
|
|
|
@@ -177,6 +213,7 @@ class KaiPlannerApp extends React.Component {
|
|
|
177
213
|
content = React.createElement(DailyTabV2, {
|
|
178
214
|
envWindow: this.props.envWindow,
|
|
179
215
|
envCtx: this.props.envCtx,
|
|
216
|
+
dataRevision: this.state.dataRevision,
|
|
180
217
|
themeTokens,
|
|
181
218
|
});
|
|
182
219
|
} else if (tab === "wishlist") {
|
|
@@ -198,6 +235,7 @@ class KaiPlannerApp extends React.Component {
|
|
|
198
235
|
content = React.createElement(this._WishlistTab, {
|
|
199
236
|
envWindow: this.props.envWindow,
|
|
200
237
|
envCtx: this.props.envCtx,
|
|
238
|
+
dataRevision: this.state.dataRevision,
|
|
201
239
|
materialResourceVersion: this.state.materialResourceVersion,
|
|
202
240
|
themeTokens,
|
|
203
241
|
});
|
|
@@ -223,6 +261,7 @@ class KaiPlannerApp extends React.Component {
|
|
|
223
261
|
content = React.createElement(this._AcquisitionTab, {
|
|
224
262
|
envWindow: this.props.envWindow,
|
|
225
263
|
envCtx: this.props.envCtx,
|
|
264
|
+
dataRevision: this.state.dataRevision,
|
|
226
265
|
themeTokens,
|
|
227
266
|
});
|
|
228
267
|
} else {
|
|
@@ -247,6 +286,7 @@ class KaiPlannerApp extends React.Component {
|
|
|
247
286
|
content = React.createElement(this._DebugTab, {
|
|
248
287
|
envWindow: this.props.envWindow,
|
|
249
288
|
envCtx: this.props.envCtx,
|
|
289
|
+
dataRevision: this.state.dataRevision,
|
|
250
290
|
themeTokens,
|
|
251
291
|
});
|
|
252
292
|
} else {
|
|
@@ -284,6 +324,13 @@ class KaiPlannerApp extends React.Component {
|
|
|
284
324
|
this.state.updateTip ? React.createElement("span", { style: { fontSize: 14, color: themeTokens.textMuted } }, this.state.updateTip) : null
|
|
285
325
|
)
|
|
286
326
|
),
|
|
327
|
+
this.state.updateDiagnostic ? React.createElement("details", { style: { marginBottom: 12 } },
|
|
328
|
+
React.createElement("summary", null, "最近一次更新未完成:查看诊断详情"),
|
|
329
|
+
React.createElement("button", { onClick: () => this.copyUpdateDiagnostic() }, "复制诊断详情"),
|
|
330
|
+
React.createElement("span", null, this.state.copyTip),
|
|
331
|
+
React.createElement("textarea", { readOnly: true, value: this.state.updateDiagnostic,
|
|
332
|
+
style: { width: "100%", height: 140 }, onFocus: (event) => event.target.select() })
|
|
333
|
+
) : null,
|
|
287
334
|
content
|
|
288
335
|
);
|
|
289
336
|
}
|
|
@@ -48,11 +48,7 @@ class AcquisitionTab extends React.Component {
|
|
|
48
48
|
constructor(props) {
|
|
49
49
|
super(props);
|
|
50
50
|
|
|
51
|
-
this.
|
|
52
|
-
this.consumeIndexes = buildConsumeIndexes(this.staticData);
|
|
53
|
-
this.upgradeIndexes = buildUpgradeIndexes(this.staticData);
|
|
54
|
-
this.pathByPair = buildPathIndexes(this.staticData).pathByPair;
|
|
55
|
-
this.arrangementIndex = buildArrangementIndex(this.staticData.improvementArrangement).index;
|
|
51
|
+
this.reloadStaticData();
|
|
56
52
|
|
|
57
53
|
this.state = {
|
|
58
54
|
nowText: formatTokyoText(),
|
|
@@ -77,11 +73,26 @@ class AcquisitionTab extends React.Component {
|
|
|
77
73
|
this.refresh = this.refresh.bind(this);
|
|
78
74
|
}
|
|
79
75
|
|
|
76
|
+
reloadStaticData() {
|
|
77
|
+
this.staticData = loadStaticData();
|
|
78
|
+
this.consumeIndexes = buildConsumeIndexes(this.staticData);
|
|
79
|
+
this.upgradeIndexes = buildUpgradeIndexes(this.staticData);
|
|
80
|
+
this.pathByPair = buildPathIndexes(this.staticData).pathByPair;
|
|
81
|
+
this.arrangementIndex = buildArrangementIndex(this.staticData.improvementArrangement).index;
|
|
82
|
+
}
|
|
83
|
+
|
|
80
84
|
componentDidMount() {
|
|
81
85
|
this._timer = setInterval(() => this.setState({ nowText: formatTokyoText() }), 1000);
|
|
82
86
|
this.refresh();
|
|
83
87
|
}
|
|
84
88
|
|
|
89
|
+
componentDidUpdate(prevProps) {
|
|
90
|
+
if (prevProps.dataRevision !== this.props.dataRevision) {
|
|
91
|
+
this.reloadStaticData();
|
|
92
|
+
this.refresh();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
85
96
|
componentWillUnmount() {
|
|
86
97
|
if (this._timer) clearInterval(this._timer);
|
|
87
98
|
}
|
|
@@ -185,6 +185,10 @@ class DailyTabV2 extends React.Component {
|
|
|
185
185
|
}, 1000);
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
componentDidUpdate(prevProps) {
|
|
189
|
+
if (prevProps.dataRevision !== this.props.dataRevision) this.refresh();
|
|
190
|
+
}
|
|
191
|
+
|
|
188
192
|
componentWillUnmount() {
|
|
189
193
|
if (this._timer) clearInterval(this._timer);
|
|
190
194
|
}
|
|
@@ -42,6 +42,7 @@ function buildDebugDiagnostics({
|
|
|
42
42
|
lastCheckAt: meta.lastCheckAt || "",
|
|
43
43
|
lastCheckOk: meta.lastCheckOk == null ? null : !!meta.lastCheckOk,
|
|
44
44
|
lastCheckReason: meta.lastCheckReason || "",
|
|
45
|
+
lastCheckDiagnostic: meta.lastCheckDiagnostic || null,
|
|
45
46
|
dataDir: staticInfo.dataDir || "",
|
|
46
47
|
cachePath: staticInfo.cachePath || "",
|
|
47
48
|
cacheExists: !!staticInfo.cacheExists,
|
|
@@ -121,11 +121,7 @@ class WishlistTabV2 extends React.Component {
|
|
|
121
121
|
constructor(props) {
|
|
122
122
|
super(props);
|
|
123
123
|
|
|
124
|
-
this.
|
|
125
|
-
this.consumeIndexes = buildConsumeIndexes(this.staticData);
|
|
126
|
-
this.upgradeIndexes = buildUpgradeIndexes(this.staticData);
|
|
127
|
-
this.pathByPair = buildPathIndexes(this.staticData).pathByPair;
|
|
128
|
-
this.arrangementIndex = buildArrangementIndex(this.staticData.improvementArrangement).index;
|
|
124
|
+
this.reloadStaticData();
|
|
129
125
|
this._ownerShipIndexCache = { shipsRef: null, map: {} };
|
|
130
126
|
this._startOptionsCache = { targetEquipId: null, equipsRef: null, plansKey: "", ownerMapRef: null, options: [] };
|
|
131
127
|
|
|
@@ -167,6 +163,14 @@ class WishlistTabV2 extends React.Component {
|
|
|
167
163
|
this.refreshPlanById = this.refreshPlanById.bind(this);
|
|
168
164
|
}
|
|
169
165
|
|
|
166
|
+
reloadStaticData() {
|
|
167
|
+
this.staticData = loadStaticData();
|
|
168
|
+
this.consumeIndexes = buildConsumeIndexes(this.staticData);
|
|
169
|
+
this.upgradeIndexes = buildUpgradeIndexes(this.staticData);
|
|
170
|
+
this.pathByPair = buildPathIndexes(this.staticData).pathByPair;
|
|
171
|
+
this.arrangementIndex = buildArrangementIndex(this.staticData.improvementArrangement).index;
|
|
172
|
+
}
|
|
173
|
+
|
|
170
174
|
componentDidMount() {
|
|
171
175
|
this._timer = setInterval(() => this.setState({ nowText: formatTokyoText() }), 1000);
|
|
172
176
|
this.refreshPlans();
|
|
@@ -179,6 +183,12 @@ class WishlistTabV2 extends React.Component {
|
|
|
179
183
|
}
|
|
180
184
|
|
|
181
185
|
componentDidUpdate(prevProps) {
|
|
186
|
+
if (prevProps.dataRevision !== this.props.dataRevision) {
|
|
187
|
+
this.reloadStaticData();
|
|
188
|
+
this._startOptionsCache = {};
|
|
189
|
+
this.refreshPlans({ preserveInteraction: true });
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
182
192
|
if (prevProps.materialResourceVersion === this.props.materialResourceVersion) return;
|
|
183
193
|
const state = this.getReduxState();
|
|
184
194
|
if (!state || !state.const || !state.info) return;
|
|
@@ -374,7 +384,8 @@ class WishlistTabV2 extends React.Component {
|
|
|
374
384
|
setFilterNote(value) {
|
|
375
385
|
this.setState(this.clearSelectionState({ filterNote: value, info: null }));
|
|
376
386
|
}
|
|
377
|
-
refreshPlans() {
|
|
387
|
+
refreshPlans({ preserveInteraction = false } = {}) {
|
|
388
|
+
const interactionPatch = (patch) => preserveInteraction ? patch : this.clearSelectionState(patch);
|
|
378
389
|
try {
|
|
379
390
|
const state = this.getReduxState();
|
|
380
391
|
const plans = loadPlans();
|
|
@@ -461,7 +472,7 @@ class WishlistTabV2 extends React.Component {
|
|
|
461
472
|
};
|
|
462
473
|
|
|
463
474
|
this.setState(
|
|
464
|
-
|
|
475
|
+
interactionPatch({
|
|
465
476
|
...buildInitialWishlistHydrationState({
|
|
466
477
|
plans,
|
|
467
478
|
initialSnapshot,
|
|
@@ -474,7 +485,7 @@ class WishlistTabV2 extends React.Component {
|
|
|
474
485
|
}
|
|
475
486
|
);
|
|
476
487
|
} catch (error) {
|
|
477
|
-
this.setState(
|
|
488
|
+
this.setState(interactionPatch({ error: String(error && (error.stack || error)), hydrating: false, hydrationQueue: [] }));
|
|
478
489
|
}
|
|
479
490
|
}
|
|
480
491
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const PLUGIN_QUERY = "?poi-plugin-kai-planner";
|
|
2
|
+
|
|
3
|
+
// Portal components execute in poi's main renderer. Never use
|
|
4
|
+
// remote.getCurrentWindow(): that would target the main window.
|
|
5
|
+
function ensurePluginWindowVisible(envWindow, envCtx, options = {}) {
|
|
6
|
+
let cancelled = false;
|
|
7
|
+
let timer = null;
|
|
8
|
+
const schedule = options.schedule || setTimeout;
|
|
9
|
+
const clear = options.clear || clearTimeout;
|
|
10
|
+
const warn = options.warn || ((error) => console.warn("[kai-planner] window visibility fallback failed", error));
|
|
11
|
+
const cancel = () => {
|
|
12
|
+
cancelled = true;
|
|
13
|
+
if (timer !== null) clear(timer);
|
|
14
|
+
timer = null;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const mountPoint = envCtx && envCtx.mountPoint;
|
|
19
|
+
if (!envWindow || envWindow.closed || envWindow.isWindowMode !== true || !mountPoint) return cancel;
|
|
20
|
+
const doc = envWindow.document;
|
|
21
|
+
const url = new URL(envWindow.location.href);
|
|
22
|
+
if (url.protocol !== "file:" || !url.pathname.endsWith("/index-plugin.html") || url.search !== PLUGIN_QUERY) return cancel;
|
|
23
|
+
if (mountPoint.ownerDocument !== doc || !mountPoint.isConnected) return cancel;
|
|
24
|
+
|
|
25
|
+
const remote = options.remote || require("@electron/remote");
|
|
26
|
+
const matches = remote.BrowserWindow.getAllWindows().filter(
|
|
27
|
+
(win) => !win.isDestroyed() && win.webContents.getURL() === url.href
|
|
28
|
+
);
|
|
29
|
+
if (matches.length !== 1) return cancel;
|
|
30
|
+
// Capture this instance now, never search again after a close/reopen.
|
|
31
|
+
const target = matches[0];
|
|
32
|
+
if (target.isVisible() || target.isMinimized()) return cancel;
|
|
33
|
+
|
|
34
|
+
// Run after the mount commit; one check only, no polling or focus call.
|
|
35
|
+
timer = schedule(() => {
|
|
36
|
+
timer = null;
|
|
37
|
+
if (cancelled) return;
|
|
38
|
+
try {
|
|
39
|
+
if (envWindow.closed || target.isDestroyed()) return;
|
|
40
|
+
if (envWindow.document !== doc || envWindow.location.href !== url.href) return;
|
|
41
|
+
if (!mountPoint.isConnected || mountPoint.ownerDocument !== doc || !mountPoint.querySelector(".kai-planner-root")) return;
|
|
42
|
+
if (target.webContents.getURL() !== url.href || target.isVisible() || target.isMinimized()) return;
|
|
43
|
+
target.show();
|
|
44
|
+
} catch (error) {
|
|
45
|
+
warn(error);
|
|
46
|
+
}
|
|
47
|
+
}, 0);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
warn(error);
|
|
50
|
+
}
|
|
51
|
+
return cancel;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = { ensurePluginWindowVisible };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"data_version": "2026.
|
|
3
|
-
"run_date": "2026-
|
|
4
|
-
"updated_at": "2026-
|
|
5
|
-
"previous_snapshot": "2026-
|
|
2
|
+
"data_version": "2026.08.26",
|
|
3
|
+
"run_date": "2026-08-26",
|
|
4
|
+
"updated_at": "2026-08-26T00:00:00+08:00",
|
|
5
|
+
"previous_snapshot": "2026-07-10",
|
|
6
6
|
"version_complete": true,
|
|
7
7
|
"source": {
|
|
8
8
|
"repo": "yukikuri/akashi-list",
|
|
@@ -10,39 +10,56 @@
|
|
|
10
10
|
"detail_path": "detail/"
|
|
11
11
|
},
|
|
12
12
|
"target_equipment_ids": [
|
|
13
|
+
2,
|
|
13
14
|
3,
|
|
14
|
-
10,
|
|
15
|
-
13,
|
|
16
|
-
14,
|
|
17
|
-
15,
|
|
18
|
-
24,
|
|
19
15
|
27,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
35,
|
|
17
|
+
39,
|
|
18
|
+
40,
|
|
19
|
+
48,
|
|
20
|
+
49,
|
|
21
|
+
63,
|
|
22
|
+
76,
|
|
25
23
|
106,
|
|
26
|
-
|
|
24
|
+
122,
|
|
25
|
+
146,
|
|
26
|
+
171,
|
|
27
|
+
174,
|
|
28
|
+
198,
|
|
29
|
+
205,
|
|
30
|
+
226,
|
|
27
31
|
229,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
286,
|
|
32
|
-
287,
|
|
33
|
-
288,
|
|
32
|
+
256,
|
|
33
|
+
266,
|
|
34
|
+
267,
|
|
34
35
|
294,
|
|
35
|
-
|
|
36
|
-
313,
|
|
36
|
+
295,
|
|
37
37
|
315,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
317,
|
|
39
|
+
362,
|
|
40
|
+
381,
|
|
41
|
+
385,
|
|
42
|
+
419,
|
|
43
|
+
468,
|
|
44
|
+
470,
|
|
45
|
+
471,
|
|
46
|
+
483,
|
|
47
|
+
503,
|
|
48
|
+
529,
|
|
49
|
+
536,
|
|
50
|
+
537,
|
|
51
|
+
541,
|
|
52
|
+
542,
|
|
53
|
+
577,
|
|
54
|
+
578,
|
|
55
|
+
579,
|
|
56
|
+
580,
|
|
57
|
+
582,
|
|
58
|
+
583,
|
|
59
|
+
584,
|
|
60
|
+
585,
|
|
61
|
+
586,
|
|
62
|
+
587
|
|
46
63
|
],
|
|
47
64
|
"fetch_report_file": "fetch_report.json",
|
|
48
65
|
"files": [
|
|
@@ -1063,6 +1063,13 @@
|
|
|
1063
1063
|
"consume_steel": 0,
|
|
1064
1064
|
"consume_bauxite": 600
|
|
1065
1065
|
},
|
|
1066
|
+
{
|
|
1067
|
+
"id": 189,
|
|
1068
|
+
"consume_fuel": 200,
|
|
1069
|
+
"consume_ammo": 190,
|
|
1070
|
+
"consume_steel": 20,
|
|
1071
|
+
"consume_bauxite": 490
|
|
1072
|
+
},
|
|
1066
1073
|
{
|
|
1067
1074
|
"id": 190,
|
|
1068
1075
|
"consume_fuel": 24,
|
|
@@ -2078,6 +2085,20 @@
|
|
|
2078
2085
|
"consume_steel": 420,
|
|
2079
2086
|
"consume_bauxite": 0
|
|
2080
2087
|
},
|
|
2088
|
+
{
|
|
2089
|
+
"id": 428,
|
|
2090
|
+
"consume_fuel": 30,
|
|
2091
|
+
"consume_ammo": 260,
|
|
2092
|
+
"consume_steel": 320,
|
|
2093
|
+
"consume_bauxite": 20
|
|
2094
|
+
},
|
|
2095
|
+
{
|
|
2096
|
+
"id": 429,
|
|
2097
|
+
"consume_fuel": 40,
|
|
2098
|
+
"consume_ammo": 320,
|
|
2099
|
+
"consume_steel": 320,
|
|
2100
|
+
"consume_bauxite": 20
|
|
2101
|
+
},
|
|
2081
2102
|
{
|
|
2082
2103
|
"id": 431,
|
|
2083
2104
|
"consume_fuel": 290,
|
|
@@ -2574,5 +2595,12 @@
|
|
|
2574
2595
|
"consume_ammo": 20,
|
|
2575
2596
|
"consume_steel": 170,
|
|
2576
2597
|
"consume_bauxite": 280
|
|
2598
|
+
},
|
|
2599
|
+
{
|
|
2600
|
+
"id": 575,
|
|
2601
|
+
"consume_fuel": 10,
|
|
2602
|
+
"consume_ammo": 40,
|
|
2603
|
+
"consume_steel": 30,
|
|
2604
|
+
"consume_bauxite": 20
|
|
2577
2605
|
}
|
|
2578
2606
|
]
|