Lots of progress testing and fixing computation engine

This commit is contained in:
Stefan Zermatten
2021-09-16 14:31:28 +02:00
parent dfd7ad4af5
commit a660ccc458
34 changed files with 775 additions and 90 deletions

View File

@@ -8,6 +8,7 @@ export default class CreatureComputation {
this.propsById = {};
this.propsByType = {};
this.propsByVariableName = {};
this.scope = {};
this.props = properties;
this.dependencyGraph = createGraph();

View File

@@ -4,7 +4,8 @@ export default function computeInactiveStatus(node){
const prop = node.node;
if (isActive(prop)) return;
// Unequipped items disable their children, but are not disabled themselves
if (prop.type !== 'item'){
// All notes do the same
if (prop.type !== 'item' && prop.type !== 'note' ){
prop.inactive = true;
prop.deactivatedBySelf = true;
}

View File

@@ -4,13 +4,16 @@
*/
export default function computeSlotQuantityFilled(node, dependencyGraph){
let slot = node.node;
if (slot.type !== 'propertySlot' || slot.type !== 'characterClass') return;
if (slot.type !== 'propertySlot') return;
slot.totalFilled = 0;
node.children.forEach(child => {
let childProp = child.node;
dependencyGraph.addLink(slot._id, childProp._id, 'slotFill')
if (childProp.type === 'slotFiller'){
slot.totalFilled += child.slotQuantityFilled;
dependencyGraph.addLink(slot._id, childProp._id, 'slotFill');
if (
childProp.type === 'slotFiller' &&
Number.isFinite(childProp.slotQuantityFilled)
){
slot.totalFilled += childProp.slotQuantityFilled;
} else {
slot.totalFilled++;
}

View File

@@ -12,6 +12,7 @@ export default function linkInventory(forest, dependencyGraph){
const top = stack[stack.length - 1];
const prop = top.node;
if (prop._computationDetails.inventoryChildrenVisited){
if (prop.type === 'container') containerStack.pop();
stack.pop();
handleProp(prop, containerStack, dependencyGraph);
} else {
@@ -28,7 +29,7 @@ export default function linkInventory(forest, dependencyGraph){
function handleProp(prop, containerStack, dependencyGraph){
// Skip props that aren't part of the inventory
if (prop.type !== 'inventory' && prop.type !== 'container') return;
if (prop.type !== 'item' && prop.type !== 'container') return;
// Determine if this property is carried, items are carried by default
let carried = prop.type === 'container' ? prop.carried : true;

View File

@@ -12,8 +12,8 @@ const linkDependenciesByType = {
spell: linkResources,
}
export default function linkTypeDependencies(dependencyGraph, prop){
linkDependenciesByType[prop.type]?.(dependencyGraph, prop);
export default function linkTypeDependencies(dependencyGraph, prop, computation){
linkDependenciesByType[prop.type]?.(dependencyGraph, prop, computation);
}
function linkClassLevel(dependencyGraph, prop){
@@ -36,19 +36,20 @@ function linkVariableName(dependencyGraph, prop){
}
function linkResources(dependencyGraph, prop, {propsById}){
if (!prop.resources) return;
prop.resources.itemsConsumed.forEach(itemConsumed => {
if (!itemConsumed.itemId) return;
const item = propsById[itemConsumed.itemId];
if (!item.equipped) {
if (!item || item.inactive){
// Unlink if the item doesn't exist or is inactive
itemConsumed.itemId = undefined;
return;
}
if (!item) return;
// none of these dependencies are computed, we can use them immediately
prop.available = item.quantity;
prop.itemName = item.name;
prop.itemIcon = item.icon;
prop.itemColor = item.color;
itemConsumed.available = item.quantity;
itemConsumed.itemName = item.name;
itemConsumed.itemIcon = item.icon;
itemConsumed.itemColor = item.color;
dependencyGraph.addLink(prop._id, item._id, 'inventory');
});
prop.resources.attributesConsumed.forEach(attConsumed => {

View File

@@ -5,11 +5,11 @@ import applyFnToKey from '/imports/api/creature/computation/newEngine/utility/ap
import { get } from 'lodash';
export default function parseCalculationFields(prop, schemas){
parseInlineCalculationFields(prop, schemas);
parseDirectCalculationFields(prop, schemas);
discoverInlineCalculationFields(prop, schemas);
parseAllCalculationFields(prop, schemas);
}
function parseInlineCalculationFields(prop, schemas){
function discoverInlineCalculationFields(prop, schemas){
// For each key in the schema
schemas[prop.type]._schemaKeys.forEach( key => {
// That ends in .inlineCalculations
@@ -35,7 +35,7 @@ function parseInlineCalculationFields(prop, schemas){
});
}
function parseDirectCalculationFields(prop, schemas){
function parseAllCalculationFields(prop, schemas){
// For each key in the schema
schemas[prop.type]._schemaKeys.forEach( key => {
// that ends in '.calculation'

View File

@@ -4,8 +4,11 @@ import { unset } from 'lodash';
export default function removeSchemaFields(schemas, prop){
schemas.forEach(schema => {
schema._schemaKeys.forEach(key => {
// Skip object keys
if (schema.getQuickTypeForKey(key) === 'object') return;
// Skip object and array keys
if (
schema.getQuickTypeForKey(key) === 'object' ||
schema.getQuickTypeForKey(key) === 'objectArray'
) return;
// Unset other computed only keys
applyFnToKey(prop, key, unset)
});

View File

@@ -0,0 +1,144 @@
import { buildComputationFromProps } from '/imports/api/creature/computation/newEngine/buildCreatureComputation.js';
import { assert } from 'chai';
import clean from '../../utility/cleanProp.testFn.js';
export default function(){
let computation = buildComputationFromProps(testProperties);
const bySelf = (propId, note) => assertDeactivatedBySelf(computation, propId, note);
const byAncestor = (propId, note) => assertDeactivatedByAncestor(computation, propId, note);
const active = (propId, note) => assertActive(computation, propId, note);
// Buffs
bySelf('buffNotAppliedId');
byAncestor('buffNotAppliedChildId');
active('buffAppliedId');
active('buffAppliedChildId');
// Items
active('itemUnequippedId', 'Unequipped items should be active');
byAncestor('itemUnequippedChildId', 'Children of unequipped items should be inactive');
active('itemEquippedId');
active('itemEquippedChildId');
// Spells
active('spellPreparedId');
active('spellPreparedChildId');
active('spellAlwaysPreparedId');
active('spellAlwaysPreparedChildId');
bySelf('spellUnpreparedId');
byAncestor('spellUnpreparedChildId');
// Notes
active('NoteId', 'Notes should be active');
byAncestor('NoteChildId', 'children of notes should always be inactive');
}
function assertDeactivatedBySelf(computation, propId, note){
const prop = computation.propsById[propId];
assert.isTrue(prop.deactivatedBySelf, note);
assert.isTrue(prop.inactive, 'The property should be inactive');
}
function assertDeactivatedByAncestor(computation, propId, note){
const prop = computation.propsById[propId];
assert.isTrue(prop.deactivatedByAncestor, note);
assert.isTrue(prop.inactive, 'The property should be inactive');
}
function assertActive(computation, propId, note){
const prop = computation.propsById[propId];
assert.isNotTrue(prop.inactive, note);
assert.isNotTrue(prop.deactivatedBySelf);
assert.isNotTrue(prop.deactivatedBySelf);
}
var testProperties = [
// Buffs
clean({
_id: 'buffNotAppliedId',
type: 'buff',
ancestors: [{id: 'charId'}],
}),
clean({
_id: 'buffNotAppliedChildId',
type: 'folder',
ancestors: [{id: 'charId'}, {id: 'buffNotAppliedId'}],
}),
clean({
_id: 'buffAppliedId',
type: 'buff',
applied: true,
ancestors: [{id: 'charId'}],
}),
clean({
_id: 'buffAppliedChildId',
type: 'folder',
ancestors: [{id: 'charId'}, {id: 'buffAppliedId'}],
}),
// Items
clean({
_id: 'itemUnequippedId',
type: 'item',
ancestors: [{id: 'charId'}],
}),
clean({
_id: 'itemUnequippedChildId',
type: 'folder',
ancestors: [{id: 'charId'}, {id: 'itemUnequippedId'}],
}),
clean({
_id: 'itemEquippedId',
type: 'item',
equipped: true,
ancestors: [{id: 'charId'}],
}),
clean({
_id: 'itemEquippedChildId',
type: 'folder',
ancestors: [{id: 'charId'}, {id: 'itemEquippedId'}],
}),
// Spells
clean({
_id: 'spellPreparedId',
type: 'spell',
ancestors: [{id: 'charId'}],
prepared: true,
}),
clean({
_id: 'spellPreparedChildId',
type: 'folder',
ancestors: [{id: 'charId'}, {id: 'spellPreparedId'}],
}),
clean({
_id: 'spellAlwaysPreparedId',
type: 'spell',
ancestors: [{id: 'charId'}],
alwaysPrepared: true,
}),
clean({
_id: 'spellAlwaysPreparedChildId',
type: 'folder',
ancestors: [{id: 'charId'}, {id: 'spellAlwaysPreparedId'}],
}),
clean({
_id: 'spellUnpreparedId',
type: 'spell',
ancestors: [{id: 'charId'}],
}),
clean({
_id: 'spellUnpreparedChildId',
type: 'folder',
ancestors: [{id: 'charId'}, {id: 'spellUnpreparedId'}],
}),
// Notes
clean({
_id: 'NoteId',
type: 'note',
ancestors: [{id: 'charId'}],
}),
clean({
_id: 'NoteChildId',
type: 'folder',
ancestors: [{id: 'charId'}, {id: 'NoteId'}],
}),
];

View File

@@ -0,0 +1,36 @@
import { buildComputationFromProps } from '/imports/api/creature/computation/newEngine/buildCreatureComputation.js';
import { assert } from 'chai';
import clean from '../../utility/cleanProp.testFn.js';
export default function(){
const computation = buildComputationFromProps(testProperties);
const totalFilled = computation.propsById['slotId'].totalFilled;
assert.equal(totalFilled, 4);
}
var testProperties = [
// Slots
clean({
_id: 'slotId',
type: 'propertySlot',
ancestors: [{id: 'charId'}],
}),
// Children
clean({
_id: 'slotFillerId',
type: 'slotFiller',
slotQuantityFilled: 3,
slotFillerType: 'item',
ancestors: [{id: 'charId'}, {id: 'slotId'}],
}),
clean({
_id: 'slotChildId',
type: 'item',
ancestors: [{id: 'charId'}, {id: 'slotId'}],
}),
clean({
_id: 'slotGrandchildId',
type: 'effect',
ancestors: [{id: 'charId'}, {id: 'slotId'}, {id: 'slotChildId'}],
}),
];

View File

@@ -0,0 +1,74 @@
import { buildComputationFromProps } from '/imports/api/creature/computation/newEngine/buildCreatureComputation.js';
import { assert } from 'chai';
import clean from '../../utility/cleanProp.testFn.js';
export default function(){
const computation = buildComputationFromProps(testProperties);
const hasLink = computation.dependencyGraph.hasLink;
assert.include(
computation.propsById['conditionToggleChildId']._computationDetails.toggleAncestors,
computation.propsById['conditionToggleId'],
'Children of toggles should store a reference to their toggle ancestor'
)
assert.isTrue(
!!hasLink('conditionToggleChildId', 'conditionToggleId'),
'Children of the condition toggle should depend on it'
);
assert.isTrue(
!!hasLink('conditionToggleGrandChildId', 'conditionToggleId'),
'Descendants of the condition toggle should depend on it'
);
assert.isFalse(
!!hasLink('disabledToggleId', 'disabledToggleChildId'),
'The dependency should not be reversed'
);
assert.isFalse(
!!hasLink('disabledToggleChildId', 'disabledToggleId'),
'Children of disabled toggle should not depend on it'
);
assert.isFalse(
!!hasLink('enabledToggleChildId', 'enabledToggleId'),
'Children of enabled toggle should not depend on it'
);
}
var testProperties = [
clean({
_id: 'enabledToggleId',
type: 'toggle',
enabled: true,
ancestors: [{id: 'charId'}],
}),
clean({
_id: 'disabledToggleId',
type: 'toggle',
disabled: true,
ancestors: [{id: 'charId'}],
}),
clean({
_id: 'conditionToggleId',
type: 'toggle',
ancestors: [{id: 'charId'}],
}),
// Children
clean({
_id: 'enabledToggleChildId',
type: 'folder',
ancestors: [{id: 'charId'}, {id: 'enabledToggleId'}],
}),
clean({
_id: 'disabledToggleChildId',
type: 'folder',
ancestors: [{id: 'charId'}, {id: 'disabledToggleId'}],
}),
clean({
_id: 'conditionToggleChildId',
type: 'folder',
ancestors: [{id: 'charId'}, {id: 'conditionToggleId'}],
}),
clean({
_id: 'conditionToggleGrandChildId',
type: 'folder',
ancestors: [{id: 'charId'}, {id: 'conditionToggleId'}, {id: 'conditionToggleChildId'}],
}),
];

View File

@@ -0,0 +1,54 @@
import { buildComputationFromProps } from '/imports/api/creature/computation/newEngine/buildCreatureComputation.js';
import { assert } from 'chai';
import clean from '../../utility/cleanProp.testFn.js';
export default function(){
const computation = buildComputationFromProps(testProperties);
const hasLink = computation.dependencyGraph.hasLink;
assert.isTrue(
!!hasLink('childId', 'spellListId'),
'Ancestor references of parent in inline calculations should create dependency'
);
assert.isTrue(
!!hasLink('grandchildId', 'spellListId'),
'References to higher ancestor should create dependency'
);
assert.isTrue(
!!hasLink('grandchildId', 'strength'),
'Variable references create dependencies'
);
assert.isTrue(
!!hasLink('grandchildId', 'wisdom'),
'Variable references create dependencies even if the attributes don\'t exist'
);
}
var testProperties = [
clean({
_id: 'spellListId',
type: 'spellList',
ancestors: [{id: 'charId'}],
}),
clean({
_id: 'childId',
type: 'spell',
description: {
text: 'DC {#spellList.dc} save or suck'
},
ancestors: [{id: 'charId'}, {id: 'spellListId'}],
}),
clean({
_id: 'grandchildId',
type: 'savingThrow',
dc: {
calculation: '#spellList.dc + strength + wisdom.modifier'
},
ancestors: [{id: 'charId'}, {id: 'spellListId'}, {id: 'childId'}],
}),
clean({
_id: 'strengthId',
type: 'attribute',
variableName: 'strength',
ancestors: [{id: 'charId'}],
}),
];

View File

@@ -0,0 +1,81 @@
import { buildComputationFromProps } from '/imports/api/creature/computation/newEngine/buildCreatureComputation.js';
import { assert } from 'chai';
import clean from '../../utility/cleanProp.testFn.js';
export default function(){
const computation = buildComputationFromProps(testProperties);
const hasLink = computation.dependencyGraph.hasLink;
assert.isTrue(
!!hasLink('weightEquipment', 'equippedAttunedItemId'),
'weight of equipment depends on equipped items'
);
assert.isTrue(
!!hasLink('valueEquipment', 'equippedAttunedItemId'),
'value of equipment depends on equipped items'
);
assert.isTrue(
!!hasLink('weightTotal', 'equippedAttunedItemId'),
'weightTotal depends on equipped items'
);
assert.isTrue(
!!hasLink('valueTotal', 'equippedAttunedItemId'),
'valueTotal depends on equipped items'
);
assert.isTrue(
!!hasLink('weightCarried', 'equippedAttunedItemId'),
'weightCarried depends on equipped items'
);
assert.isTrue(
!!hasLink('valueCarried', 'equippedAttunedItemId'),
'valueCarried depends on equipped items'
);
assert.isTrue(
!!hasLink('weightCarried', 'containerId'),
'weightCarried depends on top level containers'
);
assert.isTrue(
!!hasLink('valueCarried', 'containerId'),
'valueCarried depends on top level containers'
);
assert.isFalse(
!!hasLink('weightCarried', 'childContainerId'),
'weightCarried does not depend on nested containers'
);
assert.isFalse(
!!hasLink('valueCarried', 'childContainerId'),
'valueCarried does not depend on nested containers'
);
}
var testProperties = [
clean({
_id: 'equippedAttunedItemId',
type: 'item',
equipped: true,
attuned: true,
ancestors: [{id: 'charId'}],
}),
clean({
_id: 'containerId',
type: 'container',
carried: true,
ancestors: [{id: 'charId'}],
}),
clean({
_id: 'childContainerId',
type: 'container',
carried: true,
ancestors: [{id: 'charId'}, {id: 'containerId'}],
}),
clean({
_id: 'childItemId',
type: 'item',
ancestors: [{id: 'charId'}, {id: 'containerId'}],
}),
clean({
_id: 'grandchildItemId',
type: 'item',
ancestors: [{id: 'charId'}, {id: 'containerId'}, {id: 'childContainerId'}],
}),
];

View File

@@ -0,0 +1,27 @@
import { buildComputationFromProps } from '/imports/api/creature/computation/newEngine/buildCreatureComputation.js';
import { assert } from 'chai';
import clean from '../../utility/cleanProp.testFn.js';
export default function(){
const computation = buildComputationFromProps(testProperties);
const getLink = computation.dependencyGraph.hasLink;
const getNode = computation.dependencyGraph.getNode;
assert.equal(
getLink('strength', 'strengthId').data, 'definition',
'Links variable names to props that define them'
);
assert.exists(
getNode('strength'),
'Creates variable name nodes when attributes define them'
);
}
var testProperties = [
clean({
_id: 'strengthId',
type: 'attribute',
variableName: 'strength',
ancestors: [{id: 'charId'}],
}),
];

View File

@@ -82,14 +82,14 @@ export function buildComputationFromProps(properties){
// Walk the property trees computing things that need to be inherited
walkDown(forest, node => {
computeInactiveStatus(node);
computeToggleDependencies(node);
computeSlotQuantityFilled(node);
computeToggleDependencies(node, dependencyGraph);
computeSlotQuantityFilled(node, dependencyGraph);
});
// Link the inventory dependencies
linkInventory(forest, dependencyGraph);
// Link functions that require the above to be complete
// Link functions that require the above to be complete
properties.forEach(prop => {
linkTypeDependencies(dependencyGraph, prop, computation);
linkCalculationDependencies(dependencyGraph, prop, computation);

View File

@@ -1,12 +1,24 @@
import { buildComputationFromProps } from './buildCreatureComputation.js';
import { assert } from 'chai';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import computeInactiveStatus from './buildComputation/tests/computeInactiveStatus.testFn.js';
import computeSlotQuantityFilled from './buildComputation/tests/computeSlotQuantityFilled.testFn.js';
import computeToggleDependencies from './buildComputation/tests/computeToggleDependencies.testFn.js';
import linkCalculationDependencies from './buildComputation/tests/linkCalculationDependencies.testFn.js';
import linkInventory from './buildComputation/tests/linkInventory.testFn.js';
import linkTypeDependencies from './buildComputation/tests/linkTypeDependencies.testFn.js';
describe('buildComputation', function(){
it('Builds something at all', function(){
let computation = buildComputationFromProps(testProperties);
assert.exists(computation);
});
it('Computes inactive status', computeInactiveStatus);
it('Computes slot fill quantity', computeSlotQuantityFilled);
it('Links toggle dependencies', computeToggleDependencies);
it('Links calculation dependencies', linkCalculationDependencies);
it('Links inventory stats', linkInventory);
it('Links type dependencies', linkTypeDependencies);
});
var testProperties = [

View File

@@ -6,6 +6,7 @@ export default function computeAction(graph, node, scope){
prop.usesLeft = prop.uses.value - (prop.usesUsed || 0);
}
computeResources(graph, node, scope);
if (!prop.resources) return;
prop.resources.itemsConsumed.forEach(itemConsumed => {
if (!itemConsumed.itemId) return;
if (itemConsumed.available < itemConsumed.quantity.value){

View File

@@ -1,6 +1,7 @@
export default function computeResources(graph, node, scope){
const prop = node.data;
prop.resources.attributesConsumed.forEach(attConsumed => {
const resources = node.data?.resources;
if (!resources) return;
resources.attributesConsumed.forEach(attConsumed => {
if (!attConsumed.variableName) return;
const att = scope[attConsumed.variableName];
attConsumed.available = att.value;

View File

@@ -9,14 +9,13 @@ export default function computeVariable(graph, node, scope){
if (!node.data) node.data = {};
aggregateLinks(graph, node);
combineAggregations(node, scope);
if (node.definingProp){
if (node.data.definingProp){
// Add the defining variable to the scope
scope[node.id] = node.definingProp
scope[node.id] = node.data.definingProp
} else {
// Otherwise add an implicit variable to the scope
scope[node.id] = computeImplicitVariable(node, scope);
}
console.log('computed variable ', node);
}
function aggregateLinks(graph, node){

View File

@@ -2,7 +2,6 @@ import getAggregatorResult from './getAggregatorResult.js';
export default function computeVariableAsAttribute(node, prop, scope){
let result = getAggregatorResult(node);
console.log('computing variable as attribure ', node);
prop.total = result;
prop.value = prop.total - (prop.damage || 0);

View File

@@ -1,5 +1,6 @@
import { CompilationContext } from '/imports/parser/parser.js';
import INLINE_CALCULATION_REGEX from '/imports/constants/INLINE_CALCULTION_REGEX.js';
import ConstantNode from '/imports/parser/parseTree/ConstantNode.js';
export default function computeCalculations(node, scope){
if (!node.data) return;
@@ -17,7 +18,12 @@ function evaluateCalculation(calculation, scope){
const parseNode = calculation._parsedCalculation;
const fn = calculation._parseLevel;
const calculationScope = {...calculation._localScope, ...scope};
calculation.value = parseNode[fn](calculationScope, context);
const resultNode = parseNode[fn](calculationScope, context);
if (resultNode instanceof ConstantNode){
calculation.value = resultNode.value;
} else {
calculation.value = NaN;
}
calculation.errors = context.errors;
}

View File

@@ -0,0 +1,104 @@
import { buildComputationFromProps } from '/imports/api/creature/computation/newEngine/buildCreatureComputation.js';
import { assert } from 'chai';
import computeCreatureComputation from '../../computeCreatureComputation.js';
import clean from '../../utility/cleanProp.testFn.js';
export default function(){
const computation = buildComputationFromProps(testProperties);
computeCreatureComputation(computation);
const prop = computation.propsById['actionId'];
assert.equal(prop.summary.value, 'test summary 3 without referencing anything 7');
assert.equal(prop.description.value, 'test description 12 with reference 0.25 prop');
assert.equal(prop.uses.value, 7);
assert.equal(prop.usesLeft, 2);
const itemConsumed = prop.resources.itemsConsumed[0];
assert.equal(itemConsumed.quantity.value, 3);
assert.equal(itemConsumed.available, 27);
assert.equal(itemConsumed.itemName, 'Arrow');
assert.equal(itemConsumed.itemIcon, 'itemIcon');
assert.equal(itemConsumed.itemColor, 'itemColor');
const attConsumed = prop.resources.attributesConsumed[0];
assert.equal(attConsumed.quantity.value, 4);
assert.equal(attConsumed.available, 9);
assert.equal(attConsumed.statId, 'resourceVarId');
assert.equal(attConsumed.statName, 'Resource Var');
}
var testProperties = [
clean({
_id: 'actionId',
type: 'action',
ancestors: [{id: 'charId'}],
summary: {
text: 'test summary {1 + 2} without referencing anything {3 + 4}',
},
description: {
text: 'test description {inlineRef * 2} with reference {1/4} prop',
},
resources: {
itemsConsumed: [{
_id: 'itemConsumedId',
itemId: 'arrowId',
tag: 'arrow',
quantity: {
calculation: 'itemConsumedQuantity',
},
}],
attributesConsumed: [{
_id: 'attConsumedId',
variableName: 'resourceVar',
quantity: {
calculation: 'resourceConsumedQuantity'
}
}],
},
uses: {
calculation: 'nonExistantProperty + 7',
},
usesUsed: 5,
}),
clean({
_id: 'numItemsConumedId',
type: 'attribute',
variableName: 'itemConsumedQuantity',
baseValue: {
calculation: '3',
},
}),
clean({
_id: 'numResourceConumedId',
type: 'attribute',
variableName: 'resourceConsumedQuantity',
baseValue: {
calculation: '4',
},
}),
clean({
_id: 'resourceVarId',
name: 'Resource Var',
type: 'attribute',
variableName: 'resourceVar',
baseValue: {
calculation: '9',
},
}),
clean({
_id: 'inlineRefResourceId',
type: 'attribute',
variableName: 'inlineRef',
baseValue: {
calculation: '1 + 5',
},
}),
clean({
_id: 'arrowId',
type: 'item',
name: 'Arrow',
quantity: 27,
icon: 'itemIcon',
color: 'itemColor',
}),
];

View File

@@ -5,10 +5,14 @@ import computeByType from '/imports/api/creature/computation/newEngine/computeCo
export default function computeCreatureComputation(computation){
const stack = [];
// Computation scope of {variableName: prop}
const scope = {};
const scope = computation.scope;
const graph = computation.dependencyGraph;
// Add all nodes to the stack
graph.forEachNode(node => stack.push(node));
graph.forEachNode(node => {
node._visited = false;
node._visitedChildren = false;
stack.push(node)
});
// Depth first traversal of nodes
while (stack.length){
let top = stack[stack.length - 1];

View File

@@ -2,15 +2,15 @@ import computeCreatureComputation from './computeCreatureComputation.js';
import { buildComputationFromProps } from './buildCreatureComputation.js';
import { assert } from 'chai';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import computeAction from './computeComputation/tests/computeAction.testFn.js';
describe('Compute compuation', function(){
it('Computes something at all', function(){
console.time('compute');
let computation = buildComputationFromProps(testProperties);
computeCreatureComputation(computation);
console.timeEnd('compute');
assert.exists(computation);
});
it('Computes actions', computeAction);
});
var testProperties = [

View File

@@ -0,0 +1,6 @@
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
export default function cleanProp(prop){
let schema = CreatureProperties.simpleSchema(prop);
return schema.clean(prop);
}