Creation of Add-on libraries: Difference between revisions

From RPTools Wiki
Jump to navigation Jump to search
m (Fixed blanks lines)
(Updated guidance of moving the properties files so they are accessible by MTscript functions.)
 
(10 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{stub}}
MapTool 1.11 introduced [[Add-On Library|add-on libraries]] which are intended to be an easier to work with replacement for [[Library Token]]s while also offering a lot more functionality.


[[Library Token]]s will still function the way that they currently do in MapTool 1.11 and future versions, but will not be getting a lot of the new features that add-on libraries will get, so it is recommended that framework developers transition to add-on libraries if supporting MapTool 1.11 and above.
 


An example add-on library for examination and testing is available at https://github.com/cwisniew/test-maptool-add-on-lib
An example add-on library for examination and testing is available at https://github.com/cwisniew/test-maptool-add-on-lib
== Managing the Add-On Libraries for Your Campaign ==
The dialog to manage the add-on libraries for your campaign can be reached using the {{ui location|File > Add On Libraries...}} menu option.
[[File:addon-dialog.png|400px|thumb|left|Add-on Library Dialog]]
This dialog can be used to add or remove add-on libraries, view the details of all add-ons in the campaign and view their license/read me files.
== Drag and Drop ==
As of MapTool 1.12, add-on libraries can be dragged and dropped onto the map from your system's file explorer. This will either add the add-on library to the campaign or replace it if it is already in the campaign.


<p style="clear: both"/>
<p style="clear: both"/>


== Format of add-on library files ==
<p style="clear: both" />There are two main ways to create an Add-on Library:


Add-on libraries can be shared in a {{code|.mtlib}} file. This file is a zip file with a specific structure and content. You can import these libraries with the {{ui location|File > Add On Libraries...}} menu option.
# Create the library files and directory structure from scratch; or
# Export a Library Token as an Add-on Library.


{| class="wikitable"
Each of these approaches is described below.<p style="clear: both" />
| '''File / Directory name''' || '''Description''' ||
== 1. Create the library files and directory structure from scratch ==
|-
Firstly you will need a text editor. There are many of them mentioned below -- if in doubt, use [https://code.visualstudio.com/ VS Code].
| {{code|library.json}} || Configuration information for the add-on library ||
*[https://www.gnu.org/software/emacs/ Emacs]
|-
*[https://neovim.io/ Neovim]
| {{code|mts_properties.json}} || Properties for macro script functions in the add-on library ||
*[https://www.vim.org/ Vim]
|-
*[https://code.visualstudio.com/ VS Code]
| {{code|events.json}} || Events definition for events supported by the add-on library ||
After choosing a text editor, create a new directory to hold your Add-on.
|-
| {{code|library/}} || Contents of the add-on library ||
|-
| {{code|library/public/}} || Contents of the library that are accessible via {{code|lib://}} URI ||
|-
| {{code|library/mtscript/}} || Directory containing the macro Script files for the add-on library. ||
|-
| {{code|library/mtscript/public/}} || Directory containing the macro Script files that can be called via {{code|[macro(): ]}} outside of the add-on library. ||
|}


== Configuration File Format: {{code|library.json}} ==
Top-level files in the Add-on are metadata files; they hold information about your Add-on. The only file your Add-on needs to be accepted by MapTool is {{code|library.json}}.


<source language="javascript">
You may have other non-metadata files in a subdirectory named {{code|library}}.
{
  "name": "test-library",
  "version": "1.0.0",
  "website": "www.rptools.net",
  "gitUrl": "github.com/RPTools/test-library",
  "authors": [ "RPTools Team" ],
  "license": "GPL 3.0",
  "namespace": "net.rptools.maptool.test-library",
  "description": "My new test library for stuff",
  "shortDescription": "test library",
  "allowsUriAccess": true,
  "readMeFile": "readme.md",
  "licenseFile": "license.txt",
  "requires": [
      "net.rptools.maptool.lib.tokens"
  ],
  "exports": [
      "/somedir/",
      "/someotherdir/somefile.js"
  ]
}
</source>


{| class="wikitable"
For macro code, you may have a {{code|mtscript}} directory inside {{code|library}}. Both of those subdirectories may have a publicly accessible directory which must be named {{code|public}}.
| '''Name''' || '''Description''' || '''Required''' || '''Notes'''
|-
| {{code|name}} || The name of the add-on. || Yes || -
|-
| {{code|website}} || The website for your add-on. || No || -
|-
| {{code|gitUrl}} || The url for the git source repository. || No || -
|-
| {{code|authors}} || An array of the authors of the add-on. || Yes || -
|-
| {{code|license}} || The name or short description of the license. || No || -
|-
| {{code|namespace}} || The namespace of the add-on. || Yes || -
|-
| {{code|description}} || The description of the add-on. || No || -
|-
| {{code|shortDescription}} || The short description of the add-on. || Yes || -
|-
| {{code|allowsUriAccess}} || Should add-on allow URI access to contents. || No || -
|-
| {{code|readMeFile}} || The path to the readme file for the add-on.
Can be plain text or GitHub-Flavored Markdown. || No || -
|-
| {{code|licenseFile}} || The path to the license file for the add-on. || No || -
|-
| {{code|requires}} || An array of the add-ons that are prerequisites (namespaces). || No || Added in 1.13
|-
| {{code|exports}} || An array of directories and files that are exported to other add-ons. || No || Added in 1.13
|}


The {{code|readMeFile}} and {{code|licenseFile}} can be plain text, HTML, or GitHub-Flavored Markdown (GFM).
This structure is described in more detail in [[Technical definition of Add-on Libraries]].
These can be viewed from the Add-on Library dialog.
=== Creating library.json ===
{{Note|GitHub provides a way to host your own static site at '''''username''.github.io'''.  If you do not have your own host, this can be used for both your add-on website and reversed for a unique namespace(There is no requirement for there to be an actual website running at the address used for the namespace.)}}
The only required fields are
== Events File Format: {{code|events.json}} ==
*a name string,
*an authors array,
*a short description string, and
*a namespace string.
The other fields are described on the [[Technical definition of Add-on Libraries]] page. Most of these are self-explanatory. Just remember '''bad things''' will happen if you use the same namespace as someone else, so try to use at least 3 words or a reversed domain nameIn the example below, the namespace is {{code|io.github.Azhrei}}, which is a reverse of a hypothetical documentation page, {{code|Azhrei.github.io}}.


This configuration file controls which files are executed for which events.
An example of a minimal {{code|library.json}} could be
  {
    "name": "test",
    "authors": ["you"],
    "namespace": "io.github.Azhrei",
    "shortDescription": "test"
  }
and that is it. You have made an Add-on! Those 6 lines are enough; just zip this file and then rename it so that it ends with {{code|.mtlib}} and have fun.


<source language="javascript">
== 2. Export a [[Library Token]] as an Add-on Library ==
{
  "events": [
      { "name": "onFirstInit", "mts": "onFirstInit" },
      { "name": "onInit",      "mts": "onInit"},
      { "name": "onFirstInit",  "js": "/js/onFirstInit" },
      { "name": "onInit",      "js": "/js/onInit"}
  ],
  "legacyEvents": [
      { "name": "onInitiativeChangeRequest", "mts": "onInitiativeChangeRequest" },
      { "name": "onInitiativeChange",        "mts": "onInitiativeChange" },
      { "name": "onTokenMove",              "mts": "onTokenMove" },
      { "name": "onMultipleTokensMove",      "mts": "onMultipleTokensMove"}
  ]
}
</source>
Add-ons do not respond to the {{code|onCampaignLoad}} event. Instead they have 2 new events:


* {{code|onFirstInit}} - This is called only once, when the add-on is first added to the campaign. Add the same add-on a second time (overwriting the existing one) and it will not be called again unless the add-on is removed first.
[[File:export-library-token-as-addon.png|400px|thumb|Library token context menu]]


* {{code|onInit}} - This is called every time the campaign is loaded (including after the initial onFirstInit event), similar to how {{code|onCampaignLoad}} is called on [[Library Token]]s. It's also called on the client when the campaign is sent to the client on the initial connection.
The token pop-up menu includes a way to export your existing library tokens to an Add-on Library structure. This is useful for starting the conversion of an existing token library to an Add-on.


As of 1.13, the {{code|onFirstInit}} and {{code|onInit}} events can specify a JavaScript file to run. Unlike the MTS script, you must specify the full path to the file. If you have an entry for both MTS and JavaScript, the JavaScript script will be run first.
In all but the simplest [[Library Token]]s you will want edit the extracted data. At a minimum, you will want to examine whether you prefer to rename the macros.
 
The other events must be in the {{code|legacyEvents}} section. As the name implies, these events are now considered to be legacy events. New events will be added in the future to replace these (these will not be removed).
 
Currently, only macro scripts are supported for {{code|legacyEvents}}; in the future, JavaScript scripts will also be supported.
 
== MTScript macros ==
 
The {{code|library/public}} directory is only exposed via the {{code|lib://}} URI if {{code|allowsUriAccess}} is set (see the configuration file discussion, above).
 
MTScript macros must all end with the file extension {{code|.mts}} to be recognized.
Only MTScript files in {{code|library/mtscript/public}} can be called using {{roll|macro}} from outside of the add-on.
The path of the file becomes the macro name for the {{roll|macro}} call.
The namespace of the add-on library is used for the {{code|@}} portion (the "location" of the macro).
 
Add-on libraries support both public and private macro functions. Public macro functions must reside in the {{code|library/mtscript/public}} and can be called from anywhere (chat, other add-ons, [[Library Token]]s, and macro buttons). You can call them using the following syntax:
 
<source language="mtscript">
[macro("GetTargets@lib:net.rptools.maptool.test-library")]
</source>
The above executes the MTScript macro in the file {{code|library/mtscript/public/GetTargets.mts}}.
{{Note|The {{code|public/}} is omitted from the macro name when calling it. You can also use subdirectories to organize your macros and would call them like {{code|[macro("somedir/macroname@lib:net.rptools.maptool.test-library")]}}.}}
 
The {{code|@this}} shorthand can also be used for calling a macro from within the same add-on, similar to how it works for [[Library Token]]s. For example, {{code|[macro("mtscript2@this")]}}.
 
Macro script files that are not in the {{code|public/}} directory can only be called from within the add-on itself or by events. Given a library with the namespace {{code|net.mylib.addon}} with the following files:
 
<source>
mtsscript/func1.mts
mtsscript/public/func2.mts
</source>
Then:
<source language="mtscript">
[macro("func2@lib:net.mylib.addon")]
</source>
can be called from anywhere, but
<source language="mtscript">
[macro("func1@lib:net.mylib.addon")]
</source>
can only be called from a macro (or via an triggered event) that is on the {{code|net.mylib.addon}} add-on.
{{Note|Since the {{code|public/}} is not required, if you have two files with the same name excluding the {{code|public/}} directory component, then only the one in {{code|public/}} will be able to be executed. You will not be able to call the other macro.}}
 
The above works not just with {{roll|macro}} but the other places you would expect it to as well, such as {{func|defineFunction}} for user-defined functions and macro links.
 
== Properties File Format: {{code|mts_properties.json}} ==
 
The {{code|mts_properties.json}} file contains property information about macro scripts.
It is not required and currrently only allows you to set properties used in macro links.
 
<source language="javascript">
{
  "properties": [
    {
      "filename": "public/auto_exec.mts",
      "autoExecute": true,
      "description": "Auto executable macro link"
    },
    {
      "filename": "public/myUDF.mts",
      "description": "My Test UDF in a drop in lib."
    }
  ]
}
</source>
Where:
 
* {{code|filename}} - is the path of the file for the MacroScript function (excluding the {{code|mtscript/}} prefix).
* {{code|autoExecute}} - determines if a macro link created for this macro will be auto executable or not.
* {{code|description}} - is the description that will appear in the UDF listing; unlike [[Library Token]]s, this is just a plain string and not evaluated if it contains {{code|[]}}.
 
== {{code|public/}} Directory ==
 
The contents of this directory are exposed as a {{code|lib://}} URI as long as the {{code|allowsUriAccess}} is set to true in the configuration file. The public directory part of the filename is discared, for example {{code|public/myhtml.html}} -> {{code|lib://net.myaddons.addon1/myhtml.html}}.
 
You can add images to this directory and use {{code|<nowiki>src="lib://"</nowiki>}} in image tags in HTML. It will eventually work with audio (probably already does but I haven't tested it yet so I'm not claiming it will 🙂).
 
These assets will be included correctly in the campaign file when saving, so you do not need to add them to image tables or image tokens or any other tricks to make sure that they are included.
 
There are some differences to be aware of when using [[Library Token]] property support for add-ons.
 
The name is case sensitive, unless tokens where it is not case sensitive.
The values stored do not need to be be converted to/from strings like they do with [[Library Token]]s. In many cases related to large json values, this should result in a speed improvement.
The default properties list for the campain are not present for add-ons as they are not tokens, unlike [[Library Token]]s.
 
== Converting [[Library Token]]s ==
 
The token popup menu includes a way to export your existing library tokens to an add-on. This is useful for starting the conversion of an existing token library to an add-on. However, in all but the simplest [[Library Token]]s you will want edit the extracted data. At a minimum, you will want to examine whether you prefer to rename the macros.
 
[[File:export-library-token-as-addon.png|400px|thumb|left|Library token context menu]]


=== Things you will want to change ===
=== Things you will want to change ===


You should probably change the namespace in the {{code|library.json}} file to something that is unlikely to conflict with other users. It's a good practice to use a reversed hostname + add-on name for this.  For example, if you created an account at GitHub and are using the '''GitHub.io''' page mentioned above, an example namespace would be {{code|io.github.addon-name}}.
# You should edit the {{code|library.json}} file, and change the namespace value from the default ("") to something that is unlikely to conflict with other users. It's a good practice to use a reversed hostname + Add-on name for this.  For example, if you created an account at GitHub and are using the '''GitHub.io''' page mentioned above, an example namespace would be {{code|io.github.''add-on-name''}}.
 
# All macros (except event-based ones) are created in {{code|mtscript/public/}} with the pattern {{code|macro_''number''.mts}}.  This naming pattern is because macro names have many things that might make them invalid -- or worse, dangerous -- as filenames. There is a {{code|macro_script_map.txt}} file saved in the top-level which contains the names of your macros and the filename that they were saved in.
All macros (except event-based ones) are created in {{code|mtscript/public}} with the pattern {{code|macro_''number''.mts}}.  This is because macro names have many things that might make them invalid -- or worse, dangerous -- filenames. There is a {{code|macro_script_map.txt}} file saved in the top level which contains the names of your macros and the filename that they were saved in.
# Not all macro buttons on [[Library Token]]s contain MTscript macros.  They are sometimes used as containers for CSS or other text content. You will probably want to rename and move them to the {{code|library/public/}} directory.  Don't forget that renaming them means any references in your macros may need updating as well.
 
# The {{code|onCampaignLoad}} macro will be saved as {{code|onInit}}.
Not all macro buttons on [[Library Token]]s contain MTscript macros.  They are used as containers for CSS or other text content. You will probably want to rename and move them to the {{code|library/public/}} directory.
# All Library Token properties are saved to a directory called {{code|property/}}. You should move the contents of this directory to something accessible by [[MTscript functions related to Add-on libraries]] such as {{code|library/public/properties/}}. The Library Token properties are saved with file names {{code|prop_''number''.txt}}and a mapping file {{code|prop_file_map.txt}} is created to map these the Library Token property names to the newly-created filenames.
 
The {{code|onCampaignLoad}} macro will be saved as {{code|onInit}}.
 
All properties are saved in the {{code|library/properties}} directory. These are saved with the names {{code|prop_''number''.txt}} and a mapping file {{code|prop_file_map.txt|}} is created to map these. (This may change slightly as the data access API evolves.)
{{Note|After doing the above you should REALLY take the opportunity to source control your add-on...}}
=== Things still to be addressed. ===


* There is only minimal checking of data when importing add-ons so error reporting is not great.
These files and structures are described in more detail in [[Technical definition of Add-on Libraries]].
* Expanding the JavaScript API which will make this much more useful (part of another change set).
{{Note|After doing the above you should ''REALLY'' take the opportunity to source control your Add-on...}}
* Better replacement for user defined functions.
* Providing an equivalent to [[Library Token]]s buttons.
* Ability to check URL for later version and update from that (most likely GitHub to start with)
* Link maps to required add-ons when exporting/importing.
* Documentation / procedures for creating a GitHub release for your add-on.
* The data store could be slightly smarter about large text blocks that remain static and attempt to cache them.

Latest revision as of 23:59, 17 November 2023


An example add-on library for examination and testing is available at https://github.com/cwisniew/test-maptool-add-on-lib

There are two main ways to create an Add-on Library:

  1. Create the library files and directory structure from scratch; or
  2. Export a Library Token as an Add-on Library.

Each of these approaches is described below.

1. Create the library files and directory structure from scratch

Firstly you will need a text editor. There are many of them mentioned below -- if in doubt, use VS Code.

After choosing a text editor, create a new directory to hold your Add-on.

Top-level files in the Add-on are metadata files; they hold information about your Add-on. The only file your Add-on needs to be accepted by MapTool is library.json.

You may have other non-metadata files in a subdirectory named library.

For macro code, you may have a mtscript directory inside library. Both of those subdirectories may have a publicly accessible directory which must be named public.

This structure is described in more detail in Technical definition of Add-on Libraries.

Creating library.json

The only required fields are

  • a name string,
  • an authors array,
  • a short description string, and
  • a namespace string.

The other fields are described on the Technical definition of Add-on Libraries page. Most of these are self-explanatory. Just remember bad things will happen if you use the same namespace as someone else, so try to use at least 3 words or a reversed domain name. In the example below, the namespace is io.github.Azhrei, which is a reverse of a hypothetical documentation page, Azhrei.github.io.

An example of a minimal library.json could be

 {
   "name": "test",
   "authors": ["you"],
   "namespace": "io.github.Azhrei",
   "shortDescription": "test"
 }

and that is it. You have made an Add-on! Those 6 lines are enough; just zip this file and then rename it so that it ends with .mtlib and have fun.

2. Export a Library Token as an Add-on Library

Library token context menu

The token pop-up menu includes a way to export your existing library tokens to an Add-on Library structure. This is useful for starting the conversion of an existing token library to an Add-on.

In all but the simplest Library Tokens you will want edit the extracted data. At a minimum, you will want to examine whether you prefer to rename the macros.

Things you will want to change

  1. You should edit the library.json file, and change the namespace value from the default ("") to something that is unlikely to conflict with other users. It's a good practice to use a reversed hostname + Add-on name for this. For example, if you created an account at GitHub and are using the GitHub.io page mentioned above, an example namespace would be io.github.add-on-name.
  2. All macros (except event-based ones) are created in mtscript/public/ with the pattern macro_number.mts. This naming pattern is because macro names have many things that might make them invalid -- or worse, dangerous -- as filenames. There is a macro_script_map.txt file saved in the top-level which contains the names of your macros and the filename that they were saved in.
  3. Not all macro buttons on Library Tokens contain MTscript macros. They are sometimes used as containers for CSS or other text content. You will probably want to rename and move them to the library/public/ directory. Don't forget that renaming them means any references in your macros may need updating as well.
  4. The onCampaignLoad macro will be saved as onInit.
  5. All Library Token properties are saved to a directory called property/. You should move the contents of this directory to something accessible by MTscript functions related to Add-on libraries such as library/public/properties/. The Library Token properties are saved with file names prop_number.txt, and a mapping file prop_file_map.txt is created to map these the Library Token property names to the newly-created filenames.

These files and structures are described in more detail in Technical definition of Add-on Libraries.

After doing the above you should REALLY take the opportunity to source control your Add-on...