Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Assistance with script to handle user-defined bonus of multiple attributes

June 30 (3 weeks ago)

Edited June 30 (3 weeks ago)
mrianmerry
Pro
Sheet Author

I'm looking for feedback on this sheet worker that I've written, because I've got a gut feeling it's over-complicating the process or has some glaring hole that I can't see.

The script is as follows;

on(`change:stealth_bonus_input`, function (event) {
getAttrs(["stealth_bonus_input"], function (attributes) {
// userBonus could be a number, or it could be some calculation based on the character's attributes
// such as @{ATK} + @{DEF} + @{SPD} - this is what I'm attempting to handle
let userInput = attributes["stealth_bonus_input"];

if (!isNaN(userInput)) { /* assign attribute with user input */ } else {
// This would leave us with an array such as ["ATK", "DEF", "SPD"] from the above
let attributes = userInput.replace(/[^a-zA-Z_]+/g, ' ').split(' ');

// Throw that array into the getAttr function so we get whatever attributes match that input
getAttrs(attributes, function(attributes) {

// Parse the attributes object to get access to the key-value pairs
Object.entries(attributes).forEach(([attribute, value]) => {
// Wrap the key in the attribute-accessor tags so that we replace the whole thing from the string
userInput = userInput.replace(`@{${attribute}}`, value);
});

// userBonus would now read something like 3 + 4 + 6
// evaluate that string to get a number and then assign it
const userBonus = parseInt(eval(userInput)) || 0;
setAttrs({"stealth_bonus": userBonus});
});
}
});
});


So basically, I'm looking for advice on making this more robust to whatever craziness the user might enter or for an easier way of handling it entirely.


Edit: formatting

June 30 (3 weeks ago)

Edited June 30 (3 weeks ago)
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator

There are a few things I see.

  1. I would recommend simply getting all attributes that might be needed in the first getAttrs. GetAttrs takes 10s of ms to run regardless of how many attributes you are getting the value for, so it is more efficient to just get everything all at once. This does limit you to attributes you've defined in your sheet html, but that is a reasonable restriction imo.
  2. let attributes = userInput.replace(/[^a-zA-Z_]+/g, ' ').split(' ');
    1. I would recommend using a new variable name instead of mutating the attributes object into an array. There are many reasons for this, most of which come down to coding best practice 
  3. userInput = userInput.replace(`@{${attribute}}`, value);
    1. Curly braces have a special meaning in regex, so this is almost certainly going to error out as it will see the curly braces and try to parse the information between them as an instruction about how many @'s should be looked for.
  4. You need to account for the math function calls in roll20 syntax as well, e.g. floor, ceiling, etc
  5. You should validate that the value you are trying eval is only number and/or math operations, otherwise someone could use this to execute an injection attack.
  6. The parser needs to account for nested attribute calls, e.g. @{my-attribute} that itself has the text 2 + @{strength}. Ideally this should be supported to 99 levels deep to mimic the roll20 chat parser.

You may find some functions from the k-scaffold useful inspiration for this. Particularly parseMacro, although it will need to be modified to work outside of the k-scaffold actually, it will probably work as is outside of the k-scaffold.

July 01 (3 weeks ago)
mrianmerry
Pro
Sheet Author

Appreciate the feedback - I'll probably just drop this in favour of keeping these bonuses to simple number inputs. But there's room to learn here, so I'll keep this script on a separate branch for some exploration.

After a quick read of k-scaffold, it appears like it might be beneficial to me to spend some time going over the entire repository, and perhaps attempting to refactor my sheet to utilise it more. Thanks for the heads-up! I wasn't even aware you could have multiple files for the HTML, CSS, and script sections, so that's already breaking my head a little...

July 01 (3 weeks ago)
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator

Glad it's useful! I's important to keep in mind that the scaffold still generated a single html file and a single css file. The split of the files is purely the pug and scss files that are used on the build process.