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
This post has been closed. You can still view previous posts, but you can't post any new replies.

[PF] I have found an issue in Roll20 that causes a lot of issues on Pathfinder (and likely other) character sheets, including updates not working, macros not calculating, autocalcs not updating, attributes not being retrieved etc

1452846170

Edited 1453109543
A lot of character sheet related issues such as lack of updates, inconsistent calculations, updates not sticking etc., are very likely caused by duplicate attribute and ability names on the Attributes and Abilities page. If there are duplicate attribute names, then setting values in character sheets will update the first instance of an attribute name and calculations and retrievals may retrieve another copy. Edit: I have written a script, a link to which is posted below. The script below will automatically resolve many conflicts, and will help you resolve the rest. I have written a script that checks for duplicate attributes in the Pathfinder v0.19 character sheet without access to the API. Steps to test your character sheet for duplicates: Load your character sheet in roll20. Click Attributes & Abilities Open the Console. In Chrome, press F12. In Firefox, press Ctrl + Shift + K (for PC), or Cmd-Option-K (for Mac) Paste the following script into the Console at the > prompt, and then press Enter (or Return) Edit: I have an updated script in a post below which allows you to find the duplicate attribute names along with their associated values. var duplicates = []; //get a collection of div elements containing the attribute names var attrs = $("body").find("div[class='attributesabilities tab-pane']").find("div[class='attributes']").find("div.attrname"); //sort the elements by case-insensitive name attrs = attrs.sort(  function(a,b)  {  var texta = (a.innerHTML || "").toLowerCase(); var textb = (b.innerHTML || "").toLowerCase(); return texta.localeCompare(textb); }); //look for duplicates for (var i = 1; i < attrs.length; i++) { //get the previous attribute name var last = (attrs[i-1].innerHTML || "").toLowerCase(); //get the current attribute name var curr = (attrs[i].innerHTML || "").toLowerCase(); //if the current attribute name equals the previous name if (curr === last) { //if there is no previous duplicate to check or the current duplicate is //a new duplicate, then add it to the list if (duplicates.length === 0 || curr !== duplicates[duplicates.length-1]) { duplicates.push(curr); } } } //print out a list of duplicate attributes console.log(duplicates.join("\n")); console.log("Number of duplicates: " + duplicates.length); The console will print out all of the attributes that have one or more duplicates in your character sheet, along with the total number of duplicates. In order for your character sheet to work properly for every attribute, there should be no duplicates. You will need to go through your attributes, delete every copy except for one, and update that last copy with the correct value. If you have hundreds of duplicates (as I do in my case), it was faster for me to do the following: Write down all of the information off my character sheet (stats, buffs, HP, defenses, attacks, skills, spells, details etc, Go to the Attributes page and delete every single attribute This will delete most of the values in your character sheet. Repeating sections may be untouched, but don't take my word for it. You will now find that most of the information from your character sheet is gone. Fill in your character sheet again from the information you saved. This will refresh the list of attributes and fix most update and calculation bugs. Unfortunately, even after this fix, there is no check to ensure that duplicates will not pop up in the future. I will try once again to get the dev team to update Roll20 to disallow duplicate attributes and abilities. This will require fixing the add attribute, update attribute name and delete attribute functions. If many other people report duplicate attribute names, then we may get a response. Thanks.
1452856209

Edited 1452856254
vÍnce
Pro
Sheet Author
Have you been able to determine why one sheet has dupes and another doesn't?  I tested a handful of characters(12 or so), and 2 had 100+ duplicate attributes.  Also, would it be possible for your script to post the values of the duplicates?  Could they be the same?  Thanks
1452867089

Edited 1452867715
chris b.
Pro
Sheet Author
API Scripter
Would this double count attributes that are on the NPC tab? some are repeated on that page and also appear on a PC page. the NPC page is as follows, but i'm not sure if this would even be under the attributesabilities tab-pane div. .find("div[class='sheet-section-npc']") Given the above, would it be more correct to say they only match if they have different cases?  like below: Or secondly, count them as dupe if the value also does not match, if the value is even in there. //get the previous attribute name var last = (attrs[i-1].innerHTML || "").toLowerCase(); var mixedLast = (attrs[i-1].innerHTML || ""); //get the current attribute name var curr = (attrs[i].innerHTML || "").toLowerCase(); var mixedCurr = (attrs[i].innerHTML || ""); //if the current attribute name equals the previous name if (curr === last && mixedCur !== mixedLast)
1452877016

Edited 1452883336
Riley D.
Roll20 Team
Okay, there's a lot going on here, so let me unpack some of it. First off, attribute names are not the defining unique property of an Attribute. Every attribute has an ID (which is not exposed in the attributes and abilities pane but you can see by inspecting the HTML if you're really curious). That's what allows you to change the name of an attribute after it is created, for example, without having to delete it and re-add it. However, it is true that for the purposes of Character Sheets and the dice engine, attributes are searched by name using a case-insensitive search. So if you have 4 different Attributes all named "Strength", when you do a roll for "/r 1d20 + @{strength}" it's going to find the first one (most likely the most recently-created one although there's no guarantees on that) and return the value for that attribute. So if you're dealing primarily with Character Sheets and the dice engine (macros, rolls, abilities, etc.), then yes you would only want to have one Attribute with each name (including from a case-insensitive standpoint) to avoid confusion. However, I think the question here is actually, how did you end up with multiple Attributes with the same name in the first place? Consider that there are multiple ways to add attributes to a Character: 1) You can add them manually through the Attributes and Abilities tab. Most people who are using Character Sheets are not doing this. It is true that using this method, we aren't currently checking for existing Attribute names, so you could add multiple attributes with the same name. 2) They are automatically added by the system when you use a Character Sheet. So if you change the value for a sheet input and the sheet author says that is the "Strength" input, we first check to see if there are any existing Strength attributes (including searching case-insensitively), and then if there aren't we add one. If there is an existing one, we update it. So no duplicate attributes should exist with this method. 3) They can be added by API scripts. Using the createObj() function you can create a new Attribute. Again, here we are not doing any sort of enforcement on name uniqueness, since it's assumed if you are writing an API script you "know what you're doing." So it would be possible using the API to create multiple Attributes with the same name. Note that if you are just calling the .set() function on an existing Attribute (e.g. one found during a ":change" event) you would not have this issue. We also provide two helper fucntions, findObjs() (which you can pass a "case-insensitive" flag to for just this purpose) and getAttrByName(), which is already case-insensitive, to allow API scripts to easily find attributes the same way we do internally for Character Sheets. 4) The new Sheet Workers system, which at least the Pathfinder sheet is using, has a setAttrs() call which will create a new attribute or update an existing one. Again, this function is already case-insensitive by default so this should not create multiple attributes with different cases. Okay, so, with all of that explained, I guess my question would be: 1) How do you think these duplicate attributes were created on your character? Are you using API Scripts? Are you manually entering attributes? If you're not doing either of those things, then I think there may be a bug someplace. 2) As you can see, for all the methods that most players will be using (using a Character Sheet, basically, including Sheet Workers), there are already safeguards in place to prevent duplicate Attributes with the same name from getting created. The other two methods (the API and manual entry) are more advanced methods and I think from our end we're assuming if you're doing that, you have read the documentation and understand what you're doing. Would it be worthwhile to add further safeguards there as well? Hope that helps break it down.
Vince said: Have you been able to determine why one sheet has dupes and another doesn't?  I tested a handful of characters(12 or so), and 2 had 100+ duplicate attributes.  Also, would it be possible for your script to post the values of the duplicates?  Could they be the same?  Thanks I can modify the script to print out the values as well. I'll get to it in a bit.
1452895214

Edited 1452897658
My edits are in bold. Okay, there's a lot going on here, so let me unpack some of it. First off, attribute names are not the defining unique property of an Attribute. Every attribute has an ID (which is not exposed in the attributes and abilities pane but you can see by inspecting the HTML if you're really curious). That's what allows you to change the name of an attribute after it is created, for example, without having to delete it and re-add it. If attributes are associated with IDs, then this should automatically mean that they are unique. Even if you are allowed to change an attribute name, it should still be unique, otherwise, as you said, there will be confusion. This isn't just player confusion, it confuses the system. However, it is true that for the purposes of Character Sheets and the dice engine, attributes are searched by name using a case-insensitive search. So if you have 4 different Attributes all named "Strength", when you do a roll for "/r 1d20 + @{strength}" it's going to find the first one (most likely the most recently-created one although there's no guarantees on that) and return the value for that attribute. This is exactly my point, and it is exactly what is causing all of the issues with these character sheets. This should be the most telling. "...it's going to find the first one (most likely the most recently-created one although there's no guarantees on that) and return the value for that attribute. When you are developing a program -- any program -- every function should be deterministic. This means that it should always return the expected output for every given input. Think of a database for example. When you create a table, you might want a column called 'name' to be unique. Therefore you create an index to enforce that. You don't assume that the user of the database 'knows what they are doing.' If you didn't do this, then you could easily end up with duplicate names in the database and this could cause you to retrieve the wrong account for example. So if you're dealing primarily with Character Sheets and the dice engine (macros, rolls, abilities, etc.), then yes you would only want to have one Attribute with each name (including from a case-insensitive standpoint) to avoid confusion. This isn't about player confusion. This is about the system failing to operate correctly when there are duplicate attributes. However, I think the question here is actually, how did you end up with multiple Attributes with the same name in the first place? Consider that there are multiple ways to add attributes to a Character: And the fact that there are multiple ways to add attributes means that you need to add validation at the lowest level function that actually implements the insert. Adding validation at the top-level caller is good practice, but the really important thing is to implement validation at the lowest level. This way, no matter what code path is taken to attempt an insert, the low-level function will catch the problem and throw an exception. 1) You can add them manually through the Attributes and Abilities tab. Most people who are using Character Sheets are not doing this. It is true that using this method, we aren't currently checking for existing Attribute names, so you could add multiple attributes with the same name. Adding attributes manually is an outside world facing function. These are the *most important* functions to validate. Part of QA is to come up with scenarios that break your code. So, make sure that you get someone else to test your code. You can test your colleagues' code. Make it a competition. Can you break their code? Can they break yours? This will make your system much more robust and resilient. 2) They are automatically added by the system when you use a Character Sheet. So if you change the value for a sheet input and the sheet author says that is the "Strength" input, we first check to see if there are any existing Strength attributes (including searching case-insensitively), and then if there aren't we add one. If there is an existing one, we update it. So no duplicate attributes should exist with this method. Are you sure that every code path for automatically adding attributes to the system is validated? If you do the check, you should force the people using your APIs to do the same thing. Don't assume that they'll just do it. If you throw an error for duplicates, then it makes the users of your API check for duplicates before doing their insert. 3) They can be added by API scripts. Using the createObj() function you can create a new Attribute. Again, here we are not doing any sort of enforcement on name uniqueness, since it's assumed if you are writing an API script you "know what you're doing." So it would be possible using the API to create multiple Attributes with the same name. Note that if you are just calling the .set() function on an existing Attribute (e.g. one found during a ":change" event) you would not have this issue. We also provide two helper fucntions, findObjs() (which you can pass a "case-insensitive" flag to for just this purpose) and getAttrByName(), which is already case-insensitive, to allow API scripts to easily find attributes the same way we do internally for Character Sheets. Again, not validating the input of your APIs has caused character sheets to have hundreds of duplicates. Somewhere along the way, API calls were made that inserted duplicates and broke the character sheet. Since no error was given, there was no notification at the time that anything was wrong. This is problematic behaviour. You, as a developer, want to do everything you can to ensure that your system remains in a consistent state. You don't want other internal developers accidentally creating an inconsistent state, and you certainly don't want sheet authors doing the same. 4) The new Sheet Workers system, which at least the Pathfinder sheet is using, has a setAttrs() call which will create a new attribute or update an existing one. Again, this function is already case-insensitive by default so this should not create multiple attributes with different cases. So to be clear, does the Sheet Workers system do the check on the client side or the server side? If the check is done just on the client side, then this is a convenience to the user of your system. However, *never* rely on client side validation to maintain the integrity of your system. Always assume that someone could change the code in your Sheet Workers system to do some other customized behaviour, and that this alteration may cause the client to inadvertently insert duplicate attributes. Okay, so, with all of that explained, I guess my question would be: 1) How do you think these duplicate attributes were created on your character? Are you using API Scripts? Are you manually entering attributes? If you're not doing either of those things, then I think there may be a bug someplace. I, along with the vast majority of Roll20 users, am just a user of the system. I'm not a character sheet author or GM. I'm just a player. (Although, now I'm helping out a bit with the Pathfinder character sheet.) 2) As you can see, for all the methods that most players will be using (using a Character Sheet, basically, including Sheet Workers), there are already safeguards in place to prevent duplicate Attributes with the same name from getting created. The other two methods (the API and manual entry) are more advanced methods and I think from our end we're assuming if you're doing that, you have read the documentation and understand what you're doing. Would it be worthwhile to add further safeguards there as well? Here is where the red flag is. "The other two methods (the API and manual entry) are more advanced methods and I think from our end we're *assuming* if you're doing that, you have read the documentation and understand what you are doing. My comment here is that when you are programming defensively, *Never Assume Anything", except that your caller is evil and wants to break your system. If you think this way, you'll be a lot more paranoid about what might come in and mess things up (even if it was unintentional.) Hope that helps break it down. Riley, In *any* API, (or any function for that matter), input should be validated. Take a look at any API provided by Amazon, Google etc. Millions of people who "know what they are doing" use these services every day. These services validate their input to ensure that their systems remain in a usable state. For **any** public facing API, you need to make sure that the input you receive is acceptable to your system. For example, the most common method to attack a website is still SQL injection. This is where a developer has written something like the following: "INSERT INTO USERS (username,password, ...) VALUES (' + username + ','password'...); They don't validate the input coming in from the client. So someone comes along and enters the following for the user name: '); DROP DATABASE;-- The SQL query then becomes "INSERT INTO USERS (username,password, ...) VALUES (''); DROP DATABASE;--+ username + ','password'...); (BTW, never build SQL queries this way! It was just an example of how other websites have been hacked.) The first insert statement will just fail, but then the second statement will drop the database. Oops. Defensive programming requires you to pretend that the client is always out to get you. Assume the client is evil, (even if they aren't.) Even in the case that the client is not evil, developers make mistakes. If we didn't, we would develop bug-free software the first time, every time. Since this is not reality, we need to ensure that any API we write has validated the input as much as is possible. Is there a restriction on integer range? on string length? case sensitivity? duplicate values? Is any parameter null? Are empty strings allowed? If an array is passed in, is it allocated? Does the array contain values? Are the values it contains valid? As you can see, there are potentially many constraints to what might be acceptable input. You may be able to skip input validation with private functions, since you know the class you're in, and that the data passed in is valid. However, even in public methods of classes that the outside world will never see, the 'client' is the caller of that class. Assume the developer of the code that calls your method might make a mistake. Validate your input and tell them that they made a mistake.  To wrap up, even highly experienced developers will make mistakes. I like to think I know what I'm doing, but I screw up all the time. (I wish I could develop bug-free software. I'd be a multi-millionaire.) People that develop character sheets for Roll20 can also make mistakes, even if they know what they are doing. Somewhere along the line, someone inserted duplicate attributes. Whether it was a character sheet author, or a Roll20 dev, if the lowest level AddAttribute, UpdateAttribute and DeleteAttribute functions had input validation, these bugs would have never progressed at all. They would have been caught as soon as the person inserting the duplicate received an error. They would have corrected their bug, the widespread issue of duplicate attributes wouldn't have happened, and we wouldn't be having this discussion.  Thank you for looking into this. I would classify this as a critical fix, since it is central to the operation of every character sheet, and therefore Roll20, and is not just limited to Pathfinder. For the Pathfinder character sheet authors, it might be nice for users to have a warning where your Attention message is that uses a script such as the one above that looks for duplicate attributes and informs the user that their character sheet will not function correctly. Thank you, Paul
First off, let's take it down a notch. Your post is quite argumentative and we specifically disallow that type of point-by-point rebuttal here since it's rarely helpful. My goal here is simply to establish if there is actually a bug with the Character Sheet system or if this just a case of data corruption via API use. My original question still stands, which is quite simply, was this caused by the use of an API script and/or manual entry? Based on your response I'm assuming "yes" but it would be helpful to get confirmation on that so I know if there is an actual bug at play here. Finally, I'm not really sure why this is posted as an issue in the Character Sheet forum and a problem with the Pathfinder sheet. It seems like more of a suggestion for how we should change our philosophy regarding the API to your ideal of how it should function.  To be clear, there are a lot of ways you can break your game using the API. You could delete a bunch of your tokens. You could overwrite your character's data with nonsense. You could accidentally give away the secrets stored in your GM-only-super-secret handout to your players. And yes, you can absolutely create multiple attributes with the same name which probably isn't a great idea if you meant to update an existing attribute instead. That's not a bug, that's just a reflection of the fact that the API is low-level and very powerful. We're very explicit about this in the documentation, and there's even a big red warning on top of the API Scripts page for your game that says "Hey, be careful."  Certainly we would never leave the system open to the level of security vulnerability that you're suggesting. You can't change other people's campaign data with your script. You can't crash our entire API server with a faulty command. You can't even send a chat message that contains a reflective XSS Javascript snippet. But you can definitely do whatever you want with your own campaign data. I don't think we have any desire to change that philosophy, because it's exactly the type of power that has let people do some amazing things with the API. (And I'm not really looking to debate that, either, so let's just stick to the original point of the thread, which is to determine if there is a bug.)
1452904165

Edited 1452904385
Riley D. said: 2) They are automatically added by the system when you use a Character Sheet. So if you change the value for a sheet input and the sheet author says that is the "Strength" input, we first check to see if there are any existing Strength attributes (including searching case-insensitively), and then if there aren't we add one. If there is an existing one, we update it. So no duplicate attributes should exist with this method. I have absolutely no knowledge on the subject, but I have done some testing with the D&D shaped sheet, and I'm able to create duplicates while only changing value in the character sheet (I didn't use API nor manually change attributes and it's the shaped, so no sheetworker). Before going into details, I will point out that this is probably not the reason why you have 100+ duplicates (especially because the PF sheet is the only one affected so badly, and you can do that on every sheet), but that can create some duplicates. 1) Lag issue : First way to create duplicates is by changing the value of an input before the sheet is fully load. I set up a really really (really...) slow connection for the test, launch a campaign and immediately open a character sheet that already had strength set to 10. Due to the slow connection, the sheet was not fully loaded when I open it (I know that because Bio&Info was displaying "loading..." and I didn't see any value in the character sheet/attribute tab). I set strength to 20 and close the sheet. When the sheet finally load in, there was two "strength" attribute : one set to 10, and another set to 20. While this was on a terrible connection, I believe occasional spikes may lead to the same result. 2) Fast clicking : On the Shaped sheet, you can change the language of the sheet directly by clicking on a little flag. By switching fast enough, I was able to create duplicates. However, it was really hard and I only manage to do that once, and only for language (but I know that it can also happen why tabs as well). I suspect it may, in fact, be related to the lag issue (switching too fast so you switch before the sheet is fully loaded?). It may probably happen if you have a GM and a player messing with the sheet at the same time, and some people already reported having duplicates while only using the shaped sheet, so that's probably why. I hope it helps at least a little bit :)
1452907720

Edited 1452909144
Riley D. said: First off, let's take it down a notch. Your post is quite argumentative and we specifically disallow that type of point-by-point rebuttal here since it's rarely helpful. My goal here is simply to establish if there is actually a bug with the Character Sheet system or if this just a case of data corruption via API use. My original question still stands, which is quite simply, was this caused by the use of an API script and/or manual entry? Based on your response I'm assuming "yes" but it would be helpful to get confirmation on that so I know if there is an actual bug at play here. Finally, I'm not really sure why this is posted as an issue in the Character Sheet forum and a problem with the Pathfinder sheet. It seems like more of a suggestion for how we should change our philosophy regarding the API to your ideal of how it should function.  To be clear, there are a lot of ways you can break your game using the API. You could delete a bunch of your tokens. You could overwrite your character's data with nonsense. You could accidentally give away the secrets stored in your GM-only-super-secret handout to your players. And yes, you can absolutely create multiple attributes with the same name which probably isn't a great idea if you meant to update an existing attribute instead. That's not a bug, that's just a reflection of the fact that the API is low-level and very powerful. We're very explicit about this in the documentation, and there's even a big red warning on top of the API Scripts page for your game that says "Hey, be careful."  Certainly we would never leave the system open to the level of security vulnerability that you're suggesting. You can't change other people's campaign data with your script. You can't crash our entire API server with a faulty command. You can't even send a chat message that contains a reflective XSS Javascript snippet. But you can definitely do whatever you want with your own campaign data. I don't think we have any desire to change that philosophy, because it's exactly the type of power that has let people do some amazing things with the API. (And I'm not really looking to debate that, either, so let's just stick to the original point of the thread, which is to determine if there is a bug.) I wasn't trying to be argumentative for the sake of it. I didn't know how to convey my ideas more clearly than to respond to each point. I was not trying to convey any sense of negativity in my post. I have tried to convey my points in relatively short, succinct messages, but they have been rejected without explanation. If you say that allowing duplicate attribute names is not a bug, then can you please provide me with a use case where duplicate attributes would be allowed? If something could theoretically be allowed by the system, then I completely agree. Leave it open. However, in this case, if there is fundamentally no way a character sheet could function correctly with duplicate attributes, then this is a bug. Accidentally sending your players super secret GM notes, deleting tokens, purposely entering garbage into character sheets etc is not the same as entering duplicate attribute names. The above scenarios are easily reversed with a few clicks. Having duplicates silently insert, only to find incorrect calculations in-game is entirely different. For example, in our game, a Haste spell expired. Therefore, I unchecked the Buff for Haste. The character sheet reported that Haste was deactivated, and we continued playing. However, at some point later in the combat, I went over the bonuses and penalties that were currently being applied, and it turns out that the attack bonus for Haste was still being applied even though I had deactivated Haste. This negatively impacts games. It unfairly gives players unexpected advantages or disadvantages through no fault of any player or GM. This was posted in the Character Sheet forum because my more succinct post pointing this out as a bug was rejected without explanation. I therefore created a script specifically targeting Pathfinder Character Sheets that would allow other players to identify if they are also experiencing issues with their sheets. This script does not work with other character sheets. I'm not asking to lock down the API based on the equivalent of business rules, as these rules will obviously vary greatly by game and campaign. I am suggesting that given the widespread nature of the issues that this particular (for me a bug, for you a feature) has caused, that there should be the same check for the external API that you have internally. This issue has caused character sheets to fail to operate as expected and, in your words, has caused data corruption via the API case. Data corruption should be avoided, especially when the fix is so simple. An API should not be able to corrupt a character sheet. People (including me) have been forced to delete and completely rewrite their characters because of this issue. Since this issue remains, there is no protection against any future duplication, and therefore we may have to rewrite our character sheets on a regular basis just to keep them operating. Please consider my points before you dismiss me as argumentative. I am presenting my points rationally, without insulting, putting down or otherwise attacking anyone's ability or personality. Thank you. Edit: As point out by Alzam, duplicate attributes can be inserted into the character sheet due to lag and other issues as well. This is why the system should reject duplicates. Lag, timing, clicking etc, should not corrupt data.
1452909893

Edited 1452910176
I have updated the script that checks Pathfinder character sheets for duplicate attributes. The script will now print out the names and values of each duplicate attribute. I found many duplicates contained the same value, but many others that contain different values. Here is the updated script: var duplicates = []; //get a collection of div elements containing the attribute names var attrs = $("body").find("div[class='attributesabilities tab-pane']").find("div.attributes").find("div.attrib"); //sort the elements by case-insensitive name attrs = attrs.sort(  function(a,b)  {  var texta = ($(a).find("div.attrname").html() || "").toLowerCase(); var textb = ($(b).find("div.attrname").html() || "").toLowerCase(); return texta.localeCompare(textb); }); //look for duplicates for (var i = 1; i < attrs.length; i++) { //get the previous attribute name var last = ($(attrs[i-1]).find("div.attrname").html() || "").toLowerCase(); //get the current attribute names var curr = ($(attrs[i]).find("div.attrname").html() || "").toLowerCase(); //if the current attribute name equals the previous name if (curr === last) { var attrName = curr; var attrValue = $(attrs[i]).find("div.current input").val(); //if there is no previous duplicate to check or the current duplicate is //a new duplicate, then add it to the list, and add the last value if (duplicates[attrName] === undefined) { var attrLastValue = $(attrs[i-1]).find("div.current input").val(); duplicates[attrName] = []; duplicates[attrName].push(attrLastValue); } //add the value of the current duplicate to the list of values duplicates[attrName].push(attrValue); } } var attrCount = 0; var duplicateMessages = []; //print out a list of duplicate attributes for (var attrName in duplicates) { if (duplicates.hasOwnProperty(attrName)) { attrCount++; duplicateMessages.push("Name: " + attrName + " Values: " + duplicates[attrName].join(", ")); } } console.log(duplicateMessages.join("\n")); console.log("Number of Duplicates: " + attrCount); Please let me know if this helps find issues anyone has been having. Thank you.
Vince said: Have you been able to determine why one sheet has dupes and another doesn't?  I tested a handful of characters(12 or so), and 2 had 100+ duplicate attributes.  Also, would it be possible for your script to post the values of the duplicates?  Could they be the same?  Thanks I have not yet determined why some have dupes and some don't. One of the things that could have happened is that a worker script or some other upgrade script may have inserted duplicates when the new attributes were added. For instance, if a character sheet automatically adds an attribute for a new field, but then an upgrade script repeats the process, this may explain why there are duplicates. This is all the more reason why I believe the API should to be updated. I have provided a script in a new post that will print out the names and values of duplicate attributes. Many attributes contain the same values (probably the default), but some others have different values. This would explain inconsistent updates, display and calculation issues. It doesn't appear that Riley agrees with my assessment that duplicate attributes is a bug. Given that you are a sheet author, what is your position on this issue?
chris b. said: Would this double count attributes that are on the NPC tab? some are repeated on that page and also appear on a PC page. the NPC page is as follows, but i'm not sure if this would even be under the attributesabilities tab-pane div. .find("div[class='sheet-section-npc']") Given the above, would it be more correct to say they only match if they have different cases?  like below: Or secondly, count them as dupe if the value also does not match, if the value is even in there. //get the previous attribute name var last = (attrs[i-1].innerHTML || "").toLowerCase(); var mixedLast = (attrs[i-1].innerHTML || ""); //get the current attribute name var curr = (attrs[i].innerHTML || "").toLowerCase(); var mixedCurr = (attrs[i].innerHTML || ""); //if the current attribute name equals the previous name if (curr === last && mixedCur !== mixedLast) I have only looked for attributes with the same name. I have rewritten the script to print out the names of duplicate attributes along with the list of values these duplicate names have. It looks like the NPC character sheet stores values to the same Attributes page with a prefix of npc-. Given that you are a sheet author, what is your position on this issue?
1452912237

Edited 1452912321
Alzam said: Riley D. said: 2) They are automatically added by the system when you use a Character Sheet. So if you change the value for a sheet input and the sheet author says that is the "Strength" input, we first check to see if there are any existing Strength attributes (including searching case-insensitively), and then if there aren't we add one. If there is an existing one, we update it. So no duplicate attributes should exist with this method. I have absolutely no knowledge on the subject, but I have done some testing with the D&D shaped sheet, and I'm able to create duplicates while only changing value in the character sheet (I didn't use API nor manually change attributes and it's the shaped, so no sheetworker). Before going into details, I will point out that this is probably not the reason why you have 100+ duplicates (especially because the PF sheet is the only one affected so badly, and you can do that on every sheet), but that can create some duplicates. 1) Lag issue : First way to create duplicates is by changing the value of an input before the sheet is fully load. I set up a really really (really...) slow connection for the test, launch a campaign and immediately open a character sheet that already had strength set to 10. Due to the slow connection, the sheet was not fully loaded when I open it (I know that because Bio&Info was displaying "loading..." and I didn't see any value in the character sheet/attribute tab). I set strength to 20 and close the sheet. When the sheet finally load in, there was two "strength" attribute : one set to 10, and another set to 20. While this was on a terrible connection, I believe occasional spikes may lead to the same result. 2) Fast clicking : On the Shaped sheet, you can change the language of the sheet directly by clicking on a little flag. By switching fast enough, I was able to create duplicates. However, it was really hard and I only manage to do that once, and only for language (but I know that it can also happen why tabs as well). I suspect it may, in fact, be related to the lag issue (switching too fast so you switch before the sheet is fully loaded?). It may probably happen if you have a GM and a player messing with the sheet at the same time, and some people already reported having duplicates while only using the shaped sheet, so that's probably why. I hope it helps at least a little bit :) Thank you Alzam for doing testing. As is shown in Alzam's test cases, duplicates can be caused by latency, low bandwidth, and concurrency issues. Concurrency is an ongoing issue. My GM checks on my character sheet while I'm changing quite regularly.  Given that the issue occurs just from character sheet manipulation and not just the API should indicate that the low level function needs to be validated.
1452917747
vÍnce
Pro
Sheet Author
I'm not sure why "some" sheets have duplicate attributes while others, using the same sheet, do not.  Is it possible that sheet workers could "tie-up" some attributes during calculations making them appear non-existent?  Appologies, but I'm not far beyond 'Hello World!' in javascript. In regards to the character below,  I have no clue how the duplicates could have been created. They were not manually added and I did not generate them with an API script. Here's the results for one character that had duplicates detected.  note: this sheet seems to function without issue. Name: attk-cmb-gnote Values: , +2 grapple Name: attk-ranged Values: 3, 3 Name: buff1_ac Values: 0, 0 Name: buff1_cha Values: 0, 0 Name: buff1_con Values: 0, 0 Name: buff1_dex Values: 0, 0 Name: buff1_dmg Values: 0, 0 Name: buff1_fort Values: 0, 0 Name: buff1_hp-temp Values: 0, 0 Name: buff1_int Values: 0, 0 Name: buff1_melee Values: 0, 0 Name: buff1_ranged Values: 0, 0 Name: buff1_ref Values: 0, 0 Name: buff1_str Values: 0, 0 Name: buff1_will Values: 0, 0 Name: buff1_wis Values: 0, 0 Name: buff10_ac Values: 0, 0 Name: buff10_cha Values: 0, 0 Name: buff10_con Values: 0, 0 Name: buff10_dex Values: 0, 0 Name: buff10_dmg Values: 0, 0 Name: buff10_fort Values: 0, 0 Name: buff10_hp-temp Values: 0, 0 Name: buff10_int Values: 0, 0 Name: buff10_melee Values: 0, 0 Name: buff10_ranged Values: 0, 0 Name: buff10_ref Values: 0, 0 Name: buff10_str Values: 0, 0 Name: buff10_will Values: 0, 0 Name: buff10_wis Values: 0, 0 Name: buff2_ac Values: 0, 0 Name: buff2_cha Values: 0, 0 Name: buff2_con Values: 0, 0 Name: buff2_dex Values: 0, 0 Name: buff2_dmg Values: 0, 0 Name: buff2_fort Values: 0, 0 Name: buff2_hp-temp Values: 0, 0 Name: buff2_int Values: 0, 0 Name: buff2_melee Values: 0, 0 Name: buff2_ranged Values: 0, 0 Name: buff2_ref Values: 0, 0 Name: buff2_str Values: 0, 0 Name: buff2_will Values: 0, 0 Name: buff2_wis Values: 0, 0 Name: buff3_ac Values: 0, 0 Name: buff3_cha Values: 0, 0 Name: buff3_con Values: 0, 0 Name: buff3_dex Values: 0, 0 Name: buff3_dmg Values: 0, 0 Name: buff3_fort Values: 0, 0 Name: buff3_hp-temp Values: 0, 0 Name: buff3_int Values: 0, 0 Name: buff3_melee Values: 0, 0 Name: buff3_ranged Values: 0, 0 Name: buff3_ref Values: 0, 0 Name: buff3_str Values: 0, 0 Name: buff3_will Values: 0, 0 Name: buff3_wis Values: 0, 0 Name: buff4_ac Values: 0, 0 Name: buff4_cha Values: 0, 0 Name: buff4_con Values: 0, 0 Name: buff4_dex Values: 0, 0 Name: buff4_dmg Values: 0, 0 Name: buff4_fort Values: 0, 0 Name: buff4_hp-temp Values: 0, 0 Name: buff4_int Values: 0, 0 Name: buff4_melee Values: 0, 0 Name: buff4_ranged Values: 0, 0 Name: buff4_ref Values: 0, 0 Name: buff4_str Values: 0, 0 Name: buff4_will Values: 0, 0 Name: buff4_wis Values: 0, 0 Name: buff5_ac Values: 0, 0 Name: buff5_cha Values: 0, 0 Name: buff5_con Values: 0, 0 Name: buff5_dex Values: 0, 0 Name: buff5_dmg Values: 0, 0 Name: buff5_fort Values: 0, 0 Name: buff5_hp-temp Values: 0, 0 Name: buff5_int Values: 0, 0 Name: buff5_melee Values: 0, 0 Name: buff5_ranged Values: 0, 0 Name: buff5_ref Values: 0, 0 Name: buff5_str Values: 0, 0 Name: buff5_will Values: 0, 0 Name: buff5_wis Values: 0, 0 Name: buff6_ac Values: 0, 0 Name: buff6_cha Values: 0, 0 Name: buff6_con Values: 0, 0 Name: buff6_dex Values: 0, 0 Name: buff6_dmg Values: 0, 0 Name: buff6_fort Values: 0, 0 Name: buff6_hp-temp Values: 0, 0 Name: buff6_int Values: 0, 0 Name: buff6_melee Values: 0, 0 Name: buff6_ranged Values: 0, 0 Name: buff6_ref Values: 0, 0 Name: buff6_str Values: 0, 0 Name: buff6_will Values: 0, 0 Name: buff6_wis Values: 0, 0 Name: buff7_ac Values: 0, 0 Name: buff7_cha Values: 0, 0 Name: buff7_con Values: 0, 0 Name: buff7_dex Values: 0, 0 Name: buff7_dmg Values: 0, 0 Name: buff7_fort Values: 0, 0 Name: buff7_hp-temp Values: 0, 0 Name: buff7_int Values: 0, 0 Name: buff7_melee Values: 0, 0 Name: buff7_ranged Values: 0, 0 Name: buff7_ref Values: 0, 0 Name: buff7_str Values: 0, 0 Name: buff7_will Values: 0, 0 Name: buff7_wis Values: 0, 0 Name: buff8_ac Values: 0, 0 Name: buff8_cha Values: 0, 0 Name: buff8_con Values: 0, 0 Name: buff8_dex Values: 0, 0 Name: buff8_dmg Values: 0, 0 Name: buff8_fort Values: 0, 0 Name: buff8_hp-temp Values: 0, 0 Name: buff8_int Values: 0, 0 Name: buff8_melee Values: 0, 0 Name: buff8_ranged Values: 0, 0 Name: buff8_ref Values: 0, 0 Name: buff8_str Values: 0, 0 Name: buff8_will Values: 0, 0 Name: buff8_wis Values: 0, 0 Name: buff9_ac Values: 0, 0 Name: buff9_cha Values: 0, 0 Name: buff9_con Values: 0, 0 Name: buff9_dex Values: 0, 0 Name: buff9_dmg Values: 0, 0 Name: buff9_fort Values: 0, 0 Name: buff9_hp-temp Values: 0, 0 Name: buff9_int Values: 0, 0 Name: buff9_melee Values: 0, 0 Name: buff9_ranged Values: 0, 0 Name: buff9_ref Values: 0, 0 Name: buff9_str Values: 0, 0 Name: buff9_will Values: 0, 0 Name: buff9_wis Values: 0, 0 Name: cha-mod Values: 1, 1 Name: cmd-size Values: 0, 0 Name: con-mod Values: 2, 2 Name: dex-mod Values: 0, 0 Name: int-mod Values: 0, 0 Name: pfsheet_version Values: 0.19, 0.1 Name: recalc1 Values: 0, 0 Name: size_display Values: 0, 0 Name: size_skill Values: 0, 0 Name: size_skill_double Values: 0, 0 Name: str-mod Values: 2, 2 Name: wis-mod Values: 4, 4 VM2101:59 Number of Duplicates: 154 undefined
1452920559

Edited 1452921732
Vince said: I'm not sure why "some" sheets have duplicate attributes while others, using the same sheet, do not.  Is it possible that sheet workers could "tie-up" some attributes during calculations making them appear non-existent?  Appologies, but I'm not far beyond 'Hello World!' in javascript. In regards to the character below,  I have no clue how the duplicates could have been created. They were not manually added and I did not generate them with an API script. Here's the results for one character that had duplicates detected.  note: this sheet seems to function without issue. Name: attk-cmb-gnote Values: , +2 grapple Name: attk-ranged Values: 3, 3 Name: buff1_ac Values: 0, 0 Name: buff1_cha Values: 0, 0 Name: buff1_con Values: 0, 0 Name: buff1_dex Values: 0, 0 Name: buff1_dmg Values: 0, 0 Name: buff1_fort Values: 0, 0 Name: buff1_hp-temp Values: 0, 0 Name: buff1_int Values: 0, 0 Name: buff1_melee Values: 0, 0 Name: buff1_ranged Values: 0, 0 Name: buff1_ref Values: 0, 0 Name: buff1_str Values: 0, 0 Name: buff1_will Values: 0, 0 Name: buff1_wis Values: 0, 0 Name: buff10_ac Values: 0, 0 Name: buff10_cha Values: 0, 0 Name: buff10_con Values: 0, 0 Name: buff10_dex Values: 0, 0 Name: buff10_dmg Values: 0, 0 Name: buff10_fort Values: 0, 0 Name: buff10_hp-temp Values: 0, 0 Name: buff10_int Values: 0, 0 Name: buff10_melee Values: 0, 0 Name: buff10_ranged Values: 0, 0 Name: buff10_ref Values: 0, 0 Name: buff10_str Values: 0, 0 Name: buff10_will Values: 0, 0 Name: buff10_wis Values: 0, 0 Name: buff2_ac Values: 0, 0 Name: buff2_cha Values: 0, 0 Name: buff2_con Values: 0, 0 Name: buff2_dex Values: 0, 0 Name: buff2_dmg Values: 0, 0 Name: buff2_fort Values: 0, 0 Name: buff2_hp-temp Values: 0, 0 Name: buff2_int Values: 0, 0 Name: buff2_melee Values: 0, 0 Name: buff2_ranged Values: 0, 0 Name: buff2_ref Values: 0, 0 Name: buff2_str Values: 0, 0 Name: buff2_will Values: 0, 0 Name: buff2_wis Values: 0, 0 Name: buff3_ac Values: 0, 0 Name: buff3_cha Values: 0, 0 Name: buff3_con Values: 0, 0 Name: buff3_dex Values: 0, 0 Name: buff3_dmg Values: 0, 0 Name: buff3_fort Values: 0, 0 Name: buff3_hp-temp Values: 0, 0 Name: buff3_int Values: 0, 0 Name: buff3_melee Values: 0, 0 Name: buff3_ranged Values: 0, 0 Name: buff3_ref Values: 0, 0 Name: buff3_str Values: 0, 0 Name: buff3_will Values: 0, 0 Name: buff3_wis Values: 0, 0 Name: buff4_ac Values: 0, 0 Name: buff4_cha Values: 0, 0 Name: buff4_con Values: 0, 0 Name: buff4_dex Values: 0, 0 Name: buff4_dmg Values: 0, 0 Name: buff4_fort Values: 0, 0 Name: buff4_hp-temp Values: 0, 0 Name: buff4_int Values: 0, 0 Name: buff4_melee Values: 0, 0 Name: buff4_ranged Values: 0, 0 Name: buff4_ref Values: 0, 0 Name: buff4_str Values: 0, 0 Name: buff4_will Values: 0, 0 Name: buff4_wis Values: 0, 0 Name: buff5_ac Values: 0, 0 Name: buff5_cha Values: 0, 0 Name: buff5_con Values: 0, 0 Name: buff5_dex Values: 0, 0 Name: buff5_dmg Values: 0, 0 Name: buff5_fort Values: 0, 0 Name: buff5_hp-temp Values: 0, 0 Name: buff5_int Values: 0, 0 Name: buff5_melee Values: 0, 0 Name: buff5_ranged Values: 0, 0 Name: buff5_ref Values: 0, 0 Name: buff5_str Values: 0, 0 Name: buff5_will Values: 0, 0 Name: buff5_wis Values: 0, 0 Name: buff6_ac Values: 0, 0 Name: buff6_cha Values: 0, 0 Name: buff6_con Values: 0, 0 Name: buff6_dex Values: 0, 0 Name: buff6_dmg Values: 0, 0 Name: buff6_fort Values: 0, 0 Name: buff6_hp-temp Values: 0, 0 Name: buff6_int Values: 0, 0 Name: buff6_melee Values: 0, 0 Name: buff6_ranged Values: 0, 0 Name: buff6_ref Values: 0, 0 Name: buff6_str Values: 0, 0 Name: buff6_will Values: 0, 0 Name: buff6_wis Values: 0, 0 Name: buff7_ac Values: 0, 0 Name: buff7_cha Values: 0, 0 Name: buff7_con Values: 0, 0 Name: buff7_dex Values: 0, 0 Name: buff7_dmg Values: 0, 0 Name: buff7_fort Values: 0, 0 Name: buff7_hp-temp Values: 0, 0 Name: buff7_int Values: 0, 0 Name: buff7_melee Values: 0, 0 Name: buff7_ranged Values: 0, 0 Name: buff7_ref Values: 0, 0 Name: buff7_str Values: 0, 0 Name: buff7_will Values: 0, 0 Name: buff7_wis Values: 0, 0 Name: buff8_ac Values: 0, 0 Name: buff8_cha Values: 0, 0 Name: buff8_con Values: 0, 0 Name: buff8_dex Values: 0, 0 Name: buff8_dmg Values: 0, 0 Name: buff8_fort Values: 0, 0 Name: buff8_hp-temp Values: 0, 0 Name: buff8_int Values: 0, 0 Name: buff8_melee Values: 0, 0 Name: buff8_ranged Values: 0, 0 Name: buff8_ref Values: 0, 0 Name: buff8_str Values: 0, 0 Name: buff8_will Values: 0, 0 Name: buff8_wis Values: 0, 0 Name: buff9_ac Values: 0, 0 Name: buff9_cha Values: 0, 0 Name: buff9_con Values: 0, 0 Name: buff9_dex Values: 0, 0 Name: buff9_dmg Values: 0, 0 Name: buff9_fort Values: 0, 0 Name: buff9_hp-temp Values: 0, 0 Name: buff9_int Values: 0, 0 Name: buff9_melee Values: 0, 0 Name: buff9_ranged Values: 0, 0 Name: buff9_ref Values: 0, 0 Name: buff9_str Values: 0, 0 Name: buff9_will Values: 0, 0 Name: buff9_wis Values: 0, 0 Name: cha-mod Values: 1, 1 Name: cmd-size Values: 0, 0 Name: con-mod Values: 2, 2 Name: dex-mod Values: 0, 0 Name: int-mod Values: 0, 0 Name: pfsheet_version Values: 0.19, 0.1 Name: recalc1 Values: 0, 0 Name: size_display Values: 0, 0 Name: size_skill Values: 0, 0 Name: size_skill_double Values: 0, 0 Name: str-mod Values: 2, 2 Name: wis-mod Values: 4, 4 VM2101:59 Number of Duplicates: 154 undefined Thank you Vince for looking into this. Would you mind running some additional tests? Please try the following test case: Create a buff in slot 4 with the first value (melee) = 1, the second value (ranged) = 2, 3, 4 all the way across until the last value is 18. Fill in the buff 4 name and called it buff 4 test.  Fill in the notes with buff 4 test note. Check the check box for buff 4. Results: Check that the auto calc fields for buff 4 fill in as expected. The totals for buff_Melee-total, buff_Ranged-total, buff_DMG-total, buff_AC-total, etc all display as the values in buff4_Melee, buff4_Ranged, buff4_DMG, etc. in the Core tab on the character sheet. Verify that buff4_DMG-total = 3. (since it was the third value in the list based on the entries above) Go to the Chat window Type in @{CharacterName|buff_DMG-total}, replacing CharacterName with your actual character name. I get a value of 0. This is because I have a duplicate for buff_DMG-total and the character sheet is looking at the first instance of buff_DMG-total, but the engine is looking at the last value for buff_DMG-total. Go to the second instance of buff_DMG-total and update it from 0 to 51. Now go to the chat window and type in @{CharacterName|buff_DMG-total}, replacing CharacterName with your actual character name. When I did this, the engine came back with 51. This particular attribute (buff_DMG-total) may not be an issue for you, since I don't see it in your duplicates list. (yet). However, I do see duplicate attributes such as str-mod, dex-mod, con-mod, int-mod, wis-mod and cha-mod. Currently, they are the same value for both duplicates, and therefore no issue will currently show up. I am curious, however, what would happen if you updated your base stats (Str, Dex, Con, Int, Wis, Cha) to other values.  Can you please test the following? Keep track of the existing values for your base attributes. Update all six base stats to new values. Verify that the character sheet itself has updated the base stats, along with the associated modifiers. Then use @{CharacterName|STR-mod}, @{CharacterName|DEX-mod}, @{CharacterName|CON-mod}, @{CharacterName|INT-mod}, @{CharacterName|WIS-mod} and @{CharacterName|CHA-mod} to retrieve the associated stat modifiers from the engine. I am trying to narrow down the problem and this would help me a lot. Are the values different than the ones you expect? Try running the duplicate check script again, and look for str-mod, dex-mod etc. Are the names still duplicated? Are the values the same or are they different, based on the old and new values that you had and have in the character sheet? I did notice that you have two attribute entries for pfsheet_version, 0.19 and 0.1. Since you have upgrade code in your character sheet, I would be curious to see what happens if Roll20 returns version 0.1 when you ask for it, but your upgrade code actually runs on a character sheet that has already been upgraded. This is a case where I can see problems arising. It is also very important that the devs know that you have not created any duplicates using API calls or manual inserts. Duplicates are somehow being generated somewhere else. There are many possibilities and I'm trying to narrow the issue down. I am just not sure how and when Roll20 automatically creates attributes. It becomes a frustrating issue to look at, because if this were an open-source project, the first thing I would do is validate input on the server side and see where my unit tests and QA test cases failed. Thank you for looking into this Vince. This is a breaking issue for my sheet, and I'm trying to replicate the issue on someone else's sheet.
1452922393
vÍnce
Pro
Sheet Author
Can you please test the following? Keep track of the existing values for your base attributes. Update all six base stats to new values. Verify that the character sheet itself has updated the base stats, along with the associated modifiers. Then use @{CharacterName|STR-mod}, @{CharacterName|DEX-mod}, @{CharacterName|CON-mod}, @{CharacterName|INT-mod}, @{CharacterName|WIS-mod} and @{CharacterName|CHA-mod} to retrieve the associated stat modifiers from the engine. I am trying to narrow down the problem and this would help me a lot. Are the values different than the ones you expect? Try running the duplicate check script again, and look for str-mod, dex-mod etc. Are the names still duplicated? Are the values the same or are they different, based on the old and new values that you had and have in the character sheet? Changed all 6 base abilities.  Values for all 6 attributes were still the old values... Old base values were (14, 10, 14, 10,18,12) Values returned in chat should be 4,4,4,4,4,0,4 according to the new base values. New log after changing core abilities.  note: you can now see differences in the 6 core abilities mod attributes. Name: attk-cmb-gnote Values: +2 grapple,  Name: attk-ranged Values: 7, 3 Name: buff1_ac Values: 0, 0 Name: buff1_cha Values: 0, 0 Name: buff1_con Values: 0, 0 Name: buff1_dex Values: 0, 0 Name: buff1_dmg Values: 0, 0 Name: buff1_fort Values: 0, 0 Name: buff1_hp-temp Values: 0, 0 Name: buff1_int Values: 0, 0 Name: buff1_melee Values: 0, 0 Name: buff1_ranged Values: 0, 0 Name: buff1_ref Values: 0, 0 Name: buff1_str Values: 0, 0 Name: buff1_will Values: 0, 0 Name: buff1_wis Values: 0, 0 Name: buff10_ac Values: 0, 0 Name: buff10_cha Values: 0, 0 Name: buff10_con Values: 0, 0 Name: buff10_dex Values: 0, 0 Name: buff10_dmg Values: 0, 0 Name: buff10_fort Values: 0, 0 Name: buff10_hp-temp Values: 0, 0 Name: buff10_int Values: 0, 0 Name: buff10_melee Values: 0, 0 Name: buff10_ranged Values: 0, 0 Name: buff10_ref Values: 0, 0 Name: buff10_str Values: 0, 0 Name: buff10_will Values: 0, 0 Name: buff10_wis Values: 0, 0 Name: buff2_ac Values: 0, 0 Name: buff2_cha Values: 0, 0 Name: buff2_con Values: 0, 0 Name: buff2_dex Values: 0, 0 Name: buff2_dmg Values: 0, 0 Name: buff2_fort Values: 0, 0 Name: buff2_hp-temp Values: 0, 0 Name: buff2_int Values: 0, 0 Name: buff2_melee Values: 0, 0 Name: buff2_ranged Values: 0, 0 Name: buff2_ref Values: 0, 0 Name: buff2_str Values: 0, 0 Name: buff2_will Values: 0, 0 Name: buff2_wis Values: 0, 0 Name: buff3_ac Values: 0, 0 Name: buff3_cha Values: 0, 0 Name: buff3_con Values: 0, 0 Name: buff3_dex Values: 0, 0 Name: buff3_dmg Values: 0, 0 Name: buff3_fort Values: 0, 0 Name: buff3_hp-temp Values: 0, 0 Name: buff3_int Values: 0, 0 Name: buff3_melee Values: 0, 0 Name: buff3_ranged Values: 0, 0 Name: buff3_ref Values: 0, 0 Name: buff3_str Values: 0, 0 Name: buff3_will Values: 0, 0 Name: buff3_wis Values: 0, 0 Name: buff4_ac Values: 0, 0 Name: buff4_cha Values: 0, 0 Name: buff4_con Values: 0, 0 Name: buff4_dex Values: 0, 0 Name: buff4_dmg Values: 0, 0 Name: buff4_fort Values: 0, 0 Name: buff4_hp-temp Values: 0, 0 Name: buff4_int Values: 0, 0 Name: buff4_melee Values: 0, 0 Name: buff4_ranged Values: 0, 0 Name: buff4_ref Values: 0, 0 Name: buff4_str Values: 0, 0 Name: buff4_will Values: 0, 0 Name: buff4_wis Values: 0, 0 Name: buff5_ac Values: 0, 0 Name: buff5_cha Values: 0, 0 Name: buff5_con Values: 0, 0 Name: buff5_dex Values: 0, 0 Name: buff5_dmg Values: 0, 0 Name: buff5_fort Values: 0, 0 Name: buff5_hp-temp Values: 0, 0 Name: buff5_int Values: 0, 0 Name: buff5_melee Values: 0, 0 Name: buff5_ranged Values: 0, 0 Name: buff5_ref Values: 0, 0 Name: buff5_str Values: 0, 0 Name: buff5_will Values: 0, 0 Name: buff5_wis Values: 0, 0 Name: buff6_ac Values: 0, 0 Name: buff6_cha Values: 0, 0 Name: buff6_con Values: 0, 0 Name: buff6_dex Values: 0, 0 Name: buff6_dmg Values: 0, 0 Name: buff6_fort Values: 0, 0 Name: buff6_hp-temp Values: 0, 0 Name: buff6_int Values: 0, 0 Name: buff6_melee Values: 0, 0 Name: buff6_ranged Values: 0, 0 Name: buff6_ref Values: 0, 0 Name: buff6_str Values: 0, 0 Name: buff6_will Values: 0, 0 Name: buff6_wis Values: 0, 0 Name: buff7_ac Values: 0, 0 Name: buff7_cha Values: 0, 0 Name: buff7_con Values: 0, 0 Name: buff7_dex Values: 0, 0 Name: buff7_dmg Values: 0, 0 Name: buff7_fort Values: 0, 0 Name: buff7_hp-temp Values: 0, 0 Name: buff7_int Values: 0, 0 Name: buff7_melee Values: 0, 0 Name: buff7_ranged Values: 0, 0 Name: buff7_ref Values: 0, 0 Name: buff7_str Values: 0, 0 Name: buff7_will Values: 0, 0 Name: buff7_wis Values: 0, 0 Name: buff8_ac Values: 0, 0 Name: buff8_cha Values: 0, 0 Name: buff8_con Values: 0, 0 Name: buff8_dex Values: 0, 0 Name: buff8_dmg Values: 0, 0 Name: buff8_fort Values: 0, 0 Name: buff8_hp-temp Values: 0, 0 Name: buff8_int Values: 0, 0 Name: buff8_melee Values: 0, 0 Name: buff8_ranged Values: 0, 0 Name: buff8_ref Values: 0, 0 Name: buff8_str Values: 0, 0 Name: buff8_will Values: 0, 0 Name: buff8_wis Values: 0, 0 Name: buff9_ac Values: 0, 0 Name: buff9_cha Values: 0, 0 Name: buff9_con Values: 0, 0 Name: buff9_dex Values: 0, 0 Name: buff9_dmg Values: 0, 0 Name: buff9_fort Values: 0, 0 Name: buff9_hp-temp Values: 0, 0 Name: buff9_int Values: 0, 0 Name: buff9_melee Values: 0, 0 Name: buff9_ranged Values: 0, 0 Name: buff9_ref Values: 0, 0 Name: buff9_str Values: 0, 0 Name: buff9_will Values: 0, 0 Name: buff9_wis Values: 0, 0 Name: cha-mod Values: 1, 4 Name: cmd-size Values: 0, 0 Name: con-mod Values: 4, 2 Name: dex-mod Values: 0, 4 Name: int-mod Values: 4, 0 Name: pfsheet_version Values: 0.1, 0.19 Name: recalc1 Values: 0, 0 Name: size_display Values: 0, 0 Name: size_skill Values: 0, 0 Name: size_skill_double Values: 0, 0 Name: str-mod Values: 2, 4 Name: wis-mod Values: 4, 0 VM595:59 Number of Duplicates: 154 undefined
1452925743

Edited 1452928353
Vince said: Can you please test the following? Keep track of the existing values for your base attributes. Update all six base stats to new values. Verify that the character sheet itself has updated the base stats, along with the associated modifiers. Then use @{CharacterName|STR-mod}, @{CharacterName|DEX-mod}, @{CharacterName|CON-mod}, @{CharacterName|INT-mod}, @{CharacterName|WIS-mod} and @{CharacterName|CHA-mod} to retrieve the associated stat modifiers from the engine. I am trying to narrow down the problem and this would help me a lot. Are the values different than the ones you expect? Try running the duplicate check script again, and look for str-mod, dex-mod etc. Are the names still duplicated? Are the values the same or are they different, based on the old and new values that you had and have in the character sheet? Changed all 6 base abilities.  Values for all 6 attributes were still the old values... Old base values were (14, 10, 14, 10,18,12) Values returned in chat should be 4,4,4,4,4,0,4 according to the new base values. New log after changing core abilities.  note: you can now see differences in the 6 core abilities mod attributes. Name: attk-cmb-gnote Values: +2 grapple,  Name: attk-ranged Values: 7, 3 Name: buff1_ac Values: 0, 0 Name: buff1_cha Values: 0, 0 Name: buff1_con Values: 0, 0 Name: buff1_dex Values: 0, 0 Name: buff1_dmg Values: 0, 0 Name: buff1_fort Values: 0, 0 Name: buff1_hp-temp Values: 0, 0 Name: buff1_int Values: 0, 0 Name: buff1_melee Values: 0, 0 Name: buff1_ranged Values: 0, 0 Name: buff1_ref Values: 0, 0 Name: buff1_str Values: 0, 0 Name: buff1_will Values: 0, 0 Name: buff1_wis Values: 0, 0 Name: buff10_ac Values: 0, 0 Name: buff10_cha Values: 0, 0 Name: buff10_con Values: 0, 0 Name: buff10_dex Values: 0, 0 Name: buff10_dmg Values: 0, 0 Name: buff10_fort Values: 0, 0 Name: buff10_hp-temp Values: 0, 0 Name: buff10_int Values: 0, 0 Name: buff10_melee Values: 0, 0 Name: buff10_ranged Values: 0, 0 Name: buff10_ref Values: 0, 0 Name: buff10_str Values: 0, 0 Name: buff10_will Values: 0, 0 Name: buff10_wis Values: 0, 0 Name: buff2_ac Values: 0, 0 Name: buff2_cha Values: 0, 0 Name: buff2_con Values: 0, 0 Name: buff2_dex Values: 0, 0 Name: buff2_dmg Values: 0, 0 Name: buff2_fort Values: 0, 0 Name: buff2_hp-temp Values: 0, 0 Name: buff2_int Values: 0, 0 Name: buff2_melee Values: 0, 0 Name: buff2_ranged Values: 0, 0 Name: buff2_ref Values: 0, 0 Name: buff2_str Values: 0, 0 Name: buff2_will Values: 0, 0 Name: buff2_wis Values: 0, 0 Name: buff3_ac Values: 0, 0 Name: buff3_cha Values: 0, 0 Name: buff3_con Values: 0, 0 Name: buff3_dex Values: 0, 0 Name: buff3_dmg Values: 0, 0 Name: buff3_fort Values: 0, 0 Name: buff3_hp-temp Values: 0, 0 Name: buff3_int Values: 0, 0 Name: buff3_melee Values: 0, 0 Name: buff3_ranged Values: 0, 0 Name: buff3_ref Values: 0, 0 Name: buff3_str Values: 0, 0 Name: buff3_will Values: 0, 0 Name: buff3_wis Values: 0, 0 Name: buff4_ac Values: 0, 0 Name: buff4_cha Values: 0, 0 Name: buff4_con Values: 0, 0 Name: buff4_dex Values: 0, 0 Name: buff4_dmg Values: 0, 0 Name: buff4_fort Values: 0, 0 Name: buff4_hp-temp Values: 0, 0 Name: buff4_int Values: 0, 0 Name: buff4_melee Values: 0, 0 Name: buff4_ranged Values: 0, 0 Name: buff4_ref Values: 0, 0 Name: buff4_str Values: 0, 0 Name: buff4_will Values: 0, 0 Name: buff4_wis Values: 0, 0 Name: buff5_ac Values: 0, 0 Name: buff5_cha Values: 0, 0 Name: buff5_con Values: 0, 0 Name: buff5_dex Values: 0, 0 Name: buff5_dmg Values: 0, 0 Name: buff5_fort Values: 0, 0 Name: buff5_hp-temp Values: 0, 0 Name: buff5_int Values: 0, 0 Name: buff5_melee Values: 0, 0 Name: buff5_ranged Values: 0, 0 Name: buff5_ref Values: 0, 0 Name: buff5_str Values: 0, 0 Name: buff5_will Values: 0, 0 Name: buff5_wis Values: 0, 0 Name: buff6_ac Values: 0, 0 Name: buff6_cha Values: 0, 0 Name: buff6_con Values: 0, 0 Name: buff6_dex Values: 0, 0 Name: buff6_dmg Values: 0, 0 Name: buff6_fort Values: 0, 0 Name: buff6_hp-temp Values: 0, 0 Name: buff6_int Values: 0, 0 Name: buff6_melee Values: 0, 0 Name: buff6_ranged Values: 0, 0 Name: buff6_ref Values: 0, 0 Name: buff6_str Values: 0, 0 Name: buff6_will Values: 0, 0 Name: buff6_wis Values: 0, 0 Name: buff7_ac Values: 0, 0 Name: buff7_cha Values: 0, 0 Name: buff7_con Values: 0, 0 Name: buff7_dex Values: 0, 0 Name: buff7_dmg Values: 0, 0 Name: buff7_fort Values: 0, 0 Name: buff7_hp-temp Values: 0, 0 Name: buff7_int Values: 0, 0 Name: buff7_melee Values: 0, 0 Name: buff7_ranged Values: 0, 0 Name: buff7_ref Values: 0, 0 Name: buff7_str Values: 0, 0 Name: buff7_will Values: 0, 0 Name: buff7_wis Values: 0, 0 Name: buff8_ac Values: 0, 0 Name: buff8_cha Values: 0, 0 Name: buff8_con Values: 0, 0 Name: buff8_dex Values: 0, 0 Name: buff8_dmg Values: 0, 0 Name: buff8_fort Values: 0, 0 Name: buff8_hp-temp Values: 0, 0 Name: buff8_int Values: 0, 0 Name: buff8_melee Values: 0, 0 Name: buff8_ranged Values: 0, 0 Name: buff8_ref Values: 0, 0 Name: buff8_str Values: 0, 0 Name: buff8_will Values: 0, 0 Name: buff8_wis Values: 0, 0 Name: buff9_ac Values: 0, 0 Name: buff9_cha Values: 0, 0 Name: buff9_con Values: 0, 0 Name: buff9_dex Values: 0, 0 Name: buff9_dmg Values: 0, 0 Name: buff9_fort Values: 0, 0 Name: buff9_hp-temp Values: 0, 0 Name: buff9_int Values: 0, 0 Name: buff9_melee Values: 0, 0 Name: buff9_ranged Values: 0, 0 Name: buff9_ref Values: 0, 0 Name: buff9_str Values: 0, 0 Name: buff9_will Values: 0, 0 Name: buff9_wis Values: 0, 0 Name: cha-mod Values: 1, 4 Name: cmd-size Values: 0, 0 Name: con-mod Values: 4, 2 Name: dex-mod Values: 0, 4 Name: int-mod Values: 4, 0 Name: pfsheet_version Values: 0.1, 0.19 Name: recalc1 Values: 0, 0 Name: size_display Values: 0, 0 Name: size_skill Values: 0, 0 Name: size_skill_double Values: 0, 0 Name: str-mod Values: 2, 4 Name: wis-mod Values: 4, 0 VM595:59 Number of Duplicates: 154 undefined Thank you, Vince. This very clearly demonstrates that this is a widespread issue that needs to be looked at. Your character sheet is a prime example of the character sheet showing one value after a change, but the attribute retrieval showing a different value. This will most likely cause issues with any field that depends on these values, and it will definitely cause incorrect calculations to occur for any macros that use these values. Your test case very clearly shows the issue and the underlying cause.
Riley D. said: First off, let's take it down a notch. Your post is quite argumentative and we specifically disallow that type of point-by-point rebuttal here since it's rarely helpful. My goal here is simply to establish if there is actually a bug with the Character Sheet system or if this just a case of data corruption via API use. My original question still stands, which is quite simply, was this caused by the use of an API script and/or manual entry? Based on your response I'm assuming "yes" but it would be helpful to get confirmation on that so I know if there is an actual bug at play here. Finally, I'm not really sure why this is posted as an issue in the Character Sheet forum and a problem with the Pathfinder sheet. It seems like more of a suggestion for how we should change our philosophy regarding the API to your ideal of how it should function.  To be clear, there are a lot of ways you can break your game using the API. You could delete a bunch of your tokens. You could overwrite your character's data with nonsense. You could accidentally give away the secrets stored in your GM-only-super-secret handout to your players. And yes, you can absolutely create multiple attributes with the same name which probably isn't a great idea if you meant to update an existing attribute instead. That's not a bug, that's just a reflection of the fact that the API is low-level and very powerful. We're very explicit about this in the documentation, and there's even a big red warning on top of the API Scripts page for your game that says "Hey, be careful."  Certainly we would never leave the system open to the level of security vulnerability that you're suggesting. You can't change other people's campaign data with your script. You can't crash our entire API server with a faulty command. You can't even send a chat message that contains a reflective XSS Javascript snippet. But you can definitely do whatever you want with your own campaign data. I don't think we have any desire to change that philosophy, because it's exactly the type of power that has let people do some amazing things with the API. (And I'm not really looking to debate that, either, so let's just stick to the original point of the thread, which is to determine if there is a bug.) Vince has checked his character sheet and he has the same issues with duplicate attribute names, however with different attributes. I asked him to run tests to see if his character sheet would begin to return inconsistent results. Please see his post for complete results. When he updated his character's Str, Dex, Con, Int, Wis and Cha, the character sheet displayed the appropriate modifiers for the new values. However, when he retrieved the modifiers for Str, Dex, Con, Int, Wis and Cha in the chat window, he was given the modifiers corresponding to the old Pathfinder ability values. To be clear, this is not the same as a player deleting a token, purposely entering gibberish or any other case where you enter invalid data. This is a case where a player has entered valid data, and the character sheet and chat are producing invalid results. I just looked at the Roll20 API. Nice work on the breadth of it. I am impressed, and I am glad that you have worked hard on the security of your system. I have not questioned the capability of your team or the effort you have put in to make a fun product that a million people enjoy. I only presented the SQL injection scenario as an example that every developer would understand, not as something I actually expected you to do. (The comment about not doing that was directed more to the general user base that might read the comments.) There is a function called getAttrByName(character_id, attribute_name, value_type). Based on the description in the documentation, this function assumes that the attribute name is unique irrespective of case. This is what I would expect. However, if there are duplicate attribute names, then this function will change from a deterministic function to a nondeterministic function. If a function is intended to be deterministic, it should remain that way. Allowing duplicate attributes breaks Pathfinder character sheets and D&D 5 character sheets. Assuming every other character sheet relies on attributes in the same fashion, (a reasonable assumption), it follows that any character sheet will have nondeterministic behaviour if there are duplicate attributes. Is there a valid use case where anyone using the API or anyone on the Roll20 team would enter two duplicate attributes on purpose, and if there is, what is the expected behaviour of the system under this scenario? Thank you, Paul
1452956934

Edited 1452958989
Riley D.
Roll20 Team
It's the weekend so I'll take a look at this fully on Monday. I tired to skim it quickly this morning though. If it is possible to create multiple Attributes with the same name by just using a Character Sheet with or without a Sheet Worker, without manually entering them or using the API, that is definitely a bug that needs to be fixed. Vince go ahead and give me a link to the Game Details page of that game and I'll take a look at the underlying data to see if there are any clues. The biggest "red flag" to me is the pfsheet_version value showing a duplicate. Since that's an attribute that has only (I assume) been set by the Sheet Worker, then that would indicate that there is a bug in the way the Sheet Worker code is setting attributes and possibly what is causing duplicates. It would be super nice to have a test case that started with a fresh, new game (e.g. "Make a new Game with the Pathfinder sheet, do these 5 things, look there's duplicates!") since that way I could actually see the bug happening and fix it more quickly, but if this is all we have to go on we'll try to figure it out. But if anyone has such a test case, please let me know. Finally, since you hadn't actually looked at the API docs before (and therefore I assume haven't used any API scripts previously), I'm not really sure why we were even talking about that in the first place. So let's just leave that aside and focus on the Character Sheet system, the Sheet Workers, and manual entry, for narrowing down the scope of what might be causing the problem.
1452958558

Edited 1452966248
Riley D.
Roll20 Team
Also just to be sure, everyone is running this checker script with only one Character open, right? Because it's not scoped to a per-Character level, so if you have multiple Characters open (including minimized, popped out, etc.) you will get incorrect duplicates reported. Just making sure since it wasn't explicitly stated anywhere. I tried opening up a new Pathfinder character on a new game and wasn't able to create any duplicates just by using the sheet for a few minutes and filling in lots of random stuff, but it's possible there's another path to triggering the bug I didn't find. EDIT: I created this simple test case to verify that the character sheet system and sheet workers aren't creating duplicate attributes when different case is used: <a href="https://gist.github.com/rileydutton/93a2a270d2ae78" rel="nofollow">https://gist.github.com/rileydutton/93a2a270d2ae78</a>... As you can see, I have multiple attributes in the sheet with the same name but different case. Changing any of them changes all of them and never creates duplicate attributes. I also have the Sheet Worker fetching the attribute using a lowercase name, and setting it using different cases, and again only one attribute is created. Let me know if you see different results or if you can change this test case to produce the bug. Doesn't mean that the bug isn't happening, but I think it indicates some other factor is at play that we need to figure out.
Riley D. said: Also just to be sure, everyone is running this checker script with only one Character open, right? Because it's not scoped to a per-Character level, so if you have multiple Characters open (including minimized, popped out, etc.) you will get incorrect duplicates reported. Just making sure since it wasn't explicitly stated anywhere. I tried opening up a new Pathfinder character on a new game and wasn't able to create any duplicates just by using the sheet for a few minutes and filling in lots of random stuff, but it's possible there's another path to triggering the bug I didn't find. EDIT: I created this simple test case to verify that the character sheet system and sheet workers aren't creating duplicate attributes when different case is used: <a href="https://gist.github.com/rileydutton/93a2a270d2ae78" rel="nofollow">https://gist.github.com/rileydutton/93a2a270d2ae78</a>... As you can see, I have multiple attributes in the sheet with the same name but different case. Changing any of them changes all of them and never creates duplicate attributes. I also have the Sheet Worker fetching the attribute using a lowercase name, and setting it using different cases, and again only one attribute is created. Let me know if you see different results or if you can change this test case to produce the bug. Doesn't mean that the bug isn't happening, but I think it indicates some other factor is at play that we need to figure out I apologize that I didn't mention that only one Character Sheet can be open when you run this script. I will see if I can replicate the issue.
1452973938
vÍnce
Pro
Sheet Author
Paul T. said: I apologize that I didn't mention that only one Character Sheet can be open when you run this script. I will see if I can replicate the issue. I only had one sheet open when I ran my test above.
Vince said: Paul T. said: I apologize that I didn't mention that only one Character Sheet can be open when you run this script. I will see if I can replicate the issue. I only had one sheet open when I ran my test above. What's the link to the game where you ran the test and which Character was it? Just want to see if there's any clues in the underlying data. Paul T. said: I apologize that I didn't mention that only one Character Sheet can be open when you run this script. I will see if I can replicate the issue. No worries, just wanted to throw that out there in case anyone else read this later and did the test themselves. Let me know if you are able to replicate. Thanks!
1453009294
vÍnce
Pro
Sheet Author
PM sent. &nbsp;Thanks Riley
Riley D. said: Vince said: Paul T. said: I apologize that I didn't mention that only one Character Sheet can be open when you run this script. I will see if I can replicate the issue. I only had one sheet open when I ran my test above. What's the link to the game where you ran the test and which Character was it? Just want to see if there's any clues in the underlying data. Paul T. said: I apologize that I didn't mention that only one Character Sheet can be open when you run this script. I will see if I can replicate the issue. No worries, just wanted to throw that out there in case anyone else read this later and did the test themselves. Let me know if you are able to replicate. Thanks! I have written a script that goes through the attributes and deletes any duplicate attributes where both the attribute name and the attribute value are the same. The script will also help you go through and merge attributes that are duplicated by name, but have different values. You will be asked what value to use for each attribute that has a conflict. The script can only be run on one character sheet at a time. If you have no character sheets open, the script will ask you to open one. If you have multiple character sheets open, you will be asked to close all but one. For duplicate attributes that are identical, the script will delete all duplicates, and leave one attribute, making it unique. For duplicates attributes that are duplicated by name only, you will be prompted to provide what value you want to have updated for each duplicated attribute. The duplicates will then be deleted, and the remaining unique attribute will have its value updated to the one you provided. I have posted it to GitHub. I would appreciate it if a few people could do some further testing to make sure it behaves as expected. Here is the link:&nbsp;<a href="https://github.com/anvilis/roll20-scripts/blob/master/Pathfinder/character-sheets/Merge-Duplicate-Attributes.js" rel="nofollow">https://github.com/anvilis/roll20-scripts/blob/master/Pathfinder/character-sheets/Merge-Duplicate-Attributes.js</a>
1453096700

Edited 1453097377
vÍnce
Pro
Sheet Author
Thanks Paul. &nbsp; Is there an API command that you need to run...? &nbsp;Also I get an error when running this in the API "window is not defined". &nbsp;Help. &nbsp;Thanks update : Looks like I run this in the browser console.
1453098298

Edited 1453098826
Vince said: Thanks Paul. &nbsp;Is there an API command that you need to run...? &nbsp;Also I get an error when running this in the API "window is not defined". &nbsp;Help. &nbsp;Thanks This is why I wanted other people to test the script. :) I don't use the API because I don't assume that every player that needs the script will have access to the API. It appears that the global variable window might not be available in the scope of a function. I have updated the code. Can you please check it again? If you don't have access to 'window' at all, then I'll have to look at why. Can you please tell me your browser and OS? This is strange. I've looked into this a bit, and the script should have access to window. Thanks.
1453099167
vÍnce
Pro
Sheet Author
This works when pasted into the browser's console. &nbsp;I assumed (incorrectly) that your script needed to be ran from the API. &nbsp;Appologies. The script works well. &nbsp;I believe that auto calculated duplicates could just be given a value of "0" and as soon as the sheet is recalced, the appropriate value would be given. &nbsp;Thoughts?
1453100781

Edited 1453101013
Vince said: This works when pasted into the browser's console. &nbsp;I assumed (incorrectly) that your script needed to be ran from the API. &nbsp;Appologies. The script works well. &nbsp;I believe that auto calculated duplicates could just be given a value of "0" and as soon as the sheet is recalced, the appropriate value would be given. &nbsp;Thoughts? Do you have a lot of auto calculated duplicates where the name is the same, but the values are different? I'll look into it.
When does the character sheet autocalc? If I reset all of the duplicate autocalc fields to zero, how do we trigger a recalculation of those fields?
1453102788

Edited 1453103247
vÍnce
Pro
Sheet Author
I was specifically speaking of the recalc checkbox (@{recalc1} with a value of "1" ) at the top of the sheet to force a sheet-wide re-calculation of attributes. &nbsp;Obviously certain attributes will auto-calculate on change of certain other attributes, but to be safe, the recalc does them all.&nbsp;
1453103129
vÍnce
Pro
Sheet Author
Paul T. said: Vince said: This works when pasted into the browser's console. &nbsp;I assumed (incorrectly) that your script needed to be ran from the API. &nbsp;Appologies. The script works well. &nbsp;I believe that auto calculated duplicates could just be given a value of "0" and as soon as the sheet is recalced, the appropriate value would be given. &nbsp;Thoughts? Do you have a lot of auto calculated duplicates where the name is the same, but the values are different? I'll look into it. I only had one character that had duplicates(the one used earlier in the post). &nbsp;Out of 150+ duplicates, 9 had conflicting values. &nbsp;Some of those were caused by our test from above.(6 primary attributes). &nbsp;8 of the 9 were auto-calculating. I entered 0 for the values when I ran your script and manually hit the recalc button to force new values, since the "real" problem seems to be the duplicate attribute names.
1453104846

Edited 1453104865
Vince said: Paul T. said: Vince said: This works when pasted into the browser's console. &nbsp;I assumed (incorrectly) that your script needed to be ran from the API. &nbsp;Appologies. The script works well. &nbsp;I believe that auto calculated duplicates could just be given a value of "0" and as soon as the sheet is recalced, the appropriate value would be given. &nbsp;Thoughts? Do you have a lot of auto calculated duplicates where the name is the same, but the values are different? I'll look into it. I only had one character that had duplicates(the one used earlier in the post). &nbsp;Out of 150+ duplicates, 9 had conflicting values. &nbsp;Some of those were caused by our test from above.(6 primary attributes). &nbsp;8 of the 9 were auto-calculating. I entered 0 for the values when I ran your script and manually hit the recalc button to force new values, since the "real" problem seems to be the duplicate attribute names. Oh, that's great! Nine attributes isn't too bad to have to merge after all. You had to force the character sheet to recalc though. I was never able to get the Recalc check box to work properly. Does it only work when the character sheet is being upgraded? I thought there was someone who had something like 50 character sheets to fix.
1453106121

Edited 1453106162
vÍnce
Pro
Sheet Author
In "theory", you shouldn't need to use the recalc button. &nbsp;I believe it's set in the sheet worker script to fire if the sheet version is greater than the current version value. &nbsp;So, when the sheet gets a new version, it will run the first time you open the sheet. &nbsp;Of course we have missed on change events and such that have been worked out along the way which requires an occasional recalc. &nbsp;I believe recalc works fine, unless there are duplicate values. &nbsp;;-)
1453109073

Edited 1453109228
Riley D. said: Vince said: Paul T. said: I apologize that I didn't mention that only one Character Sheet can be open when you run this script. I will see if I can replicate the issue. I only had one sheet open when I ran my test above. What's the link to the game where you ran the test and which Character was it? Just want to see if there's any clues in the underlying data. Paul T. said: I apologize that I didn't mention that only one Character Sheet can be open when you run this script. I will see if I can replicate the issue. No worries, just wanted to throw that out there in case anyone else read this later and did the test themselves. Let me know if you are able to replicate. Thanks! Hey Riley, I have been working on this issue for most of the weekend and I think I have a reliable test case for replicating the issue. Open Roll20 in Chrome Create a new Pathfinder neceros character sheet Fill in base stats In Attacks, add a weapon, and fill it in Open another instance of Roll20. I chose to use Firefox on the same computer, but you can use a VM, whatever other method you choose Load up the character sheet in the second instance In the first instance, fill in the top Buff with Name=Test and fill in '1' for all stats across the sheet in the macro text Select the checkbox to the left of the buff to apply it Select the checkboxes for buffs 2-5. Here is the interesting part. Open Chat in both instances Type in @{CharacterName|buff_Melee-total} in both instances *BUT* don't press Enter! Make sure the chat windows in both instances are in focus, so that when you switch back and forth, you can just press Enter in order to send the chat message Go back to the first instance, and ensure the chat window has focus. Then, Press Enter, Alt-Tab, Enter This will cause both instances to send the command to retrieve the buff_Melee-total attribute. Now, close the character sheet in both instances. Now, open the character sheet in the first instance. When I followed these steps, I could reliable generate ~100 duplicate buff attributes You are welcome to use and modify my script to clean up the character sheet. Of course, for you it's probably simpler to run a few database commands. :) The reason we ran into this, is that our GM looks at our character sheets and sometimes makes changes at the same time we are. So, this is definitely a valid concurrency issue. I don't know if this is the only issue, but at least I was able to replicate the issue this way. I think there is likely an additional issue for when character sheets are upgraded, but since I don't have access to run upgrades, I can't test this scenario. Thanks.
Vince said: In "theory", you shouldn't need to use the recalc button. &nbsp;I believe it's set in the sheet worker script to fire if the sheet version is greater than the current version value. &nbsp;So, when the sheet gets a new version, it will run the first time you open the sheet. &nbsp;Of course we have missed on change events and such that have been worked out along the way which requires an occasional recalc. &nbsp;I believe recalc works fine, unless there are duplicate values. &nbsp;;-) I have been able to replicate the duplicate issue by using the same character sheet from two different browsers. This could happen if a GM and player are doing something with the same sheet, or if two players are. I also suspect there might be something going on with the character sheet upgrade process. Maybe when new fields are added, the Recalc process somehow introduces duplicates.
Vince said: I was specifically speaking of the recalc checkbox (@{recalc1} with a value of "1" ) at the top of the sheet to force a sheet-wide re-calculation of attributes. &nbsp;Obviously certain attributes will auto-calculate on change of certain other attributes, but to be safe, the recalc does them all.&nbsp; Does it do this recalc when you close and then reopen the sheet?
1453112848
vÍnce
Pro
Sheet Author
Paul T. said: Vince said: I was specifically speaking of the recalc checkbox (@{recalc1} with a value of "1" ) at the top of the sheet to force a sheet-wide re-calculation of attributes. &nbsp;Obviously certain attributes will auto-calculate on change of certain other attributes, but to be safe, the recalc does them all.&nbsp; Does it do this recalc when you close and then reopen the sheet? You would have to take a peak at the sheet worker script Paul. &nbsp;I know the routine is there(I've seen it) but I am a javascript neophyte... Chris has handled all the js and so I'm sure the two of you could have a wonderful conversation about it. &nbsp;;-)
Okay, catching up on this thread. I will take a look here in a bit and run through your test case, Paul. Thanks for that. Vince -- does that mean the PM you sent me no longer has a Character with duplicate values since you ran Paul's script on that game? Or did you do it on a copy or something?
Okay, I actually think this was caused by a bug we had logged previously and fixed but hadn't deployed yet (we fixed it Friday and tend not to deploy on Friday since we aren't around on the weekends unless it's an emergency, and we don't want to not be around in case it introduces weird behavior). Anyway, the bug was that the Sheet Worker code was being executed multiple times by mistake and could cause undefined behavior. Apparently in some cases (especially if it involved creating new attributes) that undefined behavior could create duplicate Attributes. I've deployed the fix to the Main server so go ahead and test your test case again Paul and let me know if it's fixed. I walked through it and wasn't able to replicate but I also had already deployed that bug fix this morning and I think that's what fixed it. If it's still broken let me know and I'll take another look. In addition to that if we do still have a copy of a campaign where there are duplicates that was causing undefined behavior (like that one Vice had before) let me know because I have a fix in mind that I think might be able to make it so that even if there are duplicate Attributes (which isn't ideal but there may be a lot of campaigns that have them now) it will at least make sure that what you see on the Character Sheet and what you see when rolling is consistent.
I've also just pushed out a fix which should make sure that attribute behavior is the same across character sheets, rolls, etc., even when there are duplicate attributes with the same name. So if you do end up with duplicate attributes, at least what shows up on your character sheet will match what shows up in your dice rolls, etc.&nbsp; So Vince if you're still able to use that test case from earlier where what you showed in the chat log when you rolled didn't match what was showing on your character sheet, re-run it and those should match. What this means practically is that while duplicate Attributes with the same name aren't good, for existing campaigns affected by the bug where they did produce duplicate attributes, they don't necessarily need to go and manually (or using Paul's script) clear them out, because their games will still keep working as intended. They will just have a bunch of attributes that they aren't actually using.
1453140450

Edited 1453140498
vÍnce
Pro
Sheet Author
I ran Paul's script(s) on a copy and I still have the original character "untouched" on a campaign as well. &nbsp; So, I just re-tested the same character as&nbsp; above and although we still have 154 duplicates, the "correct" value, or at least the most recent value is being used now. Looks like this has been fixed as far as my test subject goes. Thanks Paul and Riley. &nbsp;Let me know if we need to test further. RE-test results from the same character from above: <a href="https://app.roll20.net/forum/permalink/2833823/" rel="nofollow">https://app.roll20.net/forum/permalink/2833823/</a> Changed all 6 base abilities. Values for all 6 attributes return the proper value as expected even with duplicate attribute names/values present... Old base values were (18, 18, 18, 18,10,18) Values returned in chat. Top is before I changed the 6 abilities. Bottom shows the correct values after making the change, as expected.&nbsp; New log after changing core abilities. note: you can now see differences in the 6 core abilities mod attributes. console.log(duplicateMessages.join("\n")); console.log("Number of Duplicates: " + attrCount); VM444:58 Name: attk-cmb-gnote Values: , +2 grapple Name: attk-ranged Values: 7, 3 Name: buff1_ac Values: 0, 0 Name: buff1_cha Values: 0, 0 Name: buff1_con Values: 0, 0 Name: buff1_dex Values: 0, 0 Name: buff1_dmg Values: 0, 0 Name: buff1_fort Values: 0, 0 Name: buff1_hp-temp Values: 0, 0 Name: buff1_int Values: 0, 0 Name: buff1_melee Values: 0, 0 Name: buff1_ranged Values: 0, 0 Name: buff1_ref Values: 0, 0 Name: buff1_str Values: 0, 0 Name: buff1_will Values: 0, 0 Name: buff1_wis Values: 0, 0 Name: buff10_ac Values: 0, 0 Name: buff10_cha Values: 0, 0 Name: buff10_con Values: 0, 0 Name: buff10_dex Values: 0, 0 Name: buff10_dmg Values: 0, 0 Name: buff10_fort Values: 0, 0 Name: buff10_hp-temp Values: 0, 0 Name: buff10_int Values: 0, 0 Name: buff10_melee Values: 0, 0 Name: buff10_ranged Values: 0, 0 Name: buff10_ref Values: 0, 0 Name: buff10_str Values: 0, 0 Name: buff10_will Values: 0, 0 Name: buff10_wis Values: 0, 0 Name: buff2_ac Values: 0, 0 Name: buff2_cha Values: 0, 0 Name: buff2_con Values: 0, 0 Name: buff2_dex Values: 0, 0 Name: buff2_dmg Values: 0, 0 Name: buff2_fort Values: 0, 0 Name: buff2_hp-temp Values: 0, 0 Name: buff2_int Values: 0, 0 Name: buff2_melee Values: 0, 0 Name: buff2_ranged Values: 0, 0 Name: buff2_ref Values: 0, 0 Name: buff2_str Values: 0, 0 Name: buff2_will Values: 0, 0 Name: buff2_wis Values: 0, 0 Name: buff3_ac Values: 0, 0 Name: buff3_cha Values: 0, 0 Name: buff3_con Values: 0, 0 Name: buff3_dex Values: 0, 0 Name: buff3_dmg Values: 0, 0 Name: buff3_fort Values: 0, 0 Name: buff3_hp-temp Values: 0, 0 Name: buff3_int Values: 0, 0 Name: buff3_melee Values: 0, 0 Name: buff3_ranged Values: 0, 0 Name: buff3_ref Values: 0, 0 Name: buff3_str Values: 0, 0 Name: buff3_will Values: 0, 0 Name: buff3_wis Values: 0, 0 Name: buff4_ac Values: 0, 0 Name: buff4_cha Values: 0, 0 Name: buff4_con Values: 0, 0 Name: buff4_dex Values: 0, 0 Name: buff4_dmg Values: 0, 0 Name: buff4_fort Values: 0, 0 Name: buff4_hp-temp Values: 0, 0 Name: buff4_int Values: 0, 0 Name: buff4_melee Values: 0, 0 Name: buff4_ranged Values: 0, 0 Name: buff4_ref Values: 0, 0 Name: buff4_str Values: 0, 0 Name: buff4_will Values: 0, 0 Name: buff4_wis Values: 0, 0 Name: buff5_ac Values: 0, 0 Name: buff5_cha Values: 0, 0 Name: buff5_con Values: 0, 0 Name: buff5_dex Values: 0, 0 Name: buff5_dmg Values: 0, 0 Name: buff5_fort Values: 0, 0 Name: buff5_hp-temp Values: 0, 0 Name: buff5_int Values: 0, 0 Name: buff5_melee Values: 0, 0 Name: buff5_ranged Values: 0, 0 Name: buff5_ref Values: 0, 0 Name: buff5_str Values: 0, 0 Name: buff5_will Values: 0, 0 Name: buff5_wis Values: 0, 0 Name: buff6_ac Values: 0, 0 Name: buff6_cha Values: 0, 0 Name: buff6_con Values: 0, 0 Name: buff6_dex Values: 0, 0 Name: buff6_dmg Values: 0, 0 Name: buff6_fort Values: 0, 0 Name: buff6_hp-temp Values: 0, 0 Name: buff6_int Values: 0, 0 Name: buff6_melee Values: 0, 0 Name: buff6_ranged Values: 0, 0 Name: buff6_ref Values: 0, 0 Name: buff6_str Values: 0, 0 Name: buff6_will Values: 0, 0 Name: buff6_wis Values: 0, 0 Name: buff7_ac Values: 0, 0 Name: buff7_cha Values: 0, 0 Name: buff7_con Values: 0, 0 Name: buff7_dex Values: 0, 0 Name: buff7_dmg Values: 0, 0 Name: buff7_fort Values: 0, 0 Name: buff7_hp-temp Values: 0, 0 Name: buff7_int Values: 0, 0 Name: buff7_melee Values: 0, 0 Name: buff7_ranged Values: 0, 0 Name: buff7_ref Values: 0, 0 Name: buff7_str Values: 0, 0 Name: buff7_will Values: 0, 0 Name: buff7_wis Values: 0, 0 Name: buff8_ac Values: 0, 0 Name: buff8_cha Values: 0, 0 Name: buff8_con Values: 0, 0 Name: buff8_dex Values: 0, 0 Name: buff8_dmg Values: 0, 0 Name: buff8_fort Values: 0, 0 Name: buff8_hp-temp Values: 0, 0 Name: buff8_int Values: 0, 0 Name: buff8_melee Values: 0, 0 Name: buff8_ranged Values: 0, 0 Name: buff8_ref Values: 0, 0 Name: buff8_str Values: 0, 0 Name: buff8_will Values: 0, 0 Name: buff8_wis Values: 0, 0 Name: buff9_ac Values: 0, 0 Name: buff9_cha Values: 0, 0 Name: buff9_con Values: 0, 0 Name: buff9_dex Values: 0, 0 Name: buff9_dmg Values: 0, 0 Name: buff9_fort Values: 0, 0 Name: buff9_hp-temp Values: 0, 0 Name: buff9_int Values: 0, 0 Name: buff9_melee Values: 0, 0 Name: buff9_ranged Values: 0, 0 Name: buff9_ref Values: 0, 0 Name: buff9_str Values: 0, 0 Name: buff9_will Values: 0, 0 Name: buff9_wis Values: 0, 0 Name: cha-mod Values: 1, 1 Name: cmd-size Values: 0, 0 Name: con-mod Values: 2, 2 Name: dex-mod Values: 0, 0 Name: int-mod Values: 0, 0 Name: pfsheet_version Values: 0.19, 0.1 Name: recalc1 Values: 0, 0 Name: size_display Values: 0, 0 Name: size_skill Values: 0, 0 Name: size_skill_double Values: 0, 0 Name: str-mod Values: 2, 2 Name: wis-mod Values: 4, 4 VM444:59 Number of Duplicates: 154 undefined
Riley D. said: I've also just pushed out a fix which should make sure that attribute behavior is the same across character sheets, rolls, etc., even when there are duplicate attributes with the same name. So if you do end up with duplicate attributes, at least what shows up on your character sheet will match what shows up in your dice rolls, etc.&nbsp; So Vince if you're still able to use that test case from earlier where what you showed in the chat log when you rolled didn't match what was showing on your character sheet, re-run it and those should match. What this means practically is that while duplicate Attributes with the same name aren't good, for existing campaigns affected by the bug where they did produce duplicate attributes, they don't necessarily need to go and manually (or using Paul's script) clear them out, because their games will still keep working as intended. They will just have a bunch of attributes that they aren't actually using. Hey Riley I ran through my test case once today, and didn't notice any duplicates. Unfortunately, a new problem has been introduced. When I fill in buff 1 and select buffs 1-5, the buff total line remains zeros, and the engine also returns zero. Is this an issue with the character sheet, or did something happen with the Sheet Workers? Thanks.
1453162065

Edited 1453162107
vÍnce
Pro
Sheet Author
Riley brought this up. &nbsp;Might be in the repeating madness thread. &nbsp;I thought this was working earlier, so I'm not sure if this mornings updates caused a conflict or not. &nbsp;I tested with the v19&nbsp; update&nbsp; that was just merged a few hours ago and It appears to be working as expected with that version. &nbsp;There were changes made to fix buff 8. &nbsp;Which may explain the buff total update problem.
Vince said: Riley brought this up. &nbsp;Might be in the repeating madness thread. &nbsp;I thought this was working earlier, so I'm not sure if this mornings updates caused a conflict or not. &nbsp;I tested with the v19&nbsp; update&nbsp; that was just merged a few hours ago and It appears to be working as expected with that version. &nbsp;There were changes made to fix buff 8. &nbsp;Which may explain the buff total update problem. I just deployed that new sheet. So let me know if that fixed it.
1453167658
vÍnce
Pro
Sheet Author
The community sheet v19 seems to act differently between the Main and Dev. Main : create new sheet and version is 0. &nbsp;Hit recalc, no change. Refresh campaign. Sheet shows as v19. &nbsp;Buffs row total does not work. Dev : create new sheet and version is 0. &nbsp;Hit recalc, sheet changes to v19. &nbsp;Buffs row total works.
Vince said: The community sheet v19 seems to act differently between the Main and Dev. Main : create new sheet and version is 0. &nbsp;Hit recalc, no change. Refresh campaign. Sheet shows as v19. &nbsp;Buffs row total does not work. Dev : create new sheet and version is 0. &nbsp;Hit recalc, sheet changes to v19. &nbsp;Buffs row total works. Hmmm yeah the bug fixes I pushed out to Main today aren't on Dev. So I guess that means I broke something. I wonder what. I will take a look and see if I can figure it out.
Okay I just pushed a new fix to Main. Give it a try now should be fixed. Assuming it's fixed, here's what happened. Our new bug fix which fixed the bug where we were re-running Sheet Workers too often had the (unintended) side effect of causing Sheet Workers to not be notified when they changed something themselves. For example with the Pathfinder sheet, when you change @{buff1_melee_macro-text}, that causes the Sheet Worker to update the @{buff1_melee} attribute.&nbsp; Now, there is also a listener in the sheet worker that is supposed to fire when @{buff1_melee} is changed. In the new code, the assumption was that the Sheet Worker doesn't need to be re-notified about its own changes (to prevent things like infinite loops, for example, where you try to change an attribute in the listener for an attribute that depends on that attribute). However, that broke some parts of the Pathfinder sheet. I'm not really sure where I come down on this, honestly. On the one hand, I think it is probably easier for Sheet Authors to not have to necessarily load up their sheets with extra listeners considering every possibility of what attribute might be affected by them changing an attribute. On the other hand, I am cautious about introducing possible pitfalls like unintended infinite loops.&nbsp; Anyway, for now, it should be fixed, and now that I'm aware of this behavior dependency if I do decide to change it in the future I'll be sure to give plenty of notice so that we can get the Pathfinder sheet updated to not need this functionality. But for now it's staying so all should be right with the world. I believe that changing this behavior also should not have re-introduced the bugs we fixed, so let me know if it did. Thanks!
1453169301

Edited 1453169382
vÍnce
Pro
Sheet Author
Oops.. beat me by 26s Riley... &nbsp;these are before your fix. &nbsp;I'll test after the fix as well. Not sure if this helps: &nbsp;here's a console log comparison, same action performed on Dev and Main Manual Recalc DEV (appears to work properly) Main (nothing happens) CLICKED app.js?1453132489:36 Updating character sheet values app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:36 Setting up repeating sections took until 21ms app.js?1453132489:36 Finding list of dirty attributes took until 21ms app.js?1453132489:36 Querytest took until 22ms app.js?1453132489:36 Set values took until 33ms app.js?1453132489:36 Took 34ms VM38:1139 EEEE at evaluateAndSetNumber read:HP-formula-macro-text, write:HP-formula-mod, dontforce:undefined, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:NPC-HD-misc, write:NPC-HD-misc-mod, dontforce:undefined, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:Max-Skill-Ranks-Misc, write:Max-Skill-Ranks-mod, dontforce:undefined, default:undefined VM38:1141 Object {HP-formula-macro-text: "", HP-formula-mod: "0"} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField HP-formula-macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {NPC-HD-misc: "0", NPC-HD-misc-mod: "0"} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1157 it was a number VM38:1141 Object {Max-Skill-Ranks-Misc: "", Max-Skill-Ranks-mod: "0"} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField Max-Skill-Ranks-Misc at evaluateAndSetNumber VM38:1157 it was a number VM38:2512 FIXSKILL: Acrobatics : cs is 0 raw is:0 VM38:2512 FIXSKILL: Appraise : cs is 0 raw is:0 VM38:2512 FIXSKILL: Bluff : cs is 0 raw is:0 VM38:2512 FIXSKILL: Climb : cs is 0 raw is:0 VM38:2512 FIXSKILL: Craft : cs is 0 raw is:0 VM38:2512 FIXSKILL: Craft2 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Craft3 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Diplomacy : cs is 0 raw is:0 VM38:2512 FIXSKILL: Disable-Device : cs is 0 raw is:0 VM38:2512 FIXSKILL: Disguise : cs is 0 raw is:0 VM38:2512 FIXSKILL: Escape-Artist : cs is 0 raw is:0 VM38:2512 FIXSKILL: Fly : cs is 0 raw is:0 VM38:2512 FIXSKILL: Handle-Animal : cs is 0 raw is:0 VM38:2512 FIXSKILL: Heal : cs is 0 raw is:0 VM38:2512 FIXSKILL: Intimidate : cs is 0 raw is:0 VM38:2512 FIXSKILL: Linguistics : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Arcana : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Dungeoneering : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Engineering : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Geography : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-History : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Local : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Nature : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Nobility : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Planes : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Religion : cs is 0 raw is:0 VM38:2512 FIXSKILL: Perception : cs is 0 raw is:0 VM38:2512 FIXSKILL: Perform : cs is 0 raw is:0 VM38:2512 FIXSKILL: Perform2 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Perform3 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Profession : cs is 0 raw is:0 VM38:2512 FIXSKILL: Profession2 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Profession3 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Ride : cs is 0 raw is:0 VM38:2512 FIXSKILL: Sense-Motive : cs is 0 raw is:0 VM38:2512 FIXSKILL: Sleight-of-Hand : cs is 0 raw is:0 VM38:2512 FIXSKILL: Spellcraft : cs is 0 raw is:0 VM38:2512 FIXSKILL: Stealth : cs is 0 raw is:0 VM38:2512 FIXSKILL: Survival : cs is 0 raw is:0 VM38:2512 FIXSKILL: Swim : cs is 0 raw is:0 VM38:2512 FIXSKILL: Use-Magic-Device : cs is 0 raw is:0 VM38:2512 FIXSKILL: Misc-Skill-0 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Misc-Skill-1 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Misc-Skill-2 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Misc-Skill-3 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Misc-Skill-4 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Misc-Skill-5 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Artistry : cs is 0 raw is:0 VM38:2512 FIXSKILL: Lore : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Acrobatics : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Athletics : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Finesse : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Influence : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Nature : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Perception : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Performance : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Religion : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Society : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Spellcraft : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Stealth : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Survival : cs is 0 raw is:0 app.js?1453132489:36 Updating character sheet values app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:36 Setting up repeating sections took until 22ms app.js?1453132489:36 Finding list of dirty attributes took until 22ms app.js?1453132489:36 Querytest took until 23ms app.js?1453132489:36 Set values took until 32ms app.js?1453132489:36 Took 33ms CLICKED app.js?1452612449:36 Updating character sheet values app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:36 Setting up repeating sections took until 20ms app.js?1452612449:36 Finding list of dirty attributes took until 21ms app.js?1452612449:36 Querytest took until 21ms app.js?1452612449:36 Set values took until 31ms app.js?1452612449:36 Took 33ms VM38:1139 EEEE at evaluateAndSetNumber read:HP-formula-macro-text, write:HP-formula-mod, dontforce:undefined, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:NPC-HD-misc, write:NPC-HD-misc-mod, dontforce:undefined, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:Max-Skill-Ranks-Misc, write:Max-Skill-Ranks-mod, dontforce:undefined, default:undefined VM38:1141 Object {HP-formula-macro-text: "", HP-formula-mod: "0"} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField HP-formula-macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {NPC-HD-misc: "0", NPC-HD-misc-mod: "0"} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1157 it was a number VM38:1141 Object {Max-Skill-Ranks-Misc: "", Max-Skill-Ranks-mod: "0"} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField Max-Skill-Ranks-Misc at evaluateAndSetNumber VM38:1157 it was a number VM38:2512 FIXSKILL: Acrobatics : cs is 0 raw is:0 VM38:2512 FIXSKILL: Appraise : cs is 0 raw is:0 VM38:2512 FIXSKILL: Bluff : cs is 0 raw is:0 VM38:2512 FIXSKILL: Climb : cs is 0 raw is:0 VM38:2512 FIXSKILL: Craft : cs is 0 raw is:0 VM38:2512 FIXSKILL: Craft2 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Craft3 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Diplomacy : cs is 0 raw is:0 VM38:2512 FIXSKILL: Disable-Device : cs is 0 raw is:0 VM38:2512 FIXSKILL: Disguise : cs is 0 raw is:0 VM38:2512 FIXSKILL: Escape-Artist : cs is 0 raw is:0 VM38:2512 FIXSKILL: Fly : cs is 0 raw is:0 VM38:2512 FIXSKILL: Handle-Animal : cs is 0 raw is:0 VM38:2512 FIXSKILL: Heal : cs is 0 raw is:0 VM38:2512 FIXSKILL: Intimidate : cs is 0 raw is:0 VM38:2512 FIXSKILL: Linguistics : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Arcana : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Dungeoneering : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Engineering : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Geography : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-History : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Local : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Nature : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Nobility : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Planes : cs is 0 raw is:0 VM38:2512 FIXSKILL: Knowledge-Religion : cs is 0 raw is:0 VM38:2512 FIXSKILL: Perception : cs is 0 raw is:0 VM38:2512 FIXSKILL: Perform : cs is 0 raw is:0 VM38:2512 FIXSKILL: Perform2 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Perform3 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Profession : cs is 0 raw is:0 VM38:2512 FIXSKILL: Profession2 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Profession3 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Ride : cs is 0 raw is:0 VM38:2512 FIXSKILL: Sense-Motive : cs is 0 raw is:0 VM38:2512 FIXSKILL: Sleight-of-Hand : cs is 0 raw is:0 VM38:2512 FIXSKILL: Spellcraft : cs is 0 raw is:0 VM38:2512 FIXSKILL: Stealth : cs is 0 raw is:0 VM38:2512 FIXSKILL: Survival : cs is 0 raw is:0 VM38:2512 FIXSKILL: Swim : cs is 0 raw is:0 VM38:2512 FIXSKILL: Use-Magic-Device : cs is 0 raw is:0 VM38:2512 FIXSKILL: Misc-Skill-0 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Misc-Skill-1 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Misc-Skill-2 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Misc-Skill-3 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Misc-Skill-4 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Misc-Skill-5 : cs is 0 raw is:0 VM38:2512 FIXSKILL: Artistry : cs is 0 raw is:0 VM38:2512 FIXSKILL: Lore : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Acrobatics : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Athletics : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Finesse : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Influence : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Nature : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Perception : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Performance : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Religion : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Society : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Spellcraft : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Stealth : cs is 0 raw is:0 VM38:2512 FIXSKILL: CS-Survival : cs is 0 raw is:0 app.js?1452612449:36 Updating character sheet values app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:36 Setting up repeating sections took until 22ms app.js?1452612449:36 Finding list of dirty attributes took until 22ms app.js?1452612449:36 Querytest took until 23ms app.js?1452612449:36 Set values took until 28ms app.js?1452612449:36 Took 29ms Toggle ON buff1 DEV (appears to work properly) MAIN (nothing happens) CLICKED app.js?1452612449:36 Updating character sheet values app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:36 Setting up repeating sections took until 26ms app.js?1452612449:36 Finding list of dirty attributes took until 26ms app.js?1452612449:36 Querytest took until 27ms app.js?1452612449:36 Set values took until 34ms app.js?1452612449:36 Took 35ms VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Melee_macro-text, write:buff1_Melee, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Ranged_macro-text, write:buff1_Ranged, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_DMG_macro-text, write:buff1_DMG, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_AC_macro-text, write:buff1_AC, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_HP-temp_macro-text, write:buff1_HP-temp, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Fort_macro-text, write:buff1_Fort, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Ref_macro-text, write:buff1_Ref, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Will_macro-text, write:buff1_Will, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_STR_macro-text, write:buff1_STR, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_DEX_macro-text, write:buff1_DEX, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_CON_macro-text, write:buff1_CON, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_INT_macro-text, write:buff1_INT, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_WIS_macro-text, write:buff1_WIS, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_CHA_macro-text, write:buff1_CHA, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Touch_macro-text, write:buff1_Touch, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_CMD_macro-text, write:buff1_CMD, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Check_macro-text, write:buff1_Check, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_CasterLevel_macro-text, write:buff1_CasterLevel, dontforce:true, default:undefined VM38:1141 Object {buff1_Melee_macro-text: "10", buff1_Melee: 0} VM38:1146 trueDefault:0, currVal:0, value:10, isNaN:false VM38:1157 it was a number VM38:1141 Object {buff1_Ranged_macro-text: "", buff1_Ranged: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_Ranged_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_DMG_macro-text: "", buff1_DMG: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_DMG_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_AC_macro-text: "", buff1_AC: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_AC_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_HP-temp_macro-text: "", buff1_HP-temp: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_HP-temp_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_Fort_macro-text: "", buff1_Fort: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_Fort_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_Ref_macro-text: "", buff1_Ref: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_Ref_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_Will_macro-text: "", buff1_Will: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_Will_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_STR_macro-text: "", buff1_STR: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_STR_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_DEX_macro-text: "", buff1_DEX: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_DEX_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_CON_macro-text: "", buff1_CON: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_CON_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_INT_macro-text: "", buff1_INT: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_INT_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_WIS_macro-text: "", buff1_WIS: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_WIS_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_CHA_macro-text: "", buff1_CHA: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_CHA_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_Touch_macro-text: "", buff1_Touch: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_Touch_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_CMD_macro-text: "", buff1_CMD: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_CMD_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_Check_macro-text: "", buff1_Check: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_Check_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_CasterLevel_macro-text: "", buff1_CasterLevel: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_CasterLevel_macro-text at evaluateAndSetNumber VM38:1157 it was a number app.js?1452612449:36 Updating character sheet values app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:36 Setting up repeating sections took until 20ms app.js?1452612449:36 Finding list of dirty attributes took until 20ms app.js?1452612449:36 Querytest took until 21ms app.js?1452612449:36 Set values took until 27ms app.js?1452612449:36 Took 28ms app.js?1452612449:36 Updating character sheet values app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:36 Setting up repeating sections took until 42ms app.js?1452612449:36 Finding list of dirty attributes took until 42ms app.js?1452612449:36 Querytest took until 43ms app.js?1452612449:36 Set values took until 54ms app.js?1452612449:36 Took 55ms app.js?1452612449:36 Updating character sheet values app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:37 [] app.js?1452612449:36 Setting up repeating sections took until 42ms app.js?1452612449:36 Finding list of dirty attributes took until 42ms app.js?1452612449:36 Querytest took until 43ms app.js?1452612449:36 Set values took until 53ms app.js?1452612449:36 Took 54ms CLICKED app.js?1453132489:36 Updating character sheet values app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:36 Setting up repeating sections took until 25ms app.js?1453132489:36 Finding list of dirty attributes took until 25ms app.js?1453132489:36 Querytest took until 26ms app.js?1453132489:36 Set values took until 38ms app.js?1453132489:36 Took 39ms VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Melee_macro-text, write:buff1_Melee, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Ranged_macro-text, write:buff1_Ranged, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_DMG_macro-text, write:buff1_DMG, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_AC_macro-text, write:buff1_AC, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_HP-temp_macro-text, write:buff1_HP-temp, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Fort_macro-text, write:buff1_Fort, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Ref_macro-text, write:buff1_Ref, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Will_macro-text, write:buff1_Will, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_STR_macro-text, write:buff1_STR, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_DEX_macro-text, write:buff1_DEX, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_CON_macro-text, write:buff1_CON, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_INT_macro-text, write:buff1_INT, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_WIS_macro-text, write:buff1_WIS, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_CHA_macro-text, write:buff1_CHA, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Touch_macro-text, write:buff1_Touch, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_CMD_macro-text, write:buff1_CMD, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_Check_macro-text, write:buff1_Check, dontforce:true, default:undefined VM38:1139 EEEE at evaluateAndSetNumber read:buff1_CasterLevel_macro-text, write:buff1_CasterLevel, dontforce:true, default:undefined VM38:1141 Object {buff1_Melee_macro-text: "10", buff1_Melee: 0} VM38:1146 trueDefault:0, currVal:0, value:10, isNaN:false VM38:1157 it was a number VM38:1141 Object {buff1_Ranged_macro-text: "", buff1_Ranged: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_Ranged_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_DMG_macro-text: "", buff1_DMG: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_DMG_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_AC_macro-text: "", buff1_AC: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_AC_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_HP-temp_macro-text: "", buff1_HP-temp: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_HP-temp_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_Fort_macro-text: "", buff1_Fort: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_Fort_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_Ref_macro-text: "", buff1_Ref: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_Ref_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_Will_macro-text: "", buff1_Will: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_Will_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_STR_macro-text: "", buff1_STR: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_STR_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_DEX_macro-text: "", buff1_DEX: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_DEX_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_CON_macro-text: "", buff1_CON: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_CON_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_INT_macro-text: "", buff1_INT: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_INT_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_WIS_macro-text: "", buff1_WIS: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_WIS_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_CHA_macro-text: "", buff1_CHA: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_CHA_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_Touch_macro-text: "", buff1_Touch: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_Touch_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_CMD_macro-text: "", buff1_CMD: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_CMD_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_Check_macro-text: "", buff1_Check: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_Check_macro-text at evaluateAndSetNumber VM38:1157 it was a number VM38:1141 Object {buff1_CasterLevel_macro-text: "", buff1_CasterLevel: 0} VM38:1146 trueDefault:0, currVal:0, value:0, isNaN:false VM38:1151 PFSHeet Warning: could not find readField buff1_CasterLevel_macro-text at evaluateAndSetNumber VM38:1157 it was a number app.js?1453132489:36 Updating character sheet values app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:37 [] app.js?1453132489:36 Setting up repeating sections took until 49ms app.js?1453132489:36 Finding list of dirty attributes took until 49ms app.js?1453132489:36 Querytest took until 50ms app.js?1453132489:36 Set values took until 60ms app.js?1453132489:36 Took 61ms
1453169876
vÍnce
Pro
Sheet Author
That seems to have done it. &nbsp;We still have to hit recalc on a brand new character. &nbsp;I think the sheet worker script is supposed to check for lesser versions and fire a recalc if true... &nbsp;we'll have to check/test that. &nbsp;The Buffs are working as well. &nbsp;Awesome. &nbsp;Waiting to hear how others fare... &nbsp;Thanks Riley!
1453193408

Edited 1453248484
Riley D. said: Okay I just pushed a new fix to Main. Give it a try now should be fixed. Assuming it's fixed, here's what happened. Our new bug fix which fixed the bug where we were re-running Sheet Workers too often had the (unintended) side effect of causing Sheet Workers to not be notified when they changed something themselves. For example with the Pathfinder sheet, when you change @{buff1_melee_macro-text}, that causes the Sheet Worker to update the @{buff1_melee} attribute.&nbsp; Now, there is also a listener in the sheet worker that is supposed to fire when @{buff1_melee} is changed. In the new code, the assumption was that the Sheet Worker doesn't need to be re-notified about its own changes (to prevent things like infinite loops, for example, where you try to change an attribute in the listener for an attribute that depends on that attribute). However, that broke some parts of the Pathfinder sheet. I'm not really sure where I come down on this, honestly. On the one hand, I think it is probably easier for Sheet Authors to not have to necessarily load up their sheets with extra listeners considering every possibility of what attribute might be affected by them changing an attribute. On the other hand, I am cautious about introducing possible pitfalls like unintended infinite loops.&nbsp; Anyway, for now, it should be fixed, and now that I'm aware of this behavior dependency if I do decide to change it in the future I'll be sure to give plenty of notice so that we can get the Pathfinder sheet updated to not need this functionality. But for now it's staying so all should be right with the world. I believe that changing this behavior also should not have re-introduced the bugs we fixed, so let me know if it did. Thanks! Hey Riley, thanks for looking at this. I was thinking about the issue of cascading events triggering an infinite loop. This would only occur if there was a cycle somewhere in the dependencies. It would be possible to crawl through the character sheet, building a graph of attribute dependencies. Then the code could look for cycles in the graph. No cycles = no loops. Are you using an existing javascript graph library in your code anywhere?