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

[HELP] Sheetworkers being weird with API script... again

1521727378

Edited 1521728034
Missingquery
Pro
Sheet Author
API Scripter
I posted this topic before, but I accidentally deleted it. Oops! Anyways, my former problem still stands: I have a problem with a sheet workers script being triggered "out of context", so to speak. Okay, so this is the script: on("change:Skl_total change:Lck_total change:Hitmod change:repeating_weapons change:_reporder_repeating_weapons remove:repeating_weapons", function(eventInfo) {    getSectionIDsOrdered("repeating_weapons", function(idarray) {        fID = idarray[0];        getAttrs(["Skl_total","Lck_total","Hitmod","repeating_weapons_"+fID+"_hit"], function(v) {            log(JSON.stringify(v))            let wHit = parseInt(v["repeating_weapons_"+fID+"_hit"])||0;            log("wHit is " + wHit)            let Skl = v.Skl_total;            let Lck = v.Lck_total;            let Mod = v.Hitmod            setAttrs({                Hit: Math.round((Skl * 3) + wHit + (Lck / 2)) + Number(Mod)            });            console.log(Math.round((Skl * 3) + wHit + (Lck / 2)));            console.log("Hitmod is" + Mod)        });    }); }); It gets the required stats and performs the calculation necessary from there, and works fine when altering values directly on the sheet. However, it seems to be triggering within the context of an API script specifically, as the logged messages appear in the API console rather than the browser console, and it keeps getting "repeating_weapons_"+fID+"_hit" as NaN, setting the value to 0 even if the actual repeating field on the character sheet exists. The weird thing is that as far as I can tell, there are very few things in the API script that directly modify these values, with most of them not occurring in 99% of cases when running the script (the error still occurs regardless), and even if there is something that's doing so, there's no reason why "repeatingweapons"+fID+"_hit" should return as NaN in the context of a worker if the field exists on the sheet. So what on earth is going on? The API script is here , if you're interested, though I don't think it'll be very helpful for figuring out why the sheetworkers is triggering when it shouldn't. Still, I might have missed something in there that might be causing it, so there you go. Things to note: The script has actually been triggering for hit at the end of the script for a while, but it didn't actually do anything, so I largely ignored it. It's only been recently, when I changed up my hit formula, that it started doing this. I'm going to try scouring the script to see if I can find what's calling it in the first place, but I don't expect to find anything. In my test cases, JSON.stringify(v) returned this: {"Skl_total":7,"Lck_total":2,"Hitmod":0,"repeating_weapons_-l84jfnwkee27telqkyy_hit":"90"} Confirming that the repeating_weapons value does indeed exist in this test case, though introducing a default attribute doesn't seem to be working either as it keeps getting wHit as 0 (and presumably, setting it as such in the callback). The results logged to the console in said test case are: "[object Object]" "wHit is 0" "25" "Hitmod is0" "4" "[object Object]" "[object Object]" "wHit is 90" "115" "Hitmod is0" "4" "[object Object]" Which to me, seems to suggest that the error is occurring in the function callback somewhere, but that doesn't really answer many questions. I'm trying to look for any lines in the script that may be inadvertently triggering changes in the values, but none of the attributes that factor into Hit seem to be changing in my test case, so I doubt I'll find anything. Unless somehow reading the values themselves counts as a change, but that seems unlikely. Edit: Logging eventInfo.newValue returned two slightly different logs: "{\"Skl_total\":7,\"Lck_total\":2,\"Hitmod\":0,\"repeating_weapons_-l84jfnwkee27telqkyy_hit\":\"90\"}" & "{\"Skl_total\":7,\"Lck_total\":2,\"Hitmod\":\"0\",\"repeating_weapons_-l83zfufutm5g0sa5kyv_hit\":\"90\"}" It seems unlikely, but might it be possible that hitmod and the repeating section being strings instead of integers is causing the error somehow? (Though that doesn't explain why hitmod is a number in one log and not the other.) Also, Jakob brought up this point: This will not perform as expected when you reorder the section; it will always use the weapon that has been created first, since getSectionIDs does not care about reordering. If that's the case, then as an aside, how would I go about getting the firstmost repeating section, if not my current method?
1521728744

Edited 1521728860
Jakob
Sheet Author
API Scripter
I actually took a look at the script. There's is nothing in there which seems  to be setting any of the attributes, BUT there are a bunch of places where attributes are defined via eval() [ EWWW!!! ] applied to the value of some ability, so presumably it could  happen that one of the source attributes (Hitmod, Skl_total, Lck_total, probably not one of the repeating attributes) is set via the script. It's really impossible to say, because eval() makes it totally opaque. (It also seems to be unnecessary, looks like you could in theory do everything via JSON.parse()).
1521729208

Edited 1521729224
Jakob
Sheet Author
API Scripter
It seems unlikely, but might it be possible that hitmod and the repeating section being strings instead of integers is causing the error somehow? (Though that doesn't explain why hitmod is a number in one log and not the other.) You convert Hitmod to a number anyway, so I don't see how. If that's the case, then as an aside, how would I go about getting the firstmost repeating section, if not my current method? You could use the getSectionIDsOrdered() helper function on the wiki (or write your own implementation): <a href="https://wiki.roll20.net/Sheet_Worker_Scripts#getSe" rel="nofollow">https://wiki.roll20.net/Sheet_Worker_Scripts#getSe</a>...
1521754200

Edited 1521754216
Missingquery
Pro
Sheet Author
API Scripter
Yeah, I've confirmed that that's not happening in any of my test cases. To explain the eval() thing: Basically, the script gets all of the abilities on a character (which are storing JSON objects in this format) and JSON.parses them into objects that can be manipulated. There are some key values that may need to reference in-script variables, and those are wrapped in strings to prevent JSON.parse from throwing an error, then later eval()'d so they pop out as valid code. So basically, I can't JSON.parse them, since they need to be parsed into expressions, not objects. While it's possible that a few keys might have a value that modifies hit's dependant attributes in any way, I've made sure this isn't the case by simply not having abilities on either character. Also, I'm already using getSectionIDsOrdered() as seen here: getSectionIDsOrdered("repeating_weapons", function(idarray) Anyways, logging eventInfo.newValue shows that whatever is changing the values, it's setting the attribute value to itself , which only raises more questions (again, since this never explicitly occurs in the script, nor does it in my test cases).
1521836185

Edited 1521852367
Missingquery
Pro
Sheet Author
API Scripter
Doing even further testing reveals that: The first and second change:hit calls are the attacking and defending units, respectively, not attacking unit and function callback, like I originally thought. Whatever the problem is, it seems to only be affecting the attacking unit, specifically- the defending unit is fine. Whatever the problem is, it also seems to be changing on the repeating_weapons field, discounting anything in the Skill() function, as that never touches those fields. Here's a (commented) log of another test case: "{\"Skl_total\":7,\"Lck_total\":2,\"Hitmod\":\"0\",\"repeating_weapons_-l83zfufutm5g0sa5kyv_hit\":\"90\"}" //attacker logged(v) "wHit is 0" // attacker weapon hit "22" //attacker computed hit "Hitmod is0" //attacker hitmod "4" //attacker computer crit "f_WName = undefined, f_WType = undefined, f_Strengths = undefined, f_Wt = NaN, f_Mt = NaN, f_Range1 = NaN, f_Range2 = NaN, f_Uses = NaN, f_WRank = undefined, fid = -l84jfnwkee27telqkyy, " // ^ attacker's weapon attributes, all of which are undefined/NaN except for the row ID "[object Object]" "{\"Skl_total\":7,\"Lck_total\":2,\"Hitmod\":0,\"repeating_weapons_-l84jfnwkee27telqkyy_hit\":\"90\"}" //defender logged (v) "wHit is 90" //defender weapon hit "112" //defender computed hit "Hitmod is0" //defender hitmod "4" //defender crit "f_WName = Iron Sword, f_WType = Sword/Katana, f_Strengths = undefined, f_Wt = 1, f_Mt = 5, f_Range1 = 1, f_Range2 = 1, f_Uses = 48, f_WRank = undefined, fid = -l84jfnwkee27telqkyy, " // ^ defender's weapon attributes, all of which are defined and perfectly fine "[object Object]" And here's the larger change:repeating_weapons function that the weapon attributes come from: on("change:repeating_weapons change:repeating_weapons_WName change:repeating_weapons_WType change:repeating_weapons_Wt change:repeating_weapons_Mt change:repeating_weapons_Range1 change:repeating_weapons_Range2 change:_reporder_repeating_weapons remove:repeating_weapons", function() { &nbsp;&nbsp; getSectionIDsOrdered("repeating_weapons", function(idarray) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console.log(idarray); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (idarray.length &lt; 1){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console.log("No weapon! Filling in default values"); //this works as expected &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; update = { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_WName: "Empty", &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_WType: "Stones/Other", &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_Strengths: "", &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_Wt: 0, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_Mt: 0, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_Range1: 1, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_Range2: 1, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_Uses: 68932, //some arbitrarily high number &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_WRank: "E", &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fid: "" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console.log(update); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setAttrs(update); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fID = idarray[0]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getAttrs(["repeating_weapons_"+fID+"_WName","repeating_weapons_"+fID+"_WType","repeating_weapons_"+fID+"_Wt","repeating_weapons_"+fID+"_Mt","repeating_weapons_"+fID+"_Range1","repeating_weapons_"+fID+"_Range2","repeating_weapons_"+fID+"_Strengths","repeating_weapons_"+fID+"_Uses","repeating_weapons_"+fID+"_WRank"], function(v) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; update = { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_WName: v["repeating_weapons_"+fID+"_WName"], &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_WType: v["repeating_weapons_"+fID+"_WType"], &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_Strengths: v["repeating_weapons_"+fID+"_Strengths"], &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_Wt: Number(v["repeating_weapons_"+fID+"_Wt"]), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_Mt: Number(v["repeating_weapons_"+fID+"_Mt"]), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_Range1: Number(v["repeating_weapons_"+fID+"_Range1"]), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_Range2: Number(v["repeating_weapons_"+fID+"_Range2"]), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_Uses: Number(v["repeating_weapons_"+fID+"_Uses"]), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f_WRank: v["repeating_weapons_"+fID+"_WRank"], &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fid: fID &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let string = "" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(var prop in update){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string += prop + " = " + update[prop] + ", " &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console.log(string) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console.log(update); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setAttrs(update); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp; }); }); I'm getting a little closer to figuring out what's causing the problem, but the definitive cause still eludes me. :( It seems to be having trouble getting the field itself, somehow, though I'm not sure why or how. I can either solve this by figuring out what's calling the function in the first place, or more likely, bug-proofing the above function so that the errant calls don't completely break everything. Edit: Okay, so I figure this is somehow related, but the fID of the attacking unit ends up getting set to the fID of the defending unit. Somehow? I'm not sure how that ends up happening, but I assume it's probably related.
1521918135
Missingquery
Pro
Sheet Author
API Scripter
Alright, the problem's been resolved! As it turns out, the f_Name and similar attributes were entirely unnecessary, and removing them has fixed the issue.