poi-plugin-mcp 0.2.27 → 0.2.29
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/lib/pixi-hit-ledger.js +6 -2
- package/lib/poi-action-events.js +9 -0
- package/lib/poi-http-bridge.js +30 -1
- package/lib/poi-input.js +152 -10
- package/lib/poi-webview-runtime.js +25 -1
- package/package.json +1 -1
package/lib/pixi-hit-ledger.js
CHANGED
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
const fs = require('node:fs')
|
|
19
19
|
const path = require('node:path')
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
// Live 0913 title page: leaf sprites with the atlas identity sit at depth 8+;
|
|
22
|
+
// a cap of 8 truncated before them, leaving container-only stacks.
|
|
23
|
+
const MAX_STACK = 16
|
|
22
24
|
const MAX_VISIT = 4000
|
|
23
25
|
const MAX_DEPTH = 40
|
|
24
26
|
// Wall-clock bound for the whole snapshot. The page-side script has its own
|
|
@@ -195,7 +197,9 @@ function createPixiHitLedger(options = {}) {
|
|
|
195
197
|
? { x: operation.x, y: operation.y }
|
|
196
198
|
: operation.operation === 'drag'
|
|
197
199
|
? { x: operation.fromX, y: operation.fromY }
|
|
198
|
-
:
|
|
200
|
+
: operation.operation === 'scroll'
|
|
201
|
+
? { x: operation.x, y: operation.y }
|
|
202
|
+
: null
|
|
199
203
|
if (point === null) return Object.freeze({ available: false, reason: 'not_pointer' })
|
|
200
204
|
const record = {
|
|
201
205
|
at: capturedAt,
|
package/lib/poi-action-events.js
CHANGED
|
@@ -16,16 +16,21 @@ const EXACT_PATHS = new Set([
|
|
|
16
16
|
'/kcsapi/api_start2/getData',
|
|
17
17
|
'/kcsapi/api_port/port',
|
|
18
18
|
'/kcsapi/api_get_member/base_air_corps',
|
|
19
|
+
'/kcsapi/api_get_member/chart_additional_info',
|
|
19
20
|
'/kcsapi/api_get_member/deck',
|
|
21
|
+
'/kcsapi/api_get_member/furniture',
|
|
20
22
|
'/kcsapi/api_get_member/kdock',
|
|
21
23
|
'/kcsapi/api_get_member/mapinfo',
|
|
22
24
|
'/kcsapi/api_get_member/material',
|
|
25
|
+
'/kcsapi/api_get_member/mission',
|
|
23
26
|
'/kcsapi/api_get_member/ndock',
|
|
24
27
|
'/kcsapi/api_get_member/practice',
|
|
28
|
+
'/kcsapi/api_get_member/preset_deck',
|
|
25
29
|
'/kcsapi/api_get_member/questlist',
|
|
26
30
|
'/kcsapi/api_get_member/require_info',
|
|
27
31
|
'/kcsapi/api_get_member/ship2',
|
|
28
32
|
'/kcsapi/api_get_member/ship3',
|
|
33
|
+
'/kcsapi/api_get_member/ship_deck',
|
|
29
34
|
'/kcsapi/api_get_member/slot_item',
|
|
30
35
|
'/kcsapi/api_get_member/unsetslot',
|
|
31
36
|
'/kcsapi/api_get_member/useitem',
|
|
@@ -39,11 +44,13 @@ const EXACT_PATHS = new Set([
|
|
|
39
44
|
'/kcsapi/api_req_hensei/combined',
|
|
40
45
|
'/kcsapi/api_req_hensei/preset_select',
|
|
41
46
|
'/kcsapi/api_req_hokyu/charge',
|
|
47
|
+
'/kcsapi/api_req_kaisou/can_preset_slot_select',
|
|
42
48
|
'/kcsapi/api_req_kaisou/powerup',
|
|
43
49
|
'/kcsapi/api_req_kaisou/slot_select',
|
|
44
50
|
'/kcsapi/api_req_kaisou/slot_deprive',
|
|
45
51
|
'/kcsapi/api_req_kaisou/slotset',
|
|
46
52
|
'/kcsapi/api_req_kaisou/slotset_ex',
|
|
53
|
+
'/kcsapi/api_req_kaisou/unsetslot',
|
|
47
54
|
'/kcsapi/api_req_kaisou/unsetslot_all',
|
|
48
55
|
'/kcsapi/api_req_kousyou/createitem',
|
|
49
56
|
'/kcsapi/api_req_kousyou/createship',
|
|
@@ -57,6 +64,7 @@ const EXACT_PATHS = new Set([
|
|
|
57
64
|
'/kcsapi/api_req_map/start',
|
|
58
65
|
'/kcsapi/api_req_map/start_air_base',
|
|
59
66
|
'/kcsapi/api_req_member/get_practice_enemyinfo',
|
|
67
|
+
'/kcsapi/api_req_member/set_oss_condition',
|
|
60
68
|
'/kcsapi/api_req_mission/result',
|
|
61
69
|
'/kcsapi/api_req_mission/start',
|
|
62
70
|
'/kcsapi/api_req_nyukyo/speedchange',
|
|
@@ -76,6 +84,7 @@ const ALLOWED_PREFIXES = [
|
|
|
76
84
|
]
|
|
77
85
|
|
|
78
86
|
const SHARED_TELEMETRY_TIMESTAMP_PATHS = new Set([
|
|
87
|
+
'/kcsapi/api_get_member/mission',
|
|
79
88
|
'/kcsapi/api_get_member/questlist',
|
|
80
89
|
'/kcsapi/api_get_member/unsetslot',
|
|
81
90
|
'/kcsapi/api_req_quest/start',
|
package/lib/poi-http-bridge.js
CHANGED
|
@@ -290,7 +290,9 @@ function createPoiDataBridge(options = {}) {
|
|
|
290
290
|
let hit
|
|
291
291
|
if (
|
|
292
292
|
debugEvalEnabled === true &&
|
|
293
|
-
(operation.operation === 'click' ||
|
|
293
|
+
(operation.operation === 'click' ||
|
|
294
|
+
operation.operation === 'drag' ||
|
|
295
|
+
operation.operation === 'scroll')
|
|
294
296
|
) {
|
|
295
297
|
hit = await currentHitLedger().capture(operation, {
|
|
296
298
|
leaseId: claim.leaseId,
|
|
@@ -832,6 +834,33 @@ function createPoiDataBridge(options = {}) {
|
|
|
832
834
|
return
|
|
833
835
|
}
|
|
834
836
|
|
|
837
|
+
if (endpoint === '/api-responses') {
|
|
838
|
+
if (req.method !== 'GET') {
|
|
839
|
+
drainRequest(req)
|
|
840
|
+
sendJson(res, 405, {
|
|
841
|
+
error: 'API responses endpoint only accepts GET requests.',
|
|
842
|
+
})
|
|
843
|
+
return
|
|
844
|
+
}
|
|
845
|
+
const pathFilter = requestUrl.searchParams.get('path')
|
|
846
|
+
sendJson(res, 200, getApiResponses({
|
|
847
|
+
after: clampedQueryInteger(
|
|
848
|
+
requestUrl.searchParams.get('after'),
|
|
849
|
+
0,
|
|
850
|
+
0,
|
|
851
|
+
Number.MAX_SAFE_INTEGER,
|
|
852
|
+
),
|
|
853
|
+
limit: clampedQueryInteger(
|
|
854
|
+
requestUrl.searchParams.get('limit'),
|
|
855
|
+
DEFAULT_ACTION_EVENT_LIMIT,
|
|
856
|
+
1,
|
|
857
|
+
MAX_ACTION_EVENT_LIMIT,
|
|
858
|
+
),
|
|
859
|
+
...(pathFilter === null ? {} : { path: pathFilter }),
|
|
860
|
+
}))
|
|
861
|
+
return
|
|
862
|
+
}
|
|
863
|
+
|
|
835
864
|
const store = readStore()
|
|
836
865
|
const info = store.info
|
|
837
866
|
|
package/lib/poi-input.js
CHANGED
|
@@ -2,7 +2,19 @@ const CANONICAL_WIDTH = 1200
|
|
|
2
2
|
const CANONICAL_HEIGHT = 720
|
|
3
3
|
const DRAG_MOVE_STEPS = 6
|
|
4
4
|
const DRAG_RELEASE_DELAY_MS = 120
|
|
5
|
+
const HOVER_MOVE_STEPS = 10
|
|
6
|
+
const HOVER_MOVE_STEP_DELAY_MS = 45
|
|
7
|
+
const HOVER_ENTRY_OFFSET_X = 44
|
|
5
8
|
const MAX_TEXT_LENGTH = 256
|
|
9
|
+
// One wheel detent (a physical mouse-wheel notch) is WHEEL_DELTA = 120 in
|
|
10
|
+
// Win32 terms; Chromium reports ~100-120 px of deltaY per notch on Windows
|
|
11
|
+
// default scroll settings. 120 per event is the Puppeteer/Playwright
|
|
12
|
+
// convention for "one notch" and matches what a real wheel delivers here.
|
|
13
|
+
const SCROLL_NOTCH_DELTA = 120
|
|
14
|
+
const DEFAULT_SCROLL_INTERVAL_MS = 40
|
|
15
|
+
const MIN_SCROLL_INTERVAL_MS = 20
|
|
16
|
+
const MAX_SCROLL_INTERVAL_MS = 200
|
|
17
|
+
const MAX_SCROLL_NOTCHES = 50
|
|
6
18
|
|
|
7
19
|
const SUPPORTED_BUTTONS = new Set(['left', 'middle', 'right'])
|
|
8
20
|
const SUPPORTED_KEY_EVENTS = new Set(['keyDown', 'keyUp'])
|
|
@@ -44,7 +56,7 @@ function createPoiInputProvider(options = {}) {
|
|
|
44
56
|
switch (operation.operation) {
|
|
45
57
|
case 'move':
|
|
46
58
|
validateMove(operation)
|
|
47
|
-
sendMove(layout, operation)
|
|
59
|
+
await sendMove(layout, operation, delay)
|
|
48
60
|
return 'move'
|
|
49
61
|
case 'click':
|
|
50
62
|
validateClick(operation)
|
|
@@ -54,6 +66,10 @@ function createPoiInputProvider(options = {}) {
|
|
|
54
66
|
validateDrag(operation)
|
|
55
67
|
await sendDrag(layout, operation, delay)
|
|
56
68
|
return 'drag'
|
|
69
|
+
case 'scroll':
|
|
70
|
+
validateScroll(operation)
|
|
71
|
+
await sendScroll(layout, operation, delay)
|
|
72
|
+
return 'scroll'
|
|
57
73
|
case 'key':
|
|
58
74
|
validateKey(operation)
|
|
59
75
|
await layout.webContents.sendInputEvent({
|
|
@@ -164,15 +180,37 @@ function validateClick(operation) {
|
|
|
164
180
|
}
|
|
165
181
|
|
|
166
182
|
function validateMove(operation) {
|
|
167
|
-
|
|
168
|
-
|
|
183
|
+
const hasOriginX = operation.fromX !== undefined
|
|
184
|
+
const hasOriginY = operation.fromY !== undefined
|
|
185
|
+
if (hasOriginX !== hasOriginY) {
|
|
186
|
+
throw new Error('Move origin coordinates must be provided together')
|
|
187
|
+
}
|
|
188
|
+
assertExactFields(
|
|
189
|
+
operation,
|
|
190
|
+
hasOriginX
|
|
191
|
+
? ['operation', 'x', 'y', 'fromX', 'fromY']
|
|
192
|
+
: ['operation', 'x', 'y'],
|
|
193
|
+
)
|
|
194
|
+
const xCoordinates = hasOriginX
|
|
195
|
+
? [operation.x, operation.fromX]
|
|
196
|
+
: [operation.x]
|
|
197
|
+
const yCoordinates = hasOriginY
|
|
198
|
+
? [operation.y, operation.fromY]
|
|
199
|
+
: [operation.y]
|
|
200
|
+
if (
|
|
201
|
+
xCoordinates
|
|
202
|
+
.concat(yCoordinates)
|
|
203
|
+
.some((coordinate) => !Number.isFinite(coordinate))
|
|
204
|
+
) {
|
|
169
205
|
throw new Error('Move coordinates must be finite numbers')
|
|
170
206
|
}
|
|
171
207
|
if (
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
208
|
+
xCoordinates.some(
|
|
209
|
+
(coordinate) => coordinate < 0 || coordinate >= CANONICAL_WIDTH,
|
|
210
|
+
) ||
|
|
211
|
+
yCoordinates.some(
|
|
212
|
+
(coordinate) => coordinate < 0 || coordinate >= CANONICAL_HEIGHT,
|
|
213
|
+
)
|
|
176
214
|
) {
|
|
177
215
|
throw new Error('Move coordinates must be within canonical bounds')
|
|
178
216
|
}
|
|
@@ -220,6 +258,45 @@ function validateDrag(operation) {
|
|
|
220
258
|
}
|
|
221
259
|
}
|
|
222
260
|
|
|
261
|
+
function validateScroll(operation) {
|
|
262
|
+
const hasInterval = operation.intervalMs !== undefined
|
|
263
|
+
assertExactFields(
|
|
264
|
+
operation,
|
|
265
|
+
hasInterval
|
|
266
|
+
? ['operation', 'x', 'y', 'notches', 'intervalMs']
|
|
267
|
+
: ['operation', 'x', 'y', 'notches'],
|
|
268
|
+
)
|
|
269
|
+
if (!Number.isFinite(operation.x) || !Number.isFinite(operation.y)) {
|
|
270
|
+
throw new Error('Scroll coordinates must be finite numbers')
|
|
271
|
+
}
|
|
272
|
+
if (
|
|
273
|
+
operation.x < 0 ||
|
|
274
|
+
operation.x >= CANONICAL_WIDTH ||
|
|
275
|
+
operation.y < 0 ||
|
|
276
|
+
operation.y >= CANONICAL_HEIGHT
|
|
277
|
+
) {
|
|
278
|
+
throw new Error('Scroll coordinates must be within canonical bounds')
|
|
279
|
+
}
|
|
280
|
+
if (!Number.isInteger(operation.notches) || operation.notches === 0) {
|
|
281
|
+
throw new Error('Scroll notches must be a non-zero integer')
|
|
282
|
+
}
|
|
283
|
+
if (Math.abs(operation.notches) > MAX_SCROLL_NOTCHES) {
|
|
284
|
+
throw new Error(
|
|
285
|
+
`Scroll notches must be from -${MAX_SCROLL_NOTCHES} to ${MAX_SCROLL_NOTCHES}`,
|
|
286
|
+
)
|
|
287
|
+
}
|
|
288
|
+
if (
|
|
289
|
+
hasInterval &&
|
|
290
|
+
(!Number.isInteger(operation.intervalMs) ||
|
|
291
|
+
operation.intervalMs < MIN_SCROLL_INTERVAL_MS ||
|
|
292
|
+
operation.intervalMs > MAX_SCROLL_INTERVAL_MS)
|
|
293
|
+
) {
|
|
294
|
+
throw new Error(
|
|
295
|
+
`Scroll intervalMs must be an integer from ${MIN_SCROLL_INTERVAL_MS} to ${MAX_SCROLL_INTERVAL_MS}`,
|
|
296
|
+
)
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
223
300
|
function validateKey(operation) {
|
|
224
301
|
assertExactFields(operation, ['operation', 'event', 'key'])
|
|
225
302
|
if (!SUPPORTED_KEY_EVENTS.has(operation.event)) {
|
|
@@ -256,11 +333,47 @@ function assertExactFields(operation, allowedFields) {
|
|
|
256
333
|
}
|
|
257
334
|
}
|
|
258
335
|
|
|
259
|
-
function sendMove(layout, operation) {
|
|
260
|
-
|
|
336
|
+
async function sendMove(layout, operation, delay) {
|
|
337
|
+
const destination = {
|
|
261
338
|
x: Math.floor((operation.x * layout.width) / CANONICAL_WIDTH),
|
|
262
339
|
y: Math.floor((operation.y * layout.height) / CANONICAL_HEIGHT),
|
|
263
|
-
}
|
|
340
|
+
}
|
|
341
|
+
// poi-plugin-kancolle-assistant's sendFocusedMouseMove (poi mode) feeds
|
|
342
|
+
// PIXI's interaction state machine a pointermove sequence arriving across
|
|
343
|
+
// frames; a single mouseEnter + mouseMove teleport never promotes hover
|
|
344
|
+
// (the 0921 equipment-filter calibration hit exactly that). Glide in from
|
|
345
|
+
// an explicit origin — or ~44 px left of the target — then park on it: a
|
|
346
|
+
// hover must persist, so no (0, 0) reset afterwards.
|
|
347
|
+
const originX =
|
|
348
|
+
operation.fromX !== undefined
|
|
349
|
+
? operation.fromX
|
|
350
|
+
: Math.max(0, operation.x - HOVER_ENTRY_OFFSET_X)
|
|
351
|
+
const originY = operation.fromY !== undefined ? operation.fromY : operation.y
|
|
352
|
+
const start = {
|
|
353
|
+
x: Math.floor((originX * layout.width) / CANONICAL_WIDTH),
|
|
354
|
+
y: Math.floor((originY * layout.height) / CANONICAL_HEIGHT),
|
|
355
|
+
}
|
|
356
|
+
layout.webContents.sendInputEvent({ type: 'mouseEnter', x: start.x, y: start.y })
|
|
357
|
+
let previousX = start.x
|
|
358
|
+
let previousY = start.y
|
|
359
|
+
for (let step = 1; step <= HOVER_MOVE_STEPS; step += 1) {
|
|
360
|
+
await delay(HOVER_MOVE_STEP_DELAY_MS)
|
|
361
|
+
const x = Math.round(
|
|
362
|
+
start.x + ((destination.x - start.x) * step) / HOVER_MOVE_STEPS,
|
|
363
|
+
)
|
|
364
|
+
const y = Math.round(
|
|
365
|
+
start.y + ((destination.y - start.y) * step) / HOVER_MOVE_STEPS,
|
|
366
|
+
)
|
|
367
|
+
await layout.webContents.sendInputEvent({
|
|
368
|
+
type: 'mouseMove',
|
|
369
|
+
x,
|
|
370
|
+
y,
|
|
371
|
+
movementX: x - previousX,
|
|
372
|
+
movementY: y - previousY,
|
|
373
|
+
})
|
|
374
|
+
previousX = x
|
|
375
|
+
previousY = y
|
|
376
|
+
}
|
|
264
377
|
}
|
|
265
378
|
|
|
266
379
|
function sendClick(layout, operation) {
|
|
@@ -350,6 +463,35 @@ function sendPointerEnterAndMove(webContents, point) {
|
|
|
350
463
|
webContents.sendInputEvent({ type: 'mouseMove', x: point.x, y: point.y })
|
|
351
464
|
}
|
|
352
465
|
|
|
466
|
+
async function sendScroll(layout, operation, delay) {
|
|
467
|
+
const point = {
|
|
468
|
+
x: Math.floor((operation.x * layout.width) / CANONICAL_WIDTH),
|
|
469
|
+
y: Math.floor((operation.y * layout.height) / CANONICAL_HEIGHT),
|
|
470
|
+
}
|
|
471
|
+
const direction = operation.notches > 0 ? 1 : -1
|
|
472
|
+
const intervalMs =
|
|
473
|
+
operation.intervalMs === undefined
|
|
474
|
+
? DEFAULT_SCROLL_INTERVAL_MS
|
|
475
|
+
: operation.intervalMs
|
|
476
|
+
// Wheel targets hit-test at the pointer, so park the cursor on the point
|
|
477
|
+
// first (the same enter+move the drag gesture uses); one mouseWheel event
|
|
478
|
+
// per notch keeps each detent a discrete event for handlers that quantize
|
|
479
|
+
// per event — a single notches*120 mega-delta can be clamped or swallowed.
|
|
480
|
+
sendPointerEnterAndMove(layout.webContents, point)
|
|
481
|
+
for (let index = 0; index < Math.abs(operation.notches); index += 1) {
|
|
482
|
+
if (index > 0) {
|
|
483
|
+
await delay(intervalMs)
|
|
484
|
+
}
|
|
485
|
+
await layout.webContents.sendInputEvent({
|
|
486
|
+
type: 'mouseWheel',
|
|
487
|
+
x: point.x,
|
|
488
|
+
y: point.y,
|
|
489
|
+
deltaX: 0,
|
|
490
|
+
deltaY: direction * SCROLL_NOTCH_DELTA,
|
|
491
|
+
})
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
353
495
|
function defaultDelay(milliseconds) {
|
|
354
496
|
return new Promise((resolve) => setTimeout(resolve, milliseconds))
|
|
355
497
|
}
|
|
@@ -276,10 +276,17 @@ ${PIXI_ROOT_RESOLVER_SNIPPET}
|
|
|
276
276
|
const maxDepth = boundedInteger(request.maxDepth, 6, 0, 12, 'maxDepth')
|
|
277
277
|
const maxNodes = boundedInteger(request.maxNodes, 20_000, 1, 50_000, 'maxNodes')
|
|
278
278
|
const maxMatches = boundedInteger(request.maxMatches, 16, 1, 256, 'maxMatches')
|
|
279
|
+
// Visibility pruning by default: a node that fails visible/renderable/
|
|
280
|
+
// worldAlpha also stops the descent into its subtree — a hidden parent
|
|
281
|
+
// leaves children with stale own flags (worldAlpha 1, on-screen transform),
|
|
282
|
+
// so per-node checks alone let dismissed-dialog ghosts leak into matches.
|
|
283
|
+
// includeHidden restores the raw walk for forensics only.
|
|
284
|
+
const includeHidden = request.includeHidden === true
|
|
279
285
|
if (projection === 'pixi.interactive') {
|
|
280
286
|
const capturedAt = timestamp(now())
|
|
281
287
|
const expression = pixiInteractiveExpression({
|
|
282
288
|
anyRequiredKeys,
|
|
289
|
+
includeHidden,
|
|
283
290
|
maxDepth,
|
|
284
291
|
maxMatches,
|
|
285
292
|
maxNodes,
|
|
@@ -471,6 +478,7 @@ ${PIXI_ROOT_RESOLVER_SNIPPET}
|
|
|
471
478
|
|
|
472
479
|
function pixiInteractiveExpression({
|
|
473
480
|
anyRequiredKeys,
|
|
481
|
+
includeHidden,
|
|
474
482
|
maxDepth,
|
|
475
483
|
maxMatches,
|
|
476
484
|
maxNodes,
|
|
@@ -488,6 +496,7 @@ function pixiInteractiveExpression({
|
|
|
488
496
|
const maxDepth = ${maxDepth};
|
|
489
497
|
const maxNodes = ${maxNodes};
|
|
490
498
|
const maxMatches = ${maxMatches};
|
|
499
|
+
const includeHidden = ${includeHidden ? 'true' : 'false'};
|
|
491
500
|
const isObject = (value) =>
|
|
492
501
|
(typeof value === 'object' || typeof value === 'function') && value !== null;
|
|
493
502
|
const ownDescriptor = (object, key) => {
|
|
@@ -732,6 +741,7 @@ ${PIXI_ROOT_RESOLVER_SNIPPET}
|
|
|
732
741
|
let cursor = 0;
|
|
733
742
|
let visited = 0;
|
|
734
743
|
let inspectedChildren = 0;
|
|
744
|
+
let prunedSubtrees = 0;
|
|
735
745
|
let depthLimited = false;
|
|
736
746
|
let childScanLimited = false;
|
|
737
747
|
let truncatedBy = null;
|
|
@@ -745,17 +755,25 @@ ${PIXI_ROOT_RESOLVER_SNIPPET}
|
|
|
745
755
|
}
|
|
746
756
|
seen.add(current.node);
|
|
747
757
|
visited += 1;
|
|
758
|
+
const nodeShown = shown(current.node);
|
|
748
759
|
const entryIndex = entries.length;
|
|
749
760
|
entries.push({
|
|
750
761
|
node: current.node,
|
|
751
762
|
path: current.path,
|
|
752
763
|
depth: current.depth,
|
|
753
764
|
parent: current.parent,
|
|
754
|
-
ownWorldBounds:
|
|
765
|
+
ownWorldBounds: nodeShown
|
|
755
766
|
? transformedBounds(localBounds(current.node), worldTransform(current.node))
|
|
756
767
|
: null,
|
|
757
768
|
subtreeWorldBounds: null,
|
|
758
769
|
});
|
|
770
|
+
if (!nodeShown && !includeHidden) {
|
|
771
|
+
// Hidden parent: children keep stale own flags (visible=true,
|
|
772
|
+
// worldAlpha=1, on-screen transform) because PIXI skips
|
|
773
|
+
// updateTransform for invisible subtrees — do not descend.
|
|
774
|
+
prunedSubtrees += 1;
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
759
777
|
|
|
760
778
|
const children = ownData(current.node, 'children');
|
|
761
779
|
if (!Array.isArray(children)) continue;
|
|
@@ -845,6 +863,7 @@ ${PIXI_ROOT_RESOLVER_SNIPPET}
|
|
|
845
863
|
visited,
|
|
846
864
|
exhausted: truncatedBy === null,
|
|
847
865
|
truncatedBy,
|
|
866
|
+
prunedSubtrees,
|
|
848
867
|
matches,
|
|
849
868
|
};
|
|
850
869
|
})()`
|
|
@@ -935,6 +954,10 @@ function finalizePixiInteractiveProjection(value, options) {
|
|
|
935
954
|
? value.truncatedBy
|
|
936
955
|
: null
|
|
937
956
|
const exhausted = available && value.exhausted === true && truncatedBy === null
|
|
957
|
+
const prunedSubtrees = available &&
|
|
958
|
+
Number.isInteger(value.prunedSubtrees) && value.prunedSubtrees >= 0
|
|
959
|
+
? value.prunedSubtrees
|
|
960
|
+
: 0
|
|
938
961
|
const snapshotDigest = sha256Token({
|
|
939
962
|
kind: 'poi.webview.pixi.snapshot.v1',
|
|
940
963
|
available,
|
|
@@ -957,6 +980,7 @@ function finalizePixiInteractiveProjection(value, options) {
|
|
|
957
980
|
visited,
|
|
958
981
|
exhausted,
|
|
959
982
|
truncatedBy,
|
|
983
|
+
prunedSubtrees,
|
|
960
984
|
matches: identifiedMatches,
|
|
961
985
|
}
|
|
962
986
|
}
|