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

[SCRIPT] ScriptInfo - Reports scripts, versions, and locations of errors to help you troubleshoot (or to help you get help!)


Edited 1675456019
API Scripter
ScriptInfo FILE LOCATION:   My Personal Repo  (pending to the 1-click Installation next week) ABSTRACT:  ScriptInfo helps you troubleshoot script errors or to get help with odd script behavior. ScriptInfo will give you a report of installed scripts and their versions, as well as what line each script starts on. It will also connect the line number of a given sandbox error to the script that contains that line. Using ScriptInfo you can immediately tell what version of a script you are using, as well as the particular line number where you might be getting an error. Introduction Scripters try to write good code to help Roll20 users, but from time to time mistakes are made. Not all edge cases -- or, worse, use cases -- are detected, or a bug escaped our notice during testing and lurks in the code, waiting to spring. Finding that bug, even when the sandbox reports a line number where the error happened, can sometimes be tricky. Here's why... When your game's sandbox spins up, all of the scripts you have installed are collated into a single, long file of javascript code. A script might be 1000 lines of code, but if it follows another script with 2000 lines of code, it will actually span lines 2001-3000. It isn't always feasible, practical, or even possible to manually count lines of code until we discover which line the reported error number represents. This is where ScriptInfo can help. With ScriptInfo, you can run a different report to learn that an error on line X represents line Y of script Z. For a simple example, imagine you have 10 scripts installed (ScriptA, ScriptB, ScriptC, etc.), each consisting of 100 lines of code. You get an error that lists line #304 as where the error occurred. ScriptInfo would tell you that line #304 represents line 4 of ScriptD Limitations ScriptInfo interrogates a particular object in javascript that script authors must opt-in to use. If a script does not report to this object, ScriptInfo won't be able to get the information it needs, though it will still be able to tell you more general information (such as that an error occurred x-lines after a given script and/or y-lines before a given script). Many of the more widely used scripts available in the one-click do make use of this centralized reporting object, including TokenMod (as well as the rest of The Arcane Scriptomancer's scripts: RecursiveTables, GroupInit, etc.), ScriptCards, Reporter, Supernotes, Spawn, SmartAoE, and all of the metascripts. Syntax and Usage To get the report of all scripts, use the command: !scriptinfo To get a report connecting a line number to the particular script where it exists, use the same scriptinfo handle, followed by the line number you wish to know about: !scriptinfo 2549 You can supply multiple lines you're interested in by separating them with a space: !scriptinfo 180 2021 15024 For Scripters: Making Your Script Work with this Object First, credit to The Aaron for initially coming up with the idea that makes this whole process work. He implemented the solution on his scripts as a way to quickly zero-in on problematic lines in his code, and soon others followed suit. ScriptInfo is just an informational interpretation of what Aaron created. If you want to make your script easier to troubleshoot (for not only you but your users to report back to you), here's what to do: 1. Somewhere above your script code, add these lines: var API_Meta = API_Meta || {}; API_Meta.SCRIPTNAME = { offset: Number.MAX_SAFE_INTEGER, lineCount: -1 }; { try { throw new Error(''); } catch (e) { API_Meta.SCRIPTNAME.offset = (parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/, '$1'), 10) - (13)); } } What's Happening That bit of code establishes the API_Meta object if necessary, but leaves it as is if the object has already been initialized by another script. Note : This is probably the only time, and the only sort of usage, where you would want to use var as your variable declaration syntax. You're better off using either let or const every other time you instantiate a variable, however for this particular usage, we specifically need the hoisting that var provides, as well as the redefinability. After making sure API_Meta is available, the code establishes two properties (offset and lineCount) with dummy data. Finally, in a try/catch block, it intentionally throws an error so that the error stack can be parsed for the line number. Since we know the line on which we threw the error, we can use math to understand our script's overall starting line (see the steps, below, for more information). 2. Replace every instance of SCRIPTNAME with your script's unique name. 3.  Somewhere in your code, inject your script version into the the API_Meta object: API_Meta.SCRIPTNAME.version = '1.0.0'; 4. Fix your offset math. At the end of the catch block in the above example, 13 is being subtracted as a part of the offset equation. This number represents the row where we threw the error. Change this number to match the line of the error; if you paste these lines into your code so that the error occurs on line 8, you'd change that 13 to an 8. 5. Paste this code as the last line in your code, after your script's final closure: { try { throw new Error(''); } catch (e) { API_Meta.SCRIPTNAME.lineCount = (parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/, '$1'), 10) - API_Meta.SCRIPTNAME.offset); } } What's Happening As before, we throw an error and catch the return so that we can parse the current line. This time, we subtract the original offset we derived so that we know our lineCount. Note: Be sure to include an empty line at the end of your code. There is a bug in the sandbox where if your script does not have a trailing empty line your script can cause those installed after it in the sandbox to fail. 6. As in #2, replace all instances of SCRIPTNAME with your script's unique name. Template If you like, here is my template for a revealing module pattern (RMP) script, which already includes the API_Meta language. This is my current working template, so it does also have things like my name at the top, as well as my sandbox signature (the logsig()  function prints a torii to the sandbox at bootup -- one time, no matter how many of my scripts you have installed). Feel free to remove/change those pieces. Aaron also has an RMP template he has shared, which is probably a generation or 9 ahead of what I've got going. Seriously. It's probably sentient by now. Here's his discussion of the API_Meta idea, as well as his template.
David M.
API Scripter
Cool idea! (and thanks for pointing out the Spawn API_Meta issue)