-
Notifications
You must be signed in to change notification settings - Fork 5
Plugin Development
Note
This only covers the most basic of things, such as listening on events and creating commands.
It is assumed you have had at least some minor experience in making plugins for (X)ASECO, with examples from there.
- Before starting, it is a good idea to know the language you will be working in, TypeScript in our case. If you do not, it is not impossible to make a plugin, it simply will be much more of a burden than it needs to be.
- Make sure you have all the requirements (and that everything is up to date) as specified in the
README.md
file. - Create your plugin files in the
/plugins/
directory. If there are multiple files, it is best to create a directory specifically for them not to make a mess. If your plugin spans multiple files, we suggest creating a file that willimport
all other files. - Include your newly created files via
import
statements inside thePlugins.ts
file. The import extension MUST be.js
still. - Optionally, enable watch-mode compilation with
npx tsc watch
so that you are not required to typenpx tsc
after every change. - You can now write code for your very own plugin, good luck!
It might be useful to check the available controller methods first for you to be aware of what is currently possible. Do remember however, that page is not always up-to-date.
If a certain getter, function, etc. is not in the Trakman namespace and you are 100% sure it should be there, open an issue and let us know.
Do not forget, despite this being a modern app written in a modern language, the game we are interacting with is over 15 years old with little to no support from the developers. Some things are straight up impossible to implement (e.g. using ManiaScript), which is, well, unfortunate.
This is a fairly trivial task in any of the available controllers, and exactly what makes them "automatic".
First of all, we must call the static method registerEvent
of the Aseco
class, with the 2 arguments being the event name, and the callback name:
Aseco::registerEvent('onPlayerFinish', 'callback');
Afterwards, it only makes sense to add our callback function later in the file:
function callback (mixed $params): void {
# ... Code to be executed ...
}
This will execute callback
on the PlayerFinish
event.
Due to difference in language and overall coding style, our system may appear more complex.
Note
Before you continue on, make sure you have read the events list wiki page, otherwise you will not know the return type of certain events.
Start by invoking the addListener
method in the Trakman namespace (tm
):
tm.addListener(`PlayerChat`, async (info: tm.MessageInfo) => { /** ... Code to be executed ... **/ })
Note
Every element of type tm.Event
must include event
and callback
properties, former being the event to execute the function on, and latter the function itself, be it a lambda or something else.
The code above will execute the callback
function (in this case, a lambda function) on the PlayerChat
event.
Commands are valuable additions to the controller, allowing players to interact with it, or the dedicated server directly.
First of all, we must call static method addChatCommand
of the Aseco
class, with the 3 arguments being the command name, the help message and a boolean indicating whether it is an admin command (all that does is hide it from user /help
command):
Aseco::addChatCommand('ilovephp', 'Show others that you love PHP!', false);
After that, you must add the command code itself, note how every command MUST be prefixed with chat_
:
function chat_ilovephp(mixed $aseco, mixed $command): void {
# ... Code to be executed ...
}
We can add an alias to it too:
function chat_ilp(mixed $aseco, mixed $command): void {
chat_ilovephp(mixed $aseco, mixed $command);
}
Each object of type tm.Command
has 5 total properties:
Property | Type | Description |
---|---|---|
aliases |
String[] | An array of strings containing all possible aliases for your command. There is no limit |
help |
String | (optional) A string containing the command help, or generally whatever you would like. Leaving it empty makes the command invisible in /help
|
params |
Object | (optional) An array of objects containing the information about argument types. See the tm.Command entry in the types list for more information. In short, this allows you to remove all the type-checking from the callback itself, as it will be done by the Trakman chat service |
callback |
Function | The function that will be executed once the chat command is typed in (unless the controller crashes) |
privilege |
Number | An integer determining the privilege requirement to be able to use the command. 0 - User, 1 = Operator, etc |
disableForMuted |
Boolean | (Optional) A boolean determining whether the command is disabled for players currently in the mutelist |
Start by invoking the commands.add
method in the Trakman namespace (tm
):
tm.commands.add(
{
aliases: [`ilovets`, `ilovetypescript`],
help: `Show others that you love TypeScript!`,
params: [{ name: `paramNameOne`, type: `int` }, { name: `paramNameTwo`, type: `boolean`, optional: true }],
callback: async (info: tm.MessageInfo, paramNameOne: number, paramNameTwo?: boolean) => {
// ... Code to be executed ...
},
privilege: 0
},
{
// You can add another one immediately:
aliases: [`ilovejs`, `ilovejavascript`],
help: `Show others that you love JavaScript!`,
callback: async (info: tm.MessageInfo) => {
// ... Code to be executed ...
},
privilege: 0
}
)
Warning
If several commands share the same alias, they will be executed simultaneously.
Your command is ready to use after that, enjoy.
Chat routing makes every player message go through the controller first before being sent out. This way, chat messages can be altered to your liking.
The most common way of enabling chat routing in (X)ASECO is by directly adding a call to enable it after the controller startup sequence. This can be done like this:
Aseco::registerEvent('onStartup', enable);
function enable(mixed $aseco): void {
global $aseco;
$aseco->client->addCall('ChatEnableManualRouting', true, true);
}
This will enable chat routing, but will not make any messages show up at all, as (X)ASECO does not support this normally (as you could probably guess by the fact that you have to enable it yourself). To make it actually output something, you must listen on the onChat
event, and then send the chat message from the controller:
Aseco::registerEvent('onChat', message);
function message(mixed $aseco, mixed $player): void {
global $aseco;
$aseco->client->addCall('ChatSendServerMessage', '/* Whatever, I am not writing all that. */');
}
Note
This, however, is still not enough, as the method will be triggered for every server message, etc., etc.
To enable chat routing in Trakman, go to /config/Config.js/
and set manualChatRoutingEnabled
to true
. Done.
All customisations must go through the message
method you have created. Obviously, you can generate the kind of styling you want with other functions, but it all has to go through that onChat
listener.
Trakman provides several chat routing utilities via tm.chat
, as well as usage examples in /plugins/chat_routing_additions
to make your life easier:
tm.chat.addMessagePrefix
- Allows you to add a prefix/postfix to every player message (e.g. the finish counter)
tm.chat.setMessageStyle
- Allows you to modify the look of the player's name (e.g. the custom brackets)
tm.chat.addMessageTextModifier
- Allows you to modify the chat message's text directly (e.g. the url fixer)
Using these methods (and, perhaps, looking at the provided examples), it becomes fairly trivial to modify the chat to your liking.
As the author, you certainly have all the rights to keep everything you have written to yourself, the license allows for it too!
If you think that the inclusion of your plugin would immensely help our project, submit a PR, and we will look at it. Consider opening an issue first though.