From 58629c92f4b5a7bb1a5c84ec51f2b1842c5cef48 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Mon, 15 Aug 2022 16:10:40 +0200 Subject: [PATCH 01/16] Added build command to package.json --- .gitignore | 1 + app/package.json | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c795b054 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/app/package.json b/app/package.json index bc90f96d..99bb0f84 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "dicecloud", - "version": "2.0.33", + "version": "2.0.38", "description": "Unofficial Online Realtime D&D 5e App", "license": "GPL-3.0", "repository": { @@ -11,7 +11,8 @@ "scripts": { "run": "meteor", "debug": "meteor --inspect", - "test": "meteor test --driver-package meteortesting:mocha --port 3001" + "test": "meteor test --driver-package meteortesting:mocha --port 3001", + "build": "meteor build ../build --architecture os.linux.x86_64" }, "engines": { "node": "14.0.x", From 45f05d0d34a5baaed1b631a05e8d77d6de0a2956 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Tue, 16 Aug 2022 09:26:40 +0200 Subject: [PATCH 02/16] Fixed bug where actions targeting self weren't applying props to self --- .../api/engine/actions/applyPropertyByType/applyAction.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyAction.js b/app/imports/api/engine/actions/applyPropertyByType/applyAction.js index f666bad9..26da462a 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyAction.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyAction.js @@ -11,8 +11,8 @@ import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js' export default function applyAction(node, actionContext) { applyNodeTriggers(node, 'before', actionContext); const prop = node.node; - let targets = actionContext.targets; - if (prop.target === 'self') targets = [actionContext.creature]; + if (prop.target === 'self') actionContext.targets = [actionContext.creature]; + const targets = actionContext.targets; // Log the name and summary let content = { name: prop.name }; From 48331d38067e1e279ed8349301122dc2191aea8b Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Tue, 16 Aug 2022 09:49:34 +0200 Subject: [PATCH 03/16] Fixed added properties being added based on tree tab selection even when on other tabs --- .../ui/creature/character/CharacterSheetFab.vue | 9 +++++---- app/imports/ui/vuexStore.js | 13 ++++++++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/app/imports/ui/creature/character/CharacterSheetFab.vue b/app/imports/ui/creature/character/CharacterSheetFab.vue index 49590d75..5af7abd0 100644 --- a/app/imports/ui/creature/character/CharacterSheetFab.vue +++ b/app/imports/ui/creature/character/CharacterSheetFab.vue @@ -9,9 +9,9 @@ v-model="fab" color="primary" fab + small data-id="insert-creature-property-fab" class="insert-creature-property-fab" - small > (id) => { if (id in state.characterSheetTabs){ return state.characterSheetTabs[id]; } else { return 0; } + }, + tabNameById: (state) => (id) => { + const tabNumber = state.characterSheetTabs[id]; + const creature = Creatures.findOne(id); + if (creature?.settings?.hideSpellsTab) { + return tabsWithoutSpells[tabNumber]; + } else { + return tabs[tabNumber] + } } }, mutations: { From 4c2aabf90d7a6edf85a4b4f4bf223d0f6b39e20b Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Tue, 16 Aug 2022 10:03:07 +0200 Subject: [PATCH 04/16] Fixed character sheet toolbar alignment on mobile --- .../creature/character/CharacterSheetToolbar.vue | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/app/imports/ui/creature/character/CharacterSheetToolbar.vue b/app/imports/ui/creature/character/CharacterSheetToolbar.vue index e46ce38c..0cafc021 100644 --- a/app/imports/ui/creature/character/CharacterSheetToolbar.vue +++ b/app/imports/ui/creature/character/CharacterSheetToolbar.vue @@ -14,17 +14,19 @@ - -
- {{ $store.state.pageTitle }} -
-
+ + {{ $store.state.pageTitle }} +
-
+ -
+
Date: Tue, 16 Aug 2022 10:11:13 +0200 Subject: [PATCH 05/16] Fixed icons being missing from buff-applied props --- app/imports/api/engine/loadCreatures.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/app/imports/api/engine/loadCreatures.js b/app/imports/api/engine/loadCreatures.js index 9823f892..2acd342f 100644 --- a/app/imports/api/engine/loadCreatures.js +++ b/app/imports/api/engine/loadCreatures.js @@ -46,7 +46,6 @@ export function getSingleProperty(creatureId, propertyId) { 'removed': {$ne: true}, }, { sort: { order: 1 }, - fields: { icon: 0 }, }); // console.timeEnd(`Cache miss on creature properties: ${creatureId}`); return prop; @@ -65,7 +64,6 @@ export function getProperties(creatureId) { 'removed': {$ne: true}, }, { sort: { order: 1 }, - fields: { icon: 0 }, }).fetch(); // console.timeEnd(`Cache miss on creature properties: ${creatureId}`); return props; @@ -90,7 +88,6 @@ export function getPropertiesOfType(creatureId, propType) { 'type': propType, }, { sort: { order: 1 }, - fields: { icon: 0 }, }).fetch(); // console.timeEnd(`Cache miss on creature properties: ${creatureId}`); return props; @@ -103,11 +100,7 @@ export function getCreature(creatureId) { if (creature) return creature; } // console.time(`Cache miss on Creature: ${creatureId}`); - const creature = Creatures.findOne(creatureId, { - denormalizedStats: 1, - variables: 1, - dirty: 1, - }); + const creature = Creatures.findOne(creatureId); // console.timeEnd(`Cache miss on Creature: ${creatureId}`); return creature; } @@ -149,6 +142,7 @@ export function getProperyAncestors(creatureId, propertyId) { // Fetch from database return CreatureProperties.find({ _id: { $in: ancestorIds }, + removed: {$ne: true}, }, { sort: { order: 1 }, }).fetch(); @@ -175,6 +169,8 @@ export function getPropertyDecendants(creatureId, propertyId) { return CreatureProperties.find({ 'ancestors.id': propertyId, removed: { $ne: true }, + }, { + sort: { order: 1 }, }).fetch(); } } @@ -199,7 +195,6 @@ class LoadedCreature { removed: { $ne: true }, }, { sort: { order: 1 }, - fields: { icon: 0 }, }).observeChanges({ added(id, fields) { fields._id = id; From 34e3325464f8b8c45e2d39f0028109693fbd84d8 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Tue, 16 Aug 2022 11:19:16 +0200 Subject: [PATCH 06/16] Fixed dependency loops created by inactive props depending on their parent toggles --- .../computeToggleDependencies.js | 4 +++- .../computation/buildCreatureComputation.js | 4 ++++ .../computation/computeCreatureComputation.js | 21 ++++++++++++++----- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/app/imports/api/engine/computation/buildComputation/computeToggleDependencies.js b/app/imports/api/engine/computation/buildComputation/computeToggleDependencies.js index 13549e73..315d93f0 100644 --- a/app/imports/api/engine/computation/buildComputation/computeToggleDependencies.js +++ b/app/imports/api/engine/computation/buildComputation/computeToggleDependencies.js @@ -10,8 +10,10 @@ export default function computeToggleDependencies(node, dependencyGraph){ prop.enabled ) return; walkDown(node.children, child => { - child.node._computationDetails.toggleAncestors.push(prop); + // Only for children that aren't inactive + if (child.node.inactive) return; // The child nodes depend on the toggle condition compuation + child.node._computationDetails.toggleAncestors.push(prop); dependencyGraph.addLink(child.node._id, prop._id, 'toggle'); }); } diff --git a/app/imports/api/engine/computation/buildCreatureComputation.js b/app/imports/api/engine/computation/buildCreatureComputation.js index d99d9290..a5009d2c 100644 --- a/app/imports/api/engine/computation/buildCreatureComputation.js +++ b/app/imports/api/engine/computation/buildCreatureComputation.js @@ -89,6 +89,10 @@ export function buildComputationFromProps(properties, creature, variables){ // Walk the property trees computing things that need to be inherited walkDown(forest, node => { computeInactiveStatus(node); + }); + // Inactive status must be complete for the whole tree before toggle deps + // are calculated + walkDown(forest, node => { computeToggleDependencies(node, dependencyGraph); computeSlotQuantityFilled(node, dependencyGraph); }); diff --git a/app/imports/api/engine/computation/computeCreatureComputation.js b/app/imports/api/engine/computation/computeCreatureComputation.js index 88dde8c7..7cd4b41c 100644 --- a/app/imports/api/engine/computation/computeCreatureComputation.js +++ b/app/imports/api/engine/computation/computeCreatureComputation.js @@ -51,11 +51,22 @@ function compute(computation, node){ function pushDependenciesToStack(nodeId, graph, stack, computation){ graph.forEachLinkedNode(nodeId, linkedNode => { - if (linkedNode._visitedChildren && !linkedNode._visited){ - const pather = path.nba(graph, { - oriented: true - }); - const loop = pather.find(nodeId, nodeId); + if (linkedNode._visitedChildren && !linkedNode._visited) { + // This is a dependency loop, find a path from the node to itself + // and store that path as a dependency loop error + const pather = path.nba(graph, { oriented: true }); + let loop = []; + // Pather doesn't like going from a node to iteself, so find all the + // paths going from the next node back to the original node + // and return the shortest one + graph.forEachLinkedNode(nodeId, nextNode => { + const newLoop = pather.find(nextNode.id, nodeId); + if (!newLoop.length) return; + if (!loop.length || newLoop.length < loop.length - 1) { + loop = [linkedNode, ...newLoop]; + } + }, true); + if (loop.length) { computation.errors.push({ type: 'dependencyLoop', From cbac5264cd356023b55de7c3b93f407cde54ab0b Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Tue, 16 Aug 2022 11:44:08 +0200 Subject: [PATCH 07/16] Added delete buttons to slot fill card --- .../ui/creature/buildTree/BuildTreeNode.vue | 229 +++++++++++------- 1 file changed, 136 insertions(+), 93 deletions(-) diff --git a/app/imports/ui/creature/buildTree/BuildTreeNode.vue b/app/imports/ui/creature/buildTree/BuildTreeNode.vue index 5664453c..8f49fb2d 100644 --- a/app/imports/ui/creature/buildTree/BuildTreeNode.vue +++ b/app/imports/ui/creature/buildTree/BuildTreeNode.vue @@ -28,11 +28,11 @@
- + > + + + + + mdi-delete + + +
@@ -92,98 +115,118 @@ diff --git a/app/imports/ui/properties/forms/shared/propertyFormIndex.js b/app/imports/ui/properties/forms/shared/propertyFormIndex.js index 1aa8f42e..e8d6eb9f 100644 --- a/app/imports/ui/properties/forms/shared/propertyFormIndex.js +++ b/app/imports/ui/properties/forms/shared/propertyFormIndex.js @@ -2,6 +2,7 @@ const ActionForm = () => import('/imports/ui/properties/forms/ActionForm.vue'); const AdjustmentForm = () => import('/imports/ui/properties/forms/AdjustmentForm.vue'); const AttributeForm = () => import('/imports/ui/properties/forms/AttributeForm.vue'); const BuffForm = () => import('/imports/ui/properties/forms/BuffForm.vue'); +const BuffRemoverForm = () => import('/imports/ui/properties/forms/BuffRemoverForm.vue'); const BranchForm = () => import('/imports/ui/properties/forms/BranchForm.vue'); const ClassForm = () => import('/imports/ui/properties/forms/ClassForm.vue'); const ClassLevelForm = () => import('/imports/ui/properties/forms/ClassLevelForm.vue'); @@ -31,6 +32,7 @@ export default { adjustment: AdjustmentForm, attribute: AttributeForm, buff: BuffForm, + buffRemover: BuffRemoverForm, branch: BranchForm, constant: ConstantForm, container: ContainerForm, diff --git a/app/imports/ui/properties/viewers/BuffRemoverViewer.vue b/app/imports/ui/properties/viewers/BuffRemoverViewer.vue new file mode 100644 index 00000000..89097b7e --- /dev/null +++ b/app/imports/ui/properties/viewers/BuffRemoverViewer.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/app/imports/ui/properties/viewers/shared/propertyViewerIndex.js b/app/imports/ui/properties/viewers/shared/propertyViewerIndex.js index 572bfad0..cef19b01 100644 --- a/app/imports/ui/properties/viewers/shared/propertyViewerIndex.js +++ b/app/imports/ui/properties/viewers/shared/propertyViewerIndex.js @@ -2,6 +2,7 @@ const ActionViewer = () => import ('/imports/ui/properties/viewers/ActionViewer. const AdjustmentViewer = () => import ('/imports/ui/properties/viewers/AdjustmentViewer.vue'); const AttributeViewer = () => import ('/imports/ui/properties/viewers/AttributeViewer.vue'); const BuffViewer = () => import ('/imports/ui/properties/viewers/BuffViewer.vue'); +const BuffRemoverViewer = () => import ('/imports/ui/properties/viewers/BuffRemoverViewer.vue'); const BranchViewer = () => import ('/imports/ui/properties/viewers/BranchViewer.vue'); const ContainerViewer = () => import ('/imports/ui/properties/viewers/ContainerViewer.vue'); const ClassViewer = () => import ('/imports/ui/properties/viewers/ClassViewer.vue'); @@ -31,6 +32,7 @@ export default { adjustment: AdjustmentViewer, attribute: AttributeViewer, buff: BuffViewer, + buffRemover: BuffRemoverViewer, branch: BranchViewer, container: ContainerViewer, class: ClassViewer, From 21629138f019df0a7f2cc2b1df026eed75423e62 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Wed, 17 Aug 2022 12:28:00 +0200 Subject: [PATCH 14/16] Added Buff Removed action trigger --- app/imports/api/properties/Triggers.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/imports/api/properties/Triggers.js b/app/imports/api/properties/Triggers.js index f8f6c4a3..4b66e422 100644 --- a/app/imports/api/properties/Triggers.js +++ b/app/imports/api/properties/Triggers.js @@ -25,6 +25,7 @@ const actionPropertyTypeOptions = { adjustment: 'Attribute damage', branch: 'Branch', buff: 'Buff', + buffRemover: 'Buff Removed', damage: 'Damage', note: 'Note', roll: 'Roll', From 7d66c06107f07544c65c3187f9081f4a8363896c Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Wed, 17 Aug 2022 12:45:54 +0200 Subject: [PATCH 15/16] Fixed class level up w/ subscribed collections --- .../server/publications/slotFillers.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/app/imports/server/publications/slotFillers.js b/app/imports/server/publications/slotFillers.js index 30dadc9f..6427af79 100644 --- a/app/imports/server/publications/slotFillers.js +++ b/app/imports/server/publications/slotFillers.js @@ -100,21 +100,18 @@ Meteor.publish('classFillers', function(classId){ } // Get all the ids of libraries the user can access - const user = Meteor.users.findOne(userId, { - fields: {subscribedLibraries: 1} - }); - const subs = user && user.subscribedLibraries || []; - let libraries = Libraries.find({ + const creatureId = classProp.ancestors[0].id; + const libraryIds = getCreatureLibraryIds(creatureId, userId); + const libraries = Libraries.find({ $or: [ - {owner: userId}, - {writers: userId}, - {readers: userId}, - {_id: {$in: subs}}, + { owner: userId }, + { writers: userId }, + { readers: userId }, + { _id: { $in: libraryIds }, public: true }, ] }, { - fields: {_id: 1, name: 1}, + sort: { name: 1 } }); - let libraryIds = libraries.map(lib => lib._id); // Build a filter for nodes in those libraries that match the slot let filter = getSlotFillFilter({slot: classProp, libraryIds}); From 877c9ca099702f5e588bd8ac7d6fe19288303eb1 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Wed, 17 Aug 2022 17:21:18 +0200 Subject: [PATCH 16/16] Fixed cache bashing in checks Cache should only return clones of data, not references to the cached data --- app/imports/api/engine/loadCreatures.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/imports/api/engine/loadCreatures.js b/app/imports/api/engine/loadCreatures.js index 2acd342f..aa036a37 100644 --- a/app/imports/api/engine/loadCreatures.js +++ b/app/imports/api/engine/loadCreatures.js @@ -97,7 +97,10 @@ export function getCreature(creatureId) { if (loadedCreatures.has(creatureId)) { const loadedCreature = loadedCreatures.get(creatureId); const creature = loadedCreature.creature; - if (creature) return creature; + if (creature) { + const cloneCreature = EJSON.clone(creature); + return cloneCreature; + } } // console.time(`Cache miss on Creature: ${creatureId}`); const creature = Creatures.findOne(creatureId); @@ -109,7 +112,10 @@ export function getVariables(creatureId) { if (loadedCreatures.has(creatureId)) { const loadedCreature = loadedCreatures.get(creatureId); const variables = loadedCreature.variables; - if (variables) return variables; + if (variables) { + const cloneVarables = EJSON.clone(variables); + return cloneVarables; + } } // console.time(`Cache miss on variables: ${creatureId}`); const variables = CreatureVariables.findOne({_creatureId: creatureId});