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

Sheet Worker chains for attribute update

on('change:strength_magicbonus',function(){ UpdateStrength(); } UpdateStrength = function(){ getAttrs(["Strength_MagicBonus","Strength_RolledBaseValue","Strength_RaceBonus"],function(values){ setAttrs({ Strength: parseInt(values.Strength_MagicBonus)+parseInt(values.Strength_RolledBaseValue)+parseInt(values.Strength_RaceBonus)}); }); } on('change:strength'function() { UpdateCarryingCapacity(); } on('change:carryingcapacity',function(){ CheckEncumberancePenalties(); } This is a simplified version of my question to illustrate my point. When sheet worker scripts update values that other values depend on, is it better to "chain" them (writing multiple update functions that will update when their dependent values change as seen above) or have an update function that calculates all that are dependent on the updated value, and all values dependent on those values, etc, and post one update with setAttrs (as seen below). on('change:strength_magicbonus',function(){ UpdateStrength(); } UpdateStrength = function(){ getAttrs(["Strength_MagicBonus","Strength_RolledBaseValue","Strength_RaceBonus","Weapon1_BaseDamage","Weapon1_MagicBonus", "Weapon1..."],function(values){ var strength = parseInt(values.Strength_MagicBonus)+parseInt(values.Strength_RolledBaseValue)+parseInt(values.Strength_RaceBonus); setAttrs({ Strength: strength, CarryingCapacity: CalculateCaryingCapacity(strength), Weapon1_Damage: CalculateWeaponDamage(values.Weapon1_BaseDamage, values.Weapon1_MagicBonus, values.Weapon1..., Strength)}; }); } My concern is that allowing things to "chain" (example 1) makes things easier to code, by having so many dependent asynchronous calls may create significant lag in users seeing the results of updating stats. Creating monolithic functions that update everything make each individual update take longer and would be a nightmare to code effectively (updating strength_magicbonus and armor1_armortype would have a lot of overlap). So to lay out the question: "Is there an easy coding architecture that is light on system resources that handles updates to an initial value and all subsequent updates to values dependent on the initial value?  If so, what is it?"
1498062947
The Aaron
Roll20 Production Team
API Scripter
(Moved to Character Sheets forum)
1498146238

Edited 1498147015
chris b.
Pro
Sheet Author
API Scripter
The Pathfinder sheet is mostly the first way, and it's dog slow. They recently revamped the 5e shaped sheet to do it the second way and reportedly it's much faster. So I'd look at their code and see how they did it. Generally, grabbing more fields is not as expensive as going back twice to get those more fields. So it's good to do it the second way if you can make it as easy to maintain as possible.  This is how I am refactoring my code after writing it all the first way: I took my asynchronous functions and broke out the portions that were inside the getAttrs as synchronous functions. Each of these that accepted a map from getAttrs, and returned a map for setAttrs, but it doesn't actually call those two.  my basic pattern is like this. Say i had setStuff before, or maybe two setStuff1 and setStuff2 that are related like yours above. I took the fields from getAttrs in both, and combined them into one array named fields. Then I took the code inside getAttrs, and put it into two synchronous functions setSomething1 and setSomething2. Then I have one setStuffAsync, which gets ALL attributes, and calls both setSomething1 and setSomething2, then writes the results back. In between the calls, i write the values to "write" back to the values from getAttrs, so that they propagate to later functions. So then I can call either setSomething1 or setSomething2 from any other function, as long as I have all the attributes needed in the first parameter. By doing this I've seen some significant performance improvements in certain areas.  (I use _.extend() and _.size() from underscore. extend sets name,values from right side object to left side, overwriting any already there. _.size() just returned the number of keys, both are synchronous) //asnchronous functions calculate and set new values in the return object //v is map returned from getAttrs, and valsToSet is map that will be sent to setAttrs function setSomething1(v,valsToSet){ valsToSet = valsToSet||{}; valsToSet[field1]=v[y]+something; return valsToSet; } function setSomething2(v,valsToSet){ valsToSet = valsToSet||{}; valsToSet[field1]=v[y]+somethingelse; return valsToSet; } function setStuffAsync(){ var fields = [array of attributes potentially needed for all calls]; getAttrs(fields,function(valsRetrieved){ var valsToSet={}; setSomething1(valsRetreived,valsToSet); //write results back into valsRetreived, to make sure to propagate them to other calculations _.extend(valsRetreived,valsToSet); setSomething2(valsRetreived,valsToSet); if( _.size(valstoSet) > 0){ setAttrs(valsToSet,{silent:true}); } }); } on("change:somefield",function(eventInfo){ setStuffAsync(); });