diff --git a/app/.meteor/packages b/app/.meteor/packages index 46d41ea6..17aedfd9 100644 --- a/app/.meteor/packages +++ b/app/.meteor/packages @@ -47,3 +47,4 @@ ostrio:files simple:rest-bearer-token-parser simple:rest-json-error-handler littledata:synced-cron +mdg:meteor-apm-agent diff --git a/app/.meteor/versions b/app/.meteor/versions index 5652121c..65dfa36d 100644 --- a/app/.meteor/versions +++ b/app/.meteor/versions @@ -52,8 +52,10 @@ inter-process-messaging@0.1.1 lai:collection-extensions@0.3.0 launch-screen@1.3.0 littledata:synced-cron@1.5.1 +livedata@1.0.18 localstorage@1.2.0 logging@1.3.1 +mdg:meteor-apm-agent@3.5.0 mdg:validated-method@1.2.0 meteor@1.10.0 meteor-base@1.5.1 @@ -73,6 +75,7 @@ mongo@1.14.6 mongo-decimal@0.1.2 mongo-dev-server@1.1.0 mongo-id@1.0.8 +mongo-livedata@1.0.12 npm-mongo@4.3.1 oauth@2.1.1 oauth2@1.3.1 diff --git a/app/imports/api/engine/computation/CreatureComputation.js b/app/imports/api/engine/computation/CreatureComputation.js index 90e28f44..278b3276 100644 --- a/app/imports/api/engine/computation/CreatureComputation.js +++ b/app/imports/api/engine/computation/CreatureComputation.js @@ -2,7 +2,7 @@ import { EJSON } from 'meteor/ejson'; import createGraph from 'ngraph.graph'; export default class CreatureComputation { - constructor(properties){ + constructor(properties, creature){ // Set up fields this.originalPropsById = {}; this.propsById = {}; @@ -11,6 +11,7 @@ export default class CreatureComputation { this.props = properties; this.dependencyGraph = createGraph(); this.errors = []; + this.creature = creature; // Store properties for easy access later properties.forEach(prop => { diff --git a/app/imports/api/engine/computation/buildCreatureComputation.js b/app/imports/api/engine/computation/buildCreatureComputation.js index 142bda59..8350051c 100644 --- a/app/imports/api/engine/computation/buildCreatureComputation.js +++ b/app/imports/api/engine/computation/buildCreatureComputation.js @@ -73,7 +73,7 @@ function getCreature(creatureId){ export function buildComputationFromProps(properties, creature){ - const computation = new CreatureComputation(properties); + const computation = new CreatureComputation(properties, creature); // 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 diff --git a/app/imports/api/engine/computation/writeComputation/writeScope.js b/app/imports/api/engine/computation/writeComputation/writeScope.js index 3661df4a..c318fb9e 100644 --- a/app/imports/api/engine/computation/writeComputation/writeScope.js +++ b/app/imports/api/engine/computation/writeComputation/writeScope.js @@ -1,10 +1,31 @@ import Creatures from '/imports/api/creature/creatures/Creatures.js'; +import { EJSON } from 'meteor/ejson'; -export default function writeScope(creatureId, scope){ - // Remove large properties that aren't likely to be accessed +export default function writeScope(creatureId, computation) { + const scope = computation.scope; + const variables = computation.creature.variables || {}; + let $set; for (const key in scope){ + // Remove large properties that aren't likely to be accessed delete scope[key].parent; delete scope[key].ancestors; + + // Remove empty keys + for (const subKey in scope[key]) { + if (scope[key][subKey] === undefined) { + delete scope[key][subKey] + } + } + + // Only update changed fields + if (!EJSON.equals(variables[key], scope[key])) { + if (!$set) $set = {}; + + // Set the changed key in the creature variables + $set[`variables.${key}`] = scope[key]; + } + } + if ($set) { + Creatures.update(creatureId, {$set}); } - Creatures.update(creatureId, {$set: {variables: scope}}); } diff --git a/app/imports/api/engine/computeCreature.js b/app/imports/api/engine/computeCreature.js index 36d58724..55de9359 100644 --- a/app/imports/api/engine/computeCreature.js +++ b/app/imports/api/engine/computeCreature.js @@ -20,8 +20,8 @@ function computeComputation(computation, creatureId) { try { computeCreatureComputation(computation); writeAlteredProperties(computation); - writeScope(creatureId, computation.scope); - } catch (e) { + writeScope(creatureId, computation); + } catch (e){ const errorText = e.reason || e.message || e.toString(); computation.errors.push({ type: 'crash', diff --git a/app/imports/server/publications/library.js b/app/imports/server/publications/library.js index 41e2b080..10553aab 100644 --- a/app/imports/server/publications/library.js +++ b/app/imports/server/publications/library.js @@ -1,7 +1,7 @@ import SimpleSchema from 'simpl-schema'; import Libraries from '/imports/api/library/Libraries.js'; import LibraryNodes from '/imports/api/library/LibraryNodes.js'; -import { assertViewPermission } from '/imports/api/sharing/sharingPermissions.js'; +import { assertViewPermission, assertDocViewPermission } from '/imports/api/sharing/sharingPermissions.js'; Meteor.publish('libraries', function(){ this.autorun(function (){ @@ -63,12 +63,64 @@ Meteor.publish('libraryNodes', function(libraryId){ LibraryNodes.find({ 'ancestors.id': libraryId, }, { - sort: {order: 1}, + sort: { order: 1 }, + fields: { + _id: 1, + name: 1, + type: 1, + icon: 1, + color: 1, + order: 1, + parent: 1, + ancestors: 1, + // Effect + operation: 1, + targetTags: 1, + stats: 1, + // Item + quantity: 1, + plural: 1, + equipped: 1, + // Branch + branchType: 1, + // Damage: + damageType: 1, + stat: 1, + amount: 1, + // Class level + level: 1, + // Proficiency + value: 1, + // Reference + cache: 1, + } }), ]; }); }); +const nodeIdSchema = new SimpleSchema({ + libraryNodeId: { + type: String, + regEx: SimpleSchema.RegEx.Id, + }, +}); + +Meteor.publish('libraryNode', function (libraryNodeId) { + if (!libraryNodeId) return []; + nodeIdSchema.validate({ libraryNodeId }); + this.autorun(function () { + const userId = this.userId; + const nodeCursor = LibraryNodes.find({_id: libraryNodeId}); + let node = nodeCursor.fetch()[0]; + try { assertDocViewPermission(node, userId) } + catch (e) { + return this.error(e); + } + return [ nodeCursor ]; + }); +}); + Meteor.publish('softRemovedLibraryNodes', function(libraryId){ if (!libraryId) return []; libraryIdSchema.validate({libraryId}); diff --git a/app/imports/ui/library/LibraryNodeDialog.vue b/app/imports/ui/library/LibraryNodeDialog.vue index 99006a69..e67c0cc2 100644 --- a/app/imports/ui/library/LibraryNodeDialog.vue +++ b/app/imports/ui/library/LibraryNodeDialog.vue @@ -5,6 +5,7 @@ :model="model" :editing="editing" :flat="flat" + :embedded="embedded" @duplicate="duplicate" @move="move" @remove="remove" @@ -12,32 +13,41 @@ @color-changed="value => change({path: ['color'], value})" /> - + + + +

+ This property can't be viewed yet. +

+