Moved creature variables to their own collection
Another big change to the engine, expect bugs
This commit is contained in:
@@ -3,6 +3,7 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method';
|
||||
import { RateLimiterMixin } from 'ddp-rate-limiter-mixin';
|
||||
import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js';
|
||||
import Creatures from '/imports/api/creature/creatures/Creatures.js';
|
||||
import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables.js';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import { CreatureLogSchema, insertCreatureLogWork } from '/imports/api/creature/log/CreatureLogs.js';
|
||||
import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions.js';
|
||||
@@ -38,6 +39,12 @@ const doAction = new ValidatedMethod({
|
||||
let action = CreatureProperties.findOne(actionId);
|
||||
// Check permissions
|
||||
let creature = getRootCreatureAncestor(action);
|
||||
const variables = CreatureVariables.findOne({
|
||||
_creatureId: creature._id
|
||||
}, {
|
||||
fields: {_id: 0, _creatureId: 0},
|
||||
});
|
||||
creature.variables = variables;
|
||||
|
||||
assertEditPermission(creature, this.userId);
|
||||
|
||||
@@ -46,6 +53,12 @@ const doAction = new ValidatedMethod({
|
||||
targetIds.forEach(targetId => {
|
||||
let target = Creatures.findOne(targetId);
|
||||
assertEditPermission(target, this.userId);
|
||||
const variables = CreatureVariables.findOne({
|
||||
_creatureId: targetId
|
||||
}, {
|
||||
fields: {_id: 0, _creatureId: 0},
|
||||
});
|
||||
target.variables = variables;
|
||||
targets.push(target);
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { EJSON } from 'meteor/ejson';
|
||||
import createGraph from 'ngraph.graph';
|
||||
|
||||
export default class CreatureComputation {
|
||||
constructor(properties, creature){
|
||||
constructor(properties, creature, variables){
|
||||
// Set up fields
|
||||
this.originalPropsById = {};
|
||||
this.propsById = {};
|
||||
@@ -12,6 +12,7 @@ export default class CreatureComputation {
|
||||
this.dependencyGraph = createGraph();
|
||||
this.errors = [];
|
||||
this.creature = creature;
|
||||
this.variables = variables;
|
||||
|
||||
// Store properties for easy access later
|
||||
properties.forEach(prop => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import CreatureProperties,
|
||||
from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import { loadedCreatures } from '../loadCreatures.js';
|
||||
import Creatures from '/imports/api/creature/creatures/Creatures.js';
|
||||
import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables.js';
|
||||
import computedOnlySchemas from '/imports/api/properties/computedOnlyPropertySchemasIndex.js';
|
||||
import computedSchemas from '/imports/api/properties/computedPropertySchemasIndex.js';
|
||||
import linkInventory from './buildComputation/linkInventory.js';
|
||||
@@ -33,8 +34,9 @@ import removeSchemaFields from './buildComputation/removeSchemaFields.js';
|
||||
|
||||
export default function buildCreatureComputation(creatureId){
|
||||
const creature = getCreature(creatureId);
|
||||
const variables = getVariables(creatureId);
|
||||
const properties = getProperties(creatureId);
|
||||
const computation = buildComputationFromProps(properties, creature);
|
||||
const computation = buildComputationFromProps(properties, creature, variables);
|
||||
return computation;
|
||||
}
|
||||
|
||||
@@ -45,7 +47,7 @@ function getProperties(creatureId) {
|
||||
const cloneProps = EJSON.clone(props);
|
||||
return cloneProps
|
||||
}
|
||||
console.time(`Cache miss fetching from db: ${creatureId}`)
|
||||
// console.time(`Cache miss on creature properties: ${creatureId}`)
|
||||
const props = CreatureProperties.find({
|
||||
'ancestors.id': creatureId,
|
||||
'removed': {$ne: true},
|
||||
@@ -53,29 +55,41 @@ function getProperties(creatureId) {
|
||||
sort: { order: 1 },
|
||||
fields: { icon: 0 },
|
||||
}).fetch();
|
||||
console.timeEnd(`Cache miss fetching from db: ${creatureId}`);
|
||||
// console.timeEnd(`Cache miss on creature properties: ${creatureId}`);
|
||||
return props;
|
||||
}
|
||||
|
||||
function getCreature(creatureId) {
|
||||
if (loadedCreatures.has(creatureId)) {
|
||||
const loadedCreature = loadedCreatures.get(creatureId);
|
||||
const creature = loadedCreature.creatures.get(creatureId);
|
||||
const creature = loadedCreature.creature;
|
||||
if (creature) return creature;
|
||||
}
|
||||
console.time(`Cache miss on Creature: ${creatureId}`);
|
||||
// console.time(`Cache miss on Creature: ${creatureId}`);
|
||||
const creature = Creatures.findOne(creatureId, {
|
||||
denormalizedStats: 1,
|
||||
variables: 1,
|
||||
dirty: 1,
|
||||
});
|
||||
console.timeEnd(`Cache miss on Creature: ${creatureId}`);
|
||||
// console.timeEnd(`Cache miss on Creature: ${creatureId}`);
|
||||
return creature;
|
||||
}
|
||||
|
||||
export function buildComputationFromProps(properties, creature){
|
||||
function getVariables(creatureId) {
|
||||
if (loadedCreatures.has(creatureId)) {
|
||||
const loadedCreature = loadedCreatures.get(creatureId);
|
||||
const variables = loadedCreature.variables;
|
||||
if (variables) return variables;
|
||||
}
|
||||
// console.time(`Cache miss on variables: ${creatureId}`);
|
||||
const variables = CreatureVariables.findOne({_creatureId: creatureId});
|
||||
// console.timeEnd(`Cache miss on variables: ${creatureId}`);
|
||||
return variables;
|
||||
}
|
||||
|
||||
const computation = new CreatureComputation(properties, creature);
|
||||
export function buildComputationFromProps(properties, creature, variables){
|
||||
|
||||
const computation = new CreatureComputation(properties, creature, variables);
|
||||
// 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
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables.js';
|
||||
import Creatures from '/imports/api/creature/creatures/Creatures.js';
|
||||
import { EJSON } from 'meteor/ejson';
|
||||
import { omitBy } from 'lodash';
|
||||
|
||||
export default function writeScope(creatureId, computation) {
|
||||
const scope = computation.scope;
|
||||
const variables = computation.creature?.variables || {};
|
||||
let $set, $unset;
|
||||
const variables = computation.variables || {};
|
||||
delete variables._id;
|
||||
|
||||
if (computation.creature.dirty) {
|
||||
$unset = { dirty: 1 };
|
||||
}
|
||||
let $set, $unset;
|
||||
|
||||
for (const key in scope){
|
||||
// Remove large properties that aren't likely to be accessed
|
||||
@@ -26,12 +25,14 @@ export default function writeScope(creatureId, computation) {
|
||||
// Only update changed fields
|
||||
if (!EJSON.equals(variables[key], scope[key])) {
|
||||
if (!$set) $set = {};
|
||||
// Set the changed key in the creature variables
|
||||
/* Log detailed diffs
|
||||
const diff = omitBy(variables[key], (v, k) => EJSON.equals(scope[key][k], v));
|
||||
for (let subkey in diff) {
|
||||
console.log(`${key}.${subkey}: ${variables[key][subkey]} => ${scope[key][subkey]}`)
|
||||
}
|
||||
$set[`variables.${key}`] = scope[key];
|
||||
*/
|
||||
// Set the changed key in the creature variables
|
||||
$set[key] = scope[key];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +40,17 @@ export default function writeScope(creatureId, computation) {
|
||||
for (const key in variables) {
|
||||
if (!scope[key]) {
|
||||
if (!$unset) $unset = {};
|
||||
$unset[`variables.${key}`] = 1;
|
||||
$unset[key] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($set || $unset) {
|
||||
const updates = Creatures.update(creatureId, { $set, $unset });
|
||||
console.log('wrote scope: ', updates);
|
||||
const update = {};
|
||||
if ($set) update.$set = $set;
|
||||
if ($unset) update.$unset = $unset;
|
||||
CreatureVariables.upsert({_creatureId: creatureId}, update);
|
||||
}
|
||||
if (computation.creature.dirty) {
|
||||
Creatures.update({_creatureId: creatureId}, {$unset: { dirty: 1 }});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ function computeComputation(computation, creatureId) {
|
||||
logError.location = e.stack.split('\n')[1];
|
||||
}
|
||||
console.error(logError);
|
||||
throw e;
|
||||
} finally {
|
||||
writeErrors(creatureId, computation.errors);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { debounce } from 'lodash';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import Creatures from '/imports/api/creature/creatures/Creatures.js';
|
||||
import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import computeCreature from './computeCreature';
|
||||
|
||||
const COMPUTE_DEBOUNCE_TIME = 100; // ms
|
||||
@@ -68,7 +69,6 @@ class LoadedCreature {
|
||||
},
|
||||
});
|
||||
|
||||
self.creatures = new Map();
|
||||
// Observe the creature itself
|
||||
self.creatureObserver = Creatures.find({
|
||||
_id: creatureId,
|
||||
@@ -87,26 +87,62 @@ class LoadedCreature {
|
||||
},
|
||||
});
|
||||
|
||||
// Observe the creature's variables
|
||||
self.variablesObserver = CreatureVariables.find({
|
||||
_creatureId: creatureId,
|
||||
}, {
|
||||
fields: { _creatureId: 0},
|
||||
}).observeChanges({
|
||||
added(id, fields) {
|
||||
fields._id = id;
|
||||
self.addVariables(fields)
|
||||
},
|
||||
changed(id, fields) {
|
||||
self.changeVariables(id, fields);
|
||||
},
|
||||
removed(id) {
|
||||
self.removeVariables(id);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
stop() {
|
||||
this.creatureObserver.stop();
|
||||
this.propertyObserver.stop();
|
||||
this.creatureObserver.stop();
|
||||
this.variablesObserver.stop();
|
||||
}
|
||||
addProperty(prop) {
|
||||
this.properties.set(prop._id, prop);
|
||||
}
|
||||
addCreature(creature) {
|
||||
this.creatures.set(creature._id, creature);
|
||||
}
|
||||
changeProperty(id, fields) {
|
||||
this.changeMap(id, fields, this.properties);
|
||||
LoadedCreature.changeMap(id, fields, this.properties);
|
||||
}
|
||||
removeProperty(id) {
|
||||
this.properties.delete(id)
|
||||
}
|
||||
addCreature(creature) {
|
||||
this.creature = creature;
|
||||
}
|
||||
changeCreature(id, fields) {
|
||||
this.changeMap(id, fields, this.creatures);
|
||||
LoadedCreature.changeDoc(this.creature, fields);
|
||||
}
|
||||
changeMap(id, fields, map) {
|
||||
removeCreature() {
|
||||
delete this.creature;
|
||||
}
|
||||
addVariables(variables) {
|
||||
this.variables = variables;
|
||||
}
|
||||
changeVariables(id, fields) {
|
||||
LoadedCreature.changeDoc(this.variables, fields);
|
||||
}
|
||||
removeVariables() {
|
||||
delete this.variables;
|
||||
}
|
||||
static changeMap(id, fields, map) {
|
||||
const doc = map.get(id);
|
||||
LoadedCreature.changeDoc(doc, fields);
|
||||
}
|
||||
static changeDoc(doc, fields) {
|
||||
if (!doc) return;
|
||||
for (let key in fields) {
|
||||
if (key === undefined) {
|
||||
@@ -116,10 +152,4 @@ class LoadedCreature {
|
||||
}
|
||||
}
|
||||
}
|
||||
removeProperty(id) {
|
||||
this.properties.delete(id)
|
||||
}
|
||||
removeCreature(id) {
|
||||
this.creatures.delete(id)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user