Каналы сообщений
В Sponge каждый объект, в который могут быть отправлены сообщения, реализует интерфейс MessageReceiver. MessageChannel — это устройство, которое может отправлять сообщения на любое количество MessageReceiver
-ов и даже выполнять такие действия, как форматирование сообщения, зависящее от получателя.
Выбор получателей сообщений
В интерфейсе MessageChannel
есть константы и статические методы, которые можно использовать для получения или создания часто используемых каналов. Существуют также другие классы и интерфейсы, которые могут быть использованы для создания MessageChannel
, такие как AbstractMutableMessageChannel и MutableMessageChannel. Полный список их можно найти в org.spongepowered.api.text.channel и его подпакетах.
Трансляция
Наиболее распространенным каналом будет канал вещания. Его можно получить либо из Server методом Server#getBroadcastChannel(), либо из константы MessageChannel#TO_PLAYERS или MessageChannel#TO_ALL. Единственное отличие состоит в том, что TO_ALL
включает в себя не только всех игроков, подключенных к серверу, но и сервер Console
.
Канал, возвращаемый getBroadcastChannel()
, обычно является каналом MessageChannel.TO_ALL
, однако другой канал может быть установлен методом Server#setBroadcastChannel(MessageChannel).
Отправка в фиксированный список MessageReceivers
Также возможно отправить сообщение не всем подключенным игрокам, а нескольким выбранным вручную получателям. Это можно сделать, передав список предполагаемых получателей методу MessageChannel#fixed(MessageReceiver…). В отличие от большинства других каналов, список получателей не будет генерироваться динамически каждый раз, когда что-то отправляется через канал, а остается статичным до конца его существования. Тем не менее, сохраненные ссылки слабы. Это означает, что если, например, игрок отключается и соответствующий объект Player удаляется сборщиком мусора Java, этот игрок также исчезает из списка получателей каналов.
Выбор на основе Permissions
Также возможно создать канал для отправки всем получателям, у которых есть специальное разрешение. Канал получается из метода MessageChannel#permission(String) с разрешением на проверку в качестве аргумента. Когда сообщение отправляется через этот канал, он получает все объекты из PermissionService, которые имеют данное разрешение.
Объединение каналов
Также возможно объединить несколько каналов в один. Это можно сделать, передав все каналы в метод MessageChannel#combined(MessageChannel…). Результирующий канал будет ретранслировать сообщения каждому получателю, на который нацелен по меньшей мере один из комбинированных каналов.
Отправка сообщений
После того, как вы получили MessageChannel
, вы можете отправить сообщение с помощью метода MessageChannel#send(Object, Text). Этот метод является предпочтительным по сравнению с методом MessageChannel#send(Text), поскольку Object
может использоваться для идентификации или для выполнения других различных действий. Кроме того, вы можете использовать ChatType, чтобы указать, куда будет отправлено сообщение. Использование метода MessageChannel#send(Object, Text, ChatType) позволит вам сделать это. Затем канал преобразует сообщение для каждого получателя и отправляет преобразованное сообщение.
Расширенное применение: Чат-каналы
Каналы сообщений имеют очень полезное применение, поскольку они могут быть использованы для создания чат-каналов. Например, вы можете установить канал сообщений для каждого чат-канала, который вы хотите. Затем, когда MessageReceiver
присоединяется к каналу, например, через /join <channel name>
, просто устанавливайте MessageChannel
MessageReceiver
-а на соответствующий канал, используя MessageReceiver#setMessageChannel(MessageChannel). Это приведет к тому, что каждое сообщение, отправленное из MessageReceiver
, будет передано данному MessageChannel
вместо значения по умолчанию. В качестве альтернативы, вы можете прослушивать MessageChannelEvent и устанавливать соответствующий MessageChannel
, используя MessageChannelEvent#setChannel(MessageChannel). Передача null
этому методу отключит любой пользовательский канал, в результате чего сообщение будет отправлено исходному MessageChannel.
Преобразование сообщений
Вы можете применить фильтр ко всем Text
-ам, которые проходят через MessageChannel
, чтобы изменить сообщение, как вам нравится. Это возможно за счёт расширения MessageChannel
и переопределения метода MessageChannel#transformMessage(Object, MessageReceiver, Text, ChatType), как показано ниже.
Пример: Преобразование сообщений
Следующий фрагмент кода определяет класс AdminMessageChannel
, который переопределяет метод transformMessage
. Новый метод transformMessage
примет исходное сообщение и добавит красный тег [Admin]
в начало сообщения.
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.chat.ChatType;
import org.spongepowered.api.text.format.TextColors;
public class AdminMessageChannel implements MessageChannel {
@Override
public Optional<Text> transformMessage(Object sender, MessageReceiver recipient,
Text original, ChatType type) {
Text text = original;
text = Text.of(TextColors.RED, "[Admin]", TextColors.RESET, text);
return Optional.of(text);
}
@Override
public Collection<MessageReceiver> getMembers() {
return Collections.emptyList();
}
}
Обратите внимание, что мы не хотим определять каких-либо дополнительных получателей, поэтому мы возвращаем пустую коллекцию в методе MessageChannel#getMembers().
Благодаря возможностям комбинированного MessageChannel
, мы можем объединить недавно созданный AdminMessageChannel
с любым другим MessageChannel
. Теперь, если игрок зашел на сервер с разрешением myplugin.admin
, мы получим его исходный `` MessageChannel``, объединим его с AdminMessageChannel
и устанавливают объединенный канал обратно игроку. Таким образом, все его сообщения отправляются всем, указанным в исходном канале, но из-за добавления AdminMessageChannel
, будет префикс с красным тегом [Admin]
.
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.network.ClientConnectionEvent;
import org.spongepowered.api.text.channel.MessageChannel;
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);
}
}
Обратите внимание, что это будет префикс всех сообщений, относящихся к игроку. Сюда входят сообщения о смерти, сообщения о выходе и т.д. Если Вам нужны префиксы только к сообщениям чата, Вам нужно будет прослушать MessageChannelEvent.Chat и установить канал на событие, а не на игрока. Это можно сделать при помощи event.setChannel(newChannel)
для события MessageChannelEvent.Chat
. Чтобы получить игрока из события для проверки разрешений, вам нужно будет получить Player
из Cause
события. Это показано ниже:
Optional<Player> playerOptional = event.getCause().<Player>first(Player.class);
Подробнее о причинах смотрите здесь.
Примечание
При объединении нескольких MessageChannel
, определяющих различные преобразования сообщений, Text
будет преобразован в том порядке, в котором MessageChannel
передается в метод MessageChannel#combined(MessageChannel... channels)
. Обратите внимание, что любые преобразования, приводящие к пустым Optional
, будут игнорироваться, если не будут выполнены последним каналом в цепочке.
Изменяемые Каналы Сообщений
MutableMessageChannel содержит методы для изменения того, кто может получать сообщения, отправленные через наш канал. Таким образом, мы должны реализовать методы для выполнения действий, которые изменяют наших пользователей. Для этого мы просто создадим класс с именем MutableAdminMessageChannel
, который реализует MutableMessageChannel
.
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.WeakHashMap;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.channel.MessageReceiver;
import org.spongepowered.api.text.channel.MutableMessageChannel;
import org.spongepowered.api.text.chat.ChatType;
import org.spongepowered.api.text.format.TextColors;
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, ChatType type) {
Text text = original;
if(this.members.contains(recipient)) {
text = Text.of(TextColors.RED, "[Admin]", TextColors.RESET, text);
}
return Optional.of(text);
}
}
Основное различие между нашим AdminMessageChannel
и нашим новым MutableAdminMessageChannel
заключается в том, что мы проверяем, находится ли получатель в списке членов перед преобразованием сообщения. Если это так, мы можем изменить отправленное сообщение, добавив красный префикс [Admin]
. В нашем методе getMembers()
мы возвращаем неизменяемый набор, так что набор может быть изменен только соответствующими методами в нашем MutableAdminMessageChannel
.
Note that an abstract implementation for MutableMessageChannel
s exists in SpongeAPI 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.
Изменение членов
Чтобы полностью использовать наш MutableAdminMessageChannel
, мы должны иметь возможность добавлять и удалять участников из канала. Для этого мы можем просто вызвать наш MutableMessageChannel#addMember(MessageReceiver) и MutableMessageChannel#removeMember(MessageReceiver) методы, которые мы реализовали ранее, когда нам нужно добавить или удалить пользователя из набора элементов.