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

Race conditions around add:graphic event

1442219501
Lucian
Pro
API Scripter
Steps to reproduce: Drop a token on an empty map Create a new character in the journal (I'm using the 5e-shaped character sheet, but I suspect that won't make a difference for this bug) Set character HP to (say) 100 Edit the token and set it to represent the new character Link bar1 to HP attribute of the character Edit the character and set the default token to the token on the map Delete the token from the map Install the script included below in the campaign Drag the character onto the map to create a new token Expected behaviour: You should see two identical log messages in the script console, dumping the token object that has just been added. Actual behaviour: The first log message contains a "bare-bones" token with only position, graphic info and "represents" set. The one after the setTimeout has been filled in with all the rest of the details including the linked bar that was saved on the token. It would appear that Roll20 hasn't finished updating the new token at the point that the add:graphic event is fired - a further update will happen at some (non-deterministic?) point in the future. This can create all manner of horrible race conditions in scripts that are trying to make logic decisions based on the state of tokens that are added to the map. I believe that add:graphic should either not be fired until Roll20 has finished configuring the token, or there needs to be another event that is guaranteed to only be fired after the token is actually ready. NB: This behaviour may well be non-deterministic and a function of server load/connection latency/neutrino activity. The testcase works fairly reliably for me in my campaign at the moment, I haven't tried it in a blank campaign yet. Script on('ready', function() { &nbsp; 'use strict'; &nbsp; on('add:graphic', function(obj) { &nbsp;&nbsp;&nbsp; log(obj); &nbsp;&nbsp;&nbsp; setTimeout(function() { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log(obj); &nbsp;&nbsp;&nbsp; }, 200); &nbsp; }); }); Log output {"_id":"-Jz9ufriqPpLk8XTQl7W","_pageid":"-Jz9t3jds74Hx7roZsUi","left":448,"top":230,"width":70,"height":70,"rotation":0,"layer":"objects","isdrawing":false,"flipv":false,"fliph":false,"imgsrc":"<a href="https://s3.amazonaws.com/files.d20.io/marketplace/14368/ARNms5VZX4wsqwsWOnaOXg/max.png?1366986135&quot;,&quot;name&quot;:&quot;&quot;,&quot;gmnotes&quot;:&quot;&quot;,&quot;controlledby&quot;:&quot;&quot;,&quot;bar1_value&quot;:&quot;&quot;,&quot;bar1_max&quot;:&quot;&quot;,&quot;bar1_link&quot;:&quot;&quot;,&quot;bar2_value&quot;:&quot;&quot;,&quot;bar2_max&quot;:&quot;&quot;,&quot;bar2_link&quot;:&quot;&quot;,&quot;bar3_value&quot;:&quot;&quot;,&quot;bar3_max&quot;:&quot;&quot;,&quot;bar3_link&quot;:&quot;&quot;,&quot;represents&quot;:&quot;-Jz9u2zmsoFDkY4Z9A63&quot;,&quot;aura1_radius&quot;:&quot;&quot;,&quot;aura1_color&quot;:&quot;#FFFF99&quot;,&quot;aura1_square&quot;:false,&quot;aura2_radius&quot;:&quot;&quot;,&quot;aura2_color&quot;:&quot;#59E594&quot;,&quot;aura2_square&quot;:false,&quot;tint_color&quot;:&quot;transparent&quot;,&quot;statusmarkers&quot;:&quot;&quot;,&quot;showname&quot;:false,&quot;showplayers_name&quot;:false,&quot;showplayers_bar1&quot;:false,&quot;showplayers_bar2&quot;:false,&quot;showplayers_bar3&quot;:false,&quot;showplayers_aura1&quot;:false,&quot;showplayers_aura2&quot;:false,&quot;playersedit_name&quot;:true,&quot;playersedit_bar1&quot;:true,&quot;playersedit_bar2&quot;:true,&quot;playersedit_bar3&quot;:true,&quot;playersedit_aura1&quot;:true,&quot;playersedit_aura2&quot;:true,&quot;light_radius&quot;:&quot;&quot;,&quot;light_dimradius&quot;:&quot;&quot;,&quot;light_otherplayers&quot;:false,&quot;light_hassight&quot;:false,&quot;light_angle&quot;:&quot;&quot;,&quot;light_losangle&quot;:&quot;&quot;,&quot;light_multiplier&quot;:1,&quot;sides&quot;:&quot;&quot;,&quot;currentSide&quot;:0,&quot;lastmove&quot;:&quot;&quot;,&quot;_type&quot;:&quot;graphic&quot;,&quot;_subtype&quot;:&quot;token&quot;,&quot;_cardid" rel="nofollow">https://s3.amazonaws.com/files.d20.io/marketplace/14368/ARNms5VZX4wsqwsWOnaOXg/max.png?1366986135","name":"","gmnotes":"","controlledby":"","bar1_value":"","bar1_max":"","bar1_link":"","bar2_value":"","bar2_max":"","bar2_link":"","bar3_value":"","bar3_max":"","bar3_link":"","represents":"-Jz9u2zmsoFDkY4Z9A63","aura1_radius":"","aura1_color":"#FFFF99","aura1_square":false,"aura2_radius":"","aura2_color":"#59E594","aura2_square":false,"tint_color":"transparent","statusmarkers":"","showname":false,"showplayers_name":false,"showplayers_bar1":false,"showplayers_bar2":false,"showplayers_bar3":false,"showplayers_aura1":false,"showplayers_aura2":false,"playersedit_name":true,"playersedit_bar1":true,"playersedit_bar2":true,"playersedit_bar3":true,"playersedit_aura1":true,"playersedit_aura2":true,"light_radius":"","light_dimradius":"","light_otherplayers":false,"light_hassight":false,"light_angle":"","light_losangle":"","light_multiplier":1,"sides":"","currentSide":0,"lastmove":"","_type":"graphic","_subtype":"token","_cardid</a>":""} {"_id":"-Jz9ufriqPpLk8XTQl7W","_pageid":"-Jz9t3jds74Hx7roZsUi","left":448,"top":230,"width":70,"height":70,"rotation":0,"layer":"objects","isdrawing":false,"flipv":false,"fliph":false,"imgsrc":"<a href="https://s3.amazonaws.com/files.d20.io/marketplace/14368/ARNms5VZX4wsqwsWOnaOXg/max.png?1366986135&quot;,&quot;name&quot;:&quot;Test&quot;,&quot;gmnotes&quot;:&quot;&quot;,&quot;controlledby&quot;:&quot;&quot;,&quot;bar1_value&quot;:100,&quot;bar1_max&quot;:100,&quot;bar1_link&quot;:&quot;-Jz9u6aUbluAJAexf_L8&quot;,&quot;bar2_value&quot;:&quot;&quot;,&quot;bar2_max&quot;:&quot;&quot;,&quot;bar2_link&quot;:&quot;&quot;,&quot;bar3_value&quot;:&quot;&quot;,&quot;bar3_max&quot;:&quot;&quot;,&quot;bar3_link&quot;:&quot;&quot;,&quot;represents&quot;:&quot;-Jz9u2zmsoFDkY4Z9A63&quot;,&quot;aura1_radius&quot;:&quot;&quot;,&quot;aura1_color&quot;:&quot;#FFFF99&quot;,&quot;aura1_square&quot;:false,&quot;aura2_radius&quot;:&quot;&quot;,&quot;aura2_color&quot;:&quot;#59E594&quot;,&quot;aura2_square&quot;:false,&quot;tint_color&quot;:&quot;transparent&quot;,&quot;statusmarkers&quot;:&quot;&quot;,&quot;showname&quot;:false,&quot;showplayers_name&quot;:false,&quot;showplayers_bar1&quot;:false,&quot;showplayers_bar2&quot;:false,&quot;showplayers_bar3&quot;:false,&quot;showplayers_aura1&quot;:false,&quot;showplayers_aura2&quot;:false,&quot;playersedit_name&quot;:true,&quot;playersedit_bar1&quot;:true,&quot;playersedit_bar2&quot;:true,&quot;playersedit_bar3&quot;:true,&quot;playersedit_aura1&quot;:true,&quot;playersedit_aura2&quot;:true,&quot;light_radius&quot;:&quot;&quot;,&quot;light_dimradius&quot;:&quot;&quot;,&quot;light_otherplayers&quot;:false,&quot;light_hassight&quot;:false,&quot;light_angle&quot;:&quot;&quot;,&quot;light_losangle&quot;:&quot;&quot;,&quot;light_multiplier&quot;:1,&quot;sides&quot;:&quot;&quot;,&quot;currentSide&quot;:0,&quot;lastmove&quot;:&quot;627,180&quot;,&quot;_type&quot;:&quot;graphic&quot;,&quot;_subtype&quot;:&quot;token&quot;,&quot;_cardid" rel="nofollow">https://s3.amazonaws.com/files.d20.io/marketplace/14368/ARNms5VZX4wsqwsWOnaOXg/max.png?1366986135","name":"Test","gmnotes":"","controlledby":"","bar1_value":100,"bar1_max":100,"bar1_link":"-Jz9u6aUbluAJAexf_L8","bar2_value":"","bar2_max":"","bar2_link":"","bar3_value":"","bar3_max":"","bar3_link":"","represents":"-Jz9u2zmsoFDkY4Z9A63","aura1_radius":"","aura1_color":"#FFFF99","aura1_square":false,"aura2_radius":"","aura2_color":"#59E594","aura2_square":false,"tint_color":"transparent","statusmarkers":"","showname":false,"showplayers_name":false,"showplayers_bar1":false,"showplayers_bar2":false,"showplayers_bar3":false,"showplayers_aura1":false,"showplayers_aura2":false,"playersedit_name":true,"playersedit_bar1":true,"playersedit_bar2":true,"playersedit_bar3":true,"playersedit_aura1":true,"playersedit_aura2":true,"light_radius":"","light_dimradius":"","light_otherplayers":false,"light_hassight":false,"light_angle":"","light_losangle":"","light_multiplier":1,"sides":"","currentSide":0,"lastmove":"627,180","_type":"graphic","_subtype":"token","_cardid</a>":""}
This is known behavior (although something we should certainly document better). It's because on the client side when you create a token based on a saved default token (which is what you're doing), on the client it first creates a 'blank' token (with the graphic only), and then fills in the other more advanced attributes (such as the hitpoints, etc.) using a subsequent set() call. At the very least we should probably figure out an officially-supported way to better handle this, such as allowing some sort of nested one-off event listener inside the add listener...