Nachrichtenkanäle
In Sponge implementiert jedes Objekt, das Nachrichten empfangen kann, das MessageReceiver Interface. Ein MessageChannel ist ein Gerät, dass Nachrichten an eine beliebige Anzahl von MessageReceiver
n senden und sogar Aktionen wie Empfänger-spezifische Formatierungen durchführen kann.
Auswählen der Empfänger
Im MessageChannel
Interface gibt es Konstanten und statische Methoden, die dafür verwendet werden können, häufig verwendete Kanäle zu erstellen. Außerdem gibt es noch andere Klassen und Interfaces, die verwendet werden können um MessageChannel
zu erstellen wie beispielsweise AbstractMutableMessageChannel und MutableMessageChannel. Eine komplette Liste dieser kann im org.spongepowered.api.text.channel Package und seinen Unter-Packages gefunden werden.
Rundfunk
Der meistverwendetste Kanal ist der Rundfunk-Kanal. Dieser kann entweder vom Server mit der Server#getBroadcastChannel() Methode oder der MessageChannel#TO_PLAYERS bzw. MessageChannel#TO_ALL Konstante abgerufen werden. Der unterschied von TO_ALL
ist der, dass dieser nicht nur alle mit dem Server verbunden Spieler enthält sondern auch die Server Console
.
Der Kanal, der von getBroadcastChannel()
zurückgegeben wird, ist meistens der MessageChannel.TO_ALL
Kanal, aber es kann auch ein anderer Kanal mit Hilfe vor Server#setBroadcastChannel(MessageChannel) Methode gesetzt werden.
Senden an eine feststehende Liste von Empfängern
Es ist auch möglich eine Nachricht nicht an alle verbundenen Spieler zu senden, sondern nur an eine ausgewählte Menge von Empfängern. Dies kann erreicht werden, indem die gewünschte Liste von Empfängern an die MessageChannel#fixed(MessageReceiver…) Methode übergeben wird. Im Gegensatz zu den meisten anderen Kanälen ist die Liste hierfür nicht dynamisch generiert, sondern bleibt statisch hinterlegt solange dieser existiert. Aber die Referenzen auf die Objekte sind weak (schwach). Das bedeutet, dass wenn zum Beispiel ein Spieler das Spiel verlässt und das dazugehörige Player Objekt von Javas garbage collector (Müllabfuhr) entfernt wurde, dieser Spieler auch von der Liste der Empfänger verschwindet.
Rechte-basiertes Auswählen
Es ist auch möglich einen Kanal zu erstellen, der an alle Empfänger sendet, die eine bestimmte Berechtigung haben. Dieser Kanal wird von der MessageChannel#permission(String) Methode, unter Angabe der zu verwendenen Berechtigung, erstellt. Wenn eine Nachricht über diesen Kanal gesendet wird, wird diese an alle Subject
s von PermissionService weitergeleitet, die die entsprechende Berechtigung haben.
Kanäle kombinieren
It is also possible to combine multiple channels into one. This can be done by passing all channels into the MessageChannel#combined(MessageChannel…) method. The resulting channel will relay messages to every recipient that is targeted by at least one of the combined channels.
Nachrichten senden
Once you have obtained a MessageChannel
you can send a message through it via the
MessageChannel#send(Object, Text) method. This method is preferred over the
MessageChannel#send(Text) method, as the Object
can be used for identification or for performing other
various actions. Alternatively, you can use a ChatType to specify where the message will be sent to. Using
the MessageChannel#send(Object, Text, ChatType) method will allow you to accomplish this. The channel will
then transform the message for every recipient and send the transformed message.
Erweiterte Einsatzmöglichkeit: Chaträume
Message channels have a very useful application as they can be used to establish chat channels. For example, you could
establish a message channel for every chat channel you wish to have. Then, when a MessageReceiver
joins a channel,
such as with /join <channel name>
, simply set the MessageReceiver
’s MessageChannel
to the appropriate
channel using MessageReceiver#setMessageChannel(MessageChannel). This will cause every message sent from
the MessageReceiver
to be passed to the given MessageChannel
instead of the default one. Alternatively,
you could listen to MessageChannelEvent, and set the appropriate MessageChannel
using
MessageChannelEvent#setChannel(MessageChannel). Passing null
to that method will unset any custom
channel, causing the message to be sent to the original MessageChannel instead.
Nachrichten transformieren
You can apply a filter to all Text
s that pass through a MessageChannel
to change the message however you
like. This is possible by extending MessageChannel
and overriding the
MessageChannel#transformMessage(Object, MessageReceiver, Text, ChatType) method as demonstrated below.
Beispiel: Nachrichten transformieren
The following code excerpt defines an AdminMessageChannel
class which overrides the default transformMessage
method. The new transformMessage
method will take the original message and append a red [Admin]
tag to the
front of the 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();
}
}
Note that we do not wish to define any additional recipients, so we return an empty collection in the MessageChannel#getMembers() method.
Thanks to the capabilities of combined MessageChannel
s, we can combine our newly created AdminMessageChannel
with any other MessageChannel
. Now if a player joins with the myplugin.admin
permission, we will obtain the
MessageChannel
his messages are sent to, combine it with an AdminMessageChannel
and set the combined channel
back onto the player. That way all his messages are sent to everyone specified in the original channel, but due to the
addition of the AdminMessageChannel
, a red [Admin]
tag will be prefixed.
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);
}
}
Note that this will prefix all messages pertaining to a player. This includes death messages, leave messages, etc. If
you only want to prefix all chat messages, you would need to listen to MessageChannelEvent.Chat and set
the channel onto the event rather than the player. This would be done using event.setChannel(newChannel)
onto the
MessageChannelEvent.Chat
event. To get the player from the event to check for permissions, you would need to get a
Player
from the Cause
of the event. This is demonstrated below:
Optional<Player> playerOptional = event.getCause().<Player>first(Player.class);
More on causes can be found on the causes page.
Bemerkung
When combining multiple MessageChannel
s defining different message transformations, the Text
will be
transformed in the order that the MessageChannel
s are passed in to the
MessageChannel#combined(MessageChannel... channels)
method. Note that any transformations resulting in an
empty Optional
will be ignored unless performed by the last channel in the chain.
Veränderbare Nachrichten-Kanäle
A MutableMessageChannel contains methods for changing who may receive the messages sent through our channel.
As such, we must implement methods for performing actions that modify our members. To do this, we simply will create a
class named MutableAdminMessageChannel
that will implement a 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);
}
}
The main difference between our AdminMessageChannel
and our new MutableAdminMessageChannel
is that we check if
the recipient is in the member list before transforming the message. If it is, then we may alter the message that is
sent, appending the red [Admin]
prefix. In our getMembers()
method we return an immutable set, so that the set
can only be modified by the appropriate methods in our MutableAdminMessageChannel
.
Note that an abstract implementation for MutableMessageChannel
s exists in the Sponge API as
AbstractMutableMessageChannel
. Also note that our members do not persist. If a player were to leave the server,
they would be removed from the set.
Verändern der Teilnehmer
To make full use of our MutableAdminMessageChannel
, we need to be able to add and remove members from the channel.
To do this, we can simply call our MutableMessageChannel#addMember(MessageReceiver)
and MutableMessageChannel#removeMember(MessageReceiver) methods we implemented previously whenever we need
to add or remove a member from the member set.