Message Sinks¶
A MessageSink enables you to easily control the recipients of a message. The org.spongepowered.api.text.sink.MessageSinks utility class provides methods for targeting appropriate recipients, as described below.
Selecting Message Sink Recipients¶
Permission-based Selection¶
The MessageSinks class can be employed to target any player that holds the specified permission.
Example: Permission-based Targeting
For example, the code below will define a MessageSink targeting all players with the com.example.myplugin permission
import org.spongepowered.api.text.sink.MessageSink;
import org.spongepowered.api.text.sink.MessageSinks;
MessageSink permissionSink = MessageSinks.toPermission("com.example.myplugin");
Broadcasting¶
In a broadcast, every CommandSource connected to the server will be sent the same message. This can be achieved with a MessageSink, as shown below:
Example: Broadcasting
import org.spongepowered.api.text.sink.MessageSink;
import org.spongepowered.api.text.sink.MessageSinks;
MessageSink broadcastSink = MessageSinks.toAll();
Alternatively, you could retrieve the broadcast MessageSink provided by Sponge:
MessageSink broadcastSink = server.getBroadcastSink();
Combining Message Sinks¶
The MessageSinks class can also be used to combine the recipients of any arbitrary number of other MessageSinks:
Example: Combined Message Sinks
In the following block of code, any CommandSource that holds either the com.example.myplugin.permission1 or the com.example.myplugin.permission2 permissions will be targeted by the MessageSink.
import org.spongepowered.api.text.sink.MessageSink;
import org.spongepowered.api.text.sink.MessageSinks;
MessageSink sink1 = MessageSinks.toPermission("com.example.myplugin.permission1");
MessageSink sink2 = MessageSinks.toPermission("com.example.myplugin.permission2");
MessageSink combinedSink = MessageSinks.combined(sink1, sink2);
Tip
MessageSinks#combined(MessageSink... sinks) can also be used to apply message transformations, as discussed below.
Targeting Command Sources¶
Lastly, a MessageSink can be used to target any number of CommandSources. This allows a finer control over who you would like to send the message to.
Example: Targeting Command Sources
In the following example, any Player whose display name contains the prefix “[Donor]” will be added as a recipient to a new MessageSink, which could then be used to send a message thanking the players for their donations.
import java.util.HashSet;
import java.util.Set;
import org.spongepowered.api.data.manipulator.DisplayNameData;
import org.spongepowered.api.entity.player.Player;
import org.spongepowered.api.text.Texts;
import org.spongepowered.api.text.sink.MessageSink;
import org.spongepowered.api.text.sink.MessageSinks;
import org.spongepowered.api.util.command.CommandSource;
Set<CommandSource> donors = new HashSet<CommandSource>();
for(Player player: event.getGame().getServer().getOnlinePlayers()) {
DisplayNameData displayNameData = player.getDisplayNameData();
if(Texts.toPlain(displayNameData.getDisplayName()).contains("[Donor]")) {
donors.add(player);
}
}
MessageSink sink = MessageSinks.to(donors);
Sending Messages with Message Sinks¶
Once you have defined an appropriate MessageSink, you can use MessageSink#sendMessage(Text text) to send the message.
Example: Sending Messages with Message Sinks
messageSink.sendMessage(Texts.of("Yay! Message sinks!"));
Extended Application: Chat Channels¶
Message sinks have a very useful application that they can be used to establish chat channels. For example, you could establish a message sink for every chat channel you wish to have. Then, when a CommandSource joins a channel, such as with /join <channel name>, simply set the CommandSource‘s MessageSink to the appropriate channel using CommandSource#setMessageSink(MessageSink sink). Alternatively, you could listen to MessageSinkEvent, and set the appropriate MessageSink using MessageEvent#setSink(MessageSink sink).
Transforming Messages with Message Sinks¶
You can apply a filter to all Texts that pass through a MessageSink to change the message however you like. This is possible by creating a Class that extends MessageSink and defining the appropriate behavior for the MessageSink#transformMessage(CommandSource target, Text text) method, as shown below.
Example: Transforming Messages with Message Sinks
The following code excerpt defines a DonorMessageSink class which overrides the default transformMessage method. The new transformation method will first check if the CommandSource has the com.example.myplugin.donor permission, and if so, will append a [Donor] prefix, such as in a ranking system.
import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.Texts;
import org.spongepowered.api.text.format.TextColors;
import org.spongepowered.api.text.sink.MessageSink;
import org.spongepowered.api.util.command.CommandSource;
import com.google.common.collect.Lists;
public class DonorMessageSink extends MessageSink {
@Override
public Text transformMessage(CommandSource target, Text input) {
if(target.hasPermission("com.example.myplugin.donor")) {
return Texts.of("[Donor]", input);
}
return input;
}
@Override
public Iterable<CommandSource> getRecipients() {
return Lists.newArrayList();
}
}
Note that we do not wish to define any additional reecipients, so we return an empty List in the getRecipients method.
Now that we have defined our custom DonorMessageSink that will append a prefix to a player’s name, we need to apply a new MessageSink combining the existing one and the new one to the CommandSource. We can do this by using the MessageSinks#combined(MessageSink... sinks) method. In the following code excerpt, the new DonorMessageSink will be applied to any Player that joins the server.
import org.spongepowered.api.entity.player.Player;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.network.ClientConnectionEvent;
import org.spongepowered.api.text.sink.MessageSink;
import org.spongepowered.api.text.sink.MessageSinks;
@Listener
public void onClientConnectionJoin(ClientConnectionEvent.Join event) {
Player player = event.getEntity();
MessageSink originalSink = player.getMessageSink();
MessageSink newSink = MessageSinks.combined(originalSink, new DonorMessageSink());
player.setMessageSink(newSink);
}
Note
When combining multiple MessageSinks defining different message transformations, the Text will be transformed in the order that the MessageSinks are passed in to the MessageSinks#combined(MessageSink... sinks) method.