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

API sheetworkers can't read default values in repeating sections

1528366974

Edited 1528370923
Lucian
Pro
API Scripter
Reproduction steps: Create a new campaign with the following character sheet: <span>Output</span><input type="text" name="attr_output"> <br> <fieldset class="repeating_test">     <span>Input value (don't change)</span><input type="checkbox" disabled='disabled' name="attr_input" value="1" checked="true">     <br>     <span>Trigger - toggle to update output</span><input type="checkbox" name="attr_trigger" value="1">     <br>     <span>API Trigger - toggle to update output via API</span><input type="checkbox" name="attr_api_trigger" value="1"> </fieldset>   <script type="text/worker">   on("change:repeating_test:trigger", function(eventInfo) {     const prefix = eventInfo.sourceAttribute.match(/repeating_test_[^_]+_/)[0];     const inputAttrName = `${prefix}input`;     getAttrs([inputAttrName], function(values) {         log('setting output value using sheet worker');         log(values[inputAttrName]);         setAttrs({output:values[inputAttrName]});     }) });   </script> and the following API script: on('change:attribute', (attr) => {     const match = attr.get('name').match(/(repeating_test_[^_]+_)api_trigger/);     if (match) {         const prefix = match[1];         const charId = attr.get('characterid');         let triggerAttr = findObjs({type:'attribute', name: `${prefix}trigger`, characterid:charId})[0];         if (!triggerAttr) {             triggerAttr = createObj('attribute', {name:`${prefix}trigger`, characterid:charId, current:'0'});         }         const currentVal = triggerAttr.get('current');         triggerAttr.setWithWorker('current', (currentVal === 0 || currentVal === '0') ? 'on' : '0');     } }); then load the campaign up and do the following: Create a new character Open the character sheet Click the button to add a new repeating item In the new repeating item, click on the "Trigger" checkbox, Observe that the value of the Output text field is changed to reflect the value of the Input checkbox based on its default value Delete the value in the Output text field Click on the "API trigger" checkbox. Expected behaviour: The "Output" text field should be populated with the value "1" as read from the "Input" checkbox's default value Actual behaviour: The "Output" text field remains blank. Looking at the logging in the API console you will be able to see that the sheet worker script did fire, but when it attempted to read the value of the input checkbox using "getAttrs" it received "undefined" instead of the default value. Remarks: This behaviour is confined to repeating sections - reading default values from top-level fields works as expected This is not confined to checkboxes - the API sheetworkers can't read any default values within repeating sections Although this might seem a bit obscure when presented as a minimal testcase, this is actually pretty significant for real-world character sheets. There are many places on the Shaped sheet, for example, that use default values within repeating sections, and all of these will corrupt the sheet data with inaccurate values if the API happens to modify anything that triggers sheetworkers in these sections.
1528373734
Lars K.
Pro
Sheet Author
API Scripter
If I recall correctly from my previous attempts to write a usable Scala DSL over Roll20's API, this problem is actually even more general. I think Roll20 actually doesn't materialise fields that are at their default value into the backing store, but instead fills them in on demand, when read with getAttrByName. Which means in a scan of all attrs of a character (via findObjs), they don't show up. This makes it a bloody nuisance to tell the difference between a missing field in a repeating section and a field at its default value (which might be nice to know, if all you have is a repeating section ID from somewhere and you are trying to tell if it is valid).
1528374037
Lucian
Pro
API Scripter
Hey Lars, Yes, that's certainly true, but be careful not to muddy the issue here. I'm not talking about behaviour within the API itself using api functions, which is well-defined and not a bug, even if  it is occasionally frustrating as in the case you talk about. I'm talking about what happens when the API triggers sheetworkers to run on the API server via the setWithWorker call. In theory, this should act identically to how it would if a user set the  value manually through the UI on the client. In practice there have been various bugs where this was not the case - and this is a new one.
1528392234
Lars K.
Pro
Sheet Author
API Scripter
Fair enough, though I have a suspicion that this bug and said "well-defined behaviour" (for some notion of "well-defined") have the same underlying cause.
1528394916
Lucian
Pro
API Scripter
Lars K. said: Fair enough, though I have a suspicion that this bug and said "well-defined behaviour" (for some notion of "well-defined") have the same underlying cause. Yes, I guess in a sense that's true, insofar as the fact that default values don't exist as real attributes means they have to be handled explicitly, and this makes bugs more likely. The thing about the roll20 character data model is that the model itself has no schema - it's effectively just a series of key:value pairs attached to a character. AIUI it was only later that the character sheets were bolted onto the top, which allowed you to view the data through the lens of some sort of limited typing with default values, inter-field calculations etc - but all this was really only intended for display purposes on the browser client. The API has always been a slightly uneasy partner to all this, having as it does no direct access to the client and its code - and many of the behaviours of the API are effectively re-implementations of something that was created for a rather different use-case on the client side - which has resulted in various inconsistencies over the years between e.g. the chat parsing on the client and via sendChat, object creation behaviour, attribute handling, and most recently, running sheetworker scripts, which is done by a special piece of code on the API server that attempts to mimic the behaviour of the sheetworker harness on the client, but in a completely different context - one without a DOM or the rest of the Roll20 client. As always it's easy to look at it and ask "why on earth would you design it like that?" but the reality is that it evolved (very rapidly, as these things go) from a rather different product with different priorities; short of the guys tearing it up and rewriting it from scratch we just have to live with the legacy of that evolution!
Hi Lucian, Good catch and report! :) I have submitted a ticket to the devs so they can have a look