Replaced expensive getActiveProperties with cheaper filter by inactive field

This commit is contained in:
Stefan Zermatten
2021-01-28 14:29:10 +02:00
parent fc03097ed8
commit 83f2047dbe
14 changed files with 147 additions and 197 deletions

View File

@@ -3,7 +3,7 @@ import { RateLimiterMixin } from 'ddp-rate-limiter-mixin';
import SimpleSchema from 'simpl-schema';
import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js';
import Creatures from '/imports/api/creature/Creatures.js';
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
export const recomputeDamageMultipliers = new ValidatedMethod({
@@ -31,9 +31,13 @@ export const recomputeDamageMultipliers = new ValidatedMethod({
export function recomputeDamageMultipliersById(creatureId){
if (!creatureId) throw 'Creature ID is required';
let props = getActiveProperties({
ancestorId: creatureId,
filter: {type: 'damageMultiplier'},
let props = CreatureProperties.find({
'ancestors.id': creatureId,
type: 'damageMultiplier',
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {order: 1}
});
// Count of how many weakness, resistances and immunities each damage type has

View File

@@ -1,86 +0,0 @@
import Creatures from '/imports/api/creature/Creatures.js';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
export default function getActiveProperties({
ancestorId,
filter = {},
options = {sort: {order: 1}},
includeUntoggled = false,
includeUnprepared = false,
includeUnequipped = false,
excludeAncestors,
}){
filter = getActivePropertyFilter({
ancestorId,
filter,
includeUntoggled,
includeUnprepared,
includeUnequipped,
excludeAncestors,
});
return CreatureProperties.find(filter, options).fetch();
}
export function getActivePropertyFilter({
ancestorId,
filter = {},
includeUntoggled = false,
includeUnprepared = false,
includeUnequipped = false,
excludeAncestors = [],
}){
if (!ancestorId){
throw 'Ancestor Id is required to get active properties'
}
// First get ids of disabled properties, unequiped items, unapplied buffs
let disabledAncestorsFilter = {
'ancestors.id': ancestorId,
$or: [
{disabled: true}, // Everything can be disabled
{applied: false}, // Buffs can be applied
],
};
if (!includeUnequipped){
disabledAncestorsFilter.$or.push({type: 'item', equipped: {$ne: true}});
}
if (!includeUntoggled){
disabledAncestorsFilter.$or.push({toggleResult: false});
}
if (!includeUnprepared){
disabledAncestorsFilter.$or.push({
type: 'spell',
prepared: {$ne: true},
alwaysPrepared: {$ne: true}
});
}
let disabledAncestorIds = CreatureProperties.find(disabledAncestorsFilter, {
fields: {_id: 1},
}).map(prop => prop._id);
// Then get the ids of creatures that are children of this creature
// to isolate their decendent properties
Creatures.find({
'ancestors.id': ancestorId,
}, {
fields: {_id: 1},
}).forEach(subCreature => {
disabledAncestorIds.push(subCreature._id);
});
// Get all the properties that are decendents of the ancestor of interest but
// aren't from the excluded decendents
if (filter['ancestors.id'] && Meteor.isClient){
console.warn('Filtering on ancestor id is ignored')
}
filter['ancestors.id'] = {
$eq: ancestorId,
$nin: disabledAncestorIds.concat(excludeAncestors),
};
// Get properties that aren't removed
filter.removed = {$ne: true};
// Don't include the disabled ancestors themselves either
filter._id = {
$nin: disabledAncestorIds,
}
return filter;
}

View File

@@ -3,7 +3,6 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method';
import { RateLimiterMixin } from 'ddp-rate-limiter-mixin';
import Creatures from '/imports/api/creature/Creatures.js';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import getActiveProperties, { getActivePropertyFilter } from '/imports/api/creature/getActiveProperties.js';
import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js';
import { recomputeCreatureById } from '/imports/api/creature/computation/recomputeCreature.js';
@@ -43,11 +42,12 @@ const restCreature = new ValidatedMethod({
resetFilter = {$in: ['shortRest', 'longRest']}
}
// Only apply to active properties
let filter = getActivePropertyFilter({
filter: {reset: resetFilter},
ancestorId: creatureId,
includeUntoggled: true,
});
let filter = {
'ancestors.id': creatureId,
reset: resetFilter,
removed: {$ne: true},
inactive: {$ne: true},
};
// update all attribute's damage
filter.type = 'attribute';
CreatureProperties.update(filter, {
@@ -70,14 +70,18 @@ const restCreature = new ValidatedMethod({
});
// Reset half hit dice on a long rest, starting with the highest dice
if (restType === 'longRest'){
let hitDice = getActiveProperties({
ancestorId: creatureId,
filter: {type: 'attribute', attributeType: 'hitDice'},
options: {fields: {
let hitDice = CreatureProperties.find({
'ancestors.id': creatureId,
type: 'attribute',
attributeType: 'hitDice',
removed: {$ne: true},
inactive: {$ne: true},
}, {
fields: {
hitDiceSize: 1,
damage: 1,
value: 1,
}},
}
});
// Use a collator to do sorting in natural order
let collator = new Intl.Collator('en', {

View File

@@ -55,7 +55,7 @@ export default {
},
meteor: {
name(){
let creature = Creatures.findOne(this.id);
let creature = Creatures.findOne(this.id, {fields: {name: 1}});
return creature && creature.name;
},
},

View File

@@ -114,7 +114,6 @@ import Creatures from '/imports/api/creature/Creatures.js';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import NoteCard from '/imports/ui/properties/components/persona/NoteCard.vue';
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import Slots from '/imports/ui/creature/slots/Slots.vue';
import ToolbarCard from '/imports/ui/components/ToolbarCard.vue';
@@ -171,9 +170,13 @@ export default {
return Creatures.findOne(this.creatureId);
},
classLevels(){
return getActiveProperties({
ancestorId: this.creatureId,
filter: {type: 'classLevel'},
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'classLevel',
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {order: 1}
});
},
},

View File

@@ -16,7 +16,7 @@
</template>
<script>
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import FeatureCard from '/imports/ui/properties/components/features/FeatureCard.vue';
@@ -33,11 +33,13 @@ import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
},
meteor: {
features(){
return getActiveProperties({
ancestorId: this.creatureId,
filter: {
type: 'feature',
},
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'feature',
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {order: 1}
});
},
},

View File

@@ -24,7 +24,7 @@
<script>
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import SpellListCard from '/imports/ui/properties/components/spells/SpellListCard.vue';
import SpellList from '/imports/ui/properties/components/spells/SpellList.vue';
@@ -48,35 +48,42 @@ export default {
}},
meteor: {
spellLists(){
return getActiveProperties({
ancestorId: this.creatureId,
filter: {
type: 'spellList',
},
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'spellList',
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {order: 1}
});
},
spellsWithoutList(){
return getActiveProperties({
ancestorId: this.creatureId,
excludeAncestors: this.spellListIds,
filter: {
type: 'spell',
},
options: {
sort: {
level: 1,
order: 1,
},
return CreatureProperties.find({
'ancestors.id': {
$eq: this.creatureId,
$nin: this.spellListIds,
},
type: 'spell',
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {
level: 1,
order: 1,
}
});
},
spellListsWithoutAncestorSpellLists(){
return getActiveProperties({
ancestorId: this.creatureId,
excludeAncestors: this.spellListIds,
filter: {
type: 'spellList',
return CreatureProperties.find({
'ancestors.id': {
$eq: this.creatureId,
$nin: this.spellListIds,
},
type: 'spellList',
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {order: 1}
});
},
},

View File

@@ -322,7 +322,7 @@
import SpellSlotListTile from '/imports/ui/properties/components/attributes/SpellSlotListTile.vue';
import ActionCard from '/imports/ui/properties/components/actions/ActionCard.vue';
import RestButton from '/imports/ui/creature/RestButton.vue';
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import castSpellWithSlot from '/imports/api/creature/actions/castSpellWithSlot.js';
const getProperties = function(creature, filter,){
@@ -330,10 +330,11 @@
if (creature.settings.hideUnusedStats){
filter.hide = {$ne: true};
}
return getActiveProperties({
ancestorId: creature._id,
filter,
options: {sort: {order: 1}},
filter['ancestors.id'] = creature._id;
filter.removed = {$ne: true};
filter.inactive = {$ne: true};
return CreatureProperties.find(filter, {
sort: {order: 1}
});
};
@@ -422,9 +423,12 @@
},
attacks(){
let props = getProperties(this.creature, {type: 'attack'}).map(attack => {
attack.children = getActiveProperties({
ancestorId: attack._id,
options: {sort: {order: 1}},
attack.children = CreatureProperties.find({
'ancestors.id': attack._id,
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {order: 1}
});
return attack;
});

View File

@@ -59,7 +59,6 @@ import {
softRemoveProperty,
restoreProperty
} from '/imports/api/creature/CreatureProperties.js';
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import getPropertyTitle from '/imports/ui/properties/shared/getPropertyTitle.js';
export default {
@@ -122,15 +121,17 @@ export default {
},
meteor: {
slots(){
return getActiveProperties({
ancestorId: this.creatureId,
filter: {
type: 'propertySlot',
$or: [
{slotConditionResult: true},
{slotConditionResult: {$exists: false}},
],
}
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'propertySlot',
$or: [
{slotConditionResult: true},
{slotConditionResult: {$exists: false}},
],
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {order: 1}
}).map(slot => {
if (
!this.showHiddenSlots &&

View File

@@ -90,8 +90,8 @@
<script>
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import doAction from '/imports/api/creature/actions/doAction.js';
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import TreeNodeView from '/imports/ui/properties/treeNodeViews/TreeNodeView.vue';
import AttributeConsumedView from '/imports/ui/properties/components/actions/AttributeConsumedView.vue';
import ItemConsumedView from '/imports/ui/properties/components/actions/ItemConsumedView.vue';
@@ -161,10 +161,12 @@ export default {
},
meteor: {
children(){
return getActiveProperties({
ancestorId: this.model._id,
filter: {'parent.id': this.model._id},
options: {sort: {order: 1}},
return CreatureProperties.find({
'parent.id': this.model._id,
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {order: 1}
});
},
},

View File

@@ -20,7 +20,7 @@
<script>
import ItemTreeNode from '/imports/ui/properties/treeNodeViews/ItemTreeNode.vue';
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import { selectAmmoItem } from '/imports/api/creature/CreatureProperties.js';
import { findIndex } from 'lodash';
export default {
@@ -39,15 +39,16 @@ export default {
},
meteor: {
items(){
return getActiveProperties({
ancestorId: this.action.ancestors[0].id,
filter: {
tags: this.itemConsumed.tag,
equipped: true,
},
options: {
fields: {equipped: false},
}
return CreatureProperties.find({
'ancestors.id': this.action.ancestors[0].id,
type: 'item',
equipped: true,
tags: this.itemConsumed.tag,
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {order: 1},
fields: {equipped: false},
});
}
},

View File

@@ -10,7 +10,7 @@
import Creatures from '/imports/api/creature/Creatures.js';
import { damageProperty } from '/imports/api/creature/CreatureProperties.js';
import HealthBarCard from '/imports/ui/properties/components/attributes/HealthBarCard.vue';
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
export default {
components: {
@@ -30,16 +30,17 @@
let creature = this.creature;
if (!creature) return;
let filter = {
'ancestors.id': creature._id,
type: 'attribute',
attributeType: 'healthBar',
removed: {$ne: true},
inactive: {$ne: true},
};
if (creature.settings.hideUnusedStats){
filter.hide = {$ne: true};
}
return getActiveProperties({
ancestorId: creature._id,
filter,
options: {sort: {order: 1}},
return CreatureProperties.find(filter, {
sort: {order: 1}
});
},
},

View File

@@ -60,7 +60,7 @@
<script>
import ToolbarCard from '/imports/ui/components/ToolbarCard.vue';
import SpellList from '/imports/ui/properties/components/spells/SpellList.vue';
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
export default {
components: {
@@ -79,29 +79,32 @@ export default {
}},
meteor: {
spells(){
return getActiveProperties({
ancestorId: this.model._id,
filter: {
type: 'spell',
},
options: {
sort: {
level: 1,
order: 1,
},
},
includeUnprepared: this.preparingSpells,
let filter = {
'ancestors.id': this.model._id,
type: 'spell',
removed: {$ne: true},
};
if (this.preparingSpells){
filter.deactivatedByAncestor = {$ne: true};
} else {
filter.inactive = {$ne: true};
}
return CreatureProperties.find(filter, {
sort: {
level: 1,
order: 1,
}
});
},
numPrepared(){
return getActiveProperties({
ancestorId: this.model._id,
filter: {
type: 'spell',
prepared: true,
alwaysPrepared: {$ne: true},
},
}).length;
return CreatureProperties.find({
'ancestors.id': this.model._id,
type: 'spell',
removed: {$ne: true},
prepared: true,
alwaysPrepared: {$ne: true},
deactivatedByAncestor: {$ne: true},
}).count();
},
preparedError(){
if (!this.model.maxPrepared) return;

View File

@@ -9,14 +9,18 @@
</template>
<script>
import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import ActionCard from '/imports/ui/properties/components/actions/ActionCard.vue';
function getProperties(ancestorId, type){
if (!ancestorId) return [];
return getActiveProperties({
ancestorId,
filter: {type},
return CreatureProperties.find({
'ancestors.id': ancestorId,
type,
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {order: 1}
});
}