75 lines
2.1 KiB
JavaScript
75 lines
2.1 KiB
JavaScript
import evaluateCalculation from '/imports/api/creature/computation/newEngine/computeComputation/evaluateCalculation.js';
|
|
import computeVariable from '/imports/api/creature/computation/newEngine/computeComputation/computeVariable.js';
|
|
|
|
export default function computeCreatureComputation(computation){
|
|
const stack = [];
|
|
// dict of computed nodes by id
|
|
const scope = {};
|
|
const graph = computation.dependencyGraph;
|
|
// Add all nodes to the stack
|
|
graph.forEachNode(node => stack.push({
|
|
node,
|
|
visited: false,
|
|
visitedChildren: false,
|
|
}));
|
|
// Depth first traversal of nodes
|
|
while (stack.length){
|
|
let top = stack[stack.length - 1];
|
|
if (top.visited){
|
|
// The object has already
|
|
stack.pop();
|
|
} else if (top.visitedChildren){
|
|
// Compute the top object of the stack
|
|
compute(graph, top.node, scope);
|
|
// If the node holds a variable, store it in the scope
|
|
if (!top.node.data?.type){
|
|
scope[top.node.id] = top.node.data;
|
|
}
|
|
// Mark the object as visited and remove from stack
|
|
top.visited = true;
|
|
stack.pop();
|
|
} else {
|
|
// Push children to graph
|
|
pushDependenciesToStack(top.node.id, graph, stack);
|
|
top.visitedChildren = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
function compute(graph, node, scope){
|
|
// Get the property
|
|
let prop = node.data;
|
|
|
|
// evaluate all the calculations
|
|
if (prop?._computationDetails?.calculations){
|
|
prop._computationDetails.calculations.forEach(calcObj => {
|
|
evaluateCalculation(calcObj, scope)
|
|
});
|
|
}
|
|
|
|
// Compute the property by type
|
|
let typeCompute = propTypeComputations[prop?.type || '_variable'];
|
|
typeCompute?.(graph, node);
|
|
}
|
|
|
|
var propTypeComputations = {
|
|
'_variable': computeVariable,
|
|
};
|
|
|
|
function pushDependenciesToStack(nodeId, graph, stack){
|
|
graph.forEachLinkedNode(
|
|
nodeId,
|
|
(linkedNode, link) => {
|
|
// Ignore inventory links, they can't cause dependency loops
|
|
// and are already fully computed when they are created
|
|
if (link.data === 'inventory') return;
|
|
stack.push({
|
|
node: linkedNode,
|
|
visited: false,
|
|
visitedChildren: false,
|
|
});
|
|
},
|
|
true // enumerate only outbound links
|
|
);
|
|
}
|