import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree.js'; import CreatureProperties, { DenormalisedOnlyCreaturePropertySchema as denormSchema } from '/imports/api/creature/creatureProperties/CreatureProperties.js'; import Creatures from '/imports/api/creature/creatures/Creatures.js'; import computedOnlySchemas from '/imports/api/properties/computedOnlyPropertySchemasIndex.js'; import computedSchemas from '/imports/api/properties/computedPropertySchemasIndex.js'; import linkInventory from './buildComputation/linkInventory.js'; import walkDown from './utility/walkdown.js'; import parseCalculationFields from './buildComputation/parseCalculationFields.js'; import computeInactiveStatus from './buildComputation/computeInactiveStatus.js'; import computeToggleDependencies from './buildComputation/computeToggleDependencies.js'; import linkCalculationDependencies from './buildComputation/linkCalculationDependencies.js'; import linkTypeDependencies from './buildComputation/linkTypeDependencies.js'; import computeSlotQuantityFilled from './buildComputation/computeSlotQuantityFilled.js'; import CreatureComputation from './CreatureComputation.js'; import removeSchemaFields from './buildComputation/removeSchemaFields.js'; // import assignDependencyGroups from '/imports/api/engine/computation/utility/assignDependencyGroups.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 */ /** * Forseen issues: Anything that computes during the build step will not obey * computed toggles */ export default function buildCreatureComputation(creatureId){ const creature = getCreature(creatureId); const properties = getProperties(creatureId); const computation = buildComputationFromProps(properties, creature); return computation; } export function buildDependencyGroupComputation(depGroupIds, creatureId) { const creature = getCreature(creatureId); const properties = getGroupProperties(depGroupIds); const computation = buildComputationFromProps(properties, creature); return computation; } function getProperties(creatureId) { return CreatureProperties.find({ 'ancestors.id': creatureId, 'removed': {$ne: true}, }, { sort: { order: 1 }, fields: { icon: 0 }, }).fetch(); } function getGroupProperties(depGroupIds) { return CreatureProperties.find({ depGroupId: { $in: depGroupIds }, 'removed': { $ne: true }, }, { sort: { order: 1 }, fields: { icon: 0 }, }).fetch(); } function getCreature(creatureId){ return Creatures.findOne(creatureId, { denormalizedStats: 1, }); } export function buildComputationFromProps(properties, creature){ const computation = new CreatureComputation(properties); // 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 // Each node's data represents a prop or a virtual prop like a variable // Each link's data is a string representing the link type const dependencyGraph = computation.dependencyGraph; // Link the denormalizedStats from the creature if (creature && creature.denormalizedStats){ if (creature.denormalizedStats.xp){ dependencyGraph.addNode('xp', { baseValue: creature.denormalizedStats.xp, type: '_variable' }); } if (creature.denormalizedStats.milestoneLevels){ dependencyGraph.addNode('milestoneLevels', { baseValue: creature.denormalizedStats.milestoneLevels, type: '_variable' }); } } // Process the properties one by one properties.forEach(prop => { const computedSchema = computedOnlySchemas[prop.type]; removeSchemaFields([computedSchema, denormSchema], prop); // Add a place to store all the computation details prop._computationDetails = { calculations: [], inlineCalculations: [], 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, dependencyGraph); computeSlotQuantityFilled(node, dependencyGraph); }); // Link the inventory dependencies linkInventory(forest, dependencyGraph); // Link functions that require the above to be complete properties.forEach(prop => { linkTypeDependencies(dependencyGraph, prop, computation); linkCalculationDependencies(dependencyGraph, prop, computation); }); // Store the connected groups of the dependency graph // assignDependencyGroups(dependencyGraph); return computation; }