/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package pluginbase.sponge.messaging;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.command.source.ConsoleSource;
import org.spongepowered.api.text.Text;
import pluginbase.messages.BundledMessage;
import pluginbase.messages.ChatColor;
import pluginbase.messages.Message;
import pluginbase.messages.MessageProvider;
import pluginbase.messages.Messages;
import pluginbase.messages.messaging.MessageReceiver;
import pluginbase.messages.messaging.Messager;
import java.util.LinkedList;
import java.util.List;
/**
* A Sponge specific implementation of {@link pluginbase.messages.messaging.Messager}.
* <p/>
* Provides word wrapping on messages too long to fit on one line.
* <p/>
* Please refer to {@link pluginbase.messages.messaging.Messager} for javadoc for the methods in this class. This class merely adds
* convenience methods for Sponge CommandSenders.
*/
public class SpongeMessager extends Messager {
/**
* Creates a new messager backed by the given message provider.
*
* @param provider the backing message provider.
*/
protected SpongeMessager(@NotNull final MessageProvider provider) {
super(provider);
}
/** {@inheritDoc} */
@Override
public void message(@NotNull final MessageReceiver sender, @NotNull final String message) {
sendMessages(sender, WordWrapper.wrapWords(message));
}
protected void send(@NotNull final CommandSource sender,
@Nullable final String prefix,
@NotNull final Message message,
@NotNull final Object... args) {
String string = getLocalizedMessage(message, args);
if (prefix != null && !prefix.isEmpty()) {
string = prefix + " " + string;
}
message(sender, string);
}
public void message(@NotNull final CommandSource sender, @NotNull final String message) {
sendMessages(sender, WordWrapper.wrapWords(message));
}
public void message(@NotNull final CommandSource sender, @NotNull final Message message, @NotNull final Object... args) {
send(sender, "", message, args);
}
public void message(@NotNull final CommandSource sender, @NotNull final BundledMessage message) {
message(sender, message.getMessage(), message.getArgs());
}
public void message(@NotNull final CommandSource player, @NotNull final List<String> messages) {
for (String s : messages) {
player.sendMessage(Text.of(s));
}
}
public void messageSuccess(@NotNull final CommandSource sender, @NotNull final Message message, @NotNull final Object... args) {
send(sender, getLocalizedMessage(Messages.SUCCESS), message, args);
}
public void messageSuccess(@NotNull final CommandSource sender, @NotNull final BundledMessage message) {
send(sender, getLocalizedMessage(Messages.SUCCESS), message.getMessage(), message.getArgs());
}
public void messageSuccess(@NotNull final CommandSource sender, @NotNull final String message) {
message(sender, getLocalizedMessage(Messages.SUCCESS) + " " + message);
}
public void messageError(@NotNull final CommandSource sender, @NotNull final Message message, @NotNull final Object... args) {
send(sender, getLocalizedMessage(Messages.ERROR), message, args);
}
public void messageError(@NotNull final CommandSource sender, @NotNull final BundledMessage message) {
send(sender, getLocalizedMessage(Messages.ERROR), message.getMessage(), message.getArgs());
}
public void messageError(@NotNull final CommandSource sender, @NotNull final String message) {
message(sender, getLocalizedMessage(Messages.ERROR) + " " + message);
}
protected void sendMessages(@NotNull final CommandSource player, @NotNull final String[] messages) {
for (String message : messages) {
player.sendMessage(Text.of(message));
}
}
public void messageAndLog(@NotNull final CommandSource sender, @NotNull final Message message, @NotNull final Object... args) {
if (!(sender instanceof ConsoleSource)) {
message(sender, message, args);
}
getLog().info(getLocalizedMessage(message, args));
}
private static class WordWrapper {
static final int CHAT_WIDTH = 55;
static String[] wrapWords(@NotNull String rawString) {
// A string shorter than the lineWidth is a single line
if (rawString.length() <= CHAT_WIDTH && !rawString.contains("\n")) {
return new String[] {rawString};
}
char[] rawChars = rawString.toCharArray();
StringBuilder word = new StringBuilder();
StringBuilder line = new StringBuilder();
List<String> lines = new LinkedList<String>();
int lineColorChars = 0;
for (int i = 0; i < rawChars.length; i++) {
char c = rawChars[i];
// skip chat color modifiers
if (c == ChatColor.COLOR_CHAR) {
word.append(ChatColor.getByChar(rawChars[i + 1]));
lineColorChars += 2;
i++; // Eat the next character as we have already processed it
continue;
}
if (c == ' ' || c == '\n') {
if (line.length() == 0 && word.length() > CHAT_WIDTH) { // special case: extremely long word begins a line
for (String partialWord : word.toString().split("(?<=\\G.{" + CHAT_WIDTH + "})")) {
lines.add(partialWord);
}
} else if (line.length() + word.length() - lineColorChars == CHAT_WIDTH) { // Line exactly the correct length...newline
line.append(word);
lines.add(line.toString());
line = new StringBuilder();
lineColorChars = 0;
} else if (line.length() + 1 + word.length() - lineColorChars > CHAT_WIDTH) { // Line too long...break the line
for (String partialWord : word.toString().split("(?<=\\G.{" + CHAT_WIDTH + "})")) {
lines.add(line.toString());
line = new StringBuilder(partialWord);
}
lineColorChars = 0;
} else {
if (line.length() > 0) {
line.append(' ');
}
line.append(word);
}
word = new StringBuilder();
if (c == '\n') { // Newline forces the line to flush
lines.add(line.toString());
line = new StringBuilder();
}
} else {
word.append(c);
}
}
if(line.length() > 0) { // Only add the last line if there is anything to add
lines.add(line.toString());
}
// Iterate over the wrapped lines, applying the last color from one line to the beginning of the next
if (lines.get(0).length() == 0 || lines.get(0).charAt(0) != ChatColor.COLOR_CHAR) {
lines.set(0, ChatColor.WHITE + lines.get(0));
}
for (int i = 1; i < lines.size(); i++) {
final String pLine = lines.get(i-1);
final String subLine = lines.get(i);
char color = pLine.charAt(pLine.lastIndexOf(ChatColor.COLOR_CHAR) + 1);
if (subLine.length() == 0 || subLine.charAt(0) != ChatColor.COLOR_CHAR) {
lines.set(i, ChatColor.getByChar(color) + subLine);
}
}
return lines.toArray(new String[lines.size()]);
}
}
}