Character Vault
Any Concept / Any System
Compendium
Your System Come To Life
Roll20 for Android
Streamlined for your Tablet
Roll20 for iPad
Streamlined for your Tablet

Personal tools

Difference between revisions of "Mod:Use Guide"

From Roll20 Wiki

Jump to: navigation, search
m
(25 intermediate revisions by 10 users not shown)
Line 1: Line 1:
 +
<div style="background:#f0e2a1; border: 3px solid #dbc870; padding: 10px;">
 +
<big>'''''Attention:'''''
 +
''Roll20 is no longer maintaining this document on the community wiki. For the most up-to-date information please visit this page on our help center for assistance: [https://roll20.zendesk.com/hc/en-us/articles/360037772773-API-Advanced-Use-Guide Here].''</big>
 +
</div>
 +
 +
'''Roll20 API Scripts''' are a collection of scripts that can expand the tools, automation & features both [[GM|GMs]] and [[players]] have access to in a game. The [[API:Script Index]] page lists a good number of the available options, and gives a short description on what each are used for.
 +
 +
{{pro only}}
 
{{apibox}}
 
{{apibox}}
 +
__TOC__
 +
==Install API==
 +
[[File:Game Settings Menu Options.jpg|thumbnail|left|250px|]]
 +
To add an API to your game, you need to select the "API Scripts" option in the [[Game_Management#Settings|Settings]]-menu found on a campaign's main page. Only a Campaign's [[GM#Creator|Creator]] and [[GM|GMs]] have access to this page.
 +
 +
* '''{{zendesk|articles/360046238454-How-to-Install-API-Scripts-via-1-Click-Install How to Install API Scripts via 1-Click Install}}'''
 +
* '''{{forum|category/46806 API forum}}'''
 +
 +
<br>
 +
{{#evp:youtube|jam2yx8btaQ|How to Install an [[API]] (Nick Olivo) |center|600}}
  
 
==The Script Editor==
 
==The Script Editor==
To edit your campaign scripts, click on the "API Scripts" link on the Campaign Details page for your campaign (the same place where options such as the "Chat Log" and "Copy/Extend Campaign" are located). You will be presented with a page with several features:
+
[[File:Game-Management-API-scripts.png|thumbnail|right|450px|Access the editor]]
 +
To edit your game scripts (as a {{Pro}} user) , click on the '''API Scripts'''-option on the [[Game Details page for your game (the same place where options such as the "Chat Log" and "Copy/Extend Game" are located).
 +
[[File:API-script-library.png|right|thumbnail|500px|The API script Library]]
 +
<br>
 +
<br>
 +
<br>
 +
<br>
 +
<br>
 +
<br>
 +
<br>
 +
<br>
 +
<br>
 +
<br>
 +
<br>
 +
<br>
 +
You will be presented with a page with several features:
  
* A list of tabs along the top. Your campaign can have multiple scripts for ease of organization. Note that all scripts will still run in the same context, meaning that you shouldn't have multiple scripts trying to overwrite the same values at the same time or you could get unintended results.
+
* A list of tabs along the top. Your game can have multiple scripts for ease of organization. Note that all scripts will still run in the same context, meaning that you shouldn't have multiple scripts trying to overwrite the same values at the same time or you could get unintended results.
 
* A script code editor. You can use this editor or edit your scripts in an external editor of choice and then paste them in here.
 
* A script code editor. You can use this editor or edit your scripts in an external editor of choice and then paste them in here.
 
* Along the bottom is an "API Console" (see below).
 
* Along the bottom is an "API Console" (see below).
  
Whenever you click the "Save Scripts" button, the sandbox for your campaign will be '''restarted''' (losing any previous <code>state</code> data) and use the new script modifications you just made. This also applies if you add a new script, delete a script, or toggle a script to enable/disable it.
+
 
 +
Whenever you click the "Save Scripts" button, the sandbox for your game will be '''restarted''' (losing any in-memory data which hasn't been persisted in the <code>state</code> object or in Roll20 objects) and use the new script modifications you just made. This also applies if you add a new script, delete a script, or toggle a script to enable/disable it.
  
 
===The API Console===
 
===The API Console===
Line 14: Line 48:
 
The API Console is your "window" into your scripts. Since API Scripts run in a sandbox, you don't have direct access to them while they are running to view information on the script's results or errors. The API Console brings this information out of the sandbox so you can view it while you are editing your scripts. All <code>log()</code> commands will show here, as well as any errors that are encountered during the execution of your scripts. For more information, see [[API:Debugging|the information on Debugging scripts]].
 
The API Console is your "window" into your scripts. Since API Scripts run in a sandbox, you don't have direct access to them while they are running to view information on the script's results or errors. The API Console brings this information out of the sandbox so you can view it while you are editing your scripts. All <code>log()</code> commands will show here, as well as any errors that are encountered during the execution of your scripts. For more information, see [[API:Debugging|the information on Debugging scripts]].
  
==Reactive Scripts: Listen to Events, Modify Objects==
+
==Types of scripts==
 +
{{NavMacroDocs}}
 +
===Reactive Scripts: Listen to Events, Modify Objects===
 
The first (and most simple type) of API usage is to react to changes on the tabletop, and then respond by making additional changes to the changed objects. This type of script is composed of a number of functions which listen to events that happen during the game. Then it will modify objects that are passed during those events, which will change what happens on the tabletop.
 
The first (and most simple type) of API usage is to react to changes on the tabletop, and then respond by making additional changes to the changed objects. This type of script is composed of a number of functions which listen to events that happen during the game. Then it will modify objects that are passed during those events, which will change what happens on the tabletop.
  
Line 24: Line 60:
 
     left: obj.get("left") + 70     
 
     left: obj.get("left") + 70     
 
   });
 
   });
}
+
});
 
</pre>
 
</pre>
  
Line 31: Line 67:
 
'''Important Note:''' You must use <code>set</code> and <code>get</code> to set and get current values on objects or your changes will not be saved. (See below for a listing of object types and their properties, as well as a listing of all events and what arguments each event is passed.)
 
'''Important Note:''' You must use <code>set</code> and <code>get</code> to set and get current values on objects or your changes will not be saved. (See below for a listing of object types and their properties, as well as a listing of all events and what arguments each event is passed.)
  
===A Note on Utility Functions===
+
====A Note on Utility Functions====
Of course, the previous example isn't incredibly helpful because it always adds 70 pixels to the location of the token. But what if the user has changed their scale so that 5ft is 140 pixels? The Roll20 API provides several handy utility functions to help with this (and other) common scenarios. Let's modify our previous example to use the <code>distanceToPixelsfunction</code>, which will tell us how many pixels "five feet" (or inches, or meters, or whatever other distance type has been set) on the tabletop is.
+
Of course, the previous example isn't incredibly helpful because it always adds 70 pixels to the location of the [[token]]. But what if the user has changed their scale so that 5ft is 140 pixels? The Roll20 API provides several handy utility functions to help with this (and other) common scenarios. Let's modify our previous example to use the <code>distanceToPixelsfunction</code>, which will tell us how many pixels "five feet" (or inches, or meters, or whatever other distance type has been set) on the tabletop is.
  
 
<pre data-language="javascript">
 
<pre data-language="javascript">
 
on("change:graphic", function(obj) {     
 
on("change:graphic", function(obj) {     
 
   obj.set({         
 
   obj.set({         
     left: obj.get("left") + distanceToPixels(5);    
+
     left: obj.get("left") + distanceToPixels(5)     
 
   });
 
   });
}
+
})
 
</pre>
 
</pre>
  
Line 46: Line 82:
 
It's always a good idea to use utility functions whenever they're available to help keep your script from breaking if the settings of a page or a token change.
 
It's always a good idea to use utility functions whenever they're available to help keep your script from breaking if the settings of a page or a token change.
  
==Proactive Scripts: Do Things Without User Intervention==
+
===Proactive Scripts: Do Things Without User Intervention===
In addition to reacting to user events, you can also do things with the API automatically that aren't tied to a specific event from the players. For example, let's have a token that patrols back and forth on the map.
+
In addition to reacting to user events, you can also do things with the API automatically that aren't tied to a specific event from the [[players]]. For example, let's have a [[token]] that patrols back and forth on the map.
  
''Note'': Although this type of script is not dependent on user interaction, the API scripts for your campaign will still only run when at least one person is connected to your campaign.
+
''Note'': Although this type of script is not dependent on user interaction, the API scripts for your game will still only run when at least one person is connected to your game.
  
 
<pre data-language="javascript">
 
<pre data-language="javascript">
 
on("ready", function() {
 
on("ready", function() {
   //Wait until the ready event fires so we know the campaign is completely loaded.
+
   //Wait until the ready event fires so we know the game is completely loaded.
 
   //Get a reference to our patrolling token.
 
   //Get a reference to our patrolling token.
   var patroltoken = _.findObjs({_type: "graphic", name: "Guard A"})[0]; //We know there is a token in the Campaign called "Guard A".
+
   var patroltoken = findObjs({_type: "graphic", name: "Guard A"})[0]; //We know there is a token in the Game called "Guard A".
   var direction = -70; //Walk left 70 pixels.
+
   var direction = -1*distanceToPixels(5); //Walk left 70 pixels.
 
   var stepstaken = 0; //How many steps have we walked in the current direction?
 
   var stepstaken = 0; //How many steps have we walked in the current direction?
 
   setInterval(function() {
 
   setInterval(function() {
     if(stepstaken > 5) {
+
     if(stepstaken > 3) {
 
       //Switch directions!
 
       //Switch directions!
 
       direction = direction * -1; //will "flip" the direction we're walking
 
       direction = direction * -1; //will "flip" the direction we're walking
Line 69: Line 105:
 
});
 
});
 
</pre>
 
</pre>
 +
 +
===A Treatise on Asynchronous Functions===
 +
 +
An asynchronous function is one that returns the thread of control to the calling scope immediately and performs some duty in the background.  Here's a very simple and easy to understand example which you can paste in an API scripts tab:
 +
 +
<pre data-language="javascript">
 +
on('ready',function(){
 +
  log('Parent Scope - Before call to asynchronous function.');
 +
 +
  setTimeout(function(){
 +
    log('Asynchronous Function Scope - Doing the Asynchronous function work.');
 +
  },10 /* 10 milliseconds */);
 +
 +
  log('Parent Scope - after call to asynchronous function.');
 +
});
 +
</pre>
 +
 +
In the API log, you'll see something like this:
 +
<pre style="background-color:#333; color: #E6DB74;">
 +
"Parent Scope - Before call to asynchronous function."
 +
"Parent Scope - after call to asynchronous function."
 +
"Asynchronous Function Scope - Doing the Asynchronous function work."
 +
</pre>
 +
 +
Looking at that code, you think "Of course it will happen later, you told it to run in 10 milliseconds, duh?".  Here is a less obvious example that will have the same log messages:
 +
 +
<pre data-language="javascript">
 +
on('ready',function(){
 +
  log('Parent Scope - Before call to asynchronous function.');
 +
 +
  sendChat('Async Function','Evaluate this: [[1d6]]',function(msg){
 +
    log('Asynchronous Function Scope - Doing the Asynchronous function work.');
 +
  });
 +
 +
  log('Parent Scope - after call to asynchronous function.');
 +
});
 +
</pre>
 +
 +
Asynchronous functions are necessary to prevent the API from hanging all the time.  If every dice roll was handled synchronously, the API would be super sluggish and unresponsive. Almost any function you see that takes a callback is asynchronous. (Exception for some of the <code>_.map</code>, <code>_.reduce</code>, etc functions, these are examples of functional programming in contrast to the procedural programming most people are used to.)
 +
 +
==Simple API Example==
 +
Simple API with embedded explanation on what is going on, by [[Aaron|The Aaron]]
 +
<pre data-language="javascript">
 +
// Register a function for the 'ready' event.  When it occurs, which happens only once
 +
//  this function will get called.  This avoids getting events resulting from the
 +
//  loading of all the game state into the API
 +
on('ready',()=>{
 +
 +
  // Declare a function called myFunc.  This is using the "Fat Arrow" function syntax
 +
  //  and the const declaration from Javascript ES6
 +
  const myFunc = ()=>{
 +
    sendChat('myFunc','myFunc was called!');
 +
  };
 +
 +
  // Register a function for the 'chat:message' event.  This event occurs for all
 +
  //  chat messages, so it's important to filter down to just the ones you care about
 +
  on('chat:message',msg=>{
 +
    //  First check the type is an API message.  API messages are not show shown in chat
 +
    //    and begin with a ! in the first character of the message.
 +
    //
 +
    //  Next, make sure this is our API message.  The regular expression checks that the
 +
    //    command starts with "!call-my-func" and either ends or has a space, all case
 +
    //    insensitive.
 +
    if('api'===msg.type && /^!call-my-func(\b\s|$)/i.test(msg.content)){
 +
      myFunc();
 +
    }
 +
  });
 +
});
 +
</pre>
 +
 +
 +
 +
 +
 +
<br>
 +
[[Category:API|Use Guide]]
 +
[[Category:Pro]]

Revision as of 19:21, 25 March 2021

Attention: Roll20 is no longer maintaining this document on the community wiki. For the most up-to-date information please visit this page on our help center for assistance: Here.

Roll20 API Scripts are a collection of scripts that can expand the tools, automation & features both GMs and players have access to in a game. The API:Script Index page lists a good number of the available options, and gives a short description on what each are used for.

Contents

Install API

Game Settings Menu Options.jpg

To add an API to your game, you need to select the "API Scripts" option in the Settings-menu found on a campaign's main page. Only a Campaign's Creator and GMs have access to this page.


How to Install an API (Nick Olivo)

The Script Editor

Access the editor
To edit your game scripts (as a
Pro
info user) , click on the API Scripts-option on the [[Game Details page for your game (the same place where options such as the "Chat Log" and "Copy/Extend Game" are located).
The API script Library













You will be presented with a page with several features:

  • A list of tabs along the top. Your game can have multiple scripts for ease of organization. Note that all scripts will still run in the same context, meaning that you shouldn't have multiple scripts trying to overwrite the same values at the same time or you could get unintended results.
  • A script code editor. You can use this editor or edit your scripts in an external editor of choice and then paste them in here.
  • Along the bottom is an "API Console" (see below).


Whenever you click the "Save Scripts" button, the sandbox for your game will be restarted (losing any in-memory data which hasn't been persisted in the state object or in Roll20 objects) and use the new script modifications you just made. This also applies if you add a new script, delete a script, or toggle a script to enable/disable it.

The API Console

The API Console is your "window" into your scripts. Since API Scripts run in a sandbox, you don't have direct access to them while they are running to view information on the script's results or errors. The API Console brings this information out of the sandbox so you can view it while you are editing your scripts. All log() commands will show here, as well as any errors that are encountered during the execution of your scripts. For more information, see the information on Debugging scripts.

Types of scripts

Reactive Scripts: Listen to Events, Modify Objects

The first (and most simple type) of API usage is to react to changes on the tabletop, and then respond by making additional changes to the changed objects. This type of script is composed of a number of functions which listen to events that happen during the game. Then it will modify objects that are passed during those events, which will change what happens on the tabletop.

The most basic script which would simply move any piece which moved an additional 5 feet (assuming default page settings) would be:

on("change:graphic", function(obj) {
  obj.set({
    left: obj.get("left") + 70    
  });
});

As you can see, we created a simple function using on which will be executed anytime the change:graphic event is heard. The function is passed the graphic object obj. To make a change, we just modify obj using the set function -- whatever properties we change will be detected and changed on the tabletop.

Important Note: You must use set and get to set and get current values on objects or your changes will not be saved. (See below for a listing of object types and their properties, as well as a listing of all events and what arguments each event is passed.)

A Note on Utility Functions

Of course, the previous example isn't incredibly helpful because it always adds 70 pixels to the location of the token. But what if the user has changed their scale so that 5ft is 140 pixels? The Roll20 API provides several handy utility functions to help with this (and other) common scenarios. Let's modify our previous example to use the distanceToPixelsfunction, which will tell us how many pixels "five feet" (or inches, or meters, or whatever other distance type has been set) on the tabletop is.

on("change:graphic", function(obj) {    
  obj.set({        
    left: obj.get("left") + distanceToPixels(5)    
  });
})

Now if the current page is setup to use the default grid sizing, distanceToPixels(5); will still return 70 pixels, but if the page is setup to have a scale twice the size of normal, it would return 140.

It's always a good idea to use utility functions whenever they're available to help keep your script from breaking if the settings of a page or a token change.

Proactive Scripts: Do Things Without User Intervention

In addition to reacting to user events, you can also do things with the API automatically that aren't tied to a specific event from the players. For example, let's have a token that patrols back and forth on the map.

Note: Although this type of script is not dependent on user interaction, the API scripts for your game will still only run when at least one person is connected to your game.

on("ready", function() {
   //Wait until the ready event fires so we know the game is completely loaded.
   //Get a reference to our patrolling token.
   var patroltoken = findObjs({_type: "graphic", name: "Guard A"})[0]; //We know there is a token in the Game called "Guard A".
   var direction = -1*distanceToPixels(5); //Walk left 70 pixels.
   var stepstaken = 0; //How many steps have we walked in the current direction?
   setInterval(function() {
     if(stepstaken > 3) {
       //Switch directions!
       direction = direction * -1; //will "flip" the direction we're walking
       stepstaken = 0; //reset steps back to 0.
     }
     patroltoken.set("left", patroltoken.get("left") + direction); //walk!
     stepstaken++;
   }, 5000); //take an action every 5 seconds
});

A Treatise on Asynchronous Functions

An asynchronous function is one that returns the thread of control to the calling scope immediately and performs some duty in the background. Here's a very simple and easy to understand example which you can paste in an API scripts tab:

on('ready',function(){
  log('Parent Scope - Before call to asynchronous function.');

  setTimeout(function(){
    log('Asynchronous Function Scope - Doing the Asynchronous function work.');
  },10 /* 10 milliseconds */);

  log('Parent Scope - after call to asynchronous function.');
});

In the API log, you'll see something like this:

"Parent Scope - Before call to asynchronous function."
"Parent Scope - after call to asynchronous function."
"Asynchronous Function Scope - Doing the Asynchronous function work."

Looking at that code, you think "Of course it will happen later, you told it to run in 10 milliseconds, duh?". Here is a less obvious example that will have the same log messages:

on('ready',function(){
  log('Parent Scope - Before call to asynchronous function.');

  sendChat('Async Function','Evaluate this: [[1d6]]',function(msg){
    log('Asynchronous Function Scope - Doing the Asynchronous function work.');
  });

  log('Parent Scope - after call to asynchronous function.');
});

Asynchronous functions are necessary to prevent the API from hanging all the time. If every dice roll was handled synchronously, the API would be super sluggish and unresponsive. Almost any function you see that takes a callback is asynchronous. (Exception for some of the _.map, _.reduce, etc functions, these are examples of functional programming in contrast to the procedural programming most people are used to.)

Simple API Example

Simple API with embedded explanation on what is going on, by The Aaron

// Register a function for the 'ready' event.  When it occurs, which happens only once
//   this function will get called.  This avoids getting events resulting from the
//   loading of all the game state into the API
on('ready',()=>{

  // Declare a function called myFunc.  This is using the "Fat Arrow" function syntax
  //   and the const declaration from Javascript ES6
  const myFunc = ()=>{
    sendChat('myFunc','myFunc was called!');
  };

  // Register a function for the 'chat:message' event.  This event occurs for all
  //   chat messages, so it's important to filter down to just the ones you care about
  on('chat:message',msg=>{
    //  First check the type is an API message.  API messages are not show shown in chat
    //    and begin with a ! in the first character of the message.
    //
    //  Next, make sure this is our API message.  The regular expression checks that the 
    //    command starts with "!call-my-func" and either ends or has a space, all case 
    //    insensitive.
    if('api'===msg.type && /^!call-my-func(\b\s|$)/i.test(msg.content)){
      myFunc();
    }
  });
});