127 lines
4.8 KiB
JavaScript
127 lines
4.8 KiB
JavaScript
import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree.js';
|
|
import CreatureProperties,
|
|
{ DenormalisedOnlyCreaturePropertySchema as denormSchema }
|
|
from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
|
import computedOnlySchemas from '/imports/api/properties/computedOnlyPropertySchemasIndex.js';
|
|
import computedSchemas from '/imports/api/properties/computedPropertySchemasIndex.js';
|
|
import applyFnToKey from '/imports/api/creature/computation/newEngine/utility/applyFnToKey.js';
|
|
import { cloneDeep, unset } from 'lodash';
|
|
import createGraph from 'ngraph.graph';
|
|
import computeInventory from '/imports/api/creature/computation/newEngine/buildComputation/computeInventory.js';
|
|
import walkDown from '/imports/api/creature/computation/newEngine/utility/walkdown.js';
|
|
import parseCalculationFields from '/imports/api/creature/computation/newEngine/buildComputation/parseCalculationFields.js';
|
|
import computeInactiveStatus from '/imports/api/creature/computation/newEngine/buildComputation/computeInactiveStatus.js';
|
|
import computeToggleDependencies from '/imports/api/creature/computation/newEngine/buildComputation/computeToggleDependencies.js';
|
|
import linkCalculationDependencies from '/imports/api/creature/computation/newEngine/buildComputation/linkCalculationDependencies.js';
|
|
import linkTypeDependencies from '/imports/api/creature/computation/newEngine/buildComputation/linkTypeDependencies.js';
|
|
import computeSlotQuantityFilled from '/imports/api/creature/computation/newEngine/buildComputation/computeSlotQuantityFilled.js';
|
|
|
|
/**
|
|
* Store index of properties
|
|
* recompute static tree-based enabled/disabled status
|
|
* Build a dependency graph
|
|
* id -> id dependencies for docs that rely on other docs directly
|
|
* id -> variable deps for docs that rely on a variable's value
|
|
* variable -> id deps for variables that are impacted by docs
|
|
* TODO:
|
|
* Depth first traversal or dependency graph to:
|
|
* Find loops in the dependency graph
|
|
* resolve variables in dependency order
|
|
*/
|
|
|
|
/**
|
|
* TODO
|
|
* compute slots spaces left (after computed field of quantityExpected)
|
|
* compute damage multipliers
|
|
* compute dependencyGraph variables and properties
|
|
*/
|
|
|
|
export default function buildCreatureComputation(creatureId){
|
|
let properties = CreatureProperties.find({
|
|
'ancestors.id': creatureId,
|
|
'removed': {$ne: true},
|
|
}, {
|
|
sort: {order: 1}
|
|
});
|
|
|
|
// Dependency graph where edge(a, b) means a depends on b
|
|
// The graph includes all dependencies even of inactive properties
|
|
// such that any properties changing without changing their dependencies
|
|
// can limit the recompute to connected parts of the graph
|
|
const dependencyGraph = createGraph();
|
|
|
|
const computation = {
|
|
originalPropsById: {},
|
|
propsById: {},
|
|
propsByType: {},
|
|
propsByVariableName: {},
|
|
props: properties,
|
|
dependencyGraph,
|
|
};
|
|
|
|
// Process the properties one by one
|
|
properties.forEach(prop => {
|
|
|
|
// Store the prop in the memo by type, variableName and id
|
|
storePropInMemo(prop, computation)
|
|
|
|
// Store the prop in the dependency graph
|
|
dependencyGraph.addNode(prop._id, prop);
|
|
|
|
// Remove old computed only fields
|
|
computedOnlySchemas[prop.type]._schemaKeys.forEach(key =>
|
|
applyFnToKey(prop, key, unset)
|
|
);
|
|
|
|
// Remove old denormalised fields
|
|
denormSchema._schemaKeys.forEach(key =>
|
|
applyFnToKey(prop, key, unset)
|
|
);
|
|
|
|
// Add a place to store all the computation details
|
|
prop._computationDetails = {
|
|
calculations: [],
|
|
toggleAncestors: [],
|
|
};
|
|
|
|
// Parse all the calculations
|
|
parseCalculationFields(prop, computedSchemas)
|
|
});
|
|
|
|
// Get all the properties as trees based on their ancestors
|
|
let forest = nodeArrayToTree(properties);
|
|
// Walk the property trees computing things that need to be inherited
|
|
walkDown(forest, node => {
|
|
computeInactiveStatus(node);
|
|
computeToggleDependencies(node);
|
|
computeSlotQuantityFilled(node);
|
|
});
|
|
|
|
// Compute the inventory
|
|
computeInventory(forest, dependencyGraph);
|
|
|
|
// Graph functions that rely on the props being stored first
|
|
properties.forEach(prop => {
|
|
linkTypeDependencies(dependencyGraph, prop, computation.propsById);
|
|
linkCalculationDependencies(dependencyGraph, prop, computation.propsById);
|
|
});
|
|
|
|
return computation;
|
|
}
|
|
|
|
function storePropInMemo(prop, memo){
|
|
// Store dicts for easy access later
|
|
// Store a copy of the unmodified prop
|
|
memo.originalPropsById[prop._id] = cloneDeep(prop);
|
|
// Store by id
|
|
memo.propsById[prop._id] = prop;
|
|
// Store by type
|
|
memo.propsByType[prop.type] ?
|
|
memo.propsByType[prop.type].push(prop) :
|
|
memo.propsByType[prop.type] = [prop];
|
|
// Store by variableName
|
|
memo.propsByVariableName[prop.variableName] ?
|
|
memo.propsByVariableName[prop.variableName].push(prop) :
|
|
memo.propsByVariableName[prop.variableName]= [prop];
|
|
}
|