From 2e3f0320f3bbd8fb41b3772637e5dc0fb30e2695 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Mon, 2 May 2022 23:31:10 +0200 Subject: [PATCH] Added dependency grouping, but commented out for now until it's needed --- .../creatureProperties/CreatureProperties.js | 12 ++++-- .../computation/buildCreatureComputation.js | 29 ++++++++++++-- .../utility/assignDependencyGroups.js | 39 +++++++++++++++++++ .../writeAlteredProperties.js | 14 ++++--- app/imports/api/engine/computeCreature.js | 25 ++++++------ app/package.json | 3 +- app/server/main.js | 2 + 7 files changed, 99 insertions(+), 25 deletions(-) create mode 100644 app/imports/api/engine/computation/utility/assignDependencyGroups.js diff --git a/app/imports/api/creature/creatureProperties/CreatureProperties.js b/app/imports/api/creature/creatureProperties/CreatureProperties.js index b70d96d5..653f7346 100644 --- a/app/imports/api/creature/creatureProperties/CreatureProperties.js +++ b/app/imports/api/creature/creatureProperties/CreatureProperties.js @@ -82,6 +82,14 @@ const DenormalisedOnlyCreaturePropertySchema = new SimpleSchema({ index: 1, removeBeforeCompute: true, }, + // Dependency tree, the ID of the lowest ordered doc connected to this doc + // via dependencies + /*depGroupId: { + type: String, + regEx: SimpleSchema.RegEx.Id, + index: 1, + removeBeforeCompute: true, + }*/ }); CreaturePropertySchema.extend(DenormalisedOnlyCreaturePropertySchema); @@ -98,10 +106,6 @@ for (let key in propertySchemasIndex){ }); } -import '/imports/api/creature/creatureProperties/methods/index.js'; -//import '/imports/api/creature/actions/doAction.js'; -//import '/imports/api/creature/actions/castSpellWithSlot.js'; - export default CreatureProperties; export { DenormalisedOnlyCreaturePropertySchema, diff --git a/app/imports/api/engine/computation/buildCreatureComputation.js b/app/imports/api/engine/computation/buildCreatureComputation.js index 8e81e314..142bda59 100644 --- a/app/imports/api/engine/computation/buildCreatureComputation.js +++ b/app/imports/api/engine/computation/buildCreatureComputation.js @@ -15,6 +15,7 @@ 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 @@ -37,12 +38,30 @@ export default function buildCreatureComputation(creatureId){ return computation; } -function getProperties(creatureId){ +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} + 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(); } @@ -82,7 +101,7 @@ export function buildComputationFromProps(properties, creature){ // Process the properties one by one properties.forEach(prop => { - let computedSchema = computedOnlySchemas[prop.type]; + const computedSchema = computedOnlySchemas[prop.type]; removeSchemaFields([computedSchema, denormSchema], prop); // Add a place to store all the computation details @@ -114,5 +133,9 @@ export function buildComputationFromProps(properties, creature){ linkTypeDependencies(dependencyGraph, prop, computation); linkCalculationDependencies(dependencyGraph, prop, computation); }); + + // Store the connected groups of the dependency graph + // assignDependencyGroups(dependencyGraph); + return computation; } diff --git a/app/imports/api/engine/computation/utility/assignDependencyGroups.js b/app/imports/api/engine/computation/utility/assignDependencyGroups.js new file mode 100644 index 00000000..a93c2a9e --- /dev/null +++ b/app/imports/api/engine/computation/utility/assignDependencyGroups.js @@ -0,0 +1,39 @@ +export default function assignDependencyGroups(graph) { + // Iterate through all the nodes + graph.forEachNode(node => { + if (node._depGroupVisited) { + return; + } + + // DFS all the connected nodes to this node, mark visited, put in a group, + // store the lowest ordered id + const group = []; + const stack = [node]; + let top, lowestOrderId, lowestOrder; + while (stack.length) { + top = stack.pop(); + if (top._depGroupVisited) continue; + if ( + (lowestOrderId === undefined && top.data?._id) || + (top.data?._id && top.data?.order < lowestOrder) + ) { + lowestOrderId = top.data?._id; + lowestOrder = top.data?.order; + } + if (top.data?._id) { + group.push(top) + } + top._depGroupVisited = true; + graph.forEachLinkedNode(top.id, linkedNode => stack.push(linkedNode)); + } + // Assign group id + group.forEach(node => { + if (!lowestOrderId) return; + if (group.length > 1) { + node.data.depGroupId = lowestOrderId; + } else { + delete node.data.depGroupId; + } + }); + }); +} \ No newline at end of file diff --git a/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js b/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js index cd0372cb..47b72c0f 100644 --- a/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js +++ b/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js @@ -20,6 +20,7 @@ export default function writeAlteredProperties(computation){ 'deactivatedBySelf', 'deactivatedByAncestor', 'deactivatedByToggle', + 'depGroupId', 'damage', ...schema.objectKeys(), ]; @@ -28,7 +29,8 @@ export default function writeAlteredProperties(computation){ bulkWriteOperations.push(op); } }); - writePropertiesSequentially(bulkWriteOperations); + bulkWriteProperties(bulkWriteOperations); + if (bulkWriteOperations.length) console.log(`Wrote ${bulkWriteOperations.length} props`); } function addChangedKeysToOp(op, keys, original, changed) { @@ -79,10 +81,10 @@ function addUnsetOp(op, key){ } } -// We use this instead of bulkWriteProperties because it functions with latency -// compensation without needing to roll back changes, which causes multiple -// expensive redraws of the character sheet -function writePropertiesSequentially(bulkWriteOps){ +// If we re-enable client-side sheet recalculation, this needs to be run on +// both client and server to preserve latency compensation. Bulkwrite breaks +// latency compensation and causes flickering +function writePropertiesSequentially(bulkWriteOps) { bulkWriteOps.forEach(op => { let updateOneOrMany = op.updateOne || op.updateMany; CreatureProperties.update(updateOneOrMany.filter, updateOneOrMany.update, { @@ -101,7 +103,7 @@ function writePropertiesSequentially(bulkWriteOps){ function bulkWriteProperties(bulkWriteOps){ if (!bulkWriteOps.length) return; // bulkWrite is only available on the server - if (Meteor.isServer){ + if (Meteor.isServer) { CreatureProperties.rawCollection().bulkWrite( bulkWriteOps, {ordered : false}, diff --git a/app/imports/api/engine/computeCreature.js b/app/imports/api/engine/computeCreature.js index a45188bf..36d58724 100644 --- a/app/imports/api/engine/computeCreature.js +++ b/app/imports/api/engine/computeCreature.js @@ -1,4 +1,4 @@ -import buildCreatureComputation from './computation/buildCreatureComputation.js'; +import buildCreatureComputation, { buildDependencyGroupComputation } from './computation/buildCreatureComputation.js'; import computeCreatureComputation from './computation/computeCreatureComputation.js'; import writeAlteredProperties from './computation/writeComputation/writeAlteredProperties.js'; import writeScope from './computation/writeComputation/writeScope.js'; @@ -7,21 +7,31 @@ import writeErrors from './computation/writeComputation/writeErrors.js'; export default function computeCreature(creatureId){ if (Meteor.isClient) return; const computation = buildCreatureComputation(creatureId); + computeComputation(computation, creatureId); +} + +// Recompute only some groups of the dependency tree +export function computeCreatureDependencyGroup(depGroupIds, creatureId) { + const computation = buildDependencyGroupComputation(depGroupIds, creatureId); + computeComputation(computation, creatureId); +} + +function computeComputation(computation, creatureId) { try { computeCreatureComputation(computation); writeAlteredProperties(computation); writeScope(creatureId, computation.scope); - } catch (e){ + } catch (e) { const errorText = e.reason || e.message || e.toString(); computation.errors.push({ type: 'crash', - details: {error: errorText}, + details: { error: errorText }, }); const logError = { creatureId, computeError: errorText, }; - if (e.stack){ + if (e.stack) { logError.location = e.stack.split('\n')[1]; } console.error(logError); @@ -29,10 +39,3 @@ export default function computeCreature(creatureId){ writeErrors(creatureId, computation.errors); } } - -// For now just recompute the whole creature, TODO only recompute a single -// connected section of the depdendency graph -export function computeCreatureDependencyGroup(property){ - let creatureId = property.ancestors[0].id; - computeCreature(creatureId); -} diff --git a/app/package.json b/app/package.json index 64e163f3..0467b8ef 100644 --- a/app/package.json +++ b/app/package.json @@ -10,6 +10,7 @@ "author": "Stefan Zermatten", "scripts": { "run": "meteor", + "debug": "meteor debug", "test": "meteor test --driver-package meteortesting:mocha --port 3001" }, "engines": { @@ -115,4 +116,4 @@ "vuetify/no-deprecated-classes": "error" } } -} +} \ No newline at end of file diff --git a/app/server/main.js b/app/server/main.js index f377abe9..1982276f 100644 --- a/app/server/main.js +++ b/app/server/main.js @@ -13,3 +13,5 @@ import '/imports/api/engine/actions/index.js'; import '/imports/migrations/server/index.js'; import '/imports/migrations/methods/index.js' import '/imports/constants/MAINTENANCE_MODE.js'; +import '/imports/api/creature/creatureProperties/methods/index.js'; +