From 29588a87d0f0a585961e3fee93b0940e05981c75 Mon Sep 17 00:00:00 2001 From: Thaum Rystra Date: Thu, 14 May 2020 13:32:46 +0200 Subject: [PATCH] Fixed dependency loops causing a stack overflow. Added level variable --- .../creature/computation/ComputationMemo.js | 32 +++++++++++++++++-- .../api/creature/computation/computeEffect.js | 10 ++++-- .../api/creature/computation/computeStat.js | 2 ++ .../computation/evaluateCalculation.js | 1 - 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/app/imports/api/creature/computation/ComputationMemo.js b/app/imports/api/creature/computation/ComputationMemo.js index 5e76958f..175852eb 100644 --- a/app/imports/api/creature/computation/ComputationMemo.js +++ b/app/imports/api/creature/computation/ComputationMemo.js @@ -7,6 +7,7 @@ export default class ComputationMemo { this.propsById = {}; this.skillsByAbility = {}; this.unassignedEffects = []; + this.classes = {}; props.filter((prop) => { // skip effects, proficiencies, and class levels for the next pass if ( @@ -33,17 +34,44 @@ export default class ComputationMemo { prop.computationDetails = propDetails(prop); return prop; } - storeHighestClassLevel(name, prop){ + storeHighestClassLevel(name, prop, isBaseClass){ // Only store the highest level classLevel let stat = this.statsByVariableName[name] if (!stat){ this.statsByVariableName[name] = prop; + if (isBaseClass){ + this.classes[name] = prop; + } } else if (!has(stat, 'level')){ // Stat is overriden by an attribute return; } else if (stat.level < prop.level) { this.statsByVariableName[name] = prop; + if (isBaseClass){ + this.classes[name] = prop; + } } + this.updateLevel(); + } + updateLevel(){ + let currentLevel = this.statsByVariableName['level']; + if (!currentLevel){ + currentLevel = { + value: 0, + computationDetails: { + builtIn: true, + computed: true, + } + }; + this.statsByVariableName['level'] = currentLevel; + } + // bail out if overriden by an attribute + if (!currentLevel.computationDetails.builtIn) return; + let level = 0; + for (let name in this.classes){ + level += this.classes[name].level || 0; + } + this.statsByVariableName['level'].value = level; } addClassLevel(prop){ prop = this.registerProperty(prop); @@ -51,7 +79,7 @@ export default class ComputationMemo { this.storeHighestClassLevel(prop.variableName, prop); } if (prop.baseClass){ - this.storeHighestClassLevel(prop.baseClass, prop); + this.storeHighestClassLevel(prop.baseClass, prop, true); } } addStat(prop){ diff --git a/app/imports/api/creature/computation/computeEffect.js b/app/imports/api/creature/computation/computeEffect.js index 53c5a4c6..c95aab23 100644 --- a/app/imports/api/creature/computation/computeEffect.js +++ b/app/imports/api/creature/computation/computeEffect.js @@ -2,11 +2,15 @@ import evaluateCalculation from '/imports/api/creature/computation/evaluateCalcu export default function computeEffect(effect, memo){ if (effect.computationDetails.computed) return; - if (_.isFinite(effect.calculation)){ + if (!effect.calculation){ + if(effect.operation === 'add' || effect.operation === 'base'){ + effect.result = 0; + } + } else if (Number.isFinite(+effect.calculation)){ effect.result = +effect.calculation; - } else if(effect.operation === "conditional" || effect.operation === "rollBonus"){ + } else if(effect.operation === 'conditional' || effect.operation === 'rollBonus'){ effect.result = effect.calculation; - } else if(_.contains(["advantage", "disadvantage", "fail"], effect.operation)){ + } else if(_.contains(['advantage', 'disadvantage', 'fail'], effect.operation)){ effect.result = 1; } else { effect.result = evaluateCalculation(effect.calculation, memo); diff --git a/app/imports/api/creature/computation/computeStat.js b/app/imports/api/creature/computation/computeStat.js index 8e8b579c..d32767e5 100644 --- a/app/imports/api/creature/computation/computeStat.js +++ b/app/imports/api/creature/computation/computeStat.js @@ -16,6 +16,8 @@ export default function computeStat(stat, memo){ console.warn('dependencyLoop', stat); return; } + // Before doing any work, mark this stat as busy + stat.computationDetails.busyComputing = true; // Compute and aggregate all the effects let aggregator = new EffectAggregator(stat, memo) each(stat.computationDetails.effects, (effect) => { diff --git a/app/imports/api/creature/computation/evaluateCalculation.js b/app/imports/api/creature/computation/evaluateCalculation.js index 6a001857..d8446476 100644 --- a/app/imports/api/creature/computation/evaluateCalculation.js +++ b/app/imports/api/creature/computation/evaluateCalculation.js @@ -9,7 +9,6 @@ export default function evaluateCalculation(string, memo){ try { calc = math.parse(string); } catch (e) { - console.error(e); return string; } // Ensure all symbol nodes are defined and coputed