Message Channels

Dans Sponge, tous les objets auxquels des messages peuvent être envoyés implémentent l’interface MessageReceiver. Un MessageChannel est un dispositif qui peut envoyer des messages à un nombre arbitraire de MessageReceivers et même effectuer des actions tels que des mises en forme spécifiques au destinataire du message.

Sélectionner les Destinataires du Message

À l’intérieur de l’interface MessageChannel il y a des constantes et des méthodes statiques qui peuvent être utilisées pour obtenir ou créer des canaux couramment utilisés. Il y a également d’autres classes et interfaces qui peuvent être utilisées pour créer un MessageChannel, comme AbstractMutableMessageChannel et MutableMessageChannel. Une liste complète peut être trouvée dans org.spongepowered.api.text.channel et ses sous-packages.

Diffusion

Le canal le plus courant sera le canal de diffusion. Il peut être obtenu soit depuis le Server via la méthode Server#getBroadcastChannel() ou soit depuis les constantes MessageChannel#TO_PLAYERS ou MessageChannel#TO_ALL. La seule différence est que TO_ALL n’inclut pas seulement tous les joueurs connectés au serveur mais aussi la Console du serveur.

Le canal retourné par getBroadcastsChannel() sera généralement le canal MessageChannel.TO_ALL, cependant un canal différent peut être défini en utilisant la méthode Server#setBroadcastChannel(MessageChannel).

Envoyer à une liste fixe de MessageReceivers

Il est également possible d’envoyer un message non pas à tous les joueurs connectés, mais à un nombre de destinataires sélectionnés à la main. Cela peut être fait en passant la liste des destinataires voulus à la méthode MessageChannel#fixed(MessageReceiver…). Contrairement à la plupart des autres canaux, la liste des destinataires ne sera pas générée dynamiquement chaque fois que quelque chose est envoyé à travers le canal, mais reste statique pour le reste de son existence. Cependant, les références gardées sont faibles. Cela signifie que si par exemple un joueur se déconnecte et que l’objet Player correspondant est supprimé par le garbage collector de Java, ce joueur va aussi disparaître de la liste de destinaires des canaux.

Sélection basée sur les Permissions

Il est également possible de créer un canal qui envoie à tous les destinataires qui détiennent une permission spécifique. Le canal est obtenu à partir de la méthode MessageChannel#permission(String) avec la permission à vérifier en argument. Quand un message est alors envoyé par ce canal, il obtiendra tous les sujets depuis le PermissionService qui possèdent la permission donnée.

Combiner des Canaux

Il est également possible de combiner plusieurs canaux en un seul. Cela peut être fait en passant tous les canaux dans la méthode MessageChannel#combined(MessageChannel…). Le canal qui en résulte va relayer les messages à chaque destinataire qui est ciblé par au moins un des canaux combinés.

Envoyer des Messages

Une fois que vous avez obtenus un MessageChannel vous pouvez envoyer un message via lui grâce à la méthode MessageChannel#send(Object, Text). Cette méthode est préférable à la méthode MessageChannel#send(Text), puisque l”Object peut être utilisé pour l’identification ou pour effectuer d’autres actions diverses. Alternativement, vous pouvez utiliser un ChatType pour spécifier où est-ce que le message sera envoyé. Utiliser la méthode MessageChannel#send(Object, Text, ChatType) vous permettra d’y parvenir. Le canal transformera alors le message pour chaque destinataire et enverra le message transformé.

Application étendue: Canaux de discussion

Les message channels ont une application très utile, puisqu’ils peuvent être utilisés pour établir des canaux de discussion. Par exemple, vous pouvez établir un message channel pour chaque canal de discussion que vous souhaitez avoir. Ensuite, quand un MessageReceiver rejoint un canal, comme avec /join <nom du canal>, définissez simplement le MessageChannel des MessageReceivers au canal approprié en utilisant MessageReceiver#setMessageChannel(MessageChannel). Cela va faire que tous les messages envoyés depuis le MessageReceiver seront passés au MessageChannel donné plutôt qu’à celui par défaut. Alternativement, vous pouvez écouter le MessageChannelEvent, et définir le MessageChannel approprié en utilisant MessageChannelEvent#setChannel(MessageChannel). Passer null à cette méthode va désinitialiser tous les canaux personnalisés, ce qui va faire que le message sera envoyé au MessageChannel original à la place.

Transformer les Messages

Vous pouvez appliquer un filtre à tous les Texts qui passent à travers un MessageChannel pour changer le message comme bon vous semble. C’est possible en héritant MessageChannel et en réécrivant la méthode MessageChannel#transformMessage(Object, MessageReceiver, Text, ChatType) comme montré ci-dessous.

Exemple : Transformer les Messages

L’extrait de code suivant définit une classe AdminMessageChannel qui réécrit la méthode par défaut transformMessage. La nouvelle méthode transformMessage va prendre le message original et ajouter un tag rouge [Admin] au début du message.

import java.util.Collection;
import java.util.Collections;
import java.util.Optional;

import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.channel.MessageChannel;
import org.spongepowered.api.text.channel.MessageReceiver;
import org.spongepowered.api.text.format.TextColors;

public class AdminMessageChannel implements MessageChannel {

    @Override
    public Optional<Text> transformMessage(Object sender, MessageReceiver recipient,
                                                                Text original) {
        Text text = original;
        text = Text.of(TextColors.RED, "[Admin]", TextColors.RESET, text);
        return Optional.of(text);
    }

    @Override
    public Collection<MessageReceiver> getMembers() {
        return Collections.emptyList();
    }
}

Notez que nous ne souhaitons pas définir d’autres récipients, nous retournons donc une collection vide dans la méthode MessageChannel#getMembers().

Grâce aux capacités des MessageChannels combinés, nous pouvez combiner nos AdminMessageChannel nouvellement créés avec n’importe quel autre MessageChannel. Maintenant si un player rejoint avec la permission myplugin.admin, nous obtiendront le MessageChannel auquel ses messages sont envoyés, le combiner avec un AdminMessageChannel et définir le canal combiné au joueur. De cette manière tous ces messages seront envoyés à tous les joueurs spécifiés dans le canal original, mais en raison de l’ajout du AdminMessageChannel, il sera préfixé d’un tag rouge [Admin].

import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.network.ClientConnectionEvent;

private AdminMessageChannel adminChannel = new AdminMessageChannel();

@Listener
public void onClientConnectionJoin(ClientConnectionEvent.Join event) {
    Player player = event.getTargetEntity();
    if(player.hasPermission("myplugin.admin")) {
        MessageChannel originalChannel = event.getOriginalChannel();
        MessageChannel newChannel = MessageChannel.combined(originalChannel,
            adminChannel);
        player.setMessageChannel(newChannel);
    }
}

Notez que cela va préfixer tous les messages se rapportant à un joueur. Cela inclut les messages de mort, les message de déconnexion, etc… Si vous souhaitez seulement préfixer les messages de chat, vous devrez écouter à l’événement MessageChannelEvent.Chat et définir le canal à l’événement et non au joueur. Cela se fait en utilisant event.setChannel(newChannel) sur l’événement MessageChannelEvent.Chat. Pour récupérer le joueur depuis l’événement pour vérifier les permissions, vous aurez besoin de récupérer un Player depuis la Cause de l’événement. C’est illustré ci-dessous :

Optional<Player> playerOptional = event.getCause().<Player>first(Player.class);

Plus d’informations sur les causes peuvent être trouvées sur la page des causes.

Note

En combinant plusieurs MessageChannels en définissant différentes transformations de messages, le Text sera transformé dans l’ordre dans lequel les MessageChannels sont passés à la méthode MessageChannel#combined(MessageChannel... channels). Notez que toutes les transformations résultant en un Optional vide seront ignorées sauf si elles sont effectuées par le dernier canal de la chaîne.

Message Channels Muables

Un MutableMessageChannel contient des méthodes permettant de modifier qui peut recevoir les messages envoyés à travers notre canal. Par conséquent, nous devons implémenter des méthodes pour effectuer des actions qui modifient nos membres. Pour faire ceci, nous allons simplement créer une classe nommée MutableAdminMessageChannel qui va implémenter un MutableMessageChannel.

import java.util.Set;
import java.util.WeakHashMap;

import org.spongepowered.api.text.channel.MutableMessageChannel;

public class MutableAdminMessageChannel implements MutableMessageChannel {

    private Set<MessageReceiver> members;

    public MutableAdminMessageChannel() {
        this(Collections.emptySet());
    }

    public MutableAdminMessageChannel(Collection<MessageReceiver> members) {
        this.members = Collections.newSetFromMap(new WeakHashMap<>());
        this.members.addAll(members);
    }

    @Override
    public Collection<MessageReceiver> getMembers() {
        return Collections.unmodifiableSet(this.members);
    }

    @Override
    public boolean addMember(MessageReceiver member) {
        return this.members.add(member);
    }

    @Override
    public boolean removeMember(MessageReceiver member) {
        return this.members.remove(member);
    }

    @Override
    public void clearMembers() {
        this.members.clear();
    }

    @Override
    public Optional<Text> transformMessage(Object sender, MessageReceiver recipient,
                                                                Text original) {
        Text text = original;
        if(this.members.contains(recipient)) {
            text = Text.of(TextColors.RED, "[Admin]", TextColors.RESET, text);
        }
        return Optional.of(text);
    }
}

La différence principale entre notre AdminMessageChannel et notre nouveau MutableAdminMessageChannel est que nous vérifions si le destinataire est dans la liste des membres avant de transformer le message. Si il y est, alors nous pouvons altérer le message qui est envoyé, en ajoutant le tag rouge [Admin]. Dans notre méthode getMembers() nous retournons un set immuable, pour que le set puisse seulement être modifié par les méthodes appropriées dans notre MutableAdminMessageChannel.

Notez qu’une implémentation abstraite pour les MutableMessageChannels existe dans l’API Sponge comme AbstractMutableMessageChannel. Notez également que nos membres ne persistent pas. Si un joueur devait quitter le serveur, alors il serait enlevé du set.

Modification des Membres

Pour tirer pleinement parti de nos MutableAdminMessageChannel, nous devons être capable d’ajouter et d’enlever des membres du canal. Pour faire ceci, nous pouvons simplement appeler nos méthodes MutableMessageChannel#addMember(MessageReceiver) et MutableMessageChannel#removeMember(MessageReceiver) que nous avons implémentées précédemment lorsque nous avons besoin d’ajouter ou d’enlever un membre du set.