From 6f8ccc2c3ab088a93543c4ad1db983729b607690 Mon Sep 17 00:00:00 2001 From: Greg Ludington Date: Fri, 27 Nov 2020 18:16:11 -0500 Subject: [PATCH 1/6] further hacking around the activeEffects dichotomy between regular and synthetic actors --- src/conditional-visibility.ts | 10 ++++++++++ src/module/ConditionalVisibility.ts | 17 ++++++++++++++++- src/module/ConditionalVisibilityFacade.ts | 2 +- .../systems/ConditionalVisibilitySystem5e.ts | 15 +++++++++++++++ .../DefaultConditionalVisibilitySystem.ts | 5 ++++- 5 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/conditional-visibility.ts b/src/conditional-visibility.ts index c916d57..29ac3b0 100644 --- a/src/conditional-visibility.ts +++ b/src/conditional-visibility.ts @@ -65,6 +65,16 @@ Hooks.on("renderTokenHUD", (app, html, data) => { ConditionalVisibility.INSTANCE.onRenderTokenHUD(app, html, data); }); +//synthetic actors go through this Hooks.on("preUpdateToken", (scene, token, update, options, userId) => { ConditionalVisibility.INSTANCE.onPreUpdateToken(scene, token, update, options, userId); }) + +//real actors go through this +Hooks.on("preCreateActiveEffect", (actor, effect, options, userId) => { + ConditionalVisibility.INSTANCE.onPreCreateActiveEffect(actor, effect, options, userId); +}) + +Hooks.on("preDeleteActiveEffect", (actor, effect, options, userId) => { + ConditionalVisibility.INSTANCE.onPreDeleteActiveEffect(actor, effect, options, userId); +}) \ No newline at end of file diff --git a/src/module/ConditionalVisibility.ts b/src/module/ConditionalVisibility.ts index f7a0def..c96b66a 100644 --- a/src/module/ConditionalVisibility.ts +++ b/src/module/ConditionalVisibility.ts @@ -29,7 +29,8 @@ export class ConditionalVisibility { if (isVisible === false) { return false; } - if (game.user.isGM || this._controlled || !canvas.sight.tokenVision) { + console.error(this); + if (game.user.isGM || this.owner || !canvas.sight.tokenVision) { return true; } return ConditionalVisibility.canSee(this); @@ -190,6 +191,20 @@ export class ConditionalVisibility { }); } + public onPreCreateActiveEffect(actor, effect, options, userId) { + const status:Constants.StatusEffect = this._conditionalVisibilitySystem.getEffectByIcon(effect); + if (status) { + actor.setFlag(Constants.MODULE_NAME, status.visibilityId, true); + } + } + + public onPreDeleteActiveEffect(actor, effect, options, userId) { + const status:Constants.StatusEffect = this._conditionalVisibilitySystem.getEffectByIcon(effect); + if (status) { + actor.unsetFlag(Constants.MODULE_NAME, status.visibilityId); + } + } + public onPreUpdateToken(scene:any, token:any, update:any, options:any, userId:string) { const effectsFromUpdate = this._conditionalVisibilitySystem.effectsFromUpdate(update); if (effectsFromUpdate) { diff --git a/src/module/ConditionalVisibilityFacade.ts b/src/module/ConditionalVisibilityFacade.ts index bbf85b4..7f0eb59 100644 --- a/src/module/ConditionalVisibilityFacade.ts +++ b/src/module/ConditionalVisibilityFacade.ts @@ -144,7 +144,7 @@ export class ConditionalVisibilityFacadeImpl implements ConditionalVisibilityFac private has(token, condition):boolean { console.error("OKdddd"); console.error(condition); - let flags = token?.data?.flags?.[Constants.MODULE_NAME]; + let flags = token?.data?.flags?.[Constants.MODULE_NAME] || token?.actor?.data?.flags?.[Constants.MODULE_NAME]; if (flags) { return flags[condition.visibilityId] === true; } else { diff --git a/src/module/systems/ConditionalVisibilitySystem5e.ts b/src/module/systems/ConditionalVisibilitySystem5e.ts index 012a568..96d742e 100644 --- a/src/module/systems/ConditionalVisibilitySystem5e.ts +++ b/src/module/systems/ConditionalVisibilitySystem5e.ts @@ -66,6 +66,9 @@ export class ConditionalVisibilitySystem5e extends DefaultConditionalVisibilityS */ protected seeContested(target: Token, visionCapabilities: any): boolean { const hidden = this.hasStatus(target, 'hidden', 'newspaper.svg'); + console.error(target.data.name + " " + hidden); + console.error(target.data.flags); + console.error(target.actor.data.flags); if (hidden === true) { if (target.data.flags[Constants.MODULE_NAME] && target.data.flags[Constants.MODULE_NAME]._ste) { const stealth = target.data.flags[Constants.MODULE_NAME]._ste; @@ -95,6 +98,18 @@ export class ConditionalVisibilitySystem5e extends DefaultConditionalVisibilityS object.data.flags[Constants.MODULE_NAME] = {}; } object.data.flags[Constants.MODULE_NAME]._ste = result; + if (object.actor) { + if (!object.actor.data) { + object.actor.data = {}; + } + if (!object.actor.data.flags) { + object.actor.data.flags = {}; + } + if (!object.actor.data.flags[Constants.MODULE_NAME]) { + object.actor.data.flags[Constants.MODULE_NAME] = {}; + } + object.actor.data.flags[Constants.MODULE_NAME]._ste = result; + } return realOnToggleEffect(event, opts); }); return false; diff --git a/src/module/systems/DefaultConditionalVisibilitySystem.ts b/src/module/systems/DefaultConditionalVisibilitySystem.ts index ef7ae0c..a6ea50b 100644 --- a/src/module/systems/DefaultConditionalVisibilitySystem.ts +++ b/src/module/systems/DefaultConditionalVisibilitySystem.ts @@ -33,7 +33,8 @@ export class DefaultConditionalVisibilitySystem implements ConditionalVisibility _effectsByCondition: Map; hasStatus(token:Token, id:string, icon:string): boolean { - return token.data?.flags?.[MODULE_NAME]?.[id] === true; + return token.data?.flags?.[MODULE_NAME]?.[id] === true + || token.actor.data?.flags?.[MODULE_NAME]?.[id] === true; } constructor() { @@ -134,6 +135,7 @@ export class DefaultConditionalVisibilitySystem implements ConditionalVisibility * @param flags the capabilities established by the sight layer */ public canSee(target: Token, visionCapabilities: any): boolean { + console.error("in casen see for " + target.data.name) if (this.seeInvisible(target, visionCapabilities) === false) { return false; } @@ -160,6 +162,7 @@ export class DefaultConditionalVisibilitySystem implements ConditionalVisibility * @param visionCapabilities the sight capabilities of the sight layer */ protected seeInvisible(target:Token, visionCapabilities:any): boolean { + console.error(target); const invisible = this.hasStatus(target, 'invisible', 'unknown.svg'); if (invisible === true) { if (visionCapabilities.seeinvisible !== true) { From ef61352c2e3cca75197c2f77de78994cc34fd42c Mon Sep 17 00:00:00 2001 From: Greg Ludington Date: Fri, 27 Nov 2020 18:24:07 -0500 Subject: [PATCH 2/6] removed console.errors in facace --- src/module/ConditionalVisibilityFacade.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/module/ConditionalVisibilityFacade.ts b/src/module/ConditionalVisibilityFacade.ts index 7f0eb59..f042f4e 100644 --- a/src/module/ConditionalVisibilityFacade.ts +++ b/src/module/ConditionalVisibilityFacade.ts @@ -142,13 +142,11 @@ export class ConditionalVisibilityFacadeImpl implements ConditionalVisibilityFac } private has(token, condition):boolean { - console.error("OKdddd"); - console.error(condition); - let flags = token?.data?.flags?.[Constants.MODULE_NAME] || token?.actor?.data?.flags?.[Constants.MODULE_NAME]; - if (flags) { - return flags[condition.visibilityId] === true; - } else { - return false; - } + let flags = token?.data?.flags?.[Constants.MODULE_NAME] || token?.actor?.data?.flags?.[Constants.MODULE_NAME]; + if (flags) { + return flags[condition.visibilityId] === true; + } else { + return false; + } } } \ No newline at end of file From 9a78bb6a13ae2246a48438daab776443bbfe706d Mon Sep 17 00:00:00 2001 From: Greg Ludington Date: Fri, 27 Nov 2020 19:11:54 -0500 Subject: [PATCH 3/6] fix tests, add to compendium --- src/module/systems/ConditionalVisibilitySystem5e.ts | 3 --- src/module/systems/DefaultConditionalVisibilitySystem.ts | 4 +--- src/packs/visibility-scripts.db | 3 ++- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/module/systems/ConditionalVisibilitySystem5e.ts b/src/module/systems/ConditionalVisibilitySystem5e.ts index 96d742e..ffb68c4 100644 --- a/src/module/systems/ConditionalVisibilitySystem5e.ts +++ b/src/module/systems/ConditionalVisibilitySystem5e.ts @@ -66,9 +66,6 @@ export class ConditionalVisibilitySystem5e extends DefaultConditionalVisibilityS */ protected seeContested(target: Token, visionCapabilities: any): boolean { const hidden = this.hasStatus(target, 'hidden', 'newspaper.svg'); - console.error(target.data.name + " " + hidden); - console.error(target.data.flags); - console.error(target.actor.data.flags); if (hidden === true) { if (target.data.flags[Constants.MODULE_NAME] && target.data.flags[Constants.MODULE_NAME]._ste) { const stealth = target.data.flags[Constants.MODULE_NAME]._ste; diff --git a/src/module/systems/DefaultConditionalVisibilitySystem.ts b/src/module/systems/DefaultConditionalVisibilitySystem.ts index a6ea50b..823e80f 100644 --- a/src/module/systems/DefaultConditionalVisibilitySystem.ts +++ b/src/module/systems/DefaultConditionalVisibilitySystem.ts @@ -34,7 +34,7 @@ export class DefaultConditionalVisibilitySystem implements ConditionalVisibility hasStatus(token:Token, id:string, icon:string): boolean { return token.data?.flags?.[MODULE_NAME]?.[id] === true - || token.actor.data?.flags?.[MODULE_NAME]?.[id] === true; + || token.actor?.data?.flags?.[MODULE_NAME]?.[id] === true; } constructor() { @@ -135,7 +135,6 @@ export class DefaultConditionalVisibilitySystem implements ConditionalVisibility * @param flags the capabilities established by the sight layer */ public canSee(target: Token, visionCapabilities: any): boolean { - console.error("in casen see for " + target.data.name) if (this.seeInvisible(target, visionCapabilities) === false) { return false; } @@ -162,7 +161,6 @@ export class DefaultConditionalVisibilitySystem implements ConditionalVisibility * @param visionCapabilities the sight capabilities of the sight layer */ protected seeInvisible(target:Token, visionCapabilities:any): boolean { - console.error(target); const invisible = this.hasStatus(target, 'invisible', 'unknown.svg'); if (invisible === true) { if (visionCapabilities.seeinvisible !== true) { diff --git a/src/packs/visibility-scripts.db b/src/packs/visibility-scripts.db index dda8035..711e8ba 100644 --- a/src/packs/visibility-scripts.db +++ b/src/packs/visibility-scripts.db @@ -6,4 +6,5 @@ {"_id":"ioE9JiWntRzjeDFr","name":"In Darkness on","permission":{"default":0},"type":"script","sort":100003,"flags":{},"scope":"global","command":"//Sets selected tokens to in darkness\nConditionalVisibility.setCondition(canvas.tokens.controlled, 'indarkness', true)","img":"icons/svg/dice-target.svg","actorIds":[]} {"_id":"pkE9JiWntRzjeACr","name":"In Darkness off","permission":{"default":0},"type":"script","sort":100004,"flags":{},"scope":"global","command":"//Removes indarkness condition from selected tokens.\nConditionalVisibility.setCondition(canvas.tokens.controlled, 'indarkness', false)","img":"icons/svg/dice-target.svg","actorIds":[]} {"_id":"ioE9JiWntRzjeBBr","name":"Obscured on","permission":{"default":0},"type":"script","sort":100005,"flags":{},"scope":"global","command":"//Sets selected tokens to obscured\nConditionalVisibility.setCondition(canvas.tokens.controlled, 'obscured', true)","img":"icons/svg/dice-target.svg","actorIds":[]} -{"_id":"pkE9JiWntRzjeBBr","name":"Obscured off","permission":{"default":0},"type":"script","sort":100006,"flags":{},"scope":"global","command":"//Removes obscured from selected tokens.\nConditionalVisibility.setCondition(canvas.tokens.controlled, 'obscured', false)","img":"icons/svg/dice-target.svg","actorIds":[]} \ No newline at end of file +{"_id":"pkE9JiWntRzjeBBr","name":"Obscured off","permission":{"default":0},"type":"script","sort":100006,"flags":{},"scope":"global","command":"//Removes obscured from selected tokens.\nConditionalVisibility.setCondition(canvas.tokens.controlled, 'obscured', false)","img":"icons/svg/dice-target.svg","actorIds":[]} +{"_id":"pkA4JiWntARaeBBr","name":"Migrate Foundry 0.6 to 0.7","permission":{"default":0},"type":"script","sort":100017,"flags":{},"scope":"global","command":"// Removes statusEffects set in Foundry 06 and applies the equivalent effect for Foundry 0.7\n\nlet update0607ConvisMatches = {\n\t'modules/conditional-visibility/icons/unknown.svg': 'invisible',\n\t'modules/conditional-visibility/icons/newspaper.svg': 'hiding',\n\t'modules/conditional-visibility/icons/foggy.svg': 'obscured',\n\t'modules/conditional-visibility/icons/moon.svg': 'indarkness'\n}\n\nconst popper = async function(token, effects) {\n\tawait effects.reduce(async (promise, eff) => {\n\t\tawait promise;\n\t\tif (eff.endsWith('newspaper.svg')) {\n\t\t\tconsole.info('Migrating 0.6->0.7 hiding for ' + token.data.name);\n\t\t\ttoken.data.effects.splice(token.data.effects.indexOf(eff), 1);\n\t\t\tconst ste = token.data?.flags['conditional-visibility']?._ste;\n\t\t\tif (ste) {\n\t\t\t\tawait ConditionalVisibility.hide([token], ste);\n\t\t\t} else {\n\t\t\t\tawait ConditionalVisibility.hide([token]);\n\t\t\t}\n\t\t} else {\n\t\t\tconsole.info('Migrating 0.6->0.7 ' + update0607ConvisMatches[eff] + ' for ' + token.data.name);\n\t\t\ttoken.data.effects.splice(token.data.effects.indexOf(eff), 1);\n\t\t\tawait ConditionalVisibility.setCondition([token], update0607ConvisMatches[eff], true);\n\t\t}\n\t}, Promise.resolve());\n}\n\nfor (const token of canvas.tokens.placeables) {\n\tif (token.data.effects.length > 0) {\n\t\tconst name = token.data.name;\n\t\tconst effectsToToggle = token.data.effects.filter(eff => {\n\t\t\tlet toCheck;\n\t\t\tif (typeof eff === 'string') {\n\t\t\t\ttoCheck = eff;\n\t\t\t} else {\n\t\t\t\ttoCheck = eff.icon;\n\t\t\t}\n\t\t\treturn toCheck && update0607ConvisMatches[toCheck] !== undefined;\n\t\t});\n\t\tpopper(token, effectsToToggle);\n\t};\n}","img":"icons/svg/dice-target.svg","actorIds":[]} \ No newline at end of file From b5dcf8493ecaee049e19861ae10ff9c4dd4b1a9d Mon Sep 17 00:00:00 2001 From: Greg Ludington Date: Fri, 27 Nov 2020 19:26:41 -0500 Subject: [PATCH 4/6] version popup backport --- src/lang/en.json | 6 ++++ src/module/ConditionalVisibility.ts | 44 +++++++++++++++++++++++++++++ src/module/settings.ts | 7 +++++ src/templates/version_popup.html | 4 +++ 4 files changed, 61 insertions(+) create mode 100644 src/templates/version_popup.html diff --git a/src/lang/en.json b/src/lang/en.json index c7f4dc1..939bdc1 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -3,6 +3,12 @@ "CONVIS.settings.autoStealth.name": "Auto hide on stealth rolls", "CONVIS.settings.autoStealth.hint": "On supported game systems, set the hidden condition on a token's stealth roll", + "CONVIS.popup.dismissuntilupdated": "Dismiss until updated", + "CONVIS.popup.close": "Close", + "CONVIS.popup.version0910.1":"A compendium has is now part of this module, for those who wish to use macros instead of conditions icons to apply conditions, or to apply them in bulk.", + "CONVIS.popup.version0910.2":"There is also a script to migrate conditions of selected tokens from the Foundry 0.6.x model to the Foundry 0.7 model", + "CONVIS.popup.version0910.3":"Using these scripts as macros will require the installation of the Furnace module, as they are asynchronous", + "CONVIS.help.readmeat": "More instructions can be found at the", "CONVIS.help.gamesystem": "Game System", "CONVIS.help.hasStealth": "Has Stealth", diff --git a/src/module/ConditionalVisibility.ts b/src/module/ConditionalVisibility.ts index c96b66a..43016df 100644 --- a/src/module/ConditionalVisibility.ts +++ b/src/module/ConditionalVisibility.ts @@ -40,6 +40,24 @@ export class ConditionalVisibility { system.initializeStatusEffects(); } + public isSemvarGreater(first:string, second:string):boolean { + const firstSemVar:Array = this.splitOnDot(first); + const secondSemVar:Array = this.splitOnDot(second); + if (firstSemVar.length != secondSemVar.length) { + throw new Error("bad semvar"); + } + for (let i = 0; i < firstSemVar.length;i++ ){ + if (firstSemVar[i] > secondSemVar[i]) { + return true; + } + } + return false; + } + + private splitOnDot(toSplit:string):Array { + return toSplit.split(".").map(str => isNaN(Number(str)) ? 0 : Number(str)); + } + /** * A static method that will be replaced after initialization with the appropriate system specific method. * @param token the token to test @@ -157,6 +175,32 @@ export class ConditionalVisibility { // update sight layer, as custom decisons will not be executed the // first time through, and cannot be forced in setup this.draw(); + + const popupVersion = game.settings.get(MODULE_NAME, "popup-version"); + const currentVersion = game.modules.get(MODULE_NAME).data.version; + console.error(game.i18n.localize("CONVIS.popup.dismissuntilupdated")); + if (this.isSemvarGreater(currentVersion, popupVersion)) { + renderTemplate("modules/conditional-visibility/templates/version_popup.html", { + version: currentVersion, + }).then(content => { + let d = new Dialog({ + title: "Conditional Visibility", + content: content, + buttons: { + one: { + icon: '', + label: game.i18n.localize('CONVIS.popup.dismissuntilupdated'), + callback: () => game.settings.set(MODULE_NAME, 'popup-version', currentVersion) + }, + two: { + icon: '', + label: game.i18n.localize('CONVIS.popup.close') + } + } + }); + d.render(true); + }); + } } public onRenderTokenConfig(tokenConfig: any, jQuery:JQuery, data: any) { diff --git a/src/module/settings.ts b/src/module/settings.ts index c7eee5c..9594814 100644 --- a/src/module/settings.ts +++ b/src/module/settings.ts @@ -12,6 +12,13 @@ export const registerSettings = function() { onChange: value => console.log(Constants.MODULE_NAME + ' | autoStealth set to ' + value) }) + game.settings.register(Constants.MODULE_NAME, "popup-version", { + scope: "world", + config: false, + type: String, + default: "0.0.9", + }); + // Register any custom module settings here ConditionalVisibility.onInit(); } diff --git a/src/templates/version_popup.html b/src/templates/version_popup.html new file mode 100644 index 0000000..2e2fa63 --- /dev/null +++ b/src/templates/version_popup.html @@ -0,0 +1,4 @@ +

Conditional Visibility {{version}}

+

{{localize "CONVIS.popup.version0910.1"}}

+

{{localize "CONVIS.popup.version0910.2"}}

+

{{localize "CONVIS.popup.version0910.3"}}

\ No newline at end of file From 7d16e1374fc9d14174fcea80feb66e562f4e5ab3 Mon Sep 17 00:00:00 2001 From: Greg Ludington Date: Fri, 27 Nov 2020 19:51:47 -0500 Subject: [PATCH 5/6] logging and facade changes --- src/module/ConditionalVisibility.ts | 5 ++--- src/module/ConditionalVisibilityFacade.ts | 2 +- src/module/systems/DefaultConditionalVisibilitySystem.ts | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/module/ConditionalVisibility.ts b/src/module/ConditionalVisibility.ts index 43016df..0f9db58 100644 --- a/src/module/ConditionalVisibility.ts +++ b/src/module/ConditionalVisibility.ts @@ -29,7 +29,6 @@ export class ConditionalVisibility { if (isVisible === false) { return false; } - console.error(this); if (game.user.isGM || this.owner || !canvas.sight.tokenVision) { return true; } @@ -177,8 +176,8 @@ export class ConditionalVisibility { this.draw(); const popupVersion = game.settings.get(MODULE_NAME, "popup-version"); - const currentVersion = game.modules.get(MODULE_NAME).data.version; - console.error(game.i18n.localize("CONVIS.popup.dismissuntilupdated")); + const currentVersion = "0.0.3";//game.modules.get(MODULE_NAME).data.version; + if (this.isSemvarGreater(currentVersion, popupVersion)) { renderTemplate("modules/conditional-visibility/templates/version_popup.html", { version: currentVersion, diff --git a/src/module/ConditionalVisibilityFacade.ts b/src/module/ConditionalVisibilityFacade.ts index f042f4e..476bf4e 100644 --- a/src/module/ConditionalVisibilityFacade.ts +++ b/src/module/ConditionalVisibilityFacade.ts @@ -142,7 +142,7 @@ export class ConditionalVisibilityFacadeImpl implements ConditionalVisibilityFac } private has(token, condition):boolean { - let flags = token?.data?.flags?.[Constants.MODULE_NAME] || token?.actor?.data?.flags?.[Constants.MODULE_NAME]; + const flags = token.data.actorLink ? token.actor?.data?.flags?.[Constants.MODULE_NAME] : token?.data?.flags?.[Constants.MODULE_NAME]; if (flags) { return flags[condition.visibilityId] === true; } else { diff --git a/src/module/systems/DefaultConditionalVisibilitySystem.ts b/src/module/systems/DefaultConditionalVisibilitySystem.ts index 823e80f..f46b38a 100644 --- a/src/module/systems/DefaultConditionalVisibilitySystem.ts +++ b/src/module/systems/DefaultConditionalVisibilitySystem.ts @@ -33,8 +33,7 @@ export class DefaultConditionalVisibilitySystem implements ConditionalVisibility _effectsByCondition: Map; hasStatus(token:Token, id:string, icon:string): boolean { - return token.data?.flags?.[MODULE_NAME]?.[id] === true - || token.actor?.data?.flags?.[MODULE_NAME]?.[id] === true; + return token.data.actorLink ? token.actor?.data?.flags?.[MODULE_NAME]?.[id] === true : token.data?.flags?.[MODULE_NAME]?.[id] === true; } constructor() { From 0035c8096ba8953647d8997b634a16fee7077fc8 Mon Sep 17 00:00:00 2001 From: Greg Ludington Date: Fri, 27 Nov 2020 19:59:14 -0500 Subject: [PATCH 6/6] semvar fallback for dev --- src/module/ConditionalVisibility.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/module/ConditionalVisibility.ts b/src/module/ConditionalVisibility.ts index 0f9db58..61aa3e9 100644 --- a/src/module/ConditionalVisibility.ts +++ b/src/module/ConditionalVisibility.ts @@ -43,7 +43,7 @@ export class ConditionalVisibility { const firstSemVar:Array = this.splitOnDot(first); const secondSemVar:Array = this.splitOnDot(second); if (firstSemVar.length != secondSemVar.length) { - throw new Error("bad semvar"); + throw new Error("bad semvar first " + first +", second" + second); } for (let i = 0; i < firstSemVar.length;i++ ){ if (firstSemVar[i] > secondSemVar[i]) { @@ -176,7 +176,7 @@ export class ConditionalVisibility { this.draw(); const popupVersion = game.settings.get(MODULE_NAME, "popup-version"); - const currentVersion = "0.0.3";//game.modules.get(MODULE_NAME).data.version; + const currentVersion = game.modules.get(MODULE_NAME).data.version === "@tagVersion@" ? "0.0.3" : game.modules.get(MODULE_NAME).data.version; if (this.isSemvarGreater(currentVersion, popupVersion)) { renderTemplate("modules/conditional-visibility/templates/version_popup.html", {