Fixed and improved: Discord webhooks are working again with a new format

This commit is contained in:
Stefan Zermatten
2021-02-20 15:27:20 +02:00
parent 067f5df36e
commit e068675b46
9 changed files with 139 additions and 76 deletions

View File

@@ -2,23 +2,12 @@ import spendResources from '/imports/api/creature/actions/spendResources.js'
import embedInlineCalculations from '/imports/api/creature/computation/afterComputation/embedInlineCalculations.js';
export default function applyAction({prop, log}){
spendResources(prop);
// If this is not the top level action, we can add its name to the log
if (log.content.length){
log.content.push({name: prop.name});
}
let content = { name: prop.name };
if (prop.summary){
log.content.push({
description: embedInlineCalculations(
prop.summary, prop.summaryCalculations
),
});
}
if (prop.description){
log.content.push({
description: embedInlineCalculations(
prop.description, prop.descriptionCalculations
),
});
content.description = embedInlineCalculations(
prop.summary, prop.summaryCalculations
);
}
log.content.push(content);
spendResources({prop, log});
}

View File

@@ -16,10 +16,16 @@ export default function applyAdjustment({
try {
var {result, errors} = evaluateString(prop.amount, scope, 'reduce');
if (typeof result !== 'number') {
log.content.push({error: errors.join(', ') || 'Something went wrong'});
log.content.push({
name: 'Attribute damage',
error: errors.join(', ') || 'Something went wrong',
});
}
} catch (e){
log.content.push({error: e.toString()});
log.content.push({
name: 'Attribute damage',
error: e.toString(),
});
}
if (damageTargets) {
damageTargets.forEach(target => {
@@ -33,12 +39,14 @@ export default function applyAdjustment({
value: result
});
log.content.push({
name: 'Attribute damage',
resultPrefix: `${prop.stat} ${prop.operation === 'set' ? 'set to' : ''}`,
result: `${-result}`,
});
});
} else {
log.content.push({
name: 'Attribute damage',
resultPrefix: `${prop.stat} ${prop.operation === 'set' ? 'set to' : ''}`,
result: `${-result}`,
});

View File

@@ -3,12 +3,14 @@ import roll from '/imports/parser/roll.js';
export default function applyAttack({
prop,
log,
actionContext,
}){
let result = roll(1, 20)[0] + prop.rollBonusResult;
let value = roll(1, 20)[0];
actionContext.attackRoll = {value};
let result = value + prop.rollBonusResult;
log.content.push({
// If this is not the first item in the log content, give it a name
name: log.content.length ? prop.name + ' attack' : undefined,
name: 'To Hit',
resultPrefix: `1d20 [${value}] + ${prop.rollBonusResult} = `,
result,
details: 'to hit',
});
}

View File

@@ -28,6 +28,9 @@ export default function applyDamage({
}
if (damageTargets && damageTargets.length) {
damageTargets.forEach(target => {
let name = prop.damageType === 'healing' ? 'Healing' : 'Damage';
let suffix = prop.damageType +
prop.damageType !== 'healing' ? ' damage': '';
if (prop.target === 'each'){
result = evaluateString(prop.amount, scope, 'reduce');
}
@@ -38,25 +41,24 @@ export default function applyDamage({
});
if (target._id === creature._id){
log.content.push({
name,
result: damageDealt,
details: `${prop.damageType}`+
`${prop.damageType !== 'healing' ? ' damage': ''} to self`,
details: suffix + 'to self',
});
} else {
log.content.push({
name,
resultPrefix: 'Dealt ',
result: damageDealt,
details: `${prop.damageType}` +
`${prop.damageType !== 'healing'? ' damage': ''}` +
`${target.name && ' to '}${target.name}`,
details: suffix + `${target.name && ' to '}${target.name}`,
});
insertCreatureLog.call({
log: {
content: [{
name,
resultPrefix: 'Recieved ',
result: damageDealt,
details: `${prop.damageType}` +
`${prop.damageType !== 'healing'? ' damage': ''}`
details: suffix,
}],
creatureId: target._id,
}
@@ -65,6 +67,7 @@ export default function applyDamage({
});
} else {
log.content.push({
name: prop.damageType === 'healing' ? 'Healing' : 'Damage',
result,
details: `${prop.damageType}${prop.damageType !== 'healing'? ' damage': ''}`,
});

View File

@@ -3,7 +3,7 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method';
import { RateLimiterMixin } from 'ddp-rate-limiter-mixin';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import Creatures from '/imports/api/creature/Creatures.js';
import CreatureLogs, { CreatureLogSchema, insertCreatureLogWork } from '/imports/api/creature/log/CreatureLogs.js';
import { CreatureLogSchema, insertCreatureLogWork } from '/imports/api/creature/log/CreatureLogs.js';
import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js';
import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js';
import { recomputeCreatureByDoc } from '/imports/api/creature/computation/methods/recomputeCreature.js';
@@ -60,7 +60,6 @@ export function doActionWork({
}){
// Create the log
let log = CreatureLogSchema.clean({
name: action.name,
creatureId: creature._id,
creatureName: creature.name,
});

View File

@@ -2,28 +2,30 @@ import CreatureProperties from '/imports/api/creature/creatureProperties/Creatur
import { adjustQuantityWork } from '/imports/api/creature/creatureProperties/methods/adjustQuantity.js';
import { damagePropertyWork } from '/imports/api/creature/creatureProperties/methods/damageProperty.js';
export default function spendResources(action){
export default function spendResources({prop, log}){
// Check Uses
if (action.usesUsed >= action.usesResult){
if (prop.usesUsed >= prop.usesResult){
throw new Meteor.Error('Insufficient Uses',
'This action has no uses left');
'This prop has no uses left');
}
// Resources
if (action.insufficientResources){
if (prop.insufficientResources){
throw new Meteor.Error('Insufficient Resources',
'This creature doesn\'t have sufficient resources to perform this action');
'This creature doesn\'t have sufficient resources to perform this prop');
}
// Items
let itemQuantityAdjustments = [];
action.resources.itemsConsumed.forEach(itemConsumed => {
let spendLog = [];
let gainLog = [];
prop.resources.itemsConsumed.forEach(itemConsumed => {
if (!itemConsumed.itemId){
throw new Meteor.Error('Ammo not selected',
'No ammo was selected for this action');
'No ammo was selected for this prop');
}
let item = CreatureProperties.findOne(itemConsumed.itemId);
if (!item || item.ancestors[0].id !== action.ancestors[0].id){
if (!item || item.ancestors[0].id !== prop.ancestors[0].id){
throw new Meteor.Error('Ammo not found',
'The action\'s ammo was not found on the creature');
'The prop\'s ammo was not found on the creature');
}
if (!item.equipped){
throw new Meteor.Error('Ammo not equipped',
@@ -35,19 +37,36 @@ export default function spendResources(action){
operation: 'increment',
value: itemConsumed.quantity,
});
let logName = item.name;
if (itemConsumed.quantity > 1 || itemConsumed.quantity < -1){
logName = item.plural || logName;
}
if (itemConsumed.quantity > 0){
spendLog.push(logName + ': ' + itemConsumed.quantity);
} else if (itemConsumed.quantity < 0){
gainLog.push(logName + ': ' + -itemConsumed.quantity);
}
});
// No more errors should be thrown after this line
// Now that we have confirmed that there are no errors, do actual work
//Items
itemQuantityAdjustments.forEach(adjustQuantityWork);
// Use uses
CreatureProperties.update(action._id, {
$inc: {usesUsed: 1}
}, {
selector: action
});
if (prop.usesResult){
CreatureProperties.update(prop._id, {
$inc: {usesUsed: 1}
}, {
selector: prop
});
log.content.push({
name: 'Uses left',
result: prop.usesResult - prop.usesUsed - 1,
});
}
// Damage stats
action.resources.attributesConsumed.forEach(attConsumed => {
prop.resources.attributesConsumed.forEach(attConsumed => {
if (!attConsumed.quantity) return;
let stat = CreatureProperties.findOne(attConsumed.statId);
damagePropertyWork({
@@ -55,5 +74,20 @@ export default function spendResources(action){
operation: 'increment',
value: attConsumed.quantity,
});
if (attConsumed.quantity > 0){
spendLog.push(stat.name + ': ' + attConsumed.quantity);
} else if (attConsumed.quantity < 0){
gainLog.push(stat.name + ': ' + -attConsumed.quantity);
}
});
// Log all the spending
if (gainLog.length) log.content.push({
name: 'Gained',
description: gainLog.join('\n'),
});
if (spendLog.length) log.content.push({
name: 'Spent',
description: spendLog.join('\n'),
});
}

View File

@@ -18,13 +18,10 @@ if (Meteor.isServer){
let CreatureLogs = new Mongo.Collection('creatureLogs');
let CreatureLogSchema = new SimpleSchema({
name: {
type: String,
optional: true,
},
content: {
type: Array,
defaultValue: [],
maxCount: 25,
},
'content.$': {
type: LogContentSchema,
@@ -68,11 +65,45 @@ function removeOldLogs(creatureId){
});
}
function logToMessageData(log){
let embed = {
fields: [],
};
log.content.forEach(c => {
let field = {};
let descriptionField = {};
if (c.name) field.name = c.name;
let valueArray = [];
if (c.error) valueArray.push(`*${c.error}*`);
if (c.resultPrefix) valueArray.push(`${c.resultPrefix}`);
if (c.result) valueArray.push(`\`${c.result}\``);
if (c.details) valueArray.push(c.details);
if (valueArray.length) field.value = valueArray.join(' ');
if (c.description){
if (!field.value){
field.value = c.description;
} else {
descriptionField.value = c.description;
}
}
if (field.name || field.value){
if (!field.name) field.name = '\u200b';
if (!field.value) field.value = '\u200b';
embed.fields.push(field);
}
if (descriptionField.value){
descriptionField.name = '\u200b';
embed.fields.push(descriptionField);
}
});
return { embeds: [embed] };
}
function logWebhook({log, creature}){
if (Meteor.isServer){
sendWebhookAsCreature({
creature,
content: log.text,
data: logToMessageData(log),
});
}
}

View File

@@ -1,27 +1,25 @@
import Discord from 'discord.js'
export default function sendWebhook({webhookURL, message, options}){
export default function sendWebhook({webhookURL, data = {}}){
//webhookURL = https://discordapp.com/api/webhooks/<id>/<token>
let urlArray = webhookURL.split('/');
let token = urlArray.pop();
let id = urlArray.pop();
// prevent discord mention exploit
options.disableMentions = 'all';
data.disableMentions = 'all';
const hook = new Discord.WebhookClient(id, token);
// Send a message using the webhook
hook.send(message, options)
console.log(JSON.stringify(data, null, 2));
hook.send(data);
}
export function sendWebhookAsCreature({creature, content, embeds}){
export function sendWebhookAsCreature({creature, data = {}}){
if (!creature || !creature.settings || !creature.settings.discordWebhook) return;
data.username = creature.name;
data.avatarURL = creature.avatarPicture;
sendWebhook({
webhookURL: creature.settings.discordWebhook,
message: content,
options: {
username: creature.name,
avatarURL: creature.avatarPicture,
embeds,
},
data,
});
}

View File

@@ -1,26 +1,19 @@
<template lang="html">
<v-card
class="ma-2"
class="ma-2 log-entry"
>
<v-card-title
v-if="model.name"
class="pa-2"
>
<h3>
{{ model.name }}
</h3>
</v-card-title>
<v-card-text
v-if="model.text || (model.content && model.content.length)"
class="pa-2"
>
{{ model.text }}
<div
v-for="(content, index) in model.content"
:key="index"
class="content-line"
>
{{ content.name }}
<h4>
{{ content.name }}
</h4>
<span
v-if="content.error"
class="error"
@@ -35,7 +28,7 @@
>{{ content.details }}</span>
<markdown-text
v-if="content.description"
class="details"
class="description"
:markdown="content.description"
/>
</div>
@@ -69,3 +62,9 @@ export default {
display: inline-block;
}
</style>
<style lang="css">
.log-entry .description > p:last-of-type{
margin-bottom: 0;
}
</style>