Fixed empty calculations unable to be targeted by effects
This commit is contained in:
@@ -159,7 +159,7 @@ function linkEffects(dependencyGraph, prop, computation) {
|
||||
// Otherwise target a field on that property
|
||||
const key = prop.targetField || getDefaultCalculationField(targetProp);
|
||||
const calcObj = get(targetProp, key);
|
||||
if (calcObj && calcObj.calculation) {
|
||||
if (calcObj) {
|
||||
dependencyGraph.addLink(`${targetProp._id}.${key}`, prop._id, 'effect');
|
||||
}
|
||||
}
|
||||
@@ -301,7 +301,7 @@ function linkProficiencies(dependencyGraph, prop, computation) {
|
||||
// Otherwise target a field on that property
|
||||
const key = prop.targetField || getDefaultCalculationField(targetProp);
|
||||
const calcObj = get(targetProp, key);
|
||||
if (calcObj && calcObj.calculation) {
|
||||
if (calcObj) {
|
||||
dependencyGraph.addLink(`${targetProp._id}.${key}`, prop._id, 'proficiency');
|
||||
}
|
||||
}
|
||||
@@ -339,7 +339,7 @@ function linkSkill(dependencyGraph, prop, computation) {
|
||||
// other skill isn't supported
|
||||
const key = prop.targetField || getDefaultCalculationField(targetProp);
|
||||
const calcObj = get(targetProp, key);
|
||||
if (calcObj && calcObj.calculation) {
|
||||
if (calcObj) {
|
||||
dependencyGraph.addLink(`${targetProp._id}.${key}`, prop._id, 'proficiency');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import INLINE_CALCULATION_REGEX from '/imports/constants/INLINE_CALCULTION_REGEX.js';
|
||||
import { prettifyParseError, parse } from '/imports/parser/parser.js';
|
||||
import applyFnToKey from '/imports/api/engine/computation/utility/applyFnToKey.js';
|
||||
import { get, unset } from 'lodash';
|
||||
import { get, set, unset } from 'lodash';
|
||||
import errorNode from '/imports/parser/parseTree/error.js';
|
||||
import cyrb53 from '/imports/api/engine/computation/utility/cyrb53.js';
|
||||
|
||||
@@ -63,12 +63,21 @@ function parseAllCalculationFields(prop, schemas) {
|
||||
// For all fields matching they keys
|
||||
// supports `keys.$.with.$.arrays`
|
||||
applyFnToKey(prop, calcKey, (prop, key) => {
|
||||
const calcObj = get(prop, key);
|
||||
let calcObj = get(prop, key);
|
||||
// Create a calculation object if one doesn't exist, it will get deleted again later if
|
||||
// it's not used, but if an effect targets a calculated field, we should have one to target
|
||||
if (
|
||||
!calcObj
|
||||
&& subDocsExist(prop, key)
|
||||
) {
|
||||
calcObj = {};
|
||||
set(prop, key, calcObj);
|
||||
}
|
||||
// Sub document didn't exist, skip this field
|
||||
if (!calcObj) return;
|
||||
// Delete the whole calculation object if the calculation string isn't set
|
||||
// Keep a list of empty calculations for potential deletion if they aren't used
|
||||
if (!calcObj.calculation) {
|
||||
unset(prop, calcKey);
|
||||
return;
|
||||
prop._computationDetails.emptyCalculations.push(calcObj);
|
||||
}
|
||||
// Store a reference to all the calculations
|
||||
prop._computationDetails.calculations.push(calcObj);
|
||||
@@ -84,15 +93,31 @@ function parseAllCalculationFields(prop, schemas) {
|
||||
});
|
||||
}
|
||||
|
||||
function subDocsExist(prop, key) {
|
||||
const path = key.split('.');
|
||||
if (path.length < 2) return !!prop;
|
||||
path.pop();
|
||||
const subPath = path.join('.');
|
||||
return !!get(prop, subPath);
|
||||
}
|
||||
|
||||
export function removeEmptyCalculations(prop) {
|
||||
prop._computationDetails.emptyCalculations.forEach(calcObj => {
|
||||
if (!calcObj.effects?.length) {
|
||||
unset(prop, calcObj._key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function parseCalculation(calcObj) {
|
||||
const calcHash = cyrb53(calcObj.calculation);
|
||||
const calcHash = cyrb53(calcObj.calculation || '0');
|
||||
// If the cached parse calculation is equal to the calculation, skip
|
||||
if (calcHash === calcObj.hash) {
|
||||
return;
|
||||
}
|
||||
calcObj.hash = calcHash;
|
||||
try {
|
||||
calcObj.parseNode = parse(calcObj.calculation);
|
||||
calcObj.parseNode = parse(calcObj.calculation || '0');
|
||||
calcObj.parseError = null;
|
||||
} catch (e) {
|
||||
let error = {
|
||||
|
||||
@@ -75,6 +75,7 @@ export function buildComputationFromProps(properties, creature, variables) {
|
||||
// Add a place to store all the computation details
|
||||
prop._computationDetails = {
|
||||
calculations: [],
|
||||
emptyCalculations: [],
|
||||
inlineCalculations: [],
|
||||
toggleAncestors: [],
|
||||
};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import computeToggles from '/imports/api/engine/computation/computeComputation/computeToggles.js';
|
||||
import computeByType from '/imports/api/engine/computation/computeComputation/computeByType.js';
|
||||
import embedInlineCalculations from './utility/embedInlineCalculations.js';
|
||||
import { removeEmptyCalculations } from './buildComputation/parseCalculationFields.js';
|
||||
import path from 'ngraph.path';
|
||||
|
||||
export default function computeCreatureComputation(computation){
|
||||
export default function computeCreatureComputation(computation) {
|
||||
const stack = [];
|
||||
// Computation scope of {variableName: prop}
|
||||
const graph = computation.dependencyGraph;
|
||||
@@ -20,16 +21,16 @@ export default function computeCreatureComputation(computation){
|
||||
stack.reverse();
|
||||
|
||||
// Depth first traversal of nodes
|
||||
while (stack.length){
|
||||
while (stack.length) {
|
||||
let top = stack[stack.length - 1];
|
||||
if (top._visited){
|
||||
if (top._visited) {
|
||||
// The object has already been computed, skip
|
||||
stack.pop();
|
||||
} else if (top._visitedChildren){
|
||||
} else if (top._visitedChildren) {
|
||||
// Mark the object as visited and remove from stack
|
||||
top._visited = true;
|
||||
stack.pop();
|
||||
// Compute the top object of the stack
|
||||
// Compute the top object of the stack
|
||||
compute(computation, top);
|
||||
} else {
|
||||
top._visitedChildren = true;
|
||||
@@ -42,14 +43,14 @@ export default function computeCreatureComputation(computation){
|
||||
computation.props.forEach(finalizeProp);
|
||||
}
|
||||
|
||||
function compute(computation, node){
|
||||
function compute(computation, node) {
|
||||
// Determine the prop's active status by its toggles
|
||||
computeToggles(computation, node);
|
||||
// Compute the property by type
|
||||
computeByType[node.data?.type || '_variable']?.(computation, node);
|
||||
}
|
||||
|
||||
function pushDependenciesToStack(nodeId, graph, stack, computation){
|
||||
function pushDependenciesToStack(nodeId, graph, stack, computation) {
|
||||
graph.forEachLinkedNode(nodeId, linkedNode => {
|
||||
if (linkedNode._visitedChildren && !linkedNode._visited) {
|
||||
// This is a dependency loop, find a path from the node to itself
|
||||
@@ -66,7 +67,7 @@ function pushDependenciesToStack(nodeId, graph, stack, computation){
|
||||
loop = [linkedNode, ...newLoop];
|
||||
}
|
||||
}, true);
|
||||
|
||||
|
||||
if (loop.length) {
|
||||
computation.errors.push({
|
||||
type: 'dependencyLoop',
|
||||
@@ -80,11 +81,13 @@ function pushDependenciesToStack(nodeId, graph, stack, computation){
|
||||
}, true);
|
||||
}
|
||||
|
||||
function finalizeProp(prop){
|
||||
function finalizeProp(prop) {
|
||||
// Embed the inline calculations
|
||||
prop._computationDetails?.inlineCalculations?.forEach(inlineCalcObj => {
|
||||
embedInlineCalculations(inlineCalcObj);
|
||||
});
|
||||
// Clean up the calculations that were never used
|
||||
removeEmptyCalculations(prop);
|
||||
// Clean up the computation details
|
||||
delete prop._computationDetails;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user