This post describes a work in progress so details may change due to feedback. This is also
the reason that the documentation is a bit sparse. Before creating any issues check the bottom of the
post for things still to be implemented. These features required a HUGE amount of behind the scene
changes to how events, lib:tokens, and Assets work, so there will be a large amount of testing
that needs to be done, I am expecting that there are still several bugs that I have not been able
to uncover yet with my testing. Any help testing would be grealy appreciated.
It should go without sayind please don't run your games with this yet.
You can retrieve the static data that is zipped up in an add-on with the
following macro script function.
data.getStaticData(namespace, path)
If this macro function is run from the add-on then it is able to retrieve
any file that is in the add-on.
If the macro function run from ouside of the add-on then it is only able to
retrieve files in the public/ directory and only if the Allow URI Access
flag is set.
If the path does not exist in the add-on (or a macro tries to read a file that
is not in the public/ directory when not run from the add-on) then an empty
string will be returned.
This post describes a work in progress so details may change due to feedback. This is also
the reason that the documentation is a bit sparse. Before creating any issues check the bottom of the
post for things still to be implemented. These features required a HUGE amount of behind the scene
changes to how events, lib:tokens, and Assets work, so there will be a large amount of testing
that needs to be done, I am expecting that there are still several bugs that I have not been able
to uncover yet with my testing. Any help testing would be grealy appreciated.
It should go without sayind please don't run your games with this yet.
note
This information supercedes the previous blog post.
Add-On Libraries
MapTool 1.11 introduces add-on libraries which are intended to be an easier
to work with replacement for Lib:Tokens while also offering a lot more functionality.
Lib:Tokens 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 have,
so it is recommended that framework developers transition to add-on libraries if supporting
MapTool 1.11 and above.
I have a very sparse and contrived add-on library I have been using for testing available at
test-maptool-add-on-lib
Add-On libraries can be shared in a .mtlib file. This file is a zip file with a specific
structure and content. You can import these libraries with the File -> Import Add-On Library menu option.
library.json <-- Configuration information for the add-on librarymts_properties.json <-- Properties for macro script functions in libraryevents.json <-- Event definition for functions in the librarylibrary/ <-- Content of the librarylibrary/public <-- Content of the library acessable via `lib:// URI`library/mtscript <-- MTSCript fileslibrary/mtscript/public <-- MTSCript files that can be called via `[macro(): ]` outside of the library.
The library.json configuration file is a json file with the following structure.
{"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}
Add ons do not respond to the "onCampaignLoad" event, instead they have 2 new events.
onFirstInit - This is called only once, when the add on is added. Add the same add on a second time
overwriting the existing one it will not be called again unless the data for the add-on is removed first.
onInit - This is called every time the campaign is loaded (including after the inital onFirstInit event), and
on the client when sent to a client. This functionality is very much similar to onCampaignLoad.
The other events must be in the "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 though).
Currently only macro scripts are supported, in the future JavaScript scripts will also be supported.
library/public is only exposed via lib:// URI if allowsUriAccess is set (see configuration file)
MTScript macros must all end with the file extension .mts to be recognised.
Any
Only MTScript files in content/mtscript/public can be called using [macro():] from outside of the add-on
The path of the file becomes that macroname for [macro(): ] the namespace of the add-on library
is used for the @ portion.
Add-On libraries support both public and private macro functions. Public macro functions must
reside in the mtscript/public and can be called from anywhere (chat, other add-ons, lib:tokens, macro buttons).
You can call them using the following syntax
[macro("mtscript1@lib:net.rptools.maptool.test-library")] executes MTScript macro in the file
content/mtscript/public/mtscript1.mts.
note
The "public/" is ommited from the macro name when calling it.
You can also use subdirectories to organise your macros and would call them like
[macro("subdir/script@lib:net.rptools.maptool.test-library")]
The @this shorthand can also be used for calling a macro from within the same add-on, similar to how it works
for lib:Tokens. For example
[macro("mtscript2@this")]
Macro script files that are not in the "public/" directory can only be called from within the add-on itself or
by events.
Given a library with the namespace net.mylib.addon with the following files.
mtsscript/func1.mtsmtsscript/public/func2.mts
[macro("func1@lib:net.mylib.addon")] can be called from anywhere, but [macro("func2@lib:net.mylib.addon")]
can only be called from a macro that is on the net.mylib.addon add-on.
note
Since the "public/" is not required, if you have to files with the same name excluding the "public/" part, for example
mtscript/public/funct1.mts
mtscript/funct1.mts
Then only the one in public/ will be able to be executed, you will not be able to call the other macro
The above works not just with `[macro():] but the other places you would expect it to as well such as
defineFunction() for user defined functions and macro links.
The 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.
{"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."}]}
Where
filename is the path of the file for the MacroScript function (excluding mtscript/).
autoExecute determines if a macro link created for this macro will be auto executable or not.
description is the description that will appear in the UDF listing, unlike Lib:Token this is just a plain string and not evaluated if it contains []
The contents of this directory are exposed as a lib:// URI as long as the allowsUriAccess is set to true in the configuration file.
The public directory part of the filename is discared, for example
public/myhttml.html -> lib://net.myaddons.addon1/myhtml.html
You can add images to this directory and use src="lib://" in image tags in HTML.
It will eventually work with audio (probably aleady does but I haven't tested it yet so not claining it will yet :) )
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.
As Add Ons do not live on a token there are no token properties for them. Instead there has been a new
area created for storing data that is a lot more flexible -- and will allow data to be stored agisnt other
entities like maps in the future.
The existing lib property functions below have been modified to work with this new data store if called with
an add-on as the target.
setLibProperty
getLibProperty
getLibPropertyNames
getMatchingLibProperties
There are some differences to be aware of when using lib property support for add-ons.
The name is case sensitive, unles tokens where it is not case sensitive.
The values stored do not need to be be converted to/from strings like they do with lib:tokens so
in many cases for 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 Lib:Tokens
There are some macro functions that will be included in the alpha build for testing purposes that
will allow you to clear/get/edit the data store. The data store is not intended to be used like this
from macros so they will not be in the release build -- there will probably be something similar in 1.12
though.
data.createNamespace(type, namespace) - Creates namespace for data
data.listNamespaces(type) - Lists the created namespaces for a type
data.setData(type, namespace, name, value) - Sets a data value in the store
data.getData(type, namespace, name) - Gets a data value from the store
data.listData(type, namespace) - Lists the data stored in a namespace
data.clearData(type, namespace, name) - Clears the data for the given name in the data store
data.clearNamespace(type, namespace) - Clears all the data from a namespace
data.clearAllData() - Clears all the data in the data store
For add-ons the type will be 'addon:' and the namespace will be the namespace of the add-on.
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 but in all but
the simplest lib:tokens you will want edit the extracted data.
You should probably change the namespace in the library.json file to something that is unlikely to
conflict with other users. Its a good practice to use a reversed hostname + add on name for this.
All macros (except event based ones) are created in mtscript/public with the pattern macro_{number>.mts,
this is because macro names have many things that might make them invalid -- or worse dangerous -- 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.
Not all macro buttons on lib:tokens always contain MT Script macros, they are used for CSS etc as well so
you will probably want to rename and move them to the library/public/ directory.
The onCampaignLoad macro will be saved as onInit
All properties are saved in the library/properties directory. These are saved with the names prop_{number}.txt
and a mapping file prop_file_map.txt is created to map these. (this may change slightly when data access
is introduced, more the location)
note
After doing the above you should REALLY take the opportunity to source control your Add-On...
Things not yet implemented but will be (so dont create issues for these or I will just close them)#
The things detailed below will probably only be implemented for add-ons and there will be no equivalent
functionality for lib:tokens.
There is currenlty no way to properly retrieve json or other data files as data, once this is
added its recommended to store large static data here rather than in the data store as then it will
only need to be sent to client once which can cache it
There is currently no way to remove add-ons
There is only minimal checking of data when importing add-ons so error reporting is not great.
More documentation
Possibly will be added/addressed in 1.11 depends on available time#
Many file types like text/markdown etc are allowed in tate he library but the functions to use them dont yet exist
Way to create user defined functions through property file (so you dont have to call defineFunction in onInit)
Add-Ons lack a built in UI, Lib:Tokens have the macro buttons but Add-Ons dont. Better UIs can
now be created for Add-Ons using frame5/dialog5 with the lib:// URL support (we can expand that to added
other things that are needed) but do we also need something similar to what lib:tokens have.
One thing to realise is this change allows serveral things that are not immediately obvious. For example,
experiment with frame5/dialog5 and lib:// URI support and ability to store images, you would be surprised
how close it is to devloping a standard web site. Ass a proof of concept I have even been able to get
a small React App written in TypeScript running realtively easily by using webpack to bundle it and copy
it into the public directory. (Note the SVG for the beginner React app doesn't work correctly but
replacing it with a png works).
Note: This post describes a work in progress so details may change due to feedback. This is also
the reason that the documentation is a bit sparse. Before creating any issues check the bottom of the
post for things still to be implemented. Also the current code doesn't do much checking for the format
of the config/property files this will be improved.
Add-On Libraries
MapTool 1.11 introduces add-on libraries which are intended to be an easier
to work with replacement for Lib:Tokens while also offering a lot more functionality.
Lib:Tokens 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 have,
so it is recommended that framework developers transition to add-on libraries if supporting
MapTool 1.11 and above.
I have a very sparse and contrived add-on library I have been using for testing available at
test-maptool-add-on-lib
Add-On libraries can be shared in a .mtlib file. This file is a zip file with a specific
structure and content. You can import these libraries with the File -> Import Add-On Library menu option.
library.json <-- Configuration information for the add-on librarymts_properties.json <-- Properties for macro script functions in librarylibrary/ <-- Content of the librarylibrary/public <-- Content of the library acessable via `lib:// URI`library/mtscript <-- MTSCript fileslibrary/mtscript/public <-- MTSCript files that can be called via `[macro(): ]` outside of the library.
library/public is only exposed via lib:// URI if allowsUriAccess is set (see configuration file)
MTScript macros must all end with the file extension .mts to be recognised.
Only MTScript files in content/mtscript/public can be called using [macro():] from outside of the add-on
The library.json configuration file is a json file with the following structure.
{"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}
The name of the file becomes that macroname for [macro(): ] the namespace of the add-on library
is used for the @ portion. For example:
Add-On libraries support both public and private macro functions. Public macro functions must
reside in the mtscript/public and can be called from anywhere (chat, other add-ons, lib:tokens, macro buttons).
You can call them using the following syntax
[macro("[email protected]")] executes MTScript macro in the file
content/mtscript/public/mtscript1.mts.
note
The "public/" is ommited from the macro name when calling it.
You can also use subdirectories to organise your macros and would call them like
[macro("subdir/[email protected]")]
The @this shorthand can also be used for calling a macro from within the same add-on, similar to how it works
for lib:Tokens. For example
[macro("mtscript2@this")]
Macro script files that are not in the "public/" directory can only be called from within the add-on itself.
Given a library with the namespace net.mylib.addon with the following files.
mtsscript/func1.mtsmtsscript/public/func2.mts
[macro("[email protected]")] can be called from anywhere, but [macro("[email protected]")]
can only be called from a macro that is on the net.mylib.addon add-on.
note
Since the "public/" is not required, if you have to files with the same name excluding the "public/" part, for example
mtscript/public/funct1.mts
mtscript/funct1.mts
Then only the one in public/ will be able to be executed, you will not be able to call the other macro
The above works not just with `[macro():] but the other places you would expect it to as well such as
defineFunction() for user defined functions and macro links.
The 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.
{"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."}]}
Where
filename is the path of the file for the MacroScript function (excluding mtscript/).
autoExecute determines if a macro link created for this macro will be auto executable or not.
description is the description that will appear in the UDF listing, unlike Lib:Token this is just a plain string and not evaluated if it contains []
The contents of this directory are exposed as a lib:// URI as long as the allowsUriAccess is set to true in the configuration file.
The public directory part of the filename is discared, for example
public/myhttml.html -> lib://net.myaddons.addon1/myhtml.html
You an add images to this directory and use src="lib://" in image tags in HTML.
It will eventually work with audio (probably aleady does but I haven't tested it yet so not claining it will yet :) )
Issues with HTML/CSS/JavaScript Prior to MapTool 1.10#
Prior to MapTool 1.10 creating HTML pages is unnecessary cumbersome.
To create HTML dialogs, frames, and overlays you use the following roll options.
[frame(): { } ]
[frame5(): { } ]
[dialog(): { } ]
[dialog5(): { } ]
[overlay(): { } ]
The HTML is included in the [ ] which means it has to processed by the MTScript parser. This has both benefits and drawbacks.
The main benefit is that you can use [ ] to execute MTScript elements as a form of templating the HTML, for example
[frame("test): { [r: getName() ]}]
The major drawback is that everything included must be able to pass through the MTScript parser, often this will not be the case especially where CSS or JavaScript are concerned.
You can work around this problem by using macros functions to fetch text from macro, for example:
In MapTool 1.10 there is a change that allows you to access properties and macros on Lib:Tokens via a URI of the form
lib://<token name>/macro/<macro name>
lib://<token name>/property/<property name>
note
By default the text fetched using the URI is cached, if you make changes to the content it will not be reflected until you restart MapTool. To work around this you can add the cachelib=false query string as show in examples later on in this post.
Where <token name> is the name of the Lib:Token after the Lib: prefix, for example Lib:HTMLTest would be HTMLTest
There are no special requirements on ownership for the Lib:Token, to allow URI access to Lib:Token properties and macros, anyone will be able to access these values via a URI if the "Allow URI Access" flag needs is set, you can do this via the edit token dialog.
or the setAllowsURIAccess() macro function.
Reserved names
Some names are reserved for future internal usage and you will not be able set the "Allows URI Access" flags on Lib:Tokens
Reserved names are: Lib tokens with the following names (after the lib: part)
rptools
maptool
maptools (because people often call it maptools)
internal
builtin
standard
Lib tokens starting with the following names (after the lib: part)
Two new MTScript functions have been added that allow you to set or get the "Allows URI access" flag for a token. These can only be run from a trusted macro.
Lib:// URIs are useful for both CSS and JavaScript inclusion in HTML files, creating frames/dialogs/overlays with HTML, and the js.evalURI() MTScript functions.
Including JavaScript and CSS in HTML using a lib:// URI#
<html><head><linkrel="stylesheet"href="lib://HTMLTest/macro/test/test.css?cachelib=false"/></head><body><h1>This is a test</h1><divid="test1"/><scriptsrc="lib://HTMLTest/macro/test/test.js?cachelib=false"></script><imgsrc="asset://87f4e9bfa4f1f3db250b57b3599fa4e9"/></body></html>
This will include CSS from the macro called test/test.css and the JavaScript from a macro called test/test.js on the Lib:HTMLTest token.
Creating frames/dialogs/overlays using a lib:// URI#
There are also new MTScript functions that allow you to create frames/dialogs/overlays by passing a lib:// URI which contains the HTML.
These are
The URLs in the HTML file can also be specified using relative paths, for example
Given
If the HTML is loaded from test/test.html you can use relative paths for the other macros as below
<html><head><linkrel="stylesheet"href="./test.css?cachelib=false"></head><body><h1>This is a test</h1><divid='test1'/><script>document.getElementById('test1').innerHTML='...This is a test!';</script><scriptsrc="./test.js?cachelib=false"></script><imgsrc="asset://87f4e9bfa4f1f3db250b57b3599fa4e9"/><ahref="./test2.html">test2</a></body>
This will even work for hyperlink navigation as seen in the link to ./test2.htlm aboove
In addition to being able to include JavaScript in HTML via the <script> tag, lib:// URIs can be used to execute JavaScript via the js.evalUI()macro function.
Prior to version 1.10 MapTool only supported a single method of authentication which is role based authentication. Each Role (GM and Player) has a password and any client that connects and authenticates with either of these passwords gets that role. There is no restriction player names other than everyone has to have a unique name.
In MapTool 1.10 there are three authentication methods.
For player specific passwords and public keys authentication a password file must be used as these require that the name of the players are fixed so that they can be matched to the specific password or public key. When starting the server you can specify that a password file is used.
This will load the password file or create a new one if it doesn't exist.
So that the user does not have to type in a password that will not be used they can check "connect using public Key" from the connect to server dialog.
They do not have to check this box as if the server requests the client attempts to authenticates via public key the client will do so even if the user has specified a password. If this value is checked the only way the client can authenticate is via public key so any password in the password text field will be ignored.
Is the player Blocked
Blocked players will not be able to log in. When they try to connect they will get a message with a reason that they are blocked.
note
New, Added, or Modifications to players take effect immediately but the changes will not be written to the password file until this dialog is closed (either with Ok button or dialog close button). This is so that the file will not be continually overwritten many times when making several changes at once.
Clicking on the Edit or Add button will open a dialog where you can provide the player details.
This dialog is used to provide the information required for the player database entry.
Player Name (only editable for Add)
Role, Player or GM
If the player has been blocked from logging in, and if so the reason why
Authentication Type, password or public key
Player Password (only if authentication type is password)
Public Key (only if authentication type is public key)
The password is hashed which is a one way operation, so you will not be able to see a players password so if you and the player forget it you will have to change it to a new one.
Its recommended that if you want to use player specific authentication you use public keys as that way neither you or the player will need to remember the password. You can add more than one public key in the public key text field so you can easily support players who have multiple computers.
If you still prefer to use a password over a public key it is strongly recommended you use the Generate New Password button so that no one is sharing passwords they may be using elsewhere.
note
Setting a plyer to blocked will not kick the player, it will only stop them from attempting to connect to the server. You will need to kick the player if you also want to remove them immediately. At this time kicking a blocked player will not send them the reason that they are blocked/kicked but will do so in a future version.
There is a new Authentication tab on the preferences dialog which contains the public key for your client. If you have multiple machines each will have its a different public key, its also possible if you have multiple versions installed with different data directories then these may also have different public keys.
You can regenerate your public key but if you do so then you will not be able to connect to any server that has your old public key so you will need to ensure you let the person running the server know that your public key has been changed.
Your public key is also stored in the file .maptool-rptools/config/public.key (or equivalent data directory).
Warning: Your private key is also stored in this directory, do not share this with anyone as if they have both your public and private key they will be able to log in as you on other servers your public key is registered with.
The location of the password file -- assuming the standard data directory -- is .maptool-rptools/config/passwords.json always ensure that you make a backup before editing it as if you make mistakes and you don't have a backup you may need to regenerate new passwords for all players. Also never update the password file while the server is running. Public keys for players are stored in the the .maptool-rptools/config/keys directory. If you use multiple computers or share GM duties with someone else you can copy the passwords.json file and keys directory and place them in the same directory on the second computer as they contain nothing specific to the computer it was generated on. You should still endeavour to make sure that this password file is shard with as little number of people as possible. Also never use passwords that you have used anywhere else in this file even though they are hashed. If you must use passwords use the button to generate new passwords, but you should prefer public keys!
The password field contains the hashed password for the player, the salt field is a randomised value that is used in the function used hash the password.
If you want to add players you will not be able to -- or be expected to -- generate the hashed password and salt instead you can instead specify the plaintext password and no salt like the following.
Then the next time the server is started this file will be read and the password will be hashed and the file overwritten to only contain hashed passwords and the salt for the password. This will also generate a passwords.json.backup before overwriting, ensure that you delete this file after testing as it contains then non hashed version of the passwords. But you did remember to use randome passwords and not passwords that you use elsehwere correct?
Previously these callouts always render the name of the player regardless of where the callout is or impersonation status.
In MapTool 1.10 tokens can have a speech name, this can affect the name displayed for both thought and speech bubbles when the mouse pointer is over the token, or the token is impersonated.
This can be set when dragging a new token on to the map
Or by editing existing tokens.
Or via macro. setSpeechName("Speech bubble name", tokenId)
There are two related macros
getSpeechName() which returns the speech name for the current token. There is also a trusted variant getSpeechName(tokenId) which will return the speech name for the token with the specified id.
setSpeechName(SpeechBubbleName) sets the speech name for the current token. There is also a trusted variant setSpeechName(SpeechBubbleName, tokenId) which will set the speech name for the token with the specified id.
In the following examples the speech and thought bubbles look different to previous versions as another fix in MapTool 1.10 is to size them dynamically so large names wont be rendered outside of the bubbles.
No impersonated token or token under mouse
Token with Speech Name
Token with really long speech name
Both the eagle and the Dragon have a speech name
Mage and Familiar with Speech Name, mouse over Mage
Mage and Familiar with Speech Name, mouse over Familiar
In general when deciding which name to use in speech and thought bubbles MapTool will attempt to show the name associated with the following precedence
Token under the mouse with speech name(if player owns it or is GM)
Impersonated Token with speech name
The players name
Below is a more detailed overview of the logic if you really want to know what it is.
If there are multiple tokens under the mouse (e.g. a Token Stack) and at least one has a speech name then the following logic will be used to determine which is used.