diff --git a/app/imports/api/creature/creatureProperties/recomputeCreaturesByProperty.js b/app/imports/api/creature/creatureProperties/recomputeCreaturesByProperty.js deleted file mode 100644 index 06fe42c7..00000000 --- a/app/imports/api/creature/creatureProperties/recomputeCreaturesByProperty.js +++ /dev/null @@ -1,9 +0,0 @@ -import computeCreature from '/imports/api/engine/computeCreature'; - -/** - * Recomputes all ancestor creatures of this property - * @deprecated - */ -export default function recomputeCreaturesByProperty(property) { - computeCreature.call(property.root.id); -} diff --git a/app/imports/api/creature/mixins/recomputeCreatureMixin.js b/app/imports/api/creature/mixins/recomputeCreatureMixin.js deleted file mode 100644 index 32caa2f6..00000000 --- a/app/imports/api/creature/mixins/recomputeCreatureMixin.js +++ /dev/null @@ -1,17 +0,0 @@ -import computeCreature from '/imports/api/engine/computeCreature'; - -export default function recomputeCreatureMixin(methodOptions) { - let runFunc = methodOptions.run; - methodOptions.run = function ({ charId }) { - const result = runFunc.apply(this, arguments); - if ( - methodOptions.skipRecompute && - methodOptions.skipRecompute.apply(this, arguments) - ) { - return result; - } - computeCreature(charId); - return result; - }; - return methodOptions; -} diff --git a/app/imports/api/engine/action/EngineActions.ts b/app/imports/api/engine/action/EngineActions.ts index e420bd62..471206bb 100644 --- a/app/imports/api/engine/action/EngineActions.ts +++ b/app/imports/api/engine/action/EngineActions.ts @@ -130,7 +130,6 @@ const ActionSchema = new SimpleSchema({ }, }); -// @ts-expect-error Collections2 lacks TypeScript support EngineActions.attachSchema(ActionSchema); export default EngineActions; diff --git a/app/imports/api/engine/action/functions/writeActionResults.ts b/app/imports/api/engine/action/functions/writeActionResults.ts index b8f08309..13da7d94 100644 --- a/app/imports/api/engine/action/functions/writeActionResults.ts +++ b/app/imports/api/engine/action/functions/writeActionResults.ts @@ -1,11 +1,11 @@ import EngineActions, { EngineAction } from '/imports/api/engine/action/EngineActions'; import mutationToPropUpdates from './mutationToPropUpdates'; import mutationToLogUpdates from '/imports/api/engine/action/functions/mutationToLogUpdates'; -import { union } from 'lodash'; +import { union, uniq } from 'lodash'; import CreatureLogs from '/imports/api/creature/log/CreatureLogs'; import bulkWrite from '/imports/api/engine/shared/bulkWrite'; import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; -import Creatures from '/imports/api/creature/creatures/Creatures'; +import computeCreature from '/imports/api/engine/computeCreature'; export default async function writeActionResults(action: EngineAction) { if (!action._id) throw new Meteor.Error('type-error', 'Action does not have an _id'); @@ -32,14 +32,10 @@ export default async function writeActionResults(action: EngineAction) { // Write the bulk updates const bulkWritePromise = bulkWrite(creaturePropUpdates, CreatureProperties); - // Mark the creatures as dirty - const creaturePromise = Creatures.updateAsync({ - _id: { $in: [action.creatureId, ...allTargetIds] }, - }, { - $set: { dirty: true }, - }, { - multi: true, - }); + await Promise.all([engineActionPromise, logPromise, bulkWritePromise]); - return Promise.all([engineActionPromise, logPromise, bulkWritePromise, creaturePromise]); + // Recompute the creatures involved + const recomputePromises = uniq([action.creatureId, ...allTargetIds]).map(creatureId => computeCreature(creatureId)); + + return Promise.all(recomputePromises); } diff --git a/app/imports/api/engine/action/methods/runAction.ts b/app/imports/api/engine/action/methods/runAction.ts index 6c415de8..b3f6f5cf 100644 --- a/app/imports/api/engine/action/methods/runAction.ts +++ b/app/imports/api/engine/action/methods/runAction.ts @@ -1,5 +1,4 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; -import SimpleSchema from 'simpl-schema'; import EngineActions from '/imports/api/engine/action/EngineActions'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions'; import { getCreature } from '/imports/api/engine/loadCreatures'; @@ -10,7 +9,7 @@ import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; export const runAction = new ValidatedMethod({ name: 'actions.runAction', - validate: null, + validate: null, //TODO mixins: [RateLimiterMixin], rateLimit: { numRequests: 10, @@ -31,7 +30,6 @@ export const runAction = new ValidatedMethod({ await applyAction(action, userInput); // Persist changes - const writePromise = writeActionResults(action); - return writePromise; + return writeActionResults(action); }, }); diff --git a/app/imports/api/engine/action/applySilencedProps.test.ts b/app/imports/api/engine/action/test/applySilencedProps.test.ts similarity index 93% rename from app/imports/api/engine/action/applySilencedProps.test.ts rename to app/imports/api/engine/action/test/applySilencedProps.test.ts index 05254012..7fb2f980 100644 --- a/app/imports/api/engine/action/applySilencedProps.test.ts +++ b/app/imports/api/engine/action/test/applySilencedProps.test.ts @@ -4,14 +4,15 @@ import { createTestCreature, getRandomIds, removeAllCreaturesAndProps, - runActionById + runActionById, + TestCreature } from '/imports/api/engine/action/functions/actionEngineTest.testFn'; const [ creatureId, silencedNoteId ] = getRandomIds(2); -const actionTestCreature = { +const actionTestCreature: TestCreature = { _id: creatureId, props: [ { diff --git a/app/imports/api/engine/computation/writeComputation/writeErrorsAndPropCount.js b/app/imports/api/engine/computation/writeComputation/writeErrorsAndPropCount.js index 61c3f2d1..d4595c7a 100644 --- a/app/imports/api/engine/computation/writeComputation/writeErrorsAndPropCount.js +++ b/app/imports/api/engine/computation/writeComputation/writeErrorsAndPropCount.js @@ -1,4 +1,5 @@ import Creatures from '/imports/api/creature/creatures/Creatures'; +import VERSION from '/imports/constants/VERSION'; export default function writeErrorsAndPropCount(creatureId, errors = [], propCount) { if (errors.length) { @@ -7,6 +8,7 @@ export default function writeErrorsAndPropCount(creatureId, errors = [], propCou computeErrors: errors, propCount, lastComputedAt: new Date(), + computeVersion: VERSION, } }); } else { @@ -14,6 +16,7 @@ export default function writeErrorsAndPropCount(creatureId, errors = [], propCou $set: { propCount, lastComputedAt: new Date(), + computeVersion: VERSION, }, $unset: { computeErrors: 1 } }); } diff --git a/app/imports/api/engine/shared/bulkWrite.ts b/app/imports/api/engine/shared/bulkWrite.ts index f7f404e2..4deafecc 100644 --- a/app/imports/api/engine/shared/bulkWrite.ts +++ b/app/imports/api/engine/shared/bulkWrite.ts @@ -2,7 +2,7 @@ // in the UI because of incompatibility with latency compensation. If the // duplicate redraws can be fixed, this is a strictly better way of processing // writes -export default function bulkWrite(bulkWriteOps, collection: Mongo.Collection): void | Promise { +export default async function bulkWrite(bulkWriteOps, collection: Mongo.Collection): Promise { if (!bulkWriteOps.length) return; // bulkWrite is only available on the server if (!Meteor.isServer) { diff --git a/app/imports/client/ui/creature/actions/doAction.ts b/app/imports/client/ui/creature/actions/doAction.ts index 3973cdcc..373f0b86 100644 --- a/app/imports/client/ui/creature/actions/doAction.ts +++ b/app/imports/client/ui/creature/actions/doAction.ts @@ -17,10 +17,12 @@ type BaseDoActionParams = { type DoTaskParams = BaseDoActionParams & { task: Task; propId?: undefined; + targetIds?: undefined; } type DoActionParams = BaseDoActionParams & { propId: string; + targetIds: string[]; task?: undefined; } @@ -30,12 +32,16 @@ type DoActionParams = BaseDoActionParams & { * the decisions the user makes, then applying the action as a method call to the server with the * saved decisions, which will persist the action results. */ -export default async function doAction({ propId, creatureId, $store, elementId, task }: DoActionParams | DoTaskParams): Promise { +export default async function doAction({ propId, creatureId, $store, elementId, task, targetIds }: DoActionParams | DoTaskParams): Promise { if (!task) { + targetIds ??= []; if (!propId) throw new Meteor.Error('no-prop-id', 'Either propId or task must be provided'); + const prop = getSingleProperty(creatureId, propId); + if (!prop) throw new Meteor.Error('not-found', 'Property not found'); task = { - prop: getSingleProperty(creatureId, propId), - targetIds: [], + prop, + targetIds, + subtaskFn: undefined, }; } // Create the action @@ -52,12 +58,15 @@ export default async function doAction({ propId, creatureId, $store, elementId, // Get the inserted and cleaned action instance const action = EngineActions.findOne(actionId); + console.log(action); + if (!action) throw new Meteor.Error('not-found', 'The action could not be found'); // Applying the action is deterministic, so we apply it, if it asks for user input, we escape and // create a dialog that will re-apply the action, but with the ability to actually get input // Either way, call the action method afterwards try { + if (!action._id) throw new Meteor.Error('no-action-id', 'Action ID is required'); const finishedAction = await applyAction( action, getErrorOnInputRequestProvider(action._id), { simulate: true } ); @@ -96,7 +105,7 @@ const throwInputRequestedError = () => { throw 'input-requested'; } -function getErrorOnInputRequestProvider(actionId) { +function getErrorOnInputRequestProvider(actionId: string) { const errorOnInputRequest: InputProvider = { targetIds: throwInputRequestedError, nextStep: throwInputRequestedError, diff --git a/app/imports/client/ui/log/TabletopLog.vue b/app/imports/client/ui/log/TabletopLog.vue index 0b5feb5c..1bbcc15e 100644 --- a/app/imports/client/ui/log/TabletopLog.vue +++ b/app/imports/client/ui/log/TabletopLog.vue @@ -185,4 +185,3 @@ export default { margin-bottom: 0; } -resolveimport { toString } from '/imports/parser/toString'; diff --git a/app/imports/client/ui/log/TabletopLogContent.vue b/app/imports/client/ui/log/TabletopLogContent.vue index 19103458..94353f42 100644 --- a/app/imports/client/ui/log/TabletopLogContent.vue +++ b/app/imports/client/ui/log/TabletopLogContent.vue @@ -3,48 +3,60 @@
-

+
+
+ {{ content.name }} +
+ +
+
+
+
- mdi-chevron-right - - - - {{ creature.name && creature.name[0] || '?' }} - - -

-
-

- {{ content.name }} -

- -
+ + {{ creature.name }} +
@@ -104,19 +116,12 @@ export default { diff --git a/app/imports/client/ui/tabletop/TabletopToolbar.vue b/app/imports/client/ui/tabletop/TabletopToolbar.vue index 6c0d0af3..7609ddfc 100644 --- a/app/imports/client/ui/tabletop/TabletopToolbar.vue +++ b/app/imports/client/ui/tabletop/TabletopToolbar.vue @@ -1,32 +1,9 @@ - - diff --git a/app/imports/client/ui/tabletop/selectedCreatureBar/SelectedCreatureBar.vue b/app/imports/client/ui/tabletop/selectedCreatureBar/SelectedCreatureBar.vue index da43b395..1a9fdbde 100644 --- a/app/imports/client/ui/tabletop/selectedCreatureBar/SelectedCreatureBar.vue +++ b/app/imports/client/ui/tabletop/selectedCreatureBar/SelectedCreatureBar.vue @@ -30,6 +30,7 @@ transition: 'opacity 0.2s ease', }" :model="selectedProp" + :targets="targets" data-id="tabletop-action-card" @close-menu="menuOpen = false" @dialog-opened="menuOpen = false" @@ -186,6 +187,10 @@ export default { type: String, default: undefined, }, + targets: { + type: Array, + required: true, + }, }, data() { return {