From 891b42990dd4fad037337c54cb7518beb569f85f Mon Sep 17 00:00:00 2001 From: takaqiao Date: Tue, 5 May 2026 18:59:17 +0800 Subject: [PATCH] Skip MeasuredTemplate placeables whose _draw left them incomplete A MeasuredTemplate placeable can survive into canvasReady without this.template (the PIXI.Graphics) or a registered highlight layer: loadTexture rejects on a missing/failing fill, the system migrated spell areas off MeasuredTemplate (PF2e v8 places Regions instead, but legacy scene documents remain), or the placeable was created before the canvas finished initializing. The bundle currently dereferences both unconditionally: - _singleLoadFilters does placeable.document.tmfxTextureAlpha = placeable._TMFXgetSprite().alpha = updateData.opacity; which throws TypeError 'Cannot set properties of undefined' when _TMFXgetSprite() returns undefined for a TEMPLATE whose this.template was never assigned. - The defaultTemplateOnHover mousemove handler does hl.renderable = ...; template.template.alpha = ...; and crashes hundreds of times per second on a hover when either is missing. Both reproduce on Foundry v14 + PF2e v8 worlds with leftover legacy MeasuredTemplate documents. Skip the broken placeables instead of dereferencing through undefined. The Region branch already guarded its sprite this way; this brings TEMPLATE and the hover handler in line. --- tokenmagic/module/settings.js | 7 +++++++ tokenmagic/module/tokenmagic.js | 7 +++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tokenmagic/module/settings.js b/tokenmagic/module/settings.js index 91db5a3..f23d847 100644 --- a/tokenmagic/module/settings.js +++ b/tokenmagic/module/settings.js @@ -413,7 +413,14 @@ Hooks.once('init', () => { canvas.stage.on('mousemove', (event) => { const { x: mx, y: my } = event.data.getLocalPosition(canvas.templates); for (const template of canvas.templates.placeables) { + // A template whose _draw aborted (e.g. legacy scene data carried + // over from a system that no longer creates MeasuredTemplates, or + // a missing/failing texture) leaves `template.template` and the + // grid highlight layer undefined. Skip those rather than crash + // the pointermove pipeline. + if (!template.template) continue; const hl = canvas.interface.grid.getHighlightLayer(template.highlightId); + if (!hl) continue; const opacity = template.document.getFlag('tokenmagic', 'templateData')?.opacity ?? 1; if (template.texture && template.texture !== '') { const { x: cx, y: cy } = template.center; diff --git a/tokenmagic/module/tokenmagic.js b/tokenmagic/module/tokenmagic.js index 2073c8f..463bbb7 100644 --- a/tokenmagic/module/tokenmagic.js +++ b/tokenmagic/module/tokenmagic.js @@ -856,8 +856,11 @@ export function TokenMagic() { if (placeableType === PlaceableType.TEMPLATE) { let updateData = placeable.document.getFlag('tokenmagic', 'templateData'); if (!(updateData == null)) { - placeable.document.tmfxTextureAlpha = placeable._TMFXgetSprite().alpha = updateData.opacity; - placeable.document.tmfxTint = updateData.tint; + const sprite = placeable._TMFXgetSprite(); + if (sprite) { + placeable.document.tmfxTextureAlpha = sprite.alpha = updateData.opacity; + placeable.document.tmfxTint = updateData.tint; + } } } else if (placeableType === PlaceableType.REGION) { const sprite = placeable._TMFXgetSprite();