Legacy plugin upgrade guide

As of Openplanet 1.17.19, there is a brand new plugin system that simplifies development and distribution of complex plugins. This guide will explain why legacy plugins can be problematic, and why you might consider upgrading your plugin to the new system, or keep using the legacy system.

The problem with legacy plugins

With legacy plugins, a user would have to put the Plugin_Example.as file (including .sig file) in their User/Scripts/ folder. The script might reference a texture it wants to display, which would have to be placed in the separate User/Textures/ folder. The textures folder might not even exist yet, adding more steps for someone to install your plugin.

Furthermore, if you have multiple script files to consolidate logic into multiple different files, it might be inconvenient to keep those files in the same folder together with a bunch of other unrelated plugins and scripts.

Plugins were originally designed this way because the scope was much smaller - not a single plugin had dependencies - but time has proven that a more solid system was required, so the new plugin system has been developed.

Another problem is that the built-in plugin manager can't easily automatically install legacy plugins as it doesn't know what dependencies a script might rely on.

Do I have to use the new system?

Kinda. You can remain using the legacy system. All existing plugins will keep working for the time being. Being able to very quickly create an Openplanet plugin using just 1 file is very convenient, so I don't expect legacy plugins to fully disappear anytime soon.

However, if you want your plugins to be auto-updatable and installable through Openplanet's built-in Plugin Manager, you'll have to make your plugin a (packed) modern plugin.

What's changed?

Plugins are now fully contained within their own folder, for example User/Plugins/Example/. This folder is the root directory of your plugin. Any .as files located in this directory (and subdirectories) will automatically be loaded into the plugin's script module. That means you don't even have to explicitly use #include to include other scripts.

Any resource loaded from the plugin is always relative to your plugin root directory. For example, to load User/Plugins/Example/Hello.png, you would call Resources::GetTexture("Hello.png"). The only restriction currently is the IO API, which doesn't support this yet.

Plugin ID

The plugin's ID is used to store certain plugin-specific options, such as the plugin settings itself, as well as whether the user has enabled the plugin or not. With legacy plugins, the ID has always been the filename minus the extension. For example, Plugin_Foo.as would have the ID Plugin_Foo. For new modern plugins, the ID is either the folder name (eg. User/Plugins/Foo/ has the ID Foo), or the zipped plugin (.op) file (more info on this below) minus the extension (eg. User/Plugins/Foo.op has the ID Foo).

This means that upgrading your plugin from legacy to modern will bring a plugin ID change, which will bring several problems:

  1. Any settings previously saved under the old plugin ID will be reset.
  2. You can now load both the legacy and modern version of your plugin at the same time, because they don't have the same ID!

Solving the first problem is current non-trivial, so that's unfortunately not possible right now, and the settings resetting is an unfortunate side effect you'll have to deal with. Users can, if they know how, change their Settings.ini manually before starting the game, however.

Fixing the seocnd issue is done from your info.toml file, which is described below.


Every plugin must have an info.toml. This is meant to replace most preprocessor directives such as #name, #author, but also #include. Here's an example file with all of the currently available options:

name = "Test"
author = "Miss"
category = "Testing"

blocks = [ "Plugin_Test" ]

siteid = 103
version = "1.0"

perms = "paid"

min_version = "2020-12-25"
max_version = "2021-06-03"

imports = [ "Icons.as" ]

All of these values are optional, but they must follow the correct format. For example, name must always reside in a [meta] block.

Note that just like scripts, this file also has to be signed to run on Starter and Standard editions of Trackmania.

There's a few new things in this file as well compared to legacy plugins, so let's take a look at them.


This is an array of plugin ID's to block from loading. This is incredibly useful if you're porting your legacy plugin to a modern plugin, as you don't want people to keep using your old legacy plugin at the same time as your new plugin, and essentially have the same plugin running twice.

Note that legacy plugin ID's always start with Plugin_, and modern plugin ID's are just the folder name. Avoid using Plugin_ as a prefix for your folder name, as it is no longer required.


In legacy plugins you might be including files such as Icons.as to get a convenient way of adding icons to your UI. In modern plugins, #include is no longer required (in fact, it will throw an error), so this array is a list of scripts to include into the plugin module. The location of these scripts remains the same folder as legacy plugins. I'm not sure yet if this is going to change.

Zipped plugins (.op files)

Openplanet now supports zipped plugins as .op files! All a user has to do is put the plugin's .op file in Users/Plugins/. When zipping up your plugin for distribution, make sure the root of the zip file is the same as the root of your plugin folder; this means that info.toml has to be in the root of the zip. You should then rename your zip so that the file extension is .op.

If there's both a folder and a zip with the same plugin ID, eg Users/Plugins/Example/ and Users/Plugins/Example.op, then the zipped plugin is prioritized for loading instead of the folder one. This is so that plugin developers can easily test their zipped plugin version without having to temporary delete or move the folder.

Edited 2 days ago by