Canales de Mensajes
En Sponge, todos los objetos a los que se envían mensajes implementan la interfaz MessageReceiver. Un MessageChannel es un dispositivo que puede enviar mensajes a un número arbitrario de MessageReceiver
s e incluso realizar acciones como destinatario específico del mensaje.
Selección de Destinatario de Mensajes
Dentro de la interfaz de MessageChannel
hay constantes y métodos estáticos que pueden ser utilizados para obtener o crear los canales utilizados comúnmente. Hay también otras clases e interfaces que pueden utilizarse para crear un MessageChannel
, como por ejemplo AbstractMutableMessageChannel y MutableMessageChannel. Una lista completa de esto puede encontrarse en org.spongepowered.api.text.channel y sus subpaquetes.
Transmisión
El canal más común será el canal de transmisión. Esto puede ser obtenido desde Server a través del método Server#getBroadcastChannel() o desde la constante MessageChannel#TO_PLAYERS o MessageChannel#TO_ALL. La única diferencia es que TO_ALL
incluye no solo a todos los jugadores conectados al servidor sino también a al servidor Consola
.
El canal devuelto por getBroadcastChannel()
generalmente será el canal MessageChannel.TO_ALL
, sin embargo un canal diferente puede establecerse utilizando el método Server#setBroadcastChannel(MessageChannel).
Envío a una Lista Fija de MessageReceivers
También es posible enviar un mensaje no a todos los jugadores conectados, sino a un número de destinatarios seleccionados a mano. Esto puede ser hecho pasando la lista de los destinatarios al método MessageChannel#fixed(MessageReceiver…). A diferencia de la mayoría de los otros canales, la lista de destinatarios no será generada dinámicamente cada vez que algo se envíe a través del canal sino que permanece estática por el resto de su existencia. Sin embargo, las referencias que se mantienen son débiles. Esto significa que si por ejemplo un jugador se desconecta y el correspondiente objeto Player es removido por el basurero de Java, ese jugador también desaparecerá de la lista de de destinatarios del canal.
Selección basada en Permisos
También es posible crear un envío de canal a todos los destinatarios que tienen un permiso específico. El canal es obtenido desde el método MessageChannel#permission(String) con el permiso para verificar como un argumento. Cuando un mensaje es enviado a través de este canal, se obtendrán todos los temas desde el PermissionService que tienen el permiso dado.
Combinación de Canales
También se pueden combinar múltiples canales en uno. Esto puede hacerse pasando todos los canales al método :javadoc:`MessageChannel#combined(MessageChannel…). El canal resultante retransmitirá los mensajes a cada destinatario que sea el objetivo de al menos uno de los canales combinados.
Envío de Mensajes
Una vez que ha obtenido un MessageChannel
puede enviar un mensaje a través del método MessageChannel#send(Object, Text). Este método es preferido sobre el método MessageChannel#send(Text), ya que el Objecto
puede ser utilizado para la identificación o para realizar otras acciones diferentes. Alternativamente, puede utilizar un ChatType para especificar a donde los mensajes serán enviados. Utilizando el método MessageChannel#send(Object, Text, ChatType) le permitirá lograr esto. El canal después transformará el mensaje para cada destinatarios y enviará el mensaje transformado.
Aplicación Extendida: Canales de Chat
Los canales de mensaje tienen una aplicación muy útil ya que pueden ser utilizados para establecer canales de chat. Por ejemplo, puede establecer un mensaje de chat para cada canal de chat que desee tener. Entonces, cuando un MessageReceiver
se une a un canal, como un /join <channel name>
, simplemente configure el MessageChannel
del MessageReceiver
en el canal apropiado utilizando MessageReceiver#setMessageChannel(MessageChannel). Esto causará que cada mensaje enviado desde el MessageReceiver
para ser pasado al MessageChannel
dado en lugar del predeterminado. Alternativamente, puede escuchar MessageChannelEvent, y configurar el apropiado MessageChannel
utilizando MessageChannelEvent#setChannel(MessageChannel). Pasarle nulo
a ese método desconfigurará cualquier canal personalizado, causando que el mensaje sea enviado al MessageChannel original en su lugar.
Transformación de Mensajes
Puede aplicar un filtro a todos los Texto
s que pasen a través de un MessageChannel
para cambiar el mensaje como prefiera. Esto es posible extendiendo el MessageChannel
y remplazando el método MessageChannel#transformMessage(Object, MessageReceiver, Text, ChatType) como se demostrará a continuación.
Ejemplo: Transformación de Mensajes
El siguiente fragmento de código define una clase de AdminMessageChannel
que reemplaza el método predeterminado transformMessage
. El nuevo método transformMessage
tomará el mensaje original y anexará una etiqueta roja [Admin]
al frente del mensaje.
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();
}
}
Tenga en cuenta que no se desea definir ningún destinatario adicional, por lo que devolveremos una colección vacía en el método MessageChannel#getMembers().
Gracias a las capacidades de combinar MessageChannel
s, podemos combinar nuestro recién creado AdminMessageChannel
con cualquier otro MessageChannel
. Ahora si un jugador se une con el permiso myplugin.admin
, obtendremos el MessageChannel
al que sus mensajes son enviados, lo combinaremos con un AdminMessageChannel
y estbleceremos el canal combinado de vuelta al jugador. De esa manera, todos sus mensajes son enviados a todas las personas especificadas en el canal original, pero debido a la adición del AdminMessageChannel
, una etiqueta roja [Admin]
será prefijada.
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);
}
}
Tenga en cuenta que serán prefijados los mensajes todos pertenecientes a un jugador. Esto incluye mensajes muertos, mensajes abandonados, etc. Si solo quiere prefijar todos los mensajes de chat, necesitará escuchar el MessageChannelEvent.Chat y establecer el canal en el evento en lugar del jugador. Esto se haría utilizando event.setChannel(newChannel)
en el evento MessageChannelEvent.Chat
. Para que el jugador del evento verifique los permisos, necesitará obtener un Jugador
de la Causa
del evento. Esto es demostrado a continuación:
Optional<Player> playerOptional = event.getCause().<Player>first(Player.class);
Más sobre causas puede encontrarlas en causes page.
Nota
Cuando se combinan múltiples MessageChannel
s definiendo diferentes transformaciones de mensajes, el Texto
será transformado en el orden en que los MessageChannel
s son transferidos al método MessageChannel#combined(MessageChannel... channels)
. Tenga en cuenta que cualquier transformación que resulte en un vacío Opcional
será ignorada a menos que sea realizada por el último canal en la cadena.
Canales de Mensajes Mutables
Un MutableMessageChannel contiene métodos para cambiar quien puede recibir mensajes enviados a través de nuestro canal. Como tal, debemos implementar métodos para la realización de acciones que modifiquen nuestros miembros. Para hacer esto, simplemente crearemos una clase llamada MutableAdminMessageChannel
que implementará 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 principal diferencia entre nuestro AdminMessageChannel
y nuestro nuevo MutableAdminMessageChannel
es que verificaremos si el destinatario está en la lista de miembros antes de transformar el mensaje. Si es así, podemos alterar el mensaje que es enviado, anexando el prefijo en rojo [Admin]
. En nuestro método getMembers()
devolvemos un conjunto inmutable, de modo que el conjunto puede ser modificado solo por el método apropiado en nuestro MutableAdminMessageChannel
.
Tenga en cuenta que una implementación abstracta para MutableMessageChannel
s existe en Sponge API como AbstractMutableMessageChannel
. También tenga en cuenta que nuestros miembros no persisten. Si un jugador abandona el servidor, sería removido del conjunto.
Modificación de los Miembros
Para hacer completo uso de nuestro MutableAdminMessageChannel
, debemos poder agregar y eliminar miembros del canal. Para hacer esto, podemos simplemente llamar a nuestros métodos MutableMessageChannel#addMember(MessageReceiver) y MutableMessageChannel#removeMember(MessageReceiver) que implementamos previamente cada vez que necesitamos agregar o eliminar un miembro del conjunto.