diff --git a/app/imports/api/creature/creatureProperties/CreatureProperties.js b/app/imports/api/creature/creatureProperties/CreatureProperties.js
index cccf715c..33183ddc 100644
--- a/app/imports/api/creature/creatureProperties/CreatureProperties.js
+++ b/app/imports/api/creature/creatureProperties/CreatureProperties.js
@@ -82,14 +82,6 @@ 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);
diff --git a/app/imports/api/creature/creatureProperties/methods/damageProperty.js b/app/imports/api/creature/creatureProperties/methods/damageProperty.js
index 2c648c9c..51c37749 100644
--- a/app/imports/api/creature/creatureProperties/methods/damageProperty.js
+++ b/app/imports/api/creature/creatureProperties/methods/damageProperty.js
@@ -4,7 +4,7 @@ import SimpleSchema from 'simpl-schema';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js';
import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js';
-import computeCreature, { computeCreatureDependencyGroup } from '/imports/api/engine/computeCreature.js';
+import computeCreature from '/imports/api/engine/computeCreature.js';
const damageProperty = new ValidatedMethod({
name: 'creatureProperties.damage',
@@ -38,12 +38,7 @@ const damageProperty = new ValidatedMethod({
);
}
let result = damagePropertyWork({ property, operation, value });
- if (property.depGroupId) {
- // Dependencies can't be changed through damage, only recompute deps
- computeCreatureDependencyGroup([property.depGroupId], rootCreature._id);
- } else {
- computeCreature(rootCreature._id);
- }
+ computeCreature(rootCreature._id);
return result;
},
});
diff --git a/app/imports/api/engine/computation/buildCreatureComputation.js b/app/imports/api/engine/computation/buildCreatureComputation.js
index f86e610b..f2b07158 100644
--- a/app/imports/api/engine/computation/buildCreatureComputation.js
+++ b/app/imports/api/engine/computation/buildCreatureComputation.js
@@ -2,6 +2,7 @@ import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree.js';
import CreatureProperties,
{ DenormalisedOnlyCreaturePropertySchema as denormSchema }
from '/imports/api/creature/creatureProperties/CreatureProperties.js';
+import { loadedCreatures } from '../loadCreatures.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';
@@ -15,7 +16,6 @@ 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
@@ -38,35 +38,22 @@ export default function buildCreatureComputation(creatureId){
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({
+ if (loadedCreatures.has(creatureId)) {
+ const creature = loadedCreatures.get(creatureId);
+ const props = Array.from(creature.properties.values());
+ return props;
+ }
+ console.time(`fetching from db: ${creatureId}`)
+ const props = CreatureProperties.find({
'ancestors.id': creatureId,
'removed': {$ne: true},
}, {
sort: { order: 1 },
fields: { icon: 0 },
}).fetch();
-}
-
-function getGroupProperties(depGroupIds) {
- console.log({ depGroupIds });
- if (!depGroupIds || depGroupIds.includes(undefined)) {
- throw `Expected array full of ids, got ${depGroupIds}`
- }
- return CreatureProperties.find({
- depGroupId: { $in: depGroupIds },
- 'removed': { $ne: true },
- }, {
- sort: { order: 1 },
- fields: { icon: 0 },
- }).fetch();
+ console.timeEnd(`fetching from db: ${creatureId}`);
+ return props;
}
function getCreature(creatureId){
@@ -138,8 +125,5 @@ export function buildComputationFromProps(properties, creature){
linkCalculationDependencies(dependencyGraph, prop, computation);
});
- // Store the connected groups of the dependency graph
- assignDependencyGroups(dependencyGraph);
-
return computation;
}
diff --git a/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js b/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js
index 20703856..ccf8246e 100644
--- a/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js
+++ b/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js
@@ -20,7 +20,6 @@ export default function writeAlteredProperties(computation){
'deactivatedBySelf',
'deactivatedByAncestor',
'deactivatedByToggle',
- 'depGroupId',
'damage',
...schema.objectKeys(),
];
diff --git a/app/imports/api/engine/computeCreature.js b/app/imports/api/engine/computeCreature.js
index 55de9359..84c90e8a 100644
--- a/app/imports/api/engine/computeCreature.js
+++ b/app/imports/api/engine/computeCreature.js
@@ -1,4 +1,4 @@
-import buildCreatureComputation, { buildDependencyGroupComputation } from './computation/buildCreatureComputation.js';
+import buildCreatureComputation from './computation/buildCreatureComputation.js';
import computeCreatureComputation from './computation/computeCreatureComputation.js';
import writeAlteredProperties from './computation/writeComputation/writeAlteredProperties.js';
import writeScope from './computation/writeComputation/writeScope.js';
@@ -6,14 +6,10 @@ import writeErrors from './computation/writeComputation/writeErrors.js';
export default function computeCreature(creatureId){
if (Meteor.isClient) return;
+ console.time('Compute');
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);
+ console.timeEnd('Compute');
}
function computeComputation(computation, creatureId) {
diff --git a/app/imports/api/engine/loadCreatures.js b/app/imports/api/engine/loadCreatures.js
new file mode 100644
index 00000000..46090140
--- /dev/null
+++ b/app/imports/api/engine/loadCreatures.js
@@ -0,0 +1,117 @@
+import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
+import Creatures from '/imports/api/creature/creatures/Creatures.js';
+
+export const loadedCreatures = new Map(); // creatureId => {creature, properties, etc.}
+
+export function loadCreature(creatureId, subscription) {
+ if (!creatureId) throw 'creatureId is required';
+ let creature = loadedCreatures.get(creatureId);
+ if (loadedCreatures.has(creatureId)) {
+ creature.subs.add(subscription);
+ } else {
+ console.time(`loading to memory ${creatureId}`);
+ creature = new LoadedCreature(subscription, creatureId);
+ loadedCreatures.set(creatureId, creature);
+ console.timeEnd(`loading to memory ${creatureId}`);
+ console.log('Creatures in memory: ', loadedCreatures.size);
+ }
+ subscription.onStop(() => {
+ unloadCreature(creatureId, subscription);
+ });
+}
+
+function unloadCreature(creatureId, subscription) {
+ if (!creatureId) throw 'creatureId is required';
+ const creature = loadedCreatures.get(creatureId);
+ if (!creature) return;
+ creature.subs.delete(subscription);
+ if (creature.subs.size === 0) {
+ creature.stop();
+ loadedCreatures.delete(creatureId);
+ }
+ console.log('Creatures in memory: ', loadedCreatures.size);
+}
+
+class LoadedCreature {
+ constructor(sub, creatureId) {
+ // This may be called from a subscription, but we don't want the observers
+ // to be destroyed with it, so use a non-reactive context to observe
+ // the required documents
+ const self = this;
+ Tracker.nonreactive(() => {
+
+ self.subs = new Set([sub]);
+
+ self.properties = new Map();
+ // Observe all creature properties which are needed for computation
+ self.propertyObserver = CreatureProperties.find({
+ 'ancestors.id': creatureId,
+ removed: { $ne: true },
+ }, {
+ // sort: { order: 1 },
+ fields: { icon: 0 },
+ }).observeChanges({
+ added(id, fields) {
+ fields._id = id;
+ return self.addProperty(fields)
+ },
+ changed(id, fields) {
+ return self.changeProperty(id, fields);
+ },
+ removed(id) {
+ return self.removeProperty(id);
+ },
+ });
+
+ self.creatures = new Map();
+ // Observe the creature itself
+ self.creatureObserver = Creatures.find({
+ _id: creatureId,
+ }).observeChanges({
+ added(id, fields) {
+ fields._id = id;
+ self.addCreature(fields)
+ },
+ changed(id, fields) {
+ return self.changeCreature(id, fields);
+ },
+ removed(id) {
+ return self.removeCreature(id);
+ },
+ });
+
+ });
+ }
+ stop() {
+ this.creatureObserver.stop();
+ this.propertyObserver.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);
+ }
+ changeCreature(id, fields) {
+ this.changeMap(id, fields, this.creatures);
+ }
+ changeMap(id, fields, map) {
+ const doc = map.get(id);
+ for (let key in fields) {
+ if (key === undefined) {
+ delete doc[key];
+ } else {
+ doc[key] = fields[key];
+ }
+ }
+ }
+ removeProperty(id) {
+ this.properties.delete(id)
+ }
+ removeCreature(id) {
+ this.creatures.delete(id)
+ }
+}
diff --git a/app/imports/parser/TextField.vue b/app/imports/parser/TextField.vue
deleted file mode 100644
index 9c9f0919..00000000
--- a/app/imports/parser/TextField.vue
+++ /dev/null
@@ -1,38 +0,0 @@
-
- $emit('keyup', e)"
- >
-
-
-
-
-
-
-
-
-
diff --git a/app/imports/server/publications/singleCharacter.js b/app/imports/server/publications/singleCharacter.js
index 611f1d23..c2ca8c0c 100644
--- a/app/imports/server/publications/singleCharacter.js
+++ b/app/imports/server/publications/singleCharacter.js
@@ -5,6 +5,7 @@ import CreatureLogs from '/imports/api/creature/log/CreatureLogs.js';
import { assertViewPermission } from '/imports/api/creature/creatures/creaturePermissions.js';
import computeCreature from '/imports/api/engine/computeCreature.js';
import VERSION from '/imports/constants/VERSION.js';
+import { loadCreature } from '/imports/api/engine/loadCreatures.js';
let schema = new SimpleSchema({
creatureId: {
@@ -13,7 +14,8 @@ let schema = new SimpleSchema({
},
});
-Meteor.publish('singleCharacter', function(creatureId){
+Meteor.publish('singleCharacter', function (creatureId) {
+ const self = this;
try {
schema.validate({ creatureId });
} catch (e){
@@ -21,21 +23,24 @@ Meteor.publish('singleCharacter', function(creatureId){
}
this.autorun(function (computation){
let userId = this.userId;
- let creatureCursor
- creatureCursor = Creatures.find({
+ let permissionCreature = Creatures.findOne({
_id: creatureId,
+ }, {
+ fields: { owner: 1, readers: 1, writers: 1, public: 1, computeVersion: 1 }
});
- let creature = creatureCursor.fetch()[0];
- try { assertViewPermission(creature, userId) }
- catch(e){ return [] }
- if (creature.computeVersion !== VERSION && computation.firstRun){
+ try { assertViewPermission(permissionCreature, userId) }
+ catch (e) { return [] }
+ loadCreature(creatureId, self);
+ if (permissionCreature.computeVersion !== VERSION && computation.firstRun){
try {
computeCreature(creatureId)
}
catch(e){ console.error(e) }
}
return [
- creatureCursor,
+ Creatures.find({
+ _id: creatureId,
+ }),
CreatureProperties.find({
'ancestors.id': creatureId,
}),