poi-plugin-inventory-cleaner 1.14.2 → 1.15.1
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/data/quest-codes.json +1 -0
- package/i18n/en-US.json +1 -0
- package/i18n/zh-CN.json +1 -0
- package/index.js +7 -0
- package/lib/inventory.js +22 -3
- package/lib/quest-status.js +121 -0
- package/lib/style.js +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"A1":101,"A2":102,"A3":103,"A4":104,"A5":105,"A7":106,"A12":107,"A8":108,"A14":109,"A15":110,"A17":111,"A18":112,"A13":113,"A19":114,"A6":115,"A9":116,"A11":117,"A16":118,"A20":119,"A10":120,"A21":121,"A22":122,"A23":123,"A24":124,"A25":125,"A26":126,"A27":127,"A28":128,"A29":129,"A30":130,"A31":131,"A32":132,"A33":133,"WA01":134,"WA02":135,"A34":136,"A35":137,"A36":138,"A37":139,"A38":140,"A39":141,"A40":142,"A41":143,"A42":144,"A43":145,"A45":146,"A44":147,"A46":148,"A47":149,"A48":150,"A49":151,"A50":152,"A51":153,"A52":154,"A53":155,"A54":156,"A55":157,"A92":158,"A56":161,"A57":162,"A58":163,"A59":164,"A60":165,"A61":166,"A62":167,"A63":168,"A64":169,"A65":170,"A66":171,"A67":172,"A68":173,"A69":174,"A70":175,"A71":176,"A72":177,"A73":178,"A74":179,"A75":180,"A76":181,"A77":182,"A78":183,"A79":184,"A80":185,"A81":186,"A82":187,"A83":188,"A84":189,"A85":190,"A86":191,"A87":192,"A88":193,"A89":194,"A90":195,"A91":196,"A93":197,"A94":198,"L2606A1":199,"Bd1":201,"B1":202,"B2":203,"B4":204,"B5":205,"B6":206,"B7":207,"B8":208,"B9":209,"Bd3":210,"Bd4":211,"Bd6":212,"Bw3":213,"Bw1":214,"B3":215,"Bd2":216,"B10":217,"Bd5":218,"B11":219,"Bw2":220,"Bw4":221,"B12":222,"B13":223,"B14":224,"B15":225,"Bd7":226,"B16":227,"Bw5":228,"Bw6":229,"Bd8":230,"B17":231,"B18":232,"B19":233,"B135":235,"B136":236,"B138":237,"B20":239,"B21":240,"Bw7":241,"Bw8":242,"Bw9":243,"B22":244,"WB01":245,"WB02":246,"B23":247,"B24":248,"Bm1":249,"B25":250,"B26":251,"B27":252,"B28":253,"B29":254,"B30":255,"Bm2":256,"Bm3":257,"B31":258,"Bm4":259,"B32":260,"Bw10":261,"B33":262,"B34":263,"Bm6":264,"Bm5":265,"Bm7":266,"B35":267,"B36":268,"B37":269,"B39":270,"B38":271,"B40":272,"B41":273,"B42":274,"B43":275,"B44":276,"B45":277,"B46":278,"B47":279,"Bm8":280,"B129":281,"B130":282,"B137":283,"Bq11":284,"B49":285,"B48":286,"B50":287,"B51":288,"B52":289,"B128":290,"B134":291,"B133":292,"B53":293,"B54":294,"B55":295,"B56":296,"B57":297,"B124":298,"B125":299,"C1":301,"Cw1":302,"Cd1":303,"Cd2":304,"WC01":306,"C5":307,"C6":308,"C7":309,"Cm1":311,"C9":312,"Cs8":313,"Cs2":314,"Cs3":315,"C13":316,"C15":317,"Cm2":318,"C17":319,"C18":320,"C20":322,"C21":323,"C22":324,"C23":325,"Cs7":326,"C25":327,"C27":328,"Cq1":330,"C31":331,"C32":332,"C33":333,"C34":334,"C35":335,"C37":336,"Cq2":337,"C39":338,"Cq3":339,"Cq4":342,"C46":343,"C48":344,"Cy1":345,"Cy2":346,"C51":347,"Cy3":348,"Cy4":350,"C56":351,"C57":352,"Cy5":353,"Cy6":354,"Cy7":355,"Cy8":356,"Cy9":357,"C68":358,"C70":360,"Cy10":362,"C73":364,"C75":365,"C76":366,"Cy11":368,"Cy12":371,"Cy13":372,"Cy14":373,"Cy15":375,"C77":376,"Cy16":377,"L2507C1":380,"L2508C1":381,"L2606C1":382,"L2609C1":384,"L2609C2":385,"D1":401,"Dd1":402,"Dd2":403,"Dw1":404,"D5":405,"D6":406,"D7":408,"D8":409,"Dw2":410,"Dw3":411,"D10":412,"D12":413,"D13":414,"D14":415,"D15":416,"D16":417,"D17":418,"D18":419,"D19":420,"D20":422,"D21":423,"Dm1":424,"D23":425,"Dq1":426,"D25":427,"Dq2":428,"D27":429,"D28":430,"D29":431,"D30":432,"D31":433,"Dy1":434,"Dy2":436,"Dy3":437,"Dy4":438,"Dy5":439,"Dy6":440,"Dy7":442,"D39":443,"Dy8":444,"D41":445,"D42":446,"D43":447,"L2603D1":450,"E1":501,"E2":502,"Ed1":503,"Ed2":504,"F1":601,"F2":602,"F3":603,"F4":604,"Fd1":605,"Fd2":606,"Fd3":607,"Fd4":608,"Fd5":609,"F10":610,"WF01":611,"F11":612,"Fw1":613,"F13":614,"F14":615,"F15":616,"F16":617,"F17":618,"Fd6":619,"F88":620,"F89":621,"F19":622,"F20":623,"F21":624,"F23":625,"Fm1":626,"F24":627,"Fm2":628,"F26":629,"F28":630,"F27":631,"F29":632,"F30":633,"F31":634,"F32":635,"F33":636,"Fq1":637,"Fw2":638,"F36":639,"SF1":640,"F37":641,"F38":642,"Fq2":643,"F40":644,"Fm3":645,"F42":646,"F43":647,"F44":648,"F45":649,"F46":650,"F47":651,"F48":652,"Fq9":653,"Fy2":654,"Fy3":655,"F49":656,"Fy1":657,"F50":658,"F51":659,"F52":660,"F53":661,"F54":662,"Fq3":663,"F56":664,"F57":665,"F58":666,"F59":667,"F60":668,"F61":669,"F63":670,"F62":671,"F64":672,"Fd7":673,"Fd8":674,"Fq4":675,"Fw3":676,"Fw4":677,"Fq5":678,"F71":679,"Fq6":680,"Fy4":681,"F73":682,"F74":683,"F75":684,"F76":685,"Fq7":686,"F78":687,"Fq8":688,"F80":689,"F81":690,"F82":691,"F83":692,"F84":693,"F85":694,"F86":695,"F87":696,"F91":698,"G1":701,"Gd1":702,"Gw1":703,"G4":704,"G5":705,"Gy1":714,"Gy2":715,"Gy3":716,"Gy4":717,"G10":718,"G11":719,"B58":805,"B59":806,"B60":807,"B61":808,"B62":809,"B63":810,"B64":811,"B65":812,"B66":813,"B68":814,"B69":815,"B67":816,"B70":817,"B71":818,"B72":819,"B73":820,"B74":821,"Bq1":822,"B75":823,"B76":824,"B77":825,"B78":826,"B79":827,"B80":828,"B81":829,"B82":830,"B139":833,"B83":834,"B84":835,"B85":836,"B86":837,"B87":838,"B88":839,"B89":842,"B90":844,"Bq12":845,"B91":846,"B163":847,"B92":848,"B93":849,"B94":850,"B95":851,"B96":852,"B97":853,"Bq2":854,"B98":855,"B99":856,"B100":857,"B101":858,"B102":859,"B103":860,"Bq3":861,"Bq4":862,"B104":863,"B105":864,"B106":865,"B107":869,"B108":870,"B109":871,"Bq10":872,"Bq5":873,"B110":874,"Bq6":875,"B111":876,"B112":877,"B113":878,"B114":879,"B115":880,"B116":881,"B117":884,"B118":885,"B119":886,"B120":887,"Bq7":888,"B121":889,"B122":890,"B123":891,"B126":892,"Bq8":893,"Bq9":894,"B127":895,"B131":896,"B132":897,"B162":898,"B140":901,"B141":902,"Bq13":903,"By1":904,"By2":905,"B142":911,"By3":912,"B143":913,"By4":914,"L2212B1":915,"B144":916,"B145":917,"B146":918,"B147":919,"B148":920,"B149":921,"B150":922,"B151":923,"B152":924,"B153":925,"B154":926,"B155":927,"By5":928,"B156":929,"B157":930,"B158":931,"B159":933,"B160":934,"B161":935,"B164":936,"B165":937,"B166":938,"B167":939,"B168":940,"B169":943,"By6":944,"By7":945,"By8":946,"By9":947,"By10":948,"B170":949,"B171":952,"B172":957,"B173":958,"B174":961,"B175":966,"B176":967,"B177":968,"B178":969,"B179":970,"By11":973,"B180":974,"By12":975,"B181":976,"B182":977,"B183":978,"B184":980,"B185":981,"B186":982,"B187":983,"B188":989,"B193":993,"B189":995,"B190":996,"B191":997,"B192":998,"B194":1001,"B195":1003,"B196":1004,"By13":1005,"B197":1006,"B198":1007,"B199":1008,"B212":1010,"By14":1012,"B200":1013,"B201":1014,"B202":1015,"B203":1016,"B204":1017,"By15":1018,"B205":1019,"L2409B1":1020,"B206":1021,"B207":1023,"B208":1025,"B209":1029,"B210":1033,"B211":1036,"L2508B1":1037,"L2610B6":1039,"B213":1041,"B214":1042,"B215":1044,"By16":1045,"B216":1047,"L2606B1":1048,"L2606B2":1049,"By17":1050,"By18":1051,"B217":1052,"F96":1101,"F97":1102,"Fy5":1103,"Fy6":1104,"Fy7":1105,"F101":1106,"Fy8":1107,"F103":1108,"F104":1109,"F105":1111,"F106":1112,"F107":1113,"F108":1114,"F109":1115,"F110":1116,"F111":1117,"F112":1118,"Fy9":1120,"Fy10":1123,"F115":1127,"F116":1128,"F117":1129,"F118":1130,"F119":1131,"F120":1132,"F121":1133,"F122":1134,"F123":1137,"Fy11":1138,"F124":1139,"F125":1140,"F126":1141,"F127":1142,"F128":1143,"F129":1145,"F130":1148,"L2605F2":1150,"F131":1151,"F132":1152,"F133":1153,"F134":1154,"F135":1155,"F136":1158,"F137":1159,"F138":1160,"F139":1161,"F140":1162,"F141":1163,"F142":1164,"Fd9":1166,"Fw5":1167,"F143":1170}
|
package/i18n/en-US.json
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"stock.consumeQuestEquip": "quest (equip)",
|
|
30
30
|
"stock.consumeQuestStore": "quest (store)",
|
|
31
31
|
"stock.consumeOther": "other",
|
|
32
|
+
"stock.consumeHidden": "{{count}} completed quest(s) hidden",
|
|
32
33
|
"stock.keepLabel": "Keep",
|
|
33
34
|
"stock.keepUnit": "",
|
|
34
35
|
"stock.keepPlaceholder": "guide",
|
package/i18n/zh-CN.json
CHANGED
package/index.js
CHANGED
|
@@ -374,6 +374,13 @@ function StockRow({ row, onKeepChange }) {
|
|
|
374
374
|
),
|
|
375
375
|
),
|
|
376
376
|
),
|
|
377
|
+
row.consumedHidden > 0
|
|
378
|
+
? h(
|
|
379
|
+
'div',
|
|
380
|
+
{ className: 'stock-consume-hidden' },
|
|
381
|
+
t('stock.consumeHidden', { count: row.consumedHidden }),
|
|
382
|
+
)
|
|
383
|
+
: null,
|
|
377
384
|
)
|
|
378
385
|
: null,
|
|
379
386
|
)
|
package/lib/inventory.js
CHANGED
|
@@ -13,9 +13,11 @@ const INDEX = require('../data/equips-index.json')
|
|
|
13
13
|
const SCRAP = require('../data/scrap-guide.json')
|
|
14
14
|
const CONSUMED = require('../data/consumed-materials.json')
|
|
15
15
|
const GUIDE = require('../data/equipment-guide.json')
|
|
16
|
+
const QUEST_CODES = require('../data/quest-codes.json')
|
|
16
17
|
const { getProtection } = require('./protect')
|
|
17
18
|
const { buildQuestNeeds } = require('./quest-needs')
|
|
18
19
|
const { buildTypeIndex } = require('./equip-types')
|
|
20
|
+
const { getCompletedQuestNos } = require('./quest-status')
|
|
19
21
|
|
|
20
22
|
function isRecord(value) {
|
|
21
23
|
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
@@ -36,9 +38,16 @@ const CONSUME_KINDS = {
|
|
|
36
38
|
/**
|
|
37
39
|
* 把「《锤》xxx《拆》yyy」这种素材用途串拆成条目,任务类排在改修类前面。
|
|
38
40
|
*/
|
|
39
|
-
function
|
|
41
|
+
function questNoFromText(text) {
|
|
42
|
+
const matched = String(text || '').match(/^(?:\([^)]*\)\s*)?([A-Za-z]{1,2}\d{1,3})\s*[::]/)
|
|
43
|
+
if (!matched) return 0
|
|
44
|
+
return QUEST_CODES[matched[1]] || 0
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseConsumed(text, options = {}) {
|
|
40
48
|
const value = String(text || '').trim()
|
|
41
49
|
if (!value) return []
|
|
50
|
+
const completed = options.completed || null
|
|
42
51
|
|
|
43
52
|
const parts = value
|
|
44
53
|
.split(/(?=《)/)
|
|
@@ -49,7 +58,13 @@ function parseConsumed(text) {
|
|
|
49
58
|
const matched = raw.match(/^《([^》]{1,3})》\s*(.*)$/)
|
|
50
59
|
const tag = matched ? matched[1] : ''
|
|
51
60
|
const detail = matched ? matched[2] : raw
|
|
52
|
-
|
|
61
|
+
const kind = CONSUME_KINDS[tag] || 'other'
|
|
62
|
+
let done = false
|
|
63
|
+
if (kind === 'quest' && completed) {
|
|
64
|
+
const no = questNoFromText(detail)
|
|
65
|
+
done = no ? completed.has(no) : false
|
|
66
|
+
}
|
|
67
|
+
return { tag, kind, text: detail, done }
|
|
53
68
|
})
|
|
54
69
|
|
|
55
70
|
const rank = { quest: 0, improve: 1, other: 2 }
|
|
@@ -82,6 +97,7 @@ function buildInventory(state, options = {}) {
|
|
|
82
97
|
const planned = protection.planned || new Set()
|
|
83
98
|
const keeps = options.keeps || {}
|
|
84
99
|
const typeIndex = options.typeIndex || buildTypeIndex(state)
|
|
100
|
+
const completedQuests = options.completedQuests || getCompletedQuestNos(state)
|
|
85
101
|
const questNeeds = options.questNeeds || buildQuestNeeds(state)
|
|
86
102
|
|
|
87
103
|
const byId = new Map()
|
|
@@ -108,6 +124,7 @@ function buildInventory(state, options = {}) {
|
|
|
108
124
|
const consumed = CONSUMED[String(row.id)] || ''
|
|
109
125
|
|
|
110
126
|
const typeInfo = typeIndex.get(row.id) || null
|
|
127
|
+
const allConsumed = parseConsumed(consumed, { completed: completedQuests })
|
|
111
128
|
const verdict = rule ? rule.verdict : 'unknown'
|
|
112
129
|
const inPlan = planned.has(row.id)
|
|
113
130
|
const need = questNeeds.byEquip.get(row.id) || null
|
|
@@ -151,7 +168,8 @@ function buildInventory(state, options = {}) {
|
|
|
151
168
|
usage: rule ? rule.usage : '',
|
|
152
169
|
obtain: rule ? rule.obtain : '',
|
|
153
170
|
consumed,
|
|
154
|
-
consumedItems:
|
|
171
|
+
consumedItems: allConsumed.filter((item) => !item.done),
|
|
172
|
+
consumedHidden: allConsumed.filter((item) => item.done).length,
|
|
155
173
|
stage: guide ? guide.stage : '',
|
|
156
174
|
note: guide ? guide.note : '',
|
|
157
175
|
inPlan,
|
|
@@ -284,6 +302,7 @@ function filterRows(rows, options = {}) {
|
|
|
284
302
|
module.exports = {
|
|
285
303
|
OTHER_CATEGORY,
|
|
286
304
|
parseConsumed,
|
|
305
|
+
questNoFromText,
|
|
287
306
|
SORTS,
|
|
288
307
|
sortRows,
|
|
289
308
|
applyCategoryKeep,
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 已完成任务的判定。
|
|
5
|
+
*
|
|
6
|
+
* 来源(都是只读):
|
|
7
|
+
* - poi 的进行中任务里 api_state === 3 的(已接取且已完成,尚未领奖时还在列表里);
|
|
8
|
+
* - 任务信息插件 ext 里 api_state === 3 的;
|
|
9
|
+
* - 任务规划插件的 completed 集合(最完整)。
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs')
|
|
13
|
+
const path = require('path')
|
|
14
|
+
const os = require('os')
|
|
15
|
+
|
|
16
|
+
const CACHE_TTL = 15000
|
|
17
|
+
let plannerCache = { at: 0, mtime: 0, nos: null }
|
|
18
|
+
|
|
19
|
+
function appDataPath() {
|
|
20
|
+
if (process.env.POI_APPDATA_PATH) return process.env.POI_APPDATA_PATH
|
|
21
|
+
if (process.env.APPDATA) return process.env.APPDATA
|
|
22
|
+
return path.join(os.homedir(), '.config')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function questPlannerStatePath() {
|
|
26
|
+
if (process.env.QUEST_PLANNER_STATE) return process.env.QUEST_PLANNER_STATE
|
|
27
|
+
const root = path.join(appDataPath(), 'poi', 'quest-planner')
|
|
28
|
+
try {
|
|
29
|
+
const entries = fs.readdirSync(root, { withFileTypes: true })
|
|
30
|
+
let best = null
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
if (!entry.isDirectory()) continue
|
|
33
|
+
const file = path.join(root, entry.name, 'state.json')
|
|
34
|
+
try {
|
|
35
|
+
const stat = fs.statSync(file)
|
|
36
|
+
if (!best || stat.mtimeMs > best.mtimeMs) best = { file, mtimeMs: stat.mtimeMs }
|
|
37
|
+
} catch (_error) {
|
|
38
|
+
// 该目录没有 state.json
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (best) return best.file
|
|
42
|
+
} catch (_error) {
|
|
43
|
+
// 没装任务规划插件
|
|
44
|
+
}
|
|
45
|
+
return path.join(root, 'state.json')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function readPlannerCompleted(now = Date.now()) {
|
|
49
|
+
if (plannerCache.nos && now - plannerCache.at < CACHE_TTL) return plannerCache.nos
|
|
50
|
+
|
|
51
|
+
const file = questPlannerStatePath()
|
|
52
|
+
try {
|
|
53
|
+
const stat = fs.statSync(file)
|
|
54
|
+
if (plannerCache.nos && plannerCache.mtime === stat.mtimeMs) {
|
|
55
|
+
plannerCache.at = now
|
|
56
|
+
return plannerCache.nos
|
|
57
|
+
}
|
|
58
|
+
const raw = JSON.parse(fs.readFileSync(file, 'utf8').replace(/^\uFEFF/, ''))
|
|
59
|
+
const completed = raw && raw.completed && typeof raw.completed === 'object' ? raw.completed : {}
|
|
60
|
+
const nos = new Set()
|
|
61
|
+
for (const key of Object.keys(completed)) {
|
|
62
|
+
const no = Number(key)
|
|
63
|
+
if (no) nos.add(no)
|
|
64
|
+
}
|
|
65
|
+
plannerCache = { at: now, mtime: stat.mtimeMs, nos }
|
|
66
|
+
return nos
|
|
67
|
+
} catch (_error) {
|
|
68
|
+
plannerCache = { at: now, mtime: 0, nos: new Set() }
|
|
69
|
+
return plannerCache.nos
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function collectFromState(state) {
|
|
74
|
+
const nos = new Set()
|
|
75
|
+
const active =
|
|
76
|
+
state && state.info && state.info.quests ? state.info.quests.activeQuests : null
|
|
77
|
+
if (active && typeof active === 'object') {
|
|
78
|
+
for (const entry of Object.values(active)) {
|
|
79
|
+
const detail = entry && entry.detail ? entry.detail : entry
|
|
80
|
+
if (!detail || Number(detail.api_state) !== 3) continue
|
|
81
|
+
const no = Number(detail.api_no)
|
|
82
|
+
if (no) nos.add(no)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const ext = state && state.ext ? state.ext : null
|
|
87
|
+
if (ext) {
|
|
88
|
+
for (const id of ['poi-plugin-quest-info-2', 'poi-plugin-quest-info']) {
|
|
89
|
+
const entry = ext[id]
|
|
90
|
+
if (!entry) continue
|
|
91
|
+
const list =
|
|
92
|
+
(Array.isArray(entry.questList) && entry.questList) ||
|
|
93
|
+
(entry._ && Array.isArray(entry._.questList) && entry._.questList) ||
|
|
94
|
+
null
|
|
95
|
+
if (!list) continue
|
|
96
|
+
for (const detail of list) {
|
|
97
|
+
if (!detail || Number(detail.api_state) !== 3) continue
|
|
98
|
+
const no = Number(detail.api_no)
|
|
99
|
+
if (no) nos.add(no)
|
|
100
|
+
}
|
|
101
|
+
break
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return nos
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function getCompletedQuestNos(state) {
|
|
108
|
+
const nos = new Set(collectFromState(state))
|
|
109
|
+
for (const no of readPlannerCompleted()) nos.add(no)
|
|
110
|
+
return nos
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function resetCaches() {
|
|
114
|
+
plannerCache = { at: 0, mtime: 0, nos: null }
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = {
|
|
118
|
+
getCompletedQuestNos,
|
|
119
|
+
readPlannerCompleted,
|
|
120
|
+
resetCaches,
|
|
121
|
+
}
|
package/lib/style.js
CHANGED