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

Major Updates to Mod Scripts Coming in March

1713309715
The Aaron
Roll20 Production Team
API Scripter
That's completely fine, I don't mind talking about programming on any level, even the ground floor.  The people who don't struggle with imposter syndrome from time to time don't know enough about the subject to know how much they don't know yet. =D  
1713309859
The Aaron
Roll20 Production Team
API Scripter
Hey everyone! It's a few weeks later than we intended, but tomorrow is the big day! Wednesday, April 17th at 1:00pm PDT, the updated Roll20 Mod Server will be rolled out! We aren't expecting any problems, but to be prepared for good experiences in peak times, we're starting up early enough that we can monitor games as things get moving. Your feedback will be important to make sure we identify any issues early and get a good resolution to them quickly.  If there ends up being a problem, we can safely revert back to the prior version with no loss of data or configuration, so keep us posted about your experiences. I'm looking forward to seeing what we all build together, see you tomorrow!
1713384765

Edited 1713384798
Riley D.
Roll20 Team
Hey folks, We are in the process of rolling this out. One of the things to note right off the bat is that due to the underlying system that Aaron in place, it takes a bit longer to spin up the API Sandbox for large games (could take as much as 30+ seconds for some large games). We think we have a way to reduce this substantially, but we need to get real-world feedback on game sessions to know what to tweak. Note that after the sandbox spins up, the response time for the API itself should be just as fast as it was before. The other tradeoff here is that large games that wouldn't load at all in the previous version should load in this one. I think our plan right now is to let this run for a bit so we can start seeing what sort of feedback/errors/etc. folks run into, and then we may make a decision on whether to turn this back off for a bit while we make tweaks...but we're interested to hear your feedback so let us know what you see! Thanks!
1713386689
The Aaron
Roll20 Production Team
API Scripter
Hey everyone! We're going to pull this back.  We gathered some great data, but there are some memory constraints with very large games that we need to solve.  While we would be able to support 99% of current games, there would be some edge cases where games would not be able to start and that's just not tenable.  I'm going to be working on optimizing those memory constraints, and see about speeding up startup as well.  We'll post back with a new schedule when we get a handle on the changes.
Hey folks -- just a quick update on this. As you know there are quite a few significant changes that were made to the API System to modernize it and bring it up to speed on some of our newer features. I think given that, it would be a better rollout strategy to let people opt into using the new system and trying it out, rather than just rolling it out to every game all at once. So we're going to quickly build out an option to let you do that. That will delay the release of this about a week, but the good news is once this is in place, we can roll it out and leave it out (rather than it having to be "perfect" day one). In addition, this will set us up so that in the future we could have a "Beta" branch and a "Release" branch of the API to help enable faster development -- honestly this is something we should have done a long time ago. So, apologies on the delay, but we'll get this out hopefully next week and I think in the long term this short delay to invest in the API sandbox "version picker" will be well worth the wait. We'll keep you posted.
1713397824
Andrew R.
Pro
Sheet Author
Excellent! I’m keen to help with Beta testing. I missed the rollout because I was asleep in Australia at the time. 
Hey folks! We have this new opt-in system built and ready to go, I'm planning to roll it out tomorrow. At that time you'll be able to opt in to Aaron's new API changes and start testing them with your games. So we'll keep you posted when that goes live tomorrow. Thanks!
1713905385
Pat
Pro
API Scripter
Okay, I wanted to update the old Teleport mod, to do so, I believe I need checkin-checkout software to work with the mod server, but I'm short on details and it's been a few years since I've done it. Is there a quickstart around, and has it changed? 
Hey all! The first part of this went out this evening, but it's not fully enabled yet. You will now see a toggle on the Mod Scripts page where you can switch between the "Default" or "Experimental" API Sandbox version. Toggling it right now will have to real effect, but we should roll out the backend to this tomorrow. I'll keep you posted. Thanks!
Okay here we go! This is now live and working. If you go to your Mod Scripts page, you can switch to the Experimental version. You can tell that you are in the Experimental version of the sandbox because you will see the following message when the sandbox starts up: "SANDBOX: Ready fired after 7.80s, 602 objects." Note that the "switching version" stuff can be kind of finnicky for already running games. If for some reason it doesn't actually switch over, it will always work if you just leave the game entirely and let the sandbox timeout due to inactivity then come back. But just noting this isn't really meant for switching rapidly back and forth between the API Sandboxes, it's more for setting it once and then using that sandbox for that game. I'd also recommend testing the new Experimental Sandbox on a copy of your game, of course. In theory it should be fully backward compatible, but it is Beta. So go out and use it and give us your feedback, and I'll turn it over to Aaron to field questions and bug reports and all that for the actual new work that's been done :-) Thanks!
What tag do you want us to use in the help request?
1714149516

Edited 1714202065
When you start testing by copying a game without players , then adding Mod scripts without first launching the game, expect errors on mods that access the player objects. For example: adding APIHeartBeat yields TypeError: Reduce of empty array with no initial value. Launching the game once solves the issue .
1714187662
The Aaron
Roll20 Production Team
API Scripter
Oh, interesting!  I'll try and duplicate that. 
1714210314

Edited 1714211196
Currently you can identify that the Experimental sandbox is selected because the Mod Output Console shows "SANDBOX: Ready fired after 6.24s, 578 objects." would it be possible to also report whether jumpgate beta is applicable for this game? I am comparing four versions (legacy vtt, jumpgate, legacy mod, new mod) and having this in the Mod Output Console would make it easier comparing logs.
1714282582

Edited 1714299406
P1) &nbsp; The new findObjs implementation does not behave as the old one in exactly&nbsp; the same way. For example: searching on imgsrc must have had some extra logic to compare image urls. this might be a reason for the many macro creations of ApiHeartbeat. The CombatMaster mod also creates many objects too many. 2) The new toFront does not bring all objects to the front, it must have some logic to test the controlledby field. 3) iobserved that the new sandbox code checks image urls and changes these to the new image&nbsp; delivery urls. <a href="https://s3.amazonaws.com/files.d20.io" rel="nofollow">https://s3.amazonaws.com/files.d20.io</a> /... =&gt;&nbsp;&nbsp; <a href="https://files.d20.io" rel="nofollow">https://files.d20.io</a> /... Any mods that compare img url fields (with or without getCleanImgsrc) break. Details and investigation details&nbsp; have been pm-ed to the Aaron. BTW i am happily surprised that the bugs i run into are specific edge cases. This is a good first public beta.
1714288628

Edited 1714289075
Andrew R.
Pro
Sheet Author
I can report that all the Mods I use in my 13th Age Glorantha game are working exactly as expected. They are: MetaScriptToolbox TokenMod TokenNameNumber ScriptCards I noted Martijn's report above and launched once before adding Mods and switching to Experimental. Next I'm going to copy my 13G &amp; TOR2e Library games and switch to Experimental for more testing.
1714300739
Andrew R.
Pro
Sheet Author
I just tried using a ScriptCards feature that I haven't tried before, and I got an error, so I'm reporting it here and in the ScriptCards thread.&nbsp; The script I'm running is&nbsp; !scriptcard {{ &nbsp; &nbsp; --#title|Style_Runes &nbsp; &nbsp; --/| Rune-Air (Orange) &nbsp; &nbsp; --#titlecardbackground|#FFA500 &nbsp; &nbsp; --S#Rune|Air }} and the error message I get is&nbsp; "SANDBOX: Ready fired after 4.39s, 1138 objects." "WARNING: Refusing to set \"current\" to undefined. [Roll20 attribute -NwZEHmFt-tTY2RhdogE]" I was using the&nbsp; Original Method of Saving and Loading but I wanted to try the&nbsp; Enhanced Methods of Saving and Loading as part of my testing.&nbsp;
1714316309
The Aaron
Roll20 Production Team
API Scripter
Martijn S. said: Currently you can identify that the Experimental sandbox is selected because the Mod Output Console shows "SANDBOX: Ready fired after 6.24s, 578 objects." would it be possible to also report whether jumpgate beta is applicable for this game? I am comparing four versions (legacy vtt, jumpgate, legacy mod, new mod) and having this in the Mod Output Console would make it easier comparing logs. There isn't a way for the Mod API server to tell if Jumpgate is enabled that I'm aware of.&nbsp; The Mod API server operates on the data model of the game, where as Jumpgate is a different UI that uses the same data model.
1714317891
The Aaron
Roll20 Production Team
API Scripter
Martijn S. &nbsp;said: P1)&nbsp; The new findObjs implementation does not behave as the old one in exactly the same way. For example: searching on imgsrc must have had some extra logic to compare image urls. this might be a reason for the many macro creations of ApiHeartbeat. The CombatMaster mod also creates many objects too many. That's right!&nbsp; When I cleaned up the image code, and added in support for duplicating marketplace content already in the game, I set up optimization of the urls to get rid of the problem of aways needing to substitute a thumb url, and changed them to the faster image endpoint.&nbsp; However, as you surmised, that's causing a miss on finding the image.&nbsp; Internally, I'm matching the imgsrc in other places against a uniq key calculated out of the URL.&nbsp; I don't know if I can repurpose that code, but at a minimum, I can do the same transform on the incoming url before the match and that should handle the problem.&nbsp; 2) The new toFront does not bring all objects to the front, it must have some logic to test the controlledby field. I will dig into this one.&nbsp; Are you saying it only seems to work on objects you control?&nbsp; Are you using TokenMod for this by chance? 3) I observed that the new sandbox code checks image urls and changes these to the new image delivery urls. <a href="https://s3.amazonaws.com/files.d20.io/" rel="nofollow">https://s3.amazonaws.com/files.d20.io/</a>... =&gt;&nbsp; <a href="https://files.d20.io/" rel="nofollow">https://files.d20.io/</a>... Any mods that compare img url fields (with or without getCleanImgsrc) break. This is the same issue as 1), really.&nbsp; I'll get that addressed. Details and investigation details have been pm-ed to the Aaron. BTW i am happily surprised that the bugs i run into are specific edge cases. This is a good first public beta. Thanks on both counts!&nbsp; It would be great to release with no bugs at all, but as they say, "if debugging is the process of taking bugs out of code, coding is the process of putting them in there!"
1714318175
The Aaron
Roll20 Production Team
API Scripter
Andrew R. said: I just tried using a ScriptCards feature that I haven't tried before, and I got an error, so I'm reporting it here and in the ScriptCards thread.&nbsp; The script I'm running is&nbsp; !scriptcard {{ &nbsp; &nbsp; --#title|Style_Runes &nbsp; &nbsp; --/| Rune-Air (Orange) &nbsp; &nbsp; --#titlecardbackground|#FFA500 &nbsp; &nbsp; --S#Rune|Air }} and the error message I get is&nbsp; "SANDBOX: Ready fired after 4.39s, 1138 objects." "WARNING: Refusing to set \"current\" to undefined. [Roll20 attribute -NwZEHmFt-tTY2RhdogE]" I was using the&nbsp; Original Method of Saving and Loading but I wanted to try the&nbsp; Enhanced Methods of Saving and Loading as part of my testing.&nbsp; This is great, actually.&nbsp; There is a problem in the existing sandbox when attribute values get set to a bad value (particularly NaN).&nbsp; What this means is that ScriptCards has a case where it tries to set the value of current to undefined, and the new Mod Server is detecting that and not doing it.&nbsp; Right now, that means that current goes unset, and retains its prior value.&nbsp; It might make more sense in these cases to just set it to "" (empty string), assuming that a bad value means just clear it.&nbsp; I didn't make that choice initially because to my thinking it would always be a bug in the script itself if this came in as a bad value, and I'd want to find and fix that on the script side.&nbsp; Making it vocal with a warning like this should let script authors clean up those problems without breaking the sandbox when it happens.
1714515026
Victor B.
Pro
Sheet Author
API Scripter
@The Aaron, one of the challenges I faced with CM is being able to transfer the existing combat to a new page.&nbsp; The current exposed architecture of Roll20 doesn't allow for changing the current page.&nbsp; I looked at the pagefolder functionality.&nbsp; Could this be leveraged?&nbsp;
1714515966
The Aaron
Roll20 Production Team
API Scripter
PageFolders won't help with that, but it is something I've talked to Riley about.&nbsp;
1714526281
Andrew R.
Pro
Sheet Author
Thank you for the explanation, and I agree with your reasoning. I found the problem with my script and corrected it.&nbsp; The Aaron said: This is great, actually. … Making it vocal with a warning like this should let script authors clean up those problems without breaking the sandbox when it happens.
1714527219
The Aaron
Roll20 Production Team
API Scripter
Great!
This just happen. has anyone encounter the same thing.
Just in case somebody ask this is the full view. I have scripts on this campaign.
Never mind it corrected by itself.&nbsp;
I keep getting errors in one of my campaigns where the sandbox frequently crashes with not a informative error message. could someone help me out? Thanks.
1715005440
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Is there an error log below (see an example in the screen shot two posts above yours)? That might contain useful information to include here.
1715006454
The Aaron
Roll20 Production Team
API Scripter
Possible Infinite Loop Detected happens when the scripts take too long before relinquishing control back to the sandbox.&nbsp; Usually, this will be a script reacting to an event by doing something that takes a very long time.&nbsp; On rare occasions, this will happen when you start the sandbox if your game is extremely large (like, more than 500,000 objects).&nbsp; So, the two important questions are: Is your game really large? What scripts do you have installed? In the case of 1, you can move things out of the game to another game for storage and remove them from the source game.&nbsp; In the case of 2, you need to identify which script might be causing the issue and get it fixed.&nbsp; The fix is often pretty easy, and many of us can help with that.&nbsp; Just post a list of the scripts you have, and we can help you start looking into it.
I dont think its to large but I could be wrong. I can invite to game if necessary.
1715015386

Edited 1715016728
Aryan said: I dont think its to large but I could be wrong. I can invite to game if necessary. with the survey mod you can count the objects in your game and know for sure. See <a href="https://app.roll20.net/forum/permalink/10675897/" rel="nofollow">https://app.roll20.net/forum/permalink/10675897/</a> Let's go through your list of MODs. Most of these only react to chat or react to changes to single objects (and then change single objects). The way to detect whether these MODs are the culprit is to have a second browser open with the MOD Output Log next to your play game. Aura/Tint HealtColors creates some FX object on startup. As FXs are documented to be not implemented, that mod might be suspect. The '5th Edition OGL by Roll20 Companion Script' MOD sets the on('chat:message',..) outside the on('ready',...), that might give an issue if you chat something at exactly the moment that the sandbox is starting up. But as you state it is recurring, this is very unlikely.
1715023257

Edited 1715023335
The Aaron
Roll20 Production Team
API Scripter
with that list of scripts, there isn't an obvious culprit.
Nice updates!!
1716409842
The Aaron
Roll20 Production Team
API Scripter
Hi all, We've pushed out an update for the Experimental branch that should fix the issues with findObjs() when searching by image URL.&nbsp; Also some minor issues with updates to `_` properties (like `_lastpage`). Please keep the feedback coming, it's really helpful!
wow gone for 8 months and TheAaron is made official. CONGRATS and excited to see the new changes to roll20.&nbsp;
1716719935

Edited 1716719982
Richard @ Damery
Pro
API Scripter
findObjs() in the experimental sandbox still does not seem to be working correctly for finding handouts. I've not yet done extensive testing of the RPGMaster suite in the experimental sandbox, but initially mostly seems to run fine.&nbsp; However there is one issue with findObjs() for handouts. My mod suite RPGMaster creates 16 API help handouts when first loaded, and then checks for these each subsequent load (checking the version number to see if they need updating). However, if I load the RPGMaster suite into the experimental sandbox it never finds the handouts, and creates another 16 handout objects every time the campaign is loaded (or the sandbox restarts).&nbsp; The code I use to find the handouts is: let dbCS = findObjs({ type:'handout', name:obj.name },{caseInsensitive:true}); if (!dbCS || !dbCS[0]) { &nbsp; &nbsp; ... create the handout ... } else { &nbsp; &nbsp; ... check the version and update the 'notes' if necessary ... } where obj.name resolves to the name of the handout being looked for. This works fine in the default sandbox. Is this a known issue? Do you need more info?
Hi All;&nbsp;&nbsp; Would anyone know if these improvements are why one of my favourite scripts has stopped working?? Community Forums: [Script] Critical Sound Effects v1.0 | Roll20: Online virtual tabletop
1716816553

Edited 1716816639
Andrew R.
Pro
Sheet Author
Joshua C. said: Hi All;&nbsp;&nbsp; Would anyone know if these improvements are why one of my favourite scripts has stopped working?? The improvements are available only if you change to Experimental. So try it in Experimental, then change it back to Default and try it again.&nbsp;
1716836420
The Aaron
Roll20 Production Team
API Scripter
I don't know why it would quit working, but I have tried this version of it (minor updates for modern code style and loading efficiency), and it worked on both production and experimental.&nbsp; It will also output whether it was able to find the two songs needed, like this in the API log: "Script loaded: Critical Sound Effects" " * criticalHit: [Loaded]" " * criticalFail: [Loaded]" Script: //Critical Sound Effects v1.2.3 on('ready',() =&gt; { let excludeGM = false; // this to false if you wish to include GM rolls let defaults = { css: { button: { 'border': '1px solid #cccccc', 'border-radius': '2px', 'background-color': '#006dcc', 'margin': '0 .1em', 'font-weight': 'bold', 'padding': '.1em 1em', 'color': 'white' } } }; let templates = {}; let criticalHit = null; let criticalFail = null; let allsongs = findObjs({ _type: 'jukeboxtrack' }); allsongs.forEach(function(song) { if(song.get('title') === 'Critical Hit') { criticalHit = song; } else if (song.get('title') === 'Critical Fail') { criticalFail = song; } }); buildTemplates(); function criticalHitOrFail(content) { if (content.rolls) { content.rolls.forEach(function(roll) { if (roll.dice === 1 &amp;&amp; roll.sides === 20) { if (isCriticalHit(roll)) { play(criticalHit); } else if (roll.results[0].v === 1) { play(criticalFail); } } if (roll.dice === 2 &amp;&amp; roll.sides === 20 &amp;&amp; roll.mods &amp;&amp; roll.mods.customCrit) { if (keptResultIsCriticalHit(roll)) { play(criticalHit); } else if (keptResultIsCriticalFailure(roll)) { play(criticalFail); } } function isCriticalHit(roll) { return roll.results[0].v === 20 || roll.mods &amp;&amp; roll.mods.customCrit &amp;&amp; roll.results[0].v &gt;= roll.mods.customCrit[0].point; } function keptResultIsCriticalHit(roll) { let customCrit = roll.mods.customCrit[0].point; return roll.mods &amp;&amp; roll.mods.keep &amp;&amp; roll.results.some(function(result) { return result.d === undefined &amp;&amp; result.v === 20 || result.d === undefined &amp;&amp; result.v &gt;= customCrit; }); } function keptResultIsCriticalFailure(roll) { return roll.mods &amp;&amp; roll.mods.keep &amp;&amp; roll.results.some(function(result) { return result.d === undefined &amp;&amp; result.v === 1; }); } }); } } on("chat:message", function(msg) { if (!playerIsGM(msg.playerid) || !excludeGM &amp;&amp; msg.type !== "gmrollresult") { //for Shaped 5e Character Sheet if (msg.inlinerolls) { msg.inlinerolls.forEach(function(inlineRoll) { criticalHitOrFail(inlineRoll.results); }); } //for roll chat command else if (msg &amp;&amp; isJson(msg.content)) { let content = JSON.parse(msg.content); criticalHitOrFail(content); } } }); function isJson(str) { try { JSON.parse(str); } catch (e) { return false; } return true; } function play (song) { if (song) { song.set({'playing': true, 'softstop': false}); } } function buildTemplates() { templates.cssProperty =_.template( '&lt;%=name %&gt;: &lt;%=value %&gt;;' ); templates.style = _.template( 'style="&lt;%='+ '_.map(css,function(v,k) {'+ 'return templates.cssProperty({'+ 'defaults: defaults,'+ 'templates: templates,'+ 'name:k,'+ 'value:v'+ '});'+ '}).join("")'+ ' %&gt;"' ); templates.button = _.template( '&lt;a &lt;%= templates.style({'+ 'defaults: defaults,'+ 'templates: templates,'+ 'css: _.defaults(css,defaults.css.button)'+ '}) %&gt; href="&lt;%= command %&gt;"&gt;&lt;%= label||"Button" %&gt;&lt;/a&gt;' ); } log('Script loaded: Critical Sound Effects'); log(` * criticalHit: [${criticalHit?'Loaded':'Missing &lt;Critical Hit&gt;'}]`); log(` * criticalFail: [${criticalFail?'Loaded':'Missing &lt;Critical Fail&gt;'}]`); });