Added dependency grouping, but commented out for now until it's needed

This commit is contained in:
Stefan Zermatten
2022-05-02 23:31:10 +02:00
parent abb8890070
commit 2e3f0320f3
7 changed files with 99 additions and 25 deletions

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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;
}
});
});
}

View File

@@ -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},

View File

@@ -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);
}

View File

@@ -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"
}
}
}
}

View File

@@ -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';