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

[Battle Tech - A Time of War] Questions regarding updating an existing sheet

Hi guys, one of my mates has decided to start running a Battle Tech - A Time of War game, using Roll20. Well, I quickly discovered that the existing sheet is somewhat functional, but pretty poor, so I wanted to do some work to update it. I've read the Wiki page about creating character sheets, checked out the FAQ sticky threads here, and had a look at the GitHub repo, but I still have a few questions. Major changes to character sheets If I make a rather significant change to this sheet - IE, I rename the strength attribute field - what happens to everyone who is using this sheet already? Do all users automatically get the updated sheet? If so, is there a way to specify a data migration, so that data stored under a previous variable name will be copied over to a new variable name? Sheets should not include character creation or advancement - what does that mean? Under the minimum requirements of the Building Character Sheets Wiki page, it mentions this: Do not infringe on intellectual property . Community sheets should not include character creation or advancement due to potential copyright restrictions. 'By Roll20' sheets may include this content thanks to our partnerships with game creators. Sheets that are developed from the code of a 'By Roll20' will need to ensure any character creation or advancement options code it removed. Its okay to have attributes that auto-calculate based on other attributes (including the current level). We'll let you know if your submitted sheet violates this rule. What does this mean? I'm honestly confused by this, as none of the sheets I've seen seemed to have anything to do with character creation. The Pathfinder sheet has what I would sort of consider advancement (you can update the level of your class, which auto calculates how many skill points you should have assigned), but is that ok because Roll20 are partnered with Paizo? Do I need a pro account? I'm a bit confused on this point, because a pro account is mentioned, but usually in the context of creating a new sheet, or customizing an existing sheet. It seems to be implied that you don't need a pro account if you're simply improving an existing sheet, which is what I plan to do. However, I'm also not sure how I can test my code before making a pull request. Is that where I need a pro account, so that I can import my code directly to Roll20 and test it? Rules readily available - what does this mean? Again, from the Building Character Sheets page on the Wiki: Rules must be readily available . Sheets can be submitted for independent games and homebrew systems. Homebrew games will need to ensure they are not violating copyright for their respective game system. In both cases the rules need to be readily available online to the public. As far as I can tell, the rules for Battle Tech - A Time of War are not available freely online like the Pathfinder rules are. Does this mean that this sheet would fail that requirement? It does already exist, though, so should this sheet actually be removed considering the rules aren't freely available online? Community compendium contributions: I suspect I know the answer to this, but again, from the Wiki page: Compendium Integration . By designating that your sheet is compatible with a Compendium, players will have direct access to that Compendium in the right sidebar during gameplay. Compendiums are still a growing feature on Roll20 and integration is not yet available to the majority of game systems. Does this mean that currently I cannot create a compendium for Battle Tech - A Time of War and start adding in items etc? Thanks guys. :)
1546688561
Finderski
Pro
Sheet Author
Compendium Curator
Michael S. said: Major changes to character sheets If I make a rather significant change to this sheet - IE, I rename the strength attribute field - what happens to everyone who is using this sheet already? Do all users automatically get the updated sheet? If so, is there a way to specify a data migration, so that data stored under a previous variable name will be copied over to a new variable name? Depends on what you're talking about. If you mean you're changing the actual name of the input field (e.g. attr_str to attr_strength), then, yes...every game that is currently using this sheet would lose data unless you have a sheet worker that migrates the data from field to a new one. I'll also just mention, if you're making a change of any sort, to an existing sheet, it's usually a good practice to reach out to the creator of the sheet to see if they have any concerns with  you making changes.  Because these sheets are community maintained no one can really stop you from making the changes, but it's a good idea to communicate so people aren't caught by surprise, etc. Michael S. said: Sheets should not include character creation or advancement - what does that mean? Under the minimum requirements of the Building Character Sheets Wiki page, it mentions this: Do not infringe on intellectual property . Community sheets should not include character creation or advancement due to potential copyright restrictions. 'By Roll20' sheets may include this content thanks to our partnerships with game creators. Sheets that are developed from the code of a 'By Roll20' will need to ensure any character creation or advancement options code it removed. Its okay to have attributes that auto-calculate based on other attributes (including the current level). We'll let you know if your submitted sheet violates this rule. What does this mean? I'm honestly confused by this, as none of the sheets I've seen seemed to have anything to do with character creation. The Pathfinder sheet has what I would sort of consider advancement (you can update the level of your class, which auto calculates how many skill points you should have assigned), but is that ok because Roll20 are partnered with Paizo? You can't have code that does character creation or auto-advancement for the player.  Anything that would negate the need for someone to have the rules is what this is really getting at.  Think Charactermancer...that automates the character creation process and soon, it'll automate the advancement process.  This is allowed for Roll20 sheets, because they have a partnerships with the respective IP owners.  I could not do something like that for the Savage Worlds sheet, because it would infringe the IP of Pinnacle. Michael S. said: Do I need a pro account? I'm a bit confused on this point, because a pro account is mentioned, but usually in the context of creating a new sheet, or customizing an existing sheet. It seems to be implied that you don't need a pro account if you're simply improving an existing sheet, which is what I plan to do. However, I'm also not sure how I can test my code before making a pull request. Is that where I need a pro account, so that I can import my code directly to Roll20 and test it? The simple answer is, yes, you'll need a Pro account in order to test your code prior to submitting to GitHub.  There have been some who've done this without a pro account and every one of them has stated the would never do it that way again.  When developing a sheet (even modifying an existing one), the Pro level account gives you access to the Custom Character sheet option where you can upload your code and see what it looks like in an actual game. This would also allow you to test your sheet prior to uploading to GitHub.  Michael S. said: Rules readily available - what does this mean? Again, from the Building Character Sheets page on the Wiki: Rules must be readily available . Sheets can be submitted for independent games and homebrew systems. Homebrew games will need to ensure they are not violating copyright for their respective game system. In both cases the rules need to be readily available online to the public. As far as I can tell, the rules for Battle Tech - A Time of War are not available freely online like the Pathfinder rules are. Does this mean that this sheet would fail that requirement? It does already exist, though, so should this sheet actually be removed considering the rules aren't freely available online? This doesn't mean the rules need to be free, only that it should be an actual, published game.  This is to keep the character sheets from being flooded with everyone's home brew game that no one has every heard of. I did a google search for Battle Tech a Time of War and found the rules easily. This would be sufficient to pass this requirement. Michael S. said: Community compendium contributions: I suspect I know the answer to this, but again, from the Wiki page: Compendium Integration . By designating that your sheet is compatible with a Compendium, players will have direct access to that Compendium in the right sidebar during gameplay. Compendiums are still a growing feature on Roll20 and integration is not yet available to the majority of game systems. Does this mean that currently I cannot create a compendium for Battle Tech - A Time of War and start adding in items etc? Correct, we can not create custom compendiums and unless Battle Tech has something like an SRD (like D&D and Pathfinder have), then you're likely out of luck on this one. 
Thanks for your answers. :) Pretty much cleared up all the questions I had. Finderski said: Michael S. said: Major changes to character sheets If I make a rather significant change to this sheet - IE, I rename the strength attribute field - what happens to everyone who is using this sheet already? Do all users automatically get the updated sheet? If so, is there a way to specify a data migration, so that data stored under a previous variable name will be copied over to a new variable name? Depends on what you're talking about. If you mean you're changing the actual name of the input field (e.g. attr_str to attr_strength), then, yes...every game that is currently using this sheet would lose data unless you have a sheet worker that migrates the data from field to a new one. I'll also just mention, if you're making a change of any sort, to an existing sheet, it's usually a good practice to reach out to the creator of the sheet to see if they have any concerns with  you making changes.  Because these sheets are community maintained no one can really stop you from making the changes, but it's a good idea to communicate so people aren't caught by surprise, etc. Good point on communicating with the previous author; I hadn't thought to do that, since the sheet hasn't been touched since 2017, and even then it looks like they just threw something together quickly and have since abandoned it. However, I should reach out and see if they are still interested in it, and work on it with them if so. How can I write a sheet worker to migrate stuff? Is it just a simple "on sheet load, for all the new attribute values, if not populated, try to populate with old sheet values"?
1546693669
Finderski
Pro
Sheet Author
Compendium Curator
More or less, yep. Here's a very basic example of one I'm using for my character sheet re-write (redoing the Savage Worlds sheet and need to migrate stuff): on('sheet:opened', function() {   getAttrs(['character_sheet','initializeStatblock'], function(v) { console.log("<===== Begin Sheet Upgrade Conversion Process =====>"); console.log("Sheet Version: " + v.character_sheet.slice(22)); const version = parseFloat(v.character_sheet.slice(22)) || 0; upgradeSheet(version);   });   console.log("<===== End Sheet Upgrade Conversion Process =====>"); }); const upgradeSheet = function(version) { if (version < 4.0) { //migrate old fields to new const oldAtts = ["list","of","old","fields"]; const newAtts = ["list","of","new","fields"]; let sAttrs = {}; getAttrs(oldAtts, function(v) { for (let i=0; i<oldAtts.length; i++) { console.log(newAtts[i] + " = " + v[oldAtts[i]]); sAttrs[newAtts[i]] = v[oldAtts[i]]; } setAttrs(sAttrs); }); } else { console.log("!!! Sheet Already Upgraded !!!"); } }; If the sheet you're working with doesn't have a version number, I'd recommending changing that.  At the very least, you should also set a field at the end of the process so you know the upgrade is complete, and that's the value you should look for, so it doesn't keep updating every time the sheet is opened.  That will be especially important if the values can be changed over time, because then new information could be overwritten with old.
1546694900

Edited 1546694967
GiGs
Pro
Sheet Author
API Scripter
Finderski answers the question about upgrading, but another thing to consider: do you really  need to change stat names? There can be reasons to do it (typos in the original names, some name structures make using sheetworkers harder, for instance), and if your reasons are good, go for it. But if its just for your personal aesthetics, you are probably better off leaving them as is. After all, someone may come along later, decide their  aesthetics call for a different naming pattern, and write a new upgrade, and then over time you end up with a bunch of cruft in the sheet that is just waste.
Finderski said: If the sheet you're working with doesn't have a version number, I'd recommending changing that. &nbsp;At the very least, you should also set a field at the end of the process so you know the upgrade is complete, and that's the value you should look for, so it doesn't keep updating every time the sheet is opened. &nbsp;That will be especially important if the values can be changed over time, because then new information could be overwritten with old. Good call on a version number. I was wondering about how to do a migration, especially when giving attributes default values; how do you tell if an attribute has a default value because it hasn't been migrated yet, vs its actual value being the same as the default value. How do you do version numbers for sheets? Also regarding anonymous JavaScript functions, is there a reason to use "function() {}" instead of just doing a lambda? IE "() =&gt; {}" GiGs said: Finderski answers the question about upgrading, but another thing to consider: do you really &nbsp;need to change stat names? There can be reasons to do it (typos in the original names, some name structures make using sheetworkers harder, for instance), and if your reasons are good, go for it. But if its just for your personal aesthetics, you are probably better off leaving them as is. After all, someone may come along later, decide their &nbsp;aesthetics call for a different naming pattern, and write a new upgrade, and then over time you end up with a bunch of cruft in the sheet that is just waste. Good points. I'd say it's half and half. Here's an example of what I'm dealing with: <a href="https://github.com/Roll20/roll20-character-sheets/blob/master/BattleTech-A-Time-of-War/BattleTech-A-Time-of-War.html#L114-L118" rel="nofollow">https://github.com/Roll20/roll20-character-sheets/blob/master/BattleTech-A-Time-of-War/BattleTech-A-Time-of-War.html#L114-L118</a> My personal preference would be no abbreviations, fully spell it out. So I would have attr_strength_score, attr_strength_link (or maybe attr_strength_linked_value), and attr_strength_xp. I don't know if that's more in line with the guidelines on building sheets, whether abbreviations are frowned upon or not. Where I do think there's an objective reason to change it, is to make it lower case, since certain parts of the sheets/sheet workers will forcibly convert attribute names to lower case, so I think just using lower case everywhere makes things easier. Which leads me into another question I thought of; are stored attributes case sensitive? IE, if I rename attr_STRS to attr_strs, will it just use the same value it already has? Or are they considered two distinct attribute values? Thanks guys.
1546738743
Andreas J.
Forum Champion
Sheet Author
Translator
Rules readily available - what does this mean? It doesnt have to be a officialy published game, but the rules must be coherent enough to be findable with a simple web search. We have several sheets for homebrew or original rpgs, "Weaverdice" and "StarWars Homebrew for D&amp;D5E" are two examples of those kinds of sheets. Roll20 also prefers that sheet for games that ahvent yet been published aren't added to Roll20 before the game is released to everyone(free or paid verison). Think there where some game that was like&nbsp; pre-released to only Kickstarter backers was kinda gray area and Roll20 decided to approve/add sheet when the game was launched to the public. I could back my claims with links to some old closed github PRs but can't be bothered right now.
1546789200
Finderski
Pro
Sheet Author
Compendium Curator
Michael S. said: Finderski said: If the sheet you're working with doesn't have a version number, I'd recommending changing that. &nbsp;At the very least, you should also set a field at the end of the process so you know the upgrade is complete, and that's the value you should look for, so it doesn't keep updating every time the sheet is opened. &nbsp;That will be especially important if the values can be changed over time, because then new information could be overwritten with old. Good call on a version number. I was wondering about how to do a migration, especially when giving attributes default values; how do you tell if an attribute has a default value because it hasn't been migrated yet, vs its actual value being the same as the default value. How do you do version numbers for sheets? You'll want the upgrade script to set the version number for every sheet, that way, when a new sheet version number is created, you don't run into the problem if the default value being the same as the new version number. &nbsp;So, really, you're upgrade script should update something on every sheet the first time. &nbsp;Then future versions will be set. &nbsp;This first time, you'll likely want all sheets to go through the process (though you'll need to have a way to distinguish a brand new character that doesn't need anything migrated and one that does need migration).&nbsp; Michael S. said: Also regarding anonymous JavaScript functions, is there a reason to use "function() {}" instead of just doing a lambda? IE "() =&gt; {}" I just failed my comprehension check, because I have no idea what you're asking... LOL As a caveat, I'm no programmer and have barely muddled my way through a few sheet workers with a lot of help and patience from people like GiGs
1546790030

Edited 1546790932
GiGs
Pro
Sheet Author
API Scripter
Michael S. &nbsp;said: Also regarding anonymous JavaScript functions, is there a reason to use "function() {}" instead of just doing a lambda? IE "() =&gt; {}" While there are &nbsp;technical differences between them, but for your roll20 sheets, they make no real difference.&nbsp; Just use which you are most comfortable with.&nbsp; Michael S. &nbsp;said: Good call on a version number. I was wondering about how to do a migration, especially when giving attributes default values; how do you tell if an attribute has a default value because it hasn't been migrated yet, vs its actual value being the same as the default value. How do you do version numbers for sheets? Here's a pretty good way to handle the migration:&nbsp; Create a new attribute (called, say, version) in the character sheet's html, and give it a default value. (say, 0.0) Then in your version script, you have the on(sheet:opened) and check: a) is the version undefined b) is it exists, is it not a number c) if it is a number, is it less than the version it should be after the upgrade (say, less than 1) If any of the above are true, you run your sheet upgrade script. Otherwise you just end the script. At the end of your sheet upgrade script, you assign the version number (say 1.0) So, everytime a sheet is opened, the check is done, and if version is 1, nothing happens, but if less than 1, the sheet is updated and is now version 1. There is a complication, though: Finderski &nbsp;said: This first time, you'll likely want all sheets to go through the process (though you'll need to have a way to distinguish a brand new character that doesn't need anything migrated and one that does need migration).&nbsp; Is there a better way of handling than this than in your upgrade script, checking if the old attributes exist, and simply doing nothing if they don't? For instance in this section: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const oldAtts = ["list","of","old","fields"]; const newAtts = ["list","of","new","fields"]; let sAttrs = {}; getAttrs(oldAtts, function(v) { for (let i=0; i&lt;oldAtts.length; i++) { console.log(newAtts[i] + " = " + v[oldAtts[i]]); sAttrs[newAtts[i]] = v[oldAtts[i]]; } setAttrs(sAttrs); }); Include a check for the old attribute: is it undefined, if so skip it, like so: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const oldAtts = ["list","of","old","fields"]; const newAtts = ["list","of","new","fields"]; let sAttrs = {}; getAttrs(oldAtts, function(v) { for (let i=0; i&lt;oldAtts.length; i++) { console.log(newAtts[i] + " = " + v[oldAtts[i]]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(v[oldAtts[i]] != undefined) &nbsp;&nbsp;&nbsp;&nbsp;sAttrs[newAtts[i]] = v[oldAtts[i]]; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(sAttrs) &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;setAttrs(sAttrs); }); Is there a better way of handling that?
Finderski said: Michael S. said: Also regarding anonymous JavaScript functions, is there a reason to use "function() {}" instead of just doing a lambda? IE "() =&gt; {}" I just failed my comprehension check, because I have no idea what you're asking... LOL As a caveat, I'm no programmer and have barely muddled my way through a few sheet workers with a lot of help and patience from people like GiGs Yeah don't worry, that's definitely a programmer-specific question. :P I can try and explain it if you like, if you're curious about what I said, but you definitely don't have to worry about it. Regarding this whole sheet migration process, I'm only going to do that IF people agree that the current attribute names aren't great and should be changed. My opinion is that they should be changed, but I'm a newbie here, so I'd like some confirmation from the more experienced guys before I go around changing things willy nilly.
1546958861
GiGs
Pro
Sheet Author
API Scripter
Michael S. said: Regarding this whole sheet migration process, I'm only going to do that IF people agree that the current attribute names aren't great and should be changed. My opinion is that they should be changed, but I'm a newbie here, so I'd like some confirmation from the more experienced guys before I go around changing things willy nilly. I just had a look at the stat names, and I see what you mean. If I were you, I'd go ahead and change them too. Those names are pretty awful and clearly weren't chosen with macro users in mind. You'll have to be careful to make sure you catch them all in the migration, but it'll be worth it.
GiGs said: You'll have to be careful to make sure you catch them all in the migration, but it'll be worth it. So I can count on you to review my pull request, then? :P Also, is there no control for end users regarding sheet upgrades? If my pull request with updates to the sheet gets merged into the main repo, the next time anyone launches a game using that sheet, they'll have the updated version? If anyone's interested, you can check out my progress here: <a href="https://github.com/Skater901/roll20-character-sheets/tree/BTATOW" rel="nofollow">https://github.com/Skater901/roll20-character-sheets/tree/BTATOW</a> I haven't done much yet, though. Is it possible, with Roll20 character sheets, to separate out the HTML into separate files and then include each file in the main HTML file? I'm not particularly keen on these massive HTML files, and would like to be able to split it up either by tab, or section on a tab, or something like that.
1547657744
Andreas J.
Forum Champion
Sheet Author
Translator
No control for end users. Thefe is one version of any sheet, and that's what you use. Of course, Pro menbers can go to github and copy the current or an older version of a sheet and use the custom sheet option. Then the used sheet would never update.
Reviving this thread from the dead as I have another question. I've noticed that in Roll20, when choosing a character sheet for your game, this particular sheet shows up as "BattleTech: Time of War". I would prefer it to say "BattleTech: A Time of War", since that's actually what the system's called. I realise this is a pretty minor thing, but I can be pedantic. :P Anyway, I discovered that the name is set in the approved.yaml file in the character sheet repo, so my question is: who updates that? Can I just update the name in the approved.yaml file and include that in a pull request, or is that file specifically managed by the Roll20 team?
1548753640
GiGs
Pro
Sheet Author
API Scripter
You shouldnt ever edit the approved.yaml file. Thats for roll20 alone. You can send the roll20 team a message through github. Raise an issue on the site.
Dumb question, but when you set a default value for an input field, that value doesn't automatically get set as an attribute? I thought it did, but it doesn't seem to be working that way, and I just want to confirm.
1549445742
GiGs
Pro
Sheet Author
API Scripter
It does get set as a default value, it just doesnt show up on the attributes tab until you manually change it. If you call it with @{attributename} you'll find it does already exist.
Well, it didn't seem to work for my sheet version. =/ Here I set the initial sheet version via a hidden input with a default value: <a href="https://github.com/Roll20/roll20-character-sheets/blob/master/BattleTech-A-Time-of-War/BattleTech-A-Time-of-War.html#L6" rel="nofollow">https://github.com/Roll20/roll20-character-sheets/blob/master/BattleTech-A-Time-of-War/BattleTech-A-Time-of-War.html#L6</a> Then here, I check the version before doing any migration: <a href="https://github.com/Roll20/roll20-character-sheets/blob/master/BattleTech-A-Time-of-War/BattleTech-A-Time-of-War.html#L730-L736" rel="nofollow">https://github.com/Roll20/roll20-character-sheets/blob/master/BattleTech-A-Time-of-War/BattleTech-A-Time-of-War.html#L730-L736</a> So when my code went live, I opened up my character sheet... and my stat values hadn't been copied over. I checked the log messages, and I saw the log message for checking sheet version, and then nothing after that. So I'm not sure exactly what happened, but it seems like it fell over and didn't complete. Interestingly, from that point onwards, if I opened my sheet again, I would see the message about no data migration needed, but I still couldn't see the sheet version in the attributes. Manually setting the sheet version to 1 caused the migration to work perfectly. So... what did I do wrong? :(
1549755478
GiGs
Pro
Sheet Author
API Scripter
If I'm not misreading things, it looks like this is your problem: Your comparisons are using the attribute name&nbsp; " btatow_sheet_version " as in getAttrs ([ " btatow_sheet_version " ], sheetVersion =&gt; { but that is not the attribute name you created in the input: &lt; input type = " hidden " name = " attr_sheet_version " value = " 1 " /&gt; The attribute is called sheet_version . This also explains why the script didnt work the first time, but did work the second and subsequent times. Because the first time, no btatow version for the attr existed, but after the first run of the script, that attribute had been created.
1549755666

Edited 1549757025
GiGs
Pro
Sheet Author
API Scripter
Also your setAttrs function seems (to me) to be unnecessarily convoluted. I've been taught that nesting setAttrs is a bad idea.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs(newAttributes, null, () =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setAttrs({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; btatow_sheet_version: 2.0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, null, () =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log("Sheet data migration completed") &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }) Since it's a callback function, I expect it's fine, but does it provide an advantage I'm missing over the below? &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newAttributes['sheet_version'] = '2.0'; setAttrs(newAttributes); console.log("Sheet data migration completed"); Finally your code is missing a lot of semi-colons. This isnt necessarily a problem, but can cause subtle hard-to-find errors, so its a good idea to add them everywhere they should be.
GiGs said: If I'm not misreading things, it looks like this is your problem: Your comparisons are using the attribute name&nbsp; " btatow_sheet_version " as in getAttrs ([ " btatow_sheet_version " ], sheetVersion =&gt; { but that is not the attribute name you created in the input: &lt; input type = " hidden " name = " attr_sheet_version " value = " 1 " /&gt; The attribute is called sheet_version . This also explains why the script didnt work the first time, but did work the second and subsequent times. Because the first time, no btatow version for the attr existed, but after the first run of the script, that attribute had been created. *slaps forehead* The variable name mismatch! My most common programming mistake! D: That would certainly explain a lot... However, in that case, the first time that it ran, shouldn't the sheetVersion [ " btatow_sheet_version " ] == undefined check have been true, and it would have simply logged that no migration was needed, and exited? It didn't seem to do anything the first time... although now that I think about it, I recall that JavaScript is funny with its equality checking, and I think a lot of the time you need three equals signs instead of two. I'll have to look into that. GiGs said: Also your setAttrs function seems (to me) to be unnecessarily convoluted. I've been taught that nesting setAttrs is a bad idea.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs(newAttributes, null, () =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setAttrs({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; btatow_sheet_version: 2.0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, null, () =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log("Sheet data migration completed") &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }) Since it's a callback function, I expect it's fine, but does it provide an advantage I'm missing over the below? &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newAttributes['sheet_version'] = '2.0'; setAttrs(newAttributes); console.log("Sheet data migration completed"); Finally your code is missing a lot of semi-colons. This isnt necessarily a problem, but can cause subtle hard-to-find errors, so its a good idea to add them everywhere they should be. My understanding of JavaScript is that it doesn't actually parse semicolons, and thus they are optional. In fact, I think a lot of JavaScript linters will tell you to remove semicolons. The problem with character sheets is they combine HTML and JavaScript in the same file, so my IDE is giving me HTML linting, but not JavaScript linting/help. =/ Regarding the multiple setAttrs... I just had a look at the Wiki page on sheet worker scripts, and you're right; it says to avoid cascading callbacks where possible. However, I think the main thing they want to avoid is making multiple getAttr/setAttr calls to deal with attributes one by one, when you could do the entire get at once and the entire set at once. In my case, my thinking was that I only wanted to set the sheet version after the existing attribute data had been successfully migrated. Thus, by setting the sheet version in a callback function that is executed once the setAttr for the new attribute values has completed, if anything went wrong with the setAttr call to set the new attribute values, the callback function wouldn't be executed, and the sheet version wouldn't be set, so the next time the sheet is opened, the migration function can run again. I'm happy to be told I'm wrong on that, though. :) Thanks for your keen eyes spotting my variable name mismatch!
1549895536

Edited 1549895580
GiGs
Pro
Sheet Author
API Scripter
Michael S. said: However, in that case, the first time that it ran, shouldn't the sheetVersion [ " btatow_sheet_version " ] == undefined check have been true, and it would have simply logged that no migration was needed, and exited? It didn't seem to do anything the first time... although now that I think about it, I recall that JavaScript is funny with its equality checking, and I think a lot of the time you need three equals signs instead of two. I'll have to look into that. My guess is, it's because of this: if (sheetVersion[ " btatow_sheet_version " ] == undefined || sheetVersion[ " btatow_sheet_version " ] != 1 ) The second part is true, while the value is undefined, it is also not equal to -1. That is an OR comparison so only one of them needs to be true. That should be something like if (sheetVersion[ " btatow_sheet_version " ] == undefined || ( sheetVersion[ " btatow_sheet_version " ] &amp;&amp; sheetVersion[ " btatow_sheet_version " ] != 1 )) And yes, its a good idea to use three equality signs. !== or ===. This enforces type checking. != -1 compares against a number -1, and also the string '-1'.&nbsp; Using !== -1 means that it checks the value is a number as well as equals -1. once you switch top the triple equality, you need to be careful about data types. Me: Finally your code is missing a lot of semi-colons. This isnt necessarily a problem, but can cause subtle hard-to-find errors, so its a good idea to add them everywhere they should be. You: My understanding of JavaScript is that it doesn't actually parse semicolons, and thus they are optional. In fact, I think a lot of JavaScript linters will tell you to remove semicolons. The problem with character sheets is they combine HTML and JavaScript in the same file, so my IDE is giving me HTML linting, but not JavaScript linting/help. =/ Really? that's not been my experience. All the linters I've used are very scrupulous about encouraging you to place semi-colons even when they aren't needed. It's become common code styling for good practice. It's true that javascript is very permissive about semi-colons, but the closures they provide help avoid a lot of errors that are very easy to make with them. That said, it's a style preference if you know what you're doing, and a sidetrack from this thread. Sorry!. Regarding the multiple setAttrs... I just had a look at the Wiki page on sheet worker scripts, and you're right; it says to avoid cascading callbacks where possible. However, I think the main thing they want to avoid is making multiple getAttr/setAttr calls to deal with attributes one by one, when you could do the entire get at once and the entire set at once. In my case, my thinking was that I only wanted to set the sheet version after the existing attribute data had been successfully migrated. Thus, by setting the sheet version in a callback function that is executed once the setAttr for the new attribute values has completed, if anything went wrong with the setAttr call to set the new attribute values, the callback function wouldn't be executed, and the sheet version wouldn't be set, so the next time the sheet is opened, the migration function can run again. I'm happy to be told I'm wrong on that, though. :) I thought that was the reason you did it that way. My reasoning was that if anything went wrong with the setAttr, you wouldnt reach the following line anyway. But your way is probably better :)
GiGs said: Really? that's not been my experience. All the linters I've used are very scrupulous about encouraging you to place semi-colons even when they aren't needed. It's become common code styling for good practice. It's true that javascript is very permissive about semi-colons, but the closures they provide help avoid a lot of errors that are very easy to make with them. That said, it's a style preference if you know what you're doing, and a sidetrack from this thread. Sorry!. I don't quite agree here; I think that having a consistent programming style can be very beneficial, as it removes a lot of cognitive load when you're looking at brand new code. If there are style conventions for the character sheets, I am definitely keen to learn what they are and conform to them. As such, I'll go check a few of the main sheets and see if they're using semicolons, and update my code if so.