Implemented queueing system for rollWorker to limit number of concurrent workers
Moved some consts to the config.ts file Added flag to disable logging while rolling for a massive speed increase and to increase stability of the bot
This commit is contained in:
parent
b58cf31edb
commit
bb10d52506
|
@ -5,6 +5,11 @@ export const config = {
|
||||||
"localtoken": "local_testing_token", // Discord API Token for a secondary OPTIONAL testing bot, THIS MUST BE DIFFERENT FROM "token"
|
"localtoken": "local_testing_token", // Discord API Token for a secondary OPTIONAL testing bot, THIS MUST BE DIFFERENT FROM "token"
|
||||||
"prefix": "[[", // Prefix for all commands
|
"prefix": "[[", // Prefix for all commands
|
||||||
"postfix": "]]", // Postfix for rolling command
|
"postfix": "]]", // Postfix for rolling command
|
||||||
|
"limits": { // Limits for the bot functions
|
||||||
|
"maxLoops": 5000000, // Determines how long the bot will attempt a roll, number of loops before it kills a roll. Increase this at your own risk
|
||||||
|
"maxWorkers": 16, // Maximum number of worker threads to spawn at once (Set this to less than the number of threads your CPU has, Artificer will eat it all if too many rolls happen at once)
|
||||||
|
"workerTimeout": 300000 // Maximum time before the bot kills a worker thread in ms
|
||||||
|
},
|
||||||
"api": { // Setting for the built-in API
|
"api": { // Setting for the built-in API
|
||||||
"enable": false, // Leave this off if you have no intention of using this/supporting it
|
"enable": false, // Leave this off if you have no intention of using this/supporting it
|
||||||
"port": 8080, // Port for the API to listen on
|
"port": 8080, // Port for the API to listen on
|
||||||
|
|
|
@ -268,7 +268,7 @@ ${details}`,
|
||||||
details = 'Details have been ommitted from this message for being over 2000 characters.';
|
details = 'Details have been ommitted from this message for being over 2000 characters.';
|
||||||
if (b.size > 8388290) {
|
if (b.size > 8388290) {
|
||||||
details +=
|
details +=
|
||||||
'Full details could not be attached to this messaged as a \`.txt\` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one.';
|
'\n\nFull details could not be attached to this messaged as a \`.txt\` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one.';
|
||||||
return {
|
return {
|
||||||
embed: {
|
embed: {
|
||||||
color: infoColor2,
|
color: infoColor2,
|
||||||
|
@ -283,7 +283,7 @@ ${details}`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
details += 'Full details have been attached to this messaged as a \`.txt\` file for verification purposes.';
|
details += '\n\nFull details have been attached to this messaged as a \`.txt\` file for verification purposes.';
|
||||||
return {
|
return {
|
||||||
embed: {
|
embed: {
|
||||||
color: infoColor2,
|
color: infoColor2,
|
||||||
|
|
|
@ -11,10 +11,150 @@ import {
|
||||||
sendDirectMessage,
|
sendDirectMessage,
|
||||||
} from '../../deps.ts';
|
} from '../../deps.ts';
|
||||||
import { SolvedRoll } from '../solver/solver.d.ts';
|
import { SolvedRoll } from '../solver/solver.d.ts';
|
||||||
import { RollModifiers } from '../mod.d.ts';
|
import { QueuedRoll, RollModifiers } from '../mod.d.ts';
|
||||||
import { generateCountDetailsEmbed, generateDMFailed, generateRollEmbed, infoColor1, warnColor } from '../commandUtils.ts';
|
import { generateCountDetailsEmbed, generateDMFailed, generateRollEmbed, infoColor1, infoColor2, warnColor } from '../commandUtils.ts';
|
||||||
import rollFuncs from './roll/_index.ts';
|
import rollFuncs from './roll/_index.ts';
|
||||||
|
|
||||||
|
let currentWorkers = 0;
|
||||||
|
const rollQueue: Array<QueuedRoll> = [];
|
||||||
|
|
||||||
|
const rollingEmbed = {
|
||||||
|
embeds: [{
|
||||||
|
color: infoColor1,
|
||||||
|
title: 'Rolling . . .',
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle setting up and calling the rollWorker
|
||||||
|
const handleRollWorker = async (m: DiscordenoMessage, message: DiscordenoMessage, originalCommand: String, rollCmd: String, modifiers: RollModifiers) => {
|
||||||
|
currentWorkers++;
|
||||||
|
|
||||||
|
// gmModifiers used to create gmEmbed (basically just turn off the gmRoll)
|
||||||
|
const gmModifiers = JSON.parse(JSON.stringify(modifiers));
|
||||||
|
gmModifiers.gmRoll = false;
|
||||||
|
|
||||||
|
const rollWorker = new Worker(new URL('../solver/rollWorker.ts', import.meta.url).href, { type: 'module' });
|
||||||
|
|
||||||
|
const workerTimeout = setTimeout(async () => {
|
||||||
|
rollWorker.terminate();
|
||||||
|
currentWorkers--;
|
||||||
|
m.edit({
|
||||||
|
embeds: [
|
||||||
|
(await generateRollEmbed(
|
||||||
|
message.authorId,
|
||||||
|
<SolvedRoll> {
|
||||||
|
error: true,
|
||||||
|
errorCode: 'TooComplex',
|
||||||
|
errorMsg: 'Error: Roll took too long to process, try breaking roll down into simpler parts',
|
||||||
|
},
|
||||||
|
<RollModifiers> {},
|
||||||
|
)).embed,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}, config.limits.workerTimeout);
|
||||||
|
|
||||||
|
rollWorker.postMessage({
|
||||||
|
rollCmd,
|
||||||
|
modifiers,
|
||||||
|
});
|
||||||
|
|
||||||
|
rollWorker.addEventListener('message', async (workerMessage) => {
|
||||||
|
try {
|
||||||
|
currentWorkers--;
|
||||||
|
clearTimeout(workerTimeout);
|
||||||
|
const returnmsg = workerMessage.data;
|
||||||
|
const pubEmbedDetails = await generateRollEmbed(message.authorId, returnmsg, modifiers);
|
||||||
|
const gmEmbedDetails = await generateRollEmbed(message.authorId, returnmsg, gmModifiers);
|
||||||
|
const countEmbed = generateCountDetailsEmbed(returnmsg.counts);
|
||||||
|
|
||||||
|
// If there was an error, report it to the user in hopes that they can determine what they did wrong
|
||||||
|
if (returnmsg.error) {
|
||||||
|
m.edit({ embeds: [pubEmbedDetails.embed] });
|
||||||
|
|
||||||
|
if (DEVMODE && config.logRolls) {
|
||||||
|
// If enabled, log rolls so we can see what went wrong
|
||||||
|
dbClient.execute(queries.insertRollLogCmd(0, 1), [originalCommand, returnmsg.errorCode, m.id]).catch((e) => {
|
||||||
|
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Determine if we are to send a GM roll or a normal roll
|
||||||
|
if (modifiers.gmRoll) {
|
||||||
|
// Send the public embed to correct channel
|
||||||
|
m.edit({ embeds: [pubEmbedDetails.embed] });
|
||||||
|
|
||||||
|
// And message the full details to each of the GMs, alerting roller of every GM that could not be messaged
|
||||||
|
modifiers.gms.forEach(async (gm) => {
|
||||||
|
log(LT.LOG, `Messaging GM ${gm}`);
|
||||||
|
// Attempt to DM the GM and send a warning if it could not DM a GM
|
||||||
|
await sendDirectMessage(BigInt(gm.substring(2, gm.length - 1)), {
|
||||||
|
embeds: modifiers.count ? [gmEmbedDetails.embed, countEmbed] : [gmEmbedDetails.embed],
|
||||||
|
}).then(async () => {
|
||||||
|
// Check if we need to attach a file and send it after the initial details sent
|
||||||
|
if (gmEmbedDetails.hasAttachment) {
|
||||||
|
await sendDirectMessage(BigInt(gm.substring(2, gm.length - 1)), {
|
||||||
|
file: gmEmbedDetails.attachment,
|
||||||
|
}).catch(() => {
|
||||||
|
message.reply(generateDMFailed(gm));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
message.reply(generateDMFailed(gm));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Not a gm roll, so just send normal embed to correct channel
|
||||||
|
const n = await m.edit({
|
||||||
|
embeds: modifiers.count ? [pubEmbedDetails.embed, countEmbed] : [pubEmbedDetails.embed],
|
||||||
|
});
|
||||||
|
if (pubEmbedDetails.hasAttachment) {
|
||||||
|
// Attachment requires you to send a new message
|
||||||
|
n.reply({
|
||||||
|
file: pubEmbedDetails.attachment,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log(LT.ERROR, `Unddandled Error: ${JSON.stringify(e)}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Runs the roll or queues it depending on how many workers are currently running
|
||||||
|
const queueRoll = async (m: DiscordenoMessage, message: DiscordenoMessage, originalCommand: String, rollCmd: String, modifiers: RollModifiers) => {
|
||||||
|
if (!rollQueue.length && currentWorkers < config.limits.maxWorkers) {
|
||||||
|
handleRollWorker(m, message, originalCommand, rollCmd, modifiers);
|
||||||
|
} else {
|
||||||
|
m.edit({
|
||||||
|
embeds: [{
|
||||||
|
color: infoColor2,
|
||||||
|
title: `${config.name} currently has its hands full and has queued your roll.`,
|
||||||
|
description: `There are currently ${currentWorkers + rollQueue.length} rolls ahead of this roll.
|
||||||
|
|
||||||
|
The results for this roll will replace this message when it is done.`,
|
||||||
|
}],
|
||||||
|
}).catch((e) => {
|
||||||
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(m)} | ${JSON.stringify(e)}`);
|
||||||
|
});
|
||||||
|
rollQueue.push({ m, message, originalCommand, rollCmd, modifiers });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Checks the queue constantly to make sure the queue stays empty
|
||||||
|
setInterval(async () => {
|
||||||
|
log(LT.LOG, `Checking rollQueue for items, rollQueue length: ${rollQueue.length}, currentWorkers: ${currentWorkers}, config.limits.maxWorkers: ${config.limits.maxWorkers}`);
|
||||||
|
if (rollQueue.length && currentWorkers < config.limits.maxWorkers) {
|
||||||
|
const temp = rollQueue.shift();
|
||||||
|
if (temp) {
|
||||||
|
temp.m.edit(rollingEmbed).catch((e) => {
|
||||||
|
log(LT.ERROR, `Failed to send message: ${JSON.stringify(temp.m)} | ${JSON.stringify(e)}`);
|
||||||
|
});
|
||||||
|
handleRollWorker(temp.m, temp.message, temp.originalCommand, temp.rollCmd, temp.modifiers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
export const roll = async (message: DiscordenoMessage, args: string[], command: string) => {
|
export const roll = async (message: DiscordenoMessage, args: string[], command: string) => {
|
||||||
// Light telemetry to see how many times a command is being run
|
// Light telemetry to see how many times a command is being run
|
||||||
dbClient.execute(`CALL INC_CNT("roll");`).catch((e) => {
|
dbClient.execute(`CALL INC_CNT("roll");`).catch((e) => {
|
||||||
|
@ -38,20 +178,11 @@ export const roll = async (message: DiscordenoMessage, args: string[], command:
|
||||||
try {
|
try {
|
||||||
const originalCommand = `${config.prefix}${command} ${args.join(' ')}`;
|
const originalCommand = `${config.prefix}${command} ${args.join(' ')}`;
|
||||||
|
|
||||||
const m = await message.reply({
|
const m = await message.reply(rollingEmbed);
|
||||||
embeds: [{
|
|
||||||
color: infoColor1,
|
|
||||||
title: 'Rolling . . .',
|
|
||||||
}],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Get modifiers from command
|
// Get modifiers from command
|
||||||
const modifiers = rollFuncs.getModifiers(m, args, command, originalCommand);
|
const modifiers = rollFuncs.getModifiers(m, args, command, originalCommand);
|
||||||
|
|
||||||
// gmModifiers used to create gmEmbed (basically just turn off the gmRoll)
|
|
||||||
const gmModifiers = JSON.parse(JSON.stringify(modifiers));
|
|
||||||
gmModifiers.gmRoll = false;
|
|
||||||
|
|
||||||
// Return early if the modifiers were invalid
|
// Return early if the modifiers were invalid
|
||||||
if (!modifiers.valid) {
|
if (!modifiers.valid) {
|
||||||
return;
|
return;
|
||||||
|
@ -59,92 +190,8 @@ export const roll = async (message: DiscordenoMessage, args: string[], command:
|
||||||
|
|
||||||
// Rejoin all of the args and send it into the solver, if solver returns a falsy item, an error object will be substituded in
|
// Rejoin all of the args and send it into the solver, if solver returns a falsy item, an error object will be substituded in
|
||||||
const rollCmd = `${command} ${args.join(' ')}`;
|
const rollCmd = `${command} ${args.join(' ')}`;
|
||||||
// const returnmsg = solver.parseRoll(rollCmd, modifiers) || <SolvedRoll>{ error: true, errorCode: 'EmptyMessage', errorMsg: 'Error: Empty message' };
|
|
||||||
|
|
||||||
const rollWorker = new Worker(new URL('../solver/rollWorker.ts', import.meta.url).href, { type: 'module' });
|
queueRoll(m, message, originalCommand, rollCmd, modifiers);
|
||||||
|
|
||||||
const workerTimeout = setTimeout(async () => {
|
|
||||||
rollWorker.terminate();
|
|
||||||
m.edit({
|
|
||||||
embeds: [
|
|
||||||
(await generateRollEmbed(
|
|
||||||
message.authorId,
|
|
||||||
<SolvedRoll> {
|
|
||||||
error: true,
|
|
||||||
errorCode: 'TooComplex',
|
|
||||||
errorMsg: 'Error: Roll Too Complex, try breaking roll down into simpler parts',
|
|
||||||
},
|
|
||||||
<RollModifiers> {},
|
|
||||||
)).embed,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}, 60000);
|
|
||||||
|
|
||||||
rollWorker.postMessage({
|
|
||||||
rollCmd,
|
|
||||||
modifiers,
|
|
||||||
});
|
|
||||||
|
|
||||||
rollWorker.addEventListener('message', async (workerMessage) => {
|
|
||||||
try {
|
|
||||||
clearTimeout(workerTimeout);
|
|
||||||
const returnmsg = workerMessage.data;
|
|
||||||
const pubEmbedDetails = await generateRollEmbed(message.authorId, returnmsg, modifiers);
|
|
||||||
const gmEmbedDetails = await generateRollEmbed(message.authorId, returnmsg, gmModifiers);
|
|
||||||
const countEmbed = generateCountDetailsEmbed(returnmsg.counts);
|
|
||||||
|
|
||||||
// If there was an error, report it to the user in hopes that they can determine what they did wrong
|
|
||||||
if (returnmsg.error) {
|
|
||||||
m.edit({ embeds: [pubEmbedDetails.embed] });
|
|
||||||
|
|
||||||
if (DEVMODE && config.logRolls) {
|
|
||||||
// If enabled, log rolls so we can see what went wrong
|
|
||||||
dbClient.execute(queries.insertRollLogCmd(0, 1), [originalCommand, returnmsg.errorCode, m.id]).catch((e) => {
|
|
||||||
log(LT.ERROR, `Failed to insert into DB: ${JSON.stringify(e)}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Determine if we are to send a GM roll or a normal roll
|
|
||||||
if (modifiers.gmRoll) {
|
|
||||||
// Send the public embed to correct channel
|
|
||||||
m.edit({ embeds: [pubEmbedDetails.embed] });
|
|
||||||
|
|
||||||
// And message the full details to each of the GMs, alerting roller of every GM that could not be messaged
|
|
||||||
modifiers.gms.forEach(async (gm) => {
|
|
||||||
log(LT.LOG, `Messaging GM ${gm}`);
|
|
||||||
// Attempt to DM the GM and send a warning if it could not DM a GM
|
|
||||||
await sendDirectMessage(BigInt(gm.substring(2, gm.length - 1)), {
|
|
||||||
embeds: modifiers.count ? [gmEmbedDetails.embed, countEmbed] : [gmEmbedDetails.embed],
|
|
||||||
}).then(async () => {
|
|
||||||
// Check if we need to attach a file and send it after the initial details sent
|
|
||||||
if (gmEmbedDetails.hasAttachment) {
|
|
||||||
await sendDirectMessage(BigInt(gm.substring(2, gm.length - 1)), {
|
|
||||||
file: gmEmbedDetails.attachment,
|
|
||||||
}).catch(() => {
|
|
||||||
message.reply(generateDMFailed(gm));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
message.reply(generateDMFailed(gm));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Not a gm roll, so just send normal embed to correct channel
|
|
||||||
const n = await m.edit({
|
|
||||||
embeds: modifiers.count ? [pubEmbedDetails.embed, countEmbed] : [pubEmbedDetails.embed],
|
|
||||||
});
|
|
||||||
if (pubEmbedDetails.hasAttachment) {
|
|
||||||
// Attachment requires you to send a new message
|
|
||||||
n.reply({
|
|
||||||
file: pubEmbedDetails.attachment,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
log(LT.ERROR, `Unddandled Error: ${JSON.stringify(e)}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(LT.ERROR, `Undandled Error: ${JSON.stringify(e)}`);
|
log(LT.ERROR, `Undandled Error: ${JSON.stringify(e)}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// mod.d.ts custom types
|
// mod.d.ts custom types
|
||||||
|
import { DiscordenoMessage } from '../deps.ts';
|
||||||
|
|
||||||
// EmojiConf is used as a structure for the emojis stored in config.ts
|
// EmojiConf is used as a structure for the emojis stored in config.ts
|
||||||
export type EmojiConf = {
|
export type EmojiConf = {
|
||||||
|
@ -22,3 +23,12 @@ export type RollModifiers = {
|
||||||
valid: boolean;
|
valid: boolean;
|
||||||
count: boolean;
|
count: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// QueuedRoll is the structure to track rolls we could not immediately handle
|
||||||
|
export type QueuedRoll = {
|
||||||
|
m: DiscordenoMessage;
|
||||||
|
message: DiscordenoMessage;
|
||||||
|
originalCommand: String;
|
||||||
|
rollCmd: String;
|
||||||
|
modifiers: RollModifiers;
|
||||||
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@ import config from '../../config.ts';
|
||||||
|
|
||||||
import { RollModifiers } from '../mod.d.ts';
|
import { RollModifiers } from '../mod.d.ts';
|
||||||
import { CountDetails, ReturnData, SolvedRoll, SolvedStep } from './solver.d.ts';
|
import { CountDetails, ReturnData, SolvedRoll, SolvedStep } from './solver.d.ts';
|
||||||
import { compareTotalRolls, escapeCharacters } from './rollUtils.ts';
|
import { compareTotalRolls, escapeCharacters, loggingEnabled } from './rollUtils.ts';
|
||||||
import { formatRoll } from './rollFormatter.ts';
|
import { formatRoll } from './rollFormatter.ts';
|
||||||
import { fullSolver } from './solver.ts';
|
import { fullSolver } from './solver.ts';
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
|
||||||
|
|
||||||
// Loop thru all roll/math ops
|
// Loop thru all roll/math ops
|
||||||
for (const sepRoll of sepRolls) {
|
for (const sepRoll of sepRolls) {
|
||||||
log(LT.LOG, `Parsing roll ${fullCmd} | Working ${sepRoll}`);
|
loggingEnabled && log(LT.LOG, `Parsing roll ${fullCmd} | Working ${sepRoll}`);
|
||||||
// Split the current iteration on the command postfix to separate the operation to be parsed and the text formatting after the opertaion
|
// Split the current iteration on the command postfix to separate the operation to be parsed and the text formatting after the opertaion
|
||||||
const [tempConf, tempFormat] = sepRoll.split(config.postfix);
|
const [tempConf, tempFormat] = sepRoll.split(config.postfix);
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
|
||||||
// Verify there are equal numbers of opening and closing parenthesis by adding 1 for opening parens and subtracting 1 for closing parens
|
// Verify there are equal numbers of opening and closing parenthesis by adding 1 for opening parens and subtracting 1 for closing parens
|
||||||
let parenCnt = 0;
|
let parenCnt = 0;
|
||||||
mathConf.forEach((e) => {
|
mathConf.forEach((e) => {
|
||||||
log(LT.LOG, `Parsing roll ${fullCmd} | Checking parenthesis balance ${e}`);
|
loggingEnabled && log(LT.LOG, `Parsing roll ${fullCmd} | Checking parenthesis balance ${e}`);
|
||||||
if (e === '(') {
|
if (e === '(') {
|
||||||
parenCnt++;
|
parenCnt++;
|
||||||
} else if (e === ')') {
|
} else if (e === ')') {
|
||||||
|
@ -74,7 +74,7 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
|
||||||
|
|
||||||
// Evaluate all rolls into stepSolve format and all numbers into floats
|
// Evaluate all rolls into stepSolve format and all numbers into floats
|
||||||
for (let i = 0; i < mathConf.length; i++) {
|
for (let i = 0; i < mathConf.length; i++) {
|
||||||
log(LT.LOG, `Parsing roll ${fullCmd} | Evaluating rolls into mathable items ${JSON.stringify(mathConf[i])}`);
|
loggingEnabled && log(LT.LOG, `Parsing roll ${fullCmd} | Evaluating rolls into mathable items ${JSON.stringify(mathConf[i])}`);
|
||||||
if (mathConf[i].toString().length === 0) {
|
if (mathConf[i].toString().length === 0) {
|
||||||
// If its an empty string, get it out of here
|
// If its an empty string, get it out of here
|
||||||
mathConf.splice(i, 1);
|
mathConf.splice(i, 1);
|
||||||
|
@ -198,7 +198,7 @@ export const parseRoll = (fullCmd: string, modifiers: RollModifiers): SolvedRoll
|
||||||
|
|
||||||
// Fill out all of the details and results now
|
// Fill out all of the details and results now
|
||||||
tempReturnData.forEach((e) => {
|
tempReturnData.forEach((e) => {
|
||||||
log(LT.LOG, `Parsing roll ${fullCmd} | Making return text ${JSON.stringify(e)}`);
|
loggingEnabled && log(LT.LOG, `Parsing roll ${fullCmd} | Making return text ${JSON.stringify(e)}`);
|
||||||
let preFormat = '';
|
let preFormat = '';
|
||||||
let postFormat = '';
|
let postFormat = '';
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
import { roll } from './roller.ts';
|
import { roll } from './roller.ts';
|
||||||
import { rollCounter } from './counter.ts';
|
import { rollCounter } from './counter.ts';
|
||||||
import { RollFormat } from './solver.d.ts';
|
import { RollFormat } from './solver.d.ts';
|
||||||
|
import { loggingEnabled } from './rollUtils.ts';
|
||||||
|
|
||||||
// formatRoll(rollConf, maximiseRoll, nominalRoll) returns one SolvedStep
|
// formatRoll(rollConf, maximiseRoll, nominalRoll) returns one SolvedStep
|
||||||
// formatRoll handles creating and formatting the completed rolls into the SolvedStep format
|
// formatRoll handles creating and formatting the completed rolls into the SolvedStep format
|
||||||
|
@ -21,7 +22,7 @@ export const formatRoll = (rollConf: string, maximiseRoll: boolean, nominalRoll:
|
||||||
|
|
||||||
// Loop thru all parts of the roll to document everything that was done to create the total roll
|
// Loop thru all parts of the roll to document everything that was done to create the total roll
|
||||||
tempRollSet.forEach((e) => {
|
tempRollSet.forEach((e) => {
|
||||||
log(LT.LOG, `Formatting roll ${rollConf} | ${JSON.stringify(e)}`);
|
loggingEnabled && log(LT.LOG, `Formatting roll ${rollConf} | ${JSON.stringify(e)}`);
|
||||||
let preFormat = '';
|
let preFormat = '';
|
||||||
let postFormat = '';
|
let postFormat = '';
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,7 @@ import {
|
||||||
|
|
||||||
import { ReturnData, RollSet } from './solver.d.ts';
|
import { ReturnData, RollSet } from './solver.d.ts';
|
||||||
|
|
||||||
// MAXLOOPS determines how long the bot will attempt a roll
|
export const loggingEnabled = false;
|
||||||
// Default is 5000000 (5 million), which results in at most a 10 second delay before the bot calls the roll infinite or too complex
|
|
||||||
// Increase at your own risk
|
|
||||||
export const MAXLOOPS = 5000000;
|
|
||||||
|
|
||||||
// genRoll(size) returns number
|
// genRoll(size) returns number
|
||||||
// genRoll rolls a die of size size and returns the result
|
// genRoll rolls a die of size size and returns the result
|
||||||
|
@ -63,7 +60,7 @@ export const compareOrigidx = (a: RollSet, b: RollSet): number => {
|
||||||
export const escapeCharacters = (str: string, esc: string): string => {
|
export const escapeCharacters = (str: string, esc: string): string => {
|
||||||
// Loop thru each esc char one at a time
|
// Loop thru each esc char one at a time
|
||||||
for (const e of esc) {
|
for (const e of esc) {
|
||||||
log(LT.LOG, `Escaping character ${e} | ${str}, ${esc}`);
|
loggingEnabled && log(LT.LOG, `Escaping character ${e} | ${str}, ${esc}`);
|
||||||
// Create a new regex to look for that char that needs replaced and escape it
|
// Create a new regex to look for that char that needs replaced and escape it
|
||||||
const temprgx = new RegExp(`[${e}]`, 'g');
|
const temprgx = new RegExp(`[${e}]`, 'g');
|
||||||
str = str.replace(temprgx, `\\${e}`);
|
str = str.replace(temprgx, `\\${e}`);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import config from '../../config.ts';
|
||||||
import {
|
import {
|
||||||
log,
|
log,
|
||||||
// Log4Deno deps
|
// Log4Deno deps
|
||||||
|
@ -5,7 +6,7 @@ import {
|
||||||
} from '../../deps.ts';
|
} from '../../deps.ts';
|
||||||
|
|
||||||
import { RollSet } from './solver.d.ts';
|
import { RollSet } from './solver.d.ts';
|
||||||
import { compareOrigidx, compareRolls, genRoll, MAXLOOPS } from './rollUtils.ts';
|
import { compareOrigidx, compareRolls, genRoll, loggingEnabled } from './rollUtils.ts';
|
||||||
|
|
||||||
// roll(rollStr, maximiseRoll, nominalRoll) returns RollSet
|
// roll(rollStr, maximiseRoll, nominalRoll) returns RollSet
|
||||||
// roll parses and executes the rollStr, if needed it will also make the roll the maximum or average
|
// roll parses and executes the rollStr, if needed it will also make the roll the maximum or average
|
||||||
|
@ -87,8 +88,8 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
throw new Error('YouNeedAD');
|
throw new Error('YouNeedAD');
|
||||||
}
|
}
|
||||||
|
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Parsed Die Count: ${rollConf.dieCount}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsed Die Count: ${rollConf.dieCount}`);
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Parsed Die Size: ${rollConf.dieSize}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsed Die Size: ${rollConf.dieSize}`);
|
||||||
|
|
||||||
// Finish parsing the roll
|
// Finish parsing the roll
|
||||||
if (remains.length > 0) {
|
if (remains.length > 0) {
|
||||||
|
@ -99,7 +100,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
|
|
||||||
// Loop until all remaining args are parsed
|
// Loop until all remaining args are parsed
|
||||||
while (remains.length > 0) {
|
while (remains.length > 0) {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Parsing remains ${remains}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing remains ${remains}`);
|
||||||
// Find the next number in the remains to be able to cut out the rule name
|
// Find the next number in the remains to be able to cut out the rule name
|
||||||
let afterSepIdx = remains.search(/\d/);
|
let afterSepIdx = remains.search(/\d/);
|
||||||
if (afterSepIdx < 0) {
|
if (afterSepIdx < 0) {
|
||||||
|
@ -157,7 +158,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
// Configure reroll for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure reroll for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.reroll.on = true;
|
rollConf.reroll.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Parsing r> ${i}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing r> ${i}`);
|
||||||
rollConf.reroll.nums.push(i);
|
rollConf.reroll.nums.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -168,7 +169,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
// Configure reroll for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure reroll for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.reroll.on = true;
|
rollConf.reroll.on = true;
|
||||||
for (let i = 1; i <= tNum; i++) {
|
for (let i = 1; i <= tNum; i++) {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Parsing r< ${i}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing r< ${i}`);
|
||||||
rollConf.reroll.nums.push(i);
|
rollConf.reroll.nums.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -182,7 +183,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
// Configure CritScore for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritScore for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critScore.on = true;
|
rollConf.critScore.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Parsing cs> ${i}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing cs> ${i}`);
|
||||||
rollConf.critScore.range.push(i);
|
rollConf.critScore.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -190,7 +191,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
// Configure CritScore for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritScore for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critScore.on = true;
|
rollConf.critScore.on = true;
|
||||||
for (let i = 0; i <= tNum; i++) {
|
for (let i = 0; i <= tNum; i++) {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Parsing cs< ${i}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing cs< ${i}`);
|
||||||
rollConf.critScore.range.push(i);
|
rollConf.critScore.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -204,7 +205,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
// Configure CritFail for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritFail for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critFail.on = true;
|
rollConf.critFail.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Parsing cf> ${i}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing cf> ${i}`);
|
||||||
rollConf.critFail.range.push(i);
|
rollConf.critFail.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -212,7 +213,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
// Configure CritFail for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritFail for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critFail.on = true;
|
rollConf.critFail.on = true;
|
||||||
for (let i = 0; i <= tNum; i++) {
|
for (let i = 0; i <= tNum; i++) {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Parsing cf< ${i}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing cf< ${i}`);
|
||||||
rollConf.critFail.range.push(i);
|
rollConf.critFail.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -245,7 +246,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
// Configure Exploding for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure Exploding for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.exploding.on = true;
|
rollConf.exploding.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Parsing !> ${i}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing !> ${i}`);
|
||||||
rollConf.exploding.nums.push(i);
|
rollConf.exploding.nums.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -256,7 +257,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
// Configure Exploding for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure Exploding for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.exploding.on = true;
|
rollConf.exploding.on = true;
|
||||||
for (let i = 1; i <= tNum; i++) {
|
for (let i = 1; i <= tNum; i++) {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Parsing !< ${i}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Parsing !< ${i}`);
|
||||||
rollConf.exploding.nums.push(i);
|
rollConf.exploding.nums.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -279,7 +280,7 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
// Since only one drop or keep option can be active, count how many are active to throw the right error
|
// Since only one drop or keep option can be active, count how many are active to throw the right error
|
||||||
let dkdkCnt = 0;
|
let dkdkCnt = 0;
|
||||||
[rollConf.drop.on, rollConf.keep.on, rollConf.dropHigh.on, rollConf.keepLow.on].forEach((e) => {
|
[rollConf.drop.on, rollConf.keep.on, rollConf.dropHigh.on, rollConf.keepLow.on].forEach((e) => {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Checking if drop/keep is on ${e}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Checking if drop/keep is on ${e}`);
|
||||||
if (e) {
|
if (e) {
|
||||||
dkdkCnt++;
|
dkdkCnt++;
|
||||||
}
|
}
|
||||||
|
@ -344,9 +345,9 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
|
|
||||||
// Initial rolling, not handling reroll or exploding here
|
// Initial rolling, not handling reroll or exploding here
|
||||||
for (let i = 0; i < rollConf.dieCount; i++) {
|
for (let i = 0; i < rollConf.dieCount; i++) {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Initial rolling ${i} of ${JSON.stringify(rollConf)}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Initial rolling ${i} of ${JSON.stringify(rollConf)}`);
|
||||||
// If loopCount gets too high, stop trying to calculate infinity
|
// If loopCount gets too high, stop trying to calculate infinity
|
||||||
if (loopCount > MAXLOOPS) {
|
if (loopCount > config.limits.maxLoops) {
|
||||||
throw new Error('MaxLoopsExceeded');
|
throw new Error('MaxLoopsExceeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,9 +379,9 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
// If needed, handle rerolling and exploding dice now
|
// If needed, handle rerolling and exploding dice now
|
||||||
if (rollConf.reroll.on || rollConf.exploding.on) {
|
if (rollConf.reroll.on || rollConf.exploding.on) {
|
||||||
for (let i = 0; i < rollSet.length; i++) {
|
for (let i = 0; i < rollSet.length; i++) {
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Handling rerolling and exploding ${JSON.stringify(rollSet[i])}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Handling rerolling and exploding ${JSON.stringify(rollSet[i])}`);
|
||||||
// If loopCount gets too high, stop trying to calculate infinity
|
// If loopCount gets too high, stop trying to calculate infinity
|
||||||
if (loopCount > MAXLOOPS) {
|
if (loopCount > config.limits.maxLoops) {
|
||||||
throw new Error('MaxLoopsExceeded');
|
throw new Error('MaxLoopsExceeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,11 +452,11 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
if (rollConf.reroll.on) {
|
if (rollConf.reroll.on) {
|
||||||
for (let j = 0; j < rollSet.length; j++) {
|
for (let j = 0; j < rollSet.length; j++) {
|
||||||
// If loopCount gets too high, stop trying to calculate infinity
|
// If loopCount gets too high, stop trying to calculate infinity
|
||||||
if (loopCount > MAXLOOPS) {
|
if (loopCount > config.limits.maxLoops) {
|
||||||
throw new Error('MaxLoopsExceeded');
|
throw new Error('MaxLoopsExceeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Setting originalIdx on ${JSON.stringify(rollSet[j])}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Setting originalIdx on ${JSON.stringify(rollSet[j])}`);
|
||||||
rollSet[j].origidx = j;
|
rollSet[j].origidx = j;
|
||||||
|
|
||||||
if (rollSet[j].rerolled) {
|
if (rollSet[j].rerolled) {
|
||||||
|
@ -505,11 +506,11 @@ export const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (dropCount > 0 && i < rollSet.length) {
|
while (dropCount > 0 && i < rollSet.length) {
|
||||||
// If loopCount gets too high, stop trying to calculate infinity
|
// If loopCount gets too high, stop trying to calculate infinity
|
||||||
if (loopCount > MAXLOOPS) {
|
if (loopCount > config.limits.maxLoops) {
|
||||||
throw new Error('MaxLoopsExceeded');
|
throw new Error('MaxLoopsExceeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
log(LT.LOG, `Handling roll ${rollStr} | Dropping dice ${dropCount} ${JSON.stringify(rollSet[i])}`);
|
loggingEnabled && log(LT.LOG, `Handling roll ${rollStr} | Dropping dice ${dropCount} ${JSON.stringify(rollSet[i])}`);
|
||||||
// Skip all rolls that were rerolled
|
// Skip all rolls that were rerolled
|
||||||
if (!rollSet[i].rerolled) {
|
if (!rollSet[i].rerolled) {
|
||||||
rollSet[i].dropped = true;
|
rollSet[i].dropped = true;
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
} from '../../deps.ts';
|
} from '../../deps.ts';
|
||||||
|
|
||||||
import { SolvedStep } from './solver.d.ts';
|
import { SolvedStep } from './solver.d.ts';
|
||||||
|
import { loggingEnabled } from './rollUtils.ts';
|
||||||
|
|
||||||
// fullSolver(conf, wrapDetails) returns one condensed SolvedStep
|
// fullSolver(conf, wrapDetails) returns one condensed SolvedStep
|
||||||
// fullSolver is a function that recursively solves the full roll and math
|
// fullSolver is a function that recursively solves the full roll and math
|
||||||
|
@ -32,7 +33,7 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
|
|
||||||
// Evaluate all parenthesis
|
// Evaluate all parenthesis
|
||||||
while (conf.indexOf('(') > -1) {
|
while (conf.indexOf('(') > -1) {
|
||||||
log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Looking for (`);
|
loggingEnabled && log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Looking for (`);
|
||||||
// Get first open parenthesis
|
// Get first open parenthesis
|
||||||
const openParen = conf.indexOf('(');
|
const openParen = conf.indexOf('(');
|
||||||
let closeParen = -1;
|
let closeParen = -1;
|
||||||
|
@ -40,7 +41,7 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
|
|
||||||
// Using nextParen to count the opening/closing parens, find the matching paren to openParen above
|
// Using nextParen to count the opening/closing parens, find the matching paren to openParen above
|
||||||
for (let i = openParen; i < conf.length; i++) {
|
for (let i = openParen; i < conf.length; i++) {
|
||||||
log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Looking for matching ) openIdx: ${openParen} checking: ${i}`);
|
loggingEnabled && log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Looking for matching ) openIdx: ${openParen} checking: ${i}`);
|
||||||
// If we hit an open, add one (this includes the openParen we start with), if we hit a close, subtract one
|
// If we hit an open, add one (this includes the openParen we start with), if we hit a close, subtract one
|
||||||
if (conf[i] === '(') {
|
if (conf[i] === '(') {
|
||||||
nextParen++;
|
nextParen++;
|
||||||
|
@ -83,10 +84,10 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
// Evaluate all EMMDAS by looping thru each teir of operators (exponential is the higehest teir, addition/subtraction the lowest)
|
// Evaluate all EMMDAS by looping thru each teir of operators (exponential is the higehest teir, addition/subtraction the lowest)
|
||||||
const allCurOps = [['^'], ['*', '/', '%'], ['+', '-']];
|
const allCurOps = [['^'], ['*', '/', '%'], ['+', '-']];
|
||||||
allCurOps.forEach((curOps) => {
|
allCurOps.forEach((curOps) => {
|
||||||
log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Evaluating ${JSON.stringify(curOps)}`);
|
loggingEnabled && log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Evaluating ${JSON.stringify(curOps)}`);
|
||||||
// Iterate thru all operators/operands in the conf
|
// Iterate thru all operators/operands in the conf
|
||||||
for (let i = 0; i < conf.length; i++) {
|
for (let i = 0; i < conf.length; i++) {
|
||||||
log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Evaluating ${JSON.stringify(curOps)} | Checking ${JSON.stringify(conf[i])}`);
|
loggingEnabled && log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Evaluating ${JSON.stringify(curOps)} | Checking ${JSON.stringify(conf[i])}`);
|
||||||
// Check if the current index is in the active teir of operators
|
// Check if the current index is in the active teir of operators
|
||||||
if (curOps.indexOf(conf[i].toString()) > -1) {
|
if (curOps.indexOf(conf[i].toString()) > -1) {
|
||||||
// Grab the operands from before and after the operator
|
// Grab the operands from before and after the operator
|
||||||
|
@ -172,7 +173,7 @@ export const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails:
|
||||||
|
|
||||||
// If we somehow have more than one item left in conf at this point, something broke, throw an error
|
// If we somehow have more than one item left in conf at this point, something broke, throw an error
|
||||||
if (conf.length > 1) {
|
if (conf.length > 1) {
|
||||||
log(LT.LOG, `ConfWHAT? ${JSON.stringify(conf)}`);
|
loggingEnabled && log(LT.LOG, `ConfWHAT? ${JSON.stringify(conf)}`);
|
||||||
throw new Error('ConfWhat');
|
throw new Error('ConfWhat');
|
||||||
} else if (singleNum && (typeof (conf[0]) === 'number')) {
|
} else if (singleNum && (typeof (conf[0]) === 'number')) {
|
||||||
// If we are only left with a number, populate the stepSolve with it
|
// If we are only left with a number, populate the stepSolve with it
|
||||||
|
|
Loading…
Reference in New Issue