Forwards: events for other plugins
A forward is an event one plugin raises and other plugins hear - TypeScript and Pawn alike. It is how a plugin tells the rest of the server that a round of its game mode started, that a player bought something, that a setting changed.
const bought = new Forward<Player, string>("myplugin_on_bought");
server.addCommand("/buy <item>", ({ player, item }) => {
bought.emit(player, item);
});
The type parameters are the forward's arguments, up to 32 - as many as AMX
Mod X gives a forward: new Forward("myplugin_on_start") has none,
new Forward<Player, string> two. emit passes them to everyone who listens; it returns true when the
forward went out.
A Pawn plugin hears it as any forward, with a public function of that name:
public myplugin_on_bought(id, const item[])
{
client_print(id, print_chat, "You bought %s", item);
}
Listening from TypeScript
const bought = new Forward<Player, string>("myplugin_on_bought");
bought.subscribe((player, item) => {
console.log(`${player.name} bought ${item}`); // player: Player, item: string
});
bought.subscribe(onBought);
bought.unsubscribe(onBought);
function onBought(player: Player) { // may take fewer parameters than the forward
console.log(`${player.name} bought something`);
}
Another plugin makes a Forward of the same name and types and subscribes to
it. The handler's parameters take the forward's types, so an arrow needs no
annotations, and a handler of the wrong type is an error in the editor. A
plugin may also subscribe to a forward it raises itself.
A forward raised by a TypeScript plugin reaches every subscriber. A forward a Pawn plugin raises reaches TypeScript when it is declared in an include amxts comes with - AMX Mod X's, ReAPI's and those of the modules amxts supports.
Argument types
| Type parameter | What Pawn gets |
|---|---|
number | a whole number |
boolean | 1 or 0 |
string | a string |
Player | the player's index; a subscriber gets the Player |
Team | its TeamName number: "UNASSIGNED" 0, "TERRORIST" 1, "CT" 2, "SPECTATOR" 3 |
RoundWinner | its WinStatus number: "none" 0, "CT" 1, "TERRORIST" 2, "draw" 3 |
Float, or number where the include says Float: | a Float |
number[] | an array; of Floats where the include says Float: |
Vector | an array of three Floats |
Team and RoundWinner need the forward's declaration in an include: the
plugin's own (plugin({ include }))
or one the build knows. The build reads how each argument crosses from it:
// in myplugin.inc: forward myplugin_on_joined(id, TeamName:team);
const joined = new Forward<Player, Team>("myplugin_on_joined");
joined.emit(player, "CT"); // Pawn gets (id, 2)
joined.subscribe((player, team) => console.log(`${player.name}: ${team}`)); // team: "CT"
The build stops, with the place and the reason, when:
- a
Teamor aRoundWinnerhas no declaration to say which number it is; - a
RoundWinneris declared as something other thanWinStatus:; - a
stringis declared as a number (TeamName:team); - an array is declared as a number;
- an array is declared without a tag (
const data[3]): Pawn passes that as text - tag it,Float:data[3]; - the declaration has another number of arguments.
A forward no include declares crosses as its types say.
Pawn passes an array without its size. An array in a forward a Pawn plugin raises reaches a subscriber whole when the include gives the size (
Float:origin[3]); an array without one arrives empty.When the forward is made
The forward is made on its first emit, or earlier with create(). AMX
Mod X finds the Pawn plugins that hear a forward when it is made, so emit it
no earlier than when every plugin has loaded - in the "pluginsLoaded" event or later.
Subscribing does not make it.
Stopping
const vote = new Forward<Player>("myplugin_vote");
vote.stopWhen = "handled";
With "handled", the first Pawn handler that returns PLUGIN_HANDLED stops
the forward: the handlers after it do not hear it. The default is "never":
everyone hears it. Set it before the first emit.
Game events
What happens in the game - a player takes damage, spawns, dies, buys a weapon, throws a grenade, a round ends - are events on game. A listener hears the event before the game acts, and can let it go on, change it, stop it, or answer in the game's place:
Async and promises
A plugin waits the way JavaScript does: async functions, await, Promise. While one function waits - for a web request, for a few seconds - the server and the rest of the plugin go on.