This post has been closed. You can still view previous posts, but you can't post any new replies.

API Dev Server update 10/17: Sheet Worker Support

1476714919

Edited 1476719785
Riley D.
Roll20 Dev Team
Hello all, Today we've rolled out a new version of the API that's currently only active for DEV SERVER games. In particular, it adds the new function: setWithWorker(properties) This function works just like the current set() function, except when called on an Attribute object it will also cause the relevant sheet worker code to be executed by the API server, just as if a player had changed the value on the client using the character sheet. Example: getObj("attribute", "-KUI1fO2L7Jv0Y4AOSFK").setWithWorker({ current: "Cleric" }); In addition to that, you can use the new function onSheetWorkerCompleted(function() {   //do something here }); to register code that will only run after all sheet worker execution has finished for the current 'stack' of sheet worker calls. You can register the callback before you call the setWithWorker() function. Note that each callback you register will only run one time. I've tested this code with the OGL 5E sheet and it should all be working fine at this point. If you notice any issues with other sheets where the API isn't behaving the same as a client, please let me know. Thanks!
1476715666

Edited 1476715687
Jakob
Pro
API Scripter
Firstly, AWESOME. Secondly, how do you call this function? Like this: setWithWorker(attribute, {'current' : '20', 'max' : '32'}) or like this: attribute.setWithWorker({'current' : '20', 'max' : '32'})
1476716917
Kryx
Pro
Sheet Author
Great! Thanks Riley!
1476717303
Lucian
Pro
API Scripter
Fantastic - many thanks - this is going to make a lot of things much easier. One question - what does the onSheetWorkerCompleted callback relate to? Is it just the next completed set of sheetworkers, or is it all future ones?
1476718354
The Aaron
Pro
API Scripter
Jakob said: Firstly, AWESOME. Secondly, how do you call this function? Like this: setWithWorker(attribute, {'current' : '20', 'max' : '32'}) or like this: attribute.setWithWorker({'current' : '20', 'max' : '32'}) Probably both, if it works just like the current set.  Likely it's a wrapper that just passes the arguments to set() and then kicks off the sheet workers after that operation returns.
1476719018
Lucian
Pro
API Scripter
Ok, so perhaps I'm doing something daft, but if I call: attribute.setWithWorker({current: myValue}); or setWithWorker(attribute, {current:myValue}); I get TypeError: attr.setWithWorker is not a function   or equivalent in both cases. I've checked, I am on dev, and 'onSheetWorkerCompleted' seems to execute ok without error - I obviously can't test the functionality though since setWithWorker isn't correct. Am I doing something wrong or has something gone wrong in the deployment? Cheers,
1476719579
Riley D.
Roll20 Dev Team
It should be: attributeTrackedObj.setWithWorker({current: "test"}); Where attributeTrackedObj is an object you got with e.g. getObj("attribute", "-ABC123") or findObjs. Here's the example I'm running in my test game this is working currently: getObj("attribute", "-KUI1fO2L7Jv0Y4AOSFK").setWithWorker({    current: "Cleric" });
1476719621
Riley D.
Roll20 Dev Team
Also just to be sure you should be seeing a new log showing up in the API console when it starts up that says: "Found webworker script"
1476719688
Riley D.
Roll20 Dev Team
Lucian said: Fantastic - many thanks - this is going to make a lot of things much easier. One question - what does the onSheetWorkerCompleted callback relate to? Is it just the next completed set of sheetworkers, or is it all future ones? It's just the next set of completed ones. So each callback you register will only ever get called one time.
1476720551
Lucian
Pro
API Scripter
Riley D. said: Also just to be sure you should be seeing a new log showing up in the API console when it starts up that says: "Found webworker script" I was being a numpty and calling it on the array I got back from findObjs rather than extracting the first element. Sorry! Thanks for the clarification about the onSheetWorkersCompleted - that should work ok for me I think. Now to get cracking on removing all the evil hacks I've put in for lack of this functionality over the last 6 months :-)
1476722575
Lucian
Pro
API Scripter
Another observation - it seems like the onSheetWorkerCompleted callback is called after the current event processing completes irrespective of whether any calls to setWithWorkers were actually made. I guess it should be possible to work round this, but it does potentially make life a bit more complicated for script authors. If it's hard to suppress the call because of how it's implemented, could we perhaps have the callback accepting a parameter that indicates whether any workers were actually executed?
1476723118
Lucian
Pro
API Scripter
It looks like sheetworkers triggered this way don't trigger API events.  I can see why that's probably desirable in most cases - it certainly avoids a lot of potential for evil cycles etc - but it does mean that the behaviour is inconsistent with what happens when the client makes the same change. I can see that causing grief for people as well, since any scripts that rely on being able to monitor the value of an attribute are going to get blindsided if another script changes them indirectly in this way. Could this perhaps be an optional behaviour, or would that be really hard?
1476732625
Riley D.
Roll20 Dev Team
Lucian said: Another observation - it seems like the onSheetWorkerCompleted callback is called after the current event processing completes irrespective of whether any calls to setWithWorkers were actually made. I guess it should be possible to work round this, but it does potentially make life a bit more complicated for script authors. If it's hard to suppress the call because of how it's implemented, could we perhaps have the callback accepting a parameter that indicates whether any workers were actually executed? So I actually had to change the way this worked because originally when you added a callback even if you called setWithWorker() if a) there were no events triggered by the change or b) if the data you were setting wasn't different, the callback would never fire. You're saying in that situation you wouldn't want it to fire and instead it should stay on the stack and wait for the next time something does actually change?
1476732796
Riley D.
Roll20 Dev Team
Lucian said: It looks like sheetworkers triggered this way don't trigger API events.  I can see why that's probably desirable in most cases - it certainly avoids a lot of potential for evil cycles etc - but it does mean that the behaviour is inconsistent with what happens when the client makes the same change. I can see that causing grief for people as well, since any scripts that rely on being able to monitor the value of an attribute are going to get blindsided if another script changes them indirectly in this way. Could this perhaps be an optional behaviour, or would that be really hard? Yeah this is one of the weird places where things intersect. You're right that on the client if a sheetworker changed something it would trigger an API event because it would be seen as the "player" changing something. However the sheetworker modifications are considered to be done by whatever originally triggered them, so in this case the "API" is changing things, and currently the API does not self-trigger change: events whenever it changes something itself. I could possibly make a change so that we could force those API events to fire but as you said I think it opens up a lot of potential for people to get in bad infinite loops since in a lot of cases the API script author may not be completely familiar with everything the sheet worker is going to do...
1476733859
The Aaron
Pro
API Scripter
Riley D. said: Lucian said: Another observation - it seems like the onSheetWorkerCompleted callback is called after the current event processing completes irrespective of whether any calls to setWithWorkers were actually made. I guess it should be possible to work round this, but it does potentially make life a bit more complicated for script authors. If it's hard to suppress the call because of how it's implemented, could we perhaps have the callback accepting a parameter that indicates whether any workers were actually executed? So I actually had to change the way this worked because originally when you added a callback even if you called setWithWorker() if a) there were no events triggered by the change or b) if the data you were setting wasn't different, the callback would never fire. You're saying in that situation you wouldn't want it to fire and instead it should stay on the stack and wait for the next time something does actually change? What about calling the callback with some sort of context object?  Say something like: { workersExecuted: true, attributesChanged: [ 'foo','bar','repeating_inventory_-Jasd123fas_qty' ] }
1476735115
Lucian
Pro
API Scripter
Riley D. said: So I actually had to change the way this worked because originally when you added a callback even if you called setWithWorker() if a) there were no events triggered by the change or b) if the data you were setting wasn't different, the callback would never fire. You're saying in that situation you wouldn't want it to fire and instead it should stay on the stack and wait for the next time something does actually change? Hmm. Actually I guess I hadn't thought through the implications completely; it's kind of an odd callback because it isn't associated with a specific set call so the "scope" of the callback isn't totally obvious. I think what I was imagining is that the callback would simply be dumped silently if no setWithWorker calls had been made within that API invocation. But actually, I like Aaron's suggestion better :-)
1476735297
Lucian
Pro
API Scripter
Riley D. said: I could possibly make a change so that we could force those API events to fire but as you said I think it opens up a lot of potential for people to get in bad infinite loops since in a lot of cases the API script author may not be completely familiar with everything the sheet worker is going to do... Or... you could ditch client-side sheetworkers entirely and just run everything on the API server ;-) But I guess your sysadmin team (not to mention the CFO when he sees the hosting invoice) wouldn't be so happy with that!
1476738892

Edited 1476740481
Lucian
Pro
API Scripter
Ok, so I've thrown the real test at this now - I've imported a complete NPC into the Shaped Sheet using the new method call. Overall, it doesn't seem to have done too badly - most of the dependent updates seem to have taken place as I would expect. There are a few rough edges, however - mainly things that haven't been set to be visible when they should be. It's possible that something about the way things are run on the API server is revealing a hidden race condition that doesn't show up when running client-side; or it may be that there's a subtle problem/difference with the way the sheet workers are being run on the API server. Unfortunately, I'm not sure how I can tell... which brings me to my next two queries: Is there any way that we can debug sheet workers on the API server? I think the most convenient option would be to have console.log bound to the existing API log method, so that pre-existing logging output in the sheetworkers can end up in the API log. For extra Amazing Points having some option to show which sheetworker handlers were being triggered as they were run would be extremely handy... How does ordering/timing work? Do sheetworker events get queued in the order that the setWithWorker calls were made and then executed serially after the main API thread returns control back the Roll20 framework? I'm guessing that secondary sheetworker events triggered by the first batch of sheetworker updates may happen in any order, depending on the order in which responses to the first set of getAttrs/setAttrs arrive?
1476785720
Lucian
Pro
API Scripter
Ok, still doing my best to debug this - proving quite challenging without any logging - but I've found another issue that will need some sort of solution - getTranslationByKey doesn't work on the API server. This is problematic for the Shaped Sheet which uses this to be able to have a dynamic skill list with localised text available for the defaults. Can we get the translations loaded into the API server as well somehow?
1476789713
Lucian
Pro
API Scripter
Riley D. said: Yeah this is one of the weird places where things intersect. You're right that on the client if a sheetworker changed something it would trigger an API event because it would be seen as the "player" changing something. However the sheetworker modifications are considered to be done by whatever originally triggered them, so in this case the "API" is changing things, and currently the API does not self-trigger change: events whenever it changes something itself. It turns out that this isn't quite true: https://app.roll20.net/forum/post/4128877/change-event-fires-for-api-object-creation/?pageforid=4128877
1476795431
Lucian
Pro
API Scripter
I think I've made some progress nailing down what the problem might be. In the Shaped Sheet traits, actions etc are parsed from an attribute called content_srd, which is the droptarget for the Content field from the compendium. If I set this field to a value that matches the format from the compendium, the sheetworkers parse out the individual traits and actions from the content_srd value, and create new repeating rows for the relevant actions and traits. Each row gets a name value populated, and a "freetext" which contains the complete SRD text of the trait/action. Now, from here, there's a sheetworker script that is keyed against the repeating_action_freetext field, which should fire to parse out all the text of the action/trait into things like a to hit bonus, damage, etc. When dragging and dropping from the compendium this works fine, but when setting the content_srd value via the API with setWithWorker, this never happens. Interestingly, however, if I lookup the repeating section explicitly and reset the freetext value, the parsing kicks off as expected with no problems, and I end up with my fully parsed action/trait. Without being able to see more of the internals I'm stabbing in the dark here, but it looks like attribute creation (perhaps only in repeating sections?) isn't triggering things the way I'd expect, only attribute modification. Feel free to PM me if you want me to show you the specific tests I've been running in more detail.
1476800473
Riley D.
Roll20 Dev Team
I will go through and answer your questions more thoroughly tomorrow when I'm more around, but for now I'm going to push out an update that should cause the log() function called from inside the sheet worker to output to the API console which should help with your testing.
1476802128
Riley D.
Roll20 Dev Team
Okay, so the logging should be coming through now. It's not as complete as client-side logging since it doesn't support sending whole objects over the log obviously, but hopefully that will help. Also something else I noticed to keep in mind, there is no sheet:opened event that is triggered ever on the API side. I don't know if that affects anything regarding your import stuff but just something to note.
1476803136
Lucian
Pro
API Scripter
Riley D. said: Okay, so the logging should be coming through now. It's not as complete as client-side logging since it doesn't support sending whole objects over the log obviously, but hopefully that will help. Also something else I noticed to keep in mind, there is no sheet:opened event that is triggered ever on the API side. I don't know if that affects anything regarding your import stuff but just something to note. Cool, thanks, that's fantastic. Will wait to hear back tomorrow - thanks for being so responsive on this, I think when the wrinkles are ironed out this functionality is going to make a huge difference to me and a bunch of other scripters/sheet authors. I had hit the sheet:opened thing but forgot to post anything about it. For the time being I've got the API checking to see if there's a version attribute on the character (which is a good marker of whether the sheet has been opened at least once) and then flipping a dummy attribute to trigger a sheetworker that calls the sheet:opened handler. A nicer way of dealing with this would probably be a good thing - even if it's just the ability manually to fire "sheet:opened" at a time of our choosing - which will have other useful automation applications as well.
1476865450
Jakob
Pro
API Scripter
Being able to fire "sheet:opened" from the API would be great for a 'please update all my characters in this campaign to the newest sheet version' button.
1476865692
Kryx
Pro
Sheet Author
Jakob said: Being able to fire "sheet:opened" from the API would be great for a 'please update all my characters in this campaign to the newest sheet version' button. Indeed.
1476887244
Riley D.
Roll20 Dev Team
Jakob said: Being able to fire "sheet:opened" from the API would be great for a 'please update all my characters in this campaign to the newest sheet version' button. My concern with doing that via the API is just that it then precludes it for anyone who's not a Pro. Also, I'm not sure what sort of load that might put on the servers (updating like 100's of characters in a campaign all at once). That's the same reason we haven't put a button like that on the client side, either. But yeah, we'll definitely consider adding it to the client.
1476888670
Riley D.
Roll20 Dev Team
Lucian said: Is there any way that we can debug sheet workers on the API server? I think the most convenient option would be to have console.log bound to the existing API log method, so that pre-existing logging output in the sheetworkers can end up in the API log. For extra Amazing Points having some option to show which sheetworker handlers were being triggered as they were run would be extremely handy... How does ordering/timing work? Do sheetworker events get queued in the order that the setWithWorker calls were made and then executed serially after the main API thread returns control back the Roll20 framework? I'm guessing that secondary sheetworker events triggered by the first batch of sheetworker updates may happen in any order, depending on the order in which responses to the first set of getAttrs/setAttrs arrive? 1. So we added that already, hopefully that's helping. 2. Each setWithWorker() call immediately triggers all relevant events to happen inside the sheetWorker. The sheetWorker runs asynchronously though (just like on the client), so there's no guarantee that each sheetWorker event will complete before you do your next setWithWorker() call. There's only one sheetWorker thread though (just like on the client) so it's not like setting/getting is happening in parallel, it's just asynchronous. The setWithWorker() call should be equivalent to changing something on the character sheet on the client and then clicking off the field, which on the client immediately saves that one value and then fires off the sheetWorker events. On the second part, yes the second batch may happen in any order. However, again, this is exactly how it works on the client. The only thing I can think that might be a "gotcha" is that on the client I expect most people fill out the sheet rather slowly (click on a field, then wait to see what changes, then click on the next field)...if you're firing off a bunch of setWithWorker() calls back-to-back on the API server that would be happening much more quickly than on the client. You can nest setWithWorker() calls inside of onSheetWoerkerCompleted() callbacks if you want to go more "slowly." Lucian said: Ok, still doing my best to debug this - proving quite challenging without any logging - but I've found another issue that will need some sort of solution - getTranslationByKey doesn't work on the API server. This is problematic for the Shaped Sheet which uses this to be able to have a dynamic skill list with localised text available for the defaults. Can we get the translations loaded into the API server as well somehow? Yes I will add those, I didn't know if it would be needed or not but I should be able to get it in. Might take a few days, though. Lucian said: Without being able to see more of the internals I'm stabbing in the dark here, but it looks like attribute creation (perhaps only in repeating sections?) isn't triggering things the way I'd expect, only attribute modification. Feel free to PM me if you want me to show you the specific tests I've been running in more detail. I'm not sure if you gleaned anything further after the logging was put in place, but assuming this was still an issue I tried putting in some code to hopefully handle it better. The same setWithWorker() stuff should in theory be triggering on the creation of a new attribute as updating an existing attribute, but it's possible it wasn't working due to the way the API handles new object creation. Anyway, let me know if that helped. The Aaron said: What about calling the callback with some sort of context object?  Say something like: { workersExecuted: true, attributesChanged: [ 'foo','bar','repeating_inventory_-Jasd123fas_qty' ] } I added a new parameter to the callback, so you can now use it like so: onSheetWorkersCompleted(function(context) { //context.workersExecuted will be 'true' if sheet workers fired since the callback was set, 'false' otherwise. }); Okay, well hope that all helps! Let me know as you come across more stuff.
1476888849
Riley D.
Roll20 Dev Team
Lucian said: In the Shaped Sheet traits, actions etc are parsed from an attribute called content_srd, which is the droptarget for the Content field from the compendium. If I set this field to a value that matches the format from the compendium, the sheetworkers parse out the individual traits and actions from the content_srd value, and create new repeating rows for the relevant actions and traits. Each row gets a name value populated, and a "freetext" which contains the complete SRD text of the trait/action. Also, what's the current script you're working on that uses this functionality? Just curious. One of my main concerns with this (and the API in general) is basically people creating some sort of "one-click script" that ends up blowing up game sizes to something really really unreasonable. So just to be sure -- you're not making a script that like imports the whole Compendium into someone's game are you? Haha... 
1476889378
Kryx
Pro
Sheet Author
The script can only import 1 creature at a time and there are no current plans to change that. I doubt we would. The import was designed to mirror to srd import to reduce complexity and code. It fulfills the same function except imports from a user created json file.
1476889767
Riley D.
Roll20 Dev Team
Kryx said: The script can only import 1 creature at a time and there are no current plans to change that. I doubt we would. The import was designed to mirror to srd import to reduce complexity and code. It fulfills the same function except imports from a user created json file. Yeah okay that sounds fine. Basically a Compendium-style import for custom/homebrew creatures. Cool. I would just be sure to point out to people that the more Monsters you load your game up with, the larger the game file gets and that's bad because a) it takes a lot longer to load, and b) it can cause issues if it gets super large (we have some people who can't even create copies of their games right now because they have put like 400+ Characters into them). So I think if it's a situation where using the API allows you to not have to put everything into your game right away and you can just pull it in as-needed, that's a great option. I'm actually thinking of putting something on the Campaign details page where people can see the actual "size" of their game's data file just so they know how large it is, sort of as a community education thing.
1476889974
Kryx
Pro
Sheet Author
I have repeatedly warned people about importing hundreds of creatures and all the spells, but you know users as well as I. ;) Campaign size would be a nice indicator. Even better if it emphasizes the downsides of size like loading time and slower interactions.
1476890743
The Aaron
Pro
API Scripter
Ooh.. maybe add one of those little graphs with data points like "It will take 38 seconds to load this Game on an average Cable Connection."
1476945303
Lucian
Pro
API Scripter
Hey Riley, Thanks so much for looking into this. Things are a bit hectic at the moment and I haven't had a proper chance to look at the changes. An initial glance suggests that there's still a problem, but I haven't tried it with proper logging yet so I can't give you a full rundown of what's going on. I'll try and take a proper look tomorrow or over the weekend. And yes, as Kryx says, the script isn't intended to support enormous imports and we recommend against it. In fact, by allowing really easy import from custom JSON, the idea is to support people actually maintaining unused monsters *outside* the campaign so that they can keep the "live" data focussed purely on what's currently needed. Cheers,
1476993263
Scott C.
Pro
API Scripter
Not related to this, but to the previous API update. Any ETA on when noarchive will be fixed? It still isn't working after the last update (although the error is now more sporadic). Bug Report: https://app.roll20.net/forum/post/4093752/api-bug-noarchive-equals-true-still-funky/?pageforid=4093752#post-4093752
1477060636
Riley D.
Roll20 Dev Team
Scott C. said: Not related to this, but to the previous API update. Any ETA on when noarchive will be fixed? It still isn't working after the last update (although the error is now more sporadic). Bug Report:  https://app.roll20.net/forum/post/4093752/api-bug-noarchive-equals-true-still-funky/?pageforid=4093752#post-4093752 It's on my list, I don't have any further info at this time, I'll update that thread when I do.
1477060813
Scott C.
Pro
API Scripter
Sounds good, just wanted to make sure it had been noticed since I hadn't seen any response so far. Sorry to pester.
1477157972
Lucian
Pro
API Scripter
Ok, so the logging helps a lot - I now have a slightly clearer picture of what is going on.  It's still pretty tricky disentangling the various intertwined sequences of updates, but as far as I can tell, there are missing sheetworker events. Pretty much all calls to setAttrs in the Shaped Sheet go via a single function, in which I've placed a log call. Here's one piece of the output: "setFinalAttrs npc.updateContent: {\"default_ability\":\"intelligence\",\"repeating_action_-KUhPSofDH7ty6FMLD5G_name\":\"Scimitar\",\"repeating_action_-KUhPSofDH7ty6FMLD5G_freetext\":\"Melee Weapon Attack: +4 to hit, reach 5 ft., one target. Hit: 5 (1d6 + 2) slashing damage.\",\"repeating_action_-KUhPSofDH7ty6FMLD5H_name\":\"Shortbow\",\"repeating_action_-KUhPSofDH7ty6FMLD5H_freetext\":\"Ranged Weapon Attack: +4 to hit, range 80/320 ft., one target. Hit: 5 (1d6 + 2) piercing damage.\",\"repeating_trait_-KUhPSoggyg137WODfei_name\":\"Nimble Escape\",\"repeating_trait_-KUhPSoggyg137WODfei_display_text\":\"The goblin can take the Disengage or Hide action as a bonus action on each of its turns.\",\"repeating_trait_-KUhPSoggyg137WODfei_freetext\":\"The goblin can take the Disengage or Hide action as a bonus action on each of its turns.\"}" The object in there contains the attributes that are being set. You'll note that there are two repeating_actions and a repeating_trait being created. All three have a freetext field that is being set. Now, the sheet has event handlers for both 'change:repeating_action' and 'change:repeating_action:freetext'. I've put logging at the beginning of both those handlers, and they never get called. There's obviously a *lot* of other stuff going on at the same time, which complicates matters, but that seems to be the crux of it. As I pointed out before, if I *directly* modify the freetext attribute within that repeating section using the API, it looks like the handler gets fired correctly, so it's not a blanket problem with firing handlers in repeating sections. I guess it might either be an interaction with some of the other things going on at the same time, or perhaps, as I speculated before, it's connected to attribute creation specifically. Unfortunately I don't think I'm going to have time to create a more minimal testcase for a while right now - things are super-busy here - but I'm reasonably confident in stating that there *is* a problem with the sheetworker execution under the API based on the output of the logging. If it would help, I'm happy for you to experiment with the test campaign I'm using which has the relevant logging, and I can give you a small script that should trigger the problem reliably within that campaign.
1477159149
Lucian
Pro
API Scripter
Further to my previous post, I can confirm that just setting the content_srd attribute (which triggers the update mentioned in the previous post, and nothing else) also fails to trigger any subsequent sheetworker handlers despite them being registered, so it isn't any sort of interaction with the rest of the updates happening in the sheet. Hopefully this should make it more straightforward to track down.
1477346017
Lucian
Pro
API Scripter
Hey Riley, Just for the avoidance of doubt - I'm assuming you have everything you need from me at this point to track down the problem here - let me know if there's anything more you need me to provide. Cheers,
1477490938
Riley D.
Roll20 Dev Team
Okay so I'm not really able to get a test case for this yet. I realize it's happening with the sheet worker that you're using but as you noted, there's so much going on with that it could really be anything. Here's a simple test case I put together that shows that at least with simple scripts, having the API create a new attribute and then use setWithWorkers correctly triggers the sheet worker to run in the API, and if that sheet worker script that the API is executing then subsequently creates a new attribute, the sheet worker hears the change event for that attribute. https://gist.github.com/rileydutton/b988f2e1d05ff625674f89e39ee732b8 Can you modify that test case in your own testing to get it to show the behavior you're describing (where there's a 'break' in the chain?) If so that would make fixing it go a lot faster.
1477494444
Riley D.
Roll20 Dev Team
I've also just pushed out an update that adds support for using getTranslationByKey() along with loading all the relevant translation strings into the sheet worker on the API. However, note that since the API is run at a global level, the language is currently always set to "en" (US-English). I'm not really sure how we'll end up handling this long-term, it might have to be something we add to the API Settings page for the game or something like that.
1477502397
Lucian
Pro
API Scripter
Ok, thanks Riley. I will try and modify the testcase you've created to get it to break in the way I'm seeing - might be a day or two but I'll see what I can do. Thanks for the translation update - that's great. As concerns the language settings, in the future it might be nice if it was possible to change the API language programmatically, possibly along with ability to lookup the language setting for a player so that we can make the sheetworkers language-appropriate for the player that launches an API command, or controls a particular character.
1477502845
Riley D.
Roll20 Dev Team
Lucian said: Ok, thanks Riley. I will try and modify the testcase you've created to get it to break in the way I'm seeing - might be a day or two but I'll see what I can do.  Sounds good, I'll keep an eye out :-)
1477507194
Lucian
Pro
API Scripter
Ok, that was a lot easier than I was expecting. It looks like it is a repeating section issue. My modified gist is here: https://gist.github.com/symposion/a1d5ef45629170de... You'll see that if you edit the base attribute manually from the character sheet, you get a new repeating section row with both values filled in; but if you trigger it with a chat message, only one of the values in the row is filled in - the secondary sheet worker triggered from the creation of the first repeating section attribute is never fired.
1477515226
Riley D.
Roll20 Dev Team
Lucian said: Ok, that was a lot easier than I was expecting. It looks like it is a repeating section issue. My modified gist is here: https://gist.github.com/symposion/a1d5ef45629170de... You'll see that if you edit the base attribute manually from the character sheet, you get a new repeating section row with both values filled in; but if you trigger it with a chat message, only one of the values in the row is filled in - the secondary sheet worker triggered from the creation of the first repeating section attribute is never fired. Great, thanks, I can fix that :-) I'll let you know when it's fixed, might be Friday before I get a chance to get to it.
1477515400
Lucian
Pro
API Scripter
Riley D. said: Lucian said: Ok, that was a lot easier than I was expecting. It looks like it is a repeating section issue. My modified gist is here: https://gist.github.com/symposion/a1d5ef45629170de... You'll see that if you edit the base attribute manually from the character sheet, you get a new repeating section row with both values filled in; but if you trigger it with a chat message, only one of the values in the row is filled in - the secondary sheet worker triggered from the creation of the first repeating section attribute is never fired. Great, thanks, I can fix that :-) I'll let you know when it's fixed, might be Friday before I get a chance to get to it.
1477665423
Riley D.
Roll20 Dev Team
Okay I believe I have this fixed. Let me know if you run across any more oddities. Thanks!
1477674216
Lucian
Pro
API Scripter
Cool - that's looking much better now. I should be able to complete the work to change over the Shaped Companion script to use this in the next day or so and run a bunch of tests with it - I'll let you know if I find anything more.
1478022148
Lucian
Pro
API Scripter
Ok, so I've finally had a chance to finish off my conversion and although all the sheetworkers now seem to be firing, I think I've found a couple more problems (sorry!). First of all, I'm finding that the completion callback is happening early when I'm using it with a real-world case with the shaped sheet. This fires a lot of sheetworker scripts - equivalent to what happens when you drag a monster from the compendium onto the sheet - and there are many levels of dependent updates involved as well. My current assumption is that when I set a callback, it gets called after all the sheetworker activity that is triggered by all calls to setWithWorker in the current execution context has completed. In other words, if I call setWithWorker on 50 attributes, and then set an onSheetWorkerCompleted callback, it will be called when all the sheetworkers triggered by all those 50 attribute changes have finished. Furthermore, I was under the impression that there was some sort of delayed timer in place to look for dependent updates - and this timer was reset each time a new sheetworker handler was executed. If this is correct, it's possible that the delay is not working quite as hoped for my use case. If it's not already the case, I'd like to suggest that the delay timer is registered/reset *after* the completion of each sheetworker handler to be sure that any handlers that take a bit longer to complete don't result in the timer expiring unduly early. If that's already how it works, it's possible that some handlers which are doing several roundtrips of getAttrs/setAttrs with the associated callbacks are taking long enough that the timer is expiring. Would it be possible to have calls to getAttrs/setAttrs reset the timer, since this would indicate that activity is still "in full swing"? Otherwise we might have to look at increasing the timeout value, since it looks like it's not long enough to capture the dependent updates that are actually being performed. The other issue I'm seeing is that in some cases getTranslationByKey is still not working. In my simple testcase I can now look up a key successfully with no problems, but when I'm testing with the full shaped sheet I'm still seeing "key not found" errors a lot for some reason. I need a bit more time to try and formulate a minimal testcase for this, but perhaps you can double check to see if there's anything obviously wrong in the meantime - perhaps it's not working for dependent updates? I'll try and post something more on this ASAP.
1478027534
Riley D.
Roll20 Dev Team
Let me know what you find with the getTranslationByKey() stuff. At this point the function should be fully working so I don't know why the key not found errors would be happening...maybe make sure its not always happening with the same key? For the first part, the way that the callback handler works is very basic. It just has a "listener" that hears any "traffic" between the sheet worker thread and the parent thread and anytime any traffic happens, the timer gets reset. Currently the timer is just set to 250ms though, so I can try upping that to 1,000ms and see if that helps. But the timer is getting reset on any call to getAttrs() or setAttrs(). So if it's expiring faster than you think it should that probably means there is a delay due to some actual processing that is happening on the sheet worker thread (i.e. it's doing a big calculation)...I can increase the time like I said but again, this is not some really elegant solution or anything (as I pointed out when I put it in)...the only way to be extra-extra sure that something happens before something else would be to add an event listener for the specific variable that you are waiting on being set.