Rework Mail System (#3710)

* New `/mail sendtemp <time diff> <message>` command to send mail that will self-destruct after time diff.
* New `/mail clear <number>` command to clear a specific mail item.
* `/mail read` now tracks which mails you read and won't nag you about them.
* A bunch of other flexibility since we store actual data instead of strings
This commit is contained in:
Josh Roy 2021-07-01 11:23:32 -04:00 committed by GitHub
parent 55db6c2476
commit 9c451271e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 622 additions and 65 deletions

View File

@ -6,6 +6,8 @@ import org.bukkit.Server;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.UUID;
import static com.earth2me.essentials.I18n.tl; import static com.earth2me.essentials.I18n.tl;
public final class Console implements IMessageRecipient { public final class Console implements IMessageRecipient {
@ -46,6 +48,11 @@ public final class Console implements IMessageRecipient {
return Console.NAME; return Console.NAME;
} }
@Override
public UUID getUUID() {
return null;
}
@Override @Override
public String getDisplayName() { public String getDisplayName() {
return Console.DISPLAY_NAME; return Console.DISPLAY_NAME;

View File

@ -82,6 +82,7 @@ import net.ess3.provider.providers.PaperRecipeBookListener;
import net.ess3.provider.providers.PaperSerializationProvider; import net.ess3.provider.providers.PaperSerializationProvider;
import net.ess3.provider.providers.PaperServerStateProvider; import net.ess3.provider.providers.PaperServerStateProvider;
import net.essentialsx.api.v2.services.BalanceTop; import net.essentialsx.api.v2.services.BalanceTop;
import net.essentialsx.api.v2.services.mail.MailService;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.World; import org.bukkit.World;
@ -147,6 +148,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
private transient UserMap userMap; private transient UserMap userMap;
private transient BalanceTopImpl balanceTop; private transient BalanceTopImpl balanceTop;
private transient ExecuteTimer execTimer; private transient ExecuteTimer execTimer;
private transient MailService mail;
private transient I18n i18n; private transient I18n i18n;
private transient MetricsWrapper metrics; private transient MetricsWrapper metrics;
private transient EssentialsTimer timer; private transient EssentialsTimer timer;
@ -204,6 +206,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
LOGGER.log(Level.INFO, tl("usingTempFolderForTesting")); LOGGER.log(Level.INFO, tl("usingTempFolderForTesting"));
LOGGER.log(Level.INFO, dataFolder.toString()); LOGGER.log(Level.INFO, dataFolder.toString());
settings = new Settings(this); settings = new Settings(this);
mail = new MailServiceImpl(this);
userMap = new UserMap(this); userMap = new UserMap(this);
balanceTop = new BalanceTopImpl(this); balanceTop = new BalanceTopImpl(this);
permissionsHandler = new PermissionsHandler(this, false); permissionsHandler = new PermissionsHandler(this, false);
@ -277,6 +280,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
confList.add(settings); confList.add(settings);
execTimer.mark("Settings"); execTimer.mark("Settings");
mail = new MailServiceImpl(this);
execTimer.mark("Init(Mail)");
userMap = new UserMap(this); userMap = new UserMap(this);
confList.add(userMap); confList.add(userMap);
execTimer.mark("Init(Usermap)"); execTimer.mark("Init(Usermap)");
@ -1159,6 +1165,11 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return timer; return timer;
} }
@Override
public MailService getMail() {
return mail;
}
@Override @Override
public List<String> getVanishedPlayers() { public List<String> getVanishedPlayers() {
return Collections.unmodifiableList(new ArrayList<>(vanishedPlayers)); return Collections.unmodifiableList(new ArrayList<>(vanishedPlayers));

View File

@ -364,8 +364,7 @@ public class EssentialsPlayerListener implements Listener {
} }
if (!ess.getSettings().isCommandDisabled("mail") && user.isAuthorized("essentials.mail")) { if (!ess.getSettings().isCommandDisabled("mail") && user.isAuthorized("essentials.mail")) {
final List<String> mail = user.getMails(); if (user.getUnreadMailAmount() == 0) {
if (mail.isEmpty()) {
if (ess.getSettings().isNotifyNoNewMail()) { if (ess.getSettings().isNotifyNoNewMail()) {
user.sendMessage(tl("noNewMail")); // Only notify if they want us to. user.sendMessage(tl("noNewMail")); // Only notify if they want us to.
} }

View File

@ -7,7 +7,9 @@ import com.earth2me.essentials.craftbukkit.BanLookup;
import com.earth2me.essentials.utils.StringUtil; import com.earth2me.essentials.utils.StringUtil;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.gson.reflect.TypeToken;
import net.ess3.api.IEssentials; import net.ess3.api.IEssentials;
import net.essentialsx.api.v2.services.mail.MailMessage;
import org.bukkit.BanList; import org.bukkit.BanList;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -146,6 +148,46 @@ public class EssentialsUpgrade {
ess.getLogger().info("To rerun the conversion type /essentials uuidconvert"); ess.getLogger().info("To rerun the conversion type /essentials uuidconvert");
} }
public void convertMailList() {
if (doneFile.getBoolean("updateUsersMailList", false)) {
return;
}
final File userdataFolder = new File(ess.getDataFolder(), "userdata");
if (!userdataFolder.exists() || !userdataFolder.isDirectory()) {
return;
}
final File[] userFiles = userdataFolder.listFiles();
for (File file : userFiles) {
if (!file.isFile() || !file.getName().endsWith(".yml")) {
continue;
}
final EssentialsConfiguration config = new EssentialsConfiguration(file);
try {
config.load();
if (config.hasProperty("mail") && config.isList("mail")) {
final ArrayList<MailMessage> messages = new ArrayList<>();
for (String mailStr : Collections.synchronizedList(config.getList("mail", String.class))) {
if (mailStr == null) {
continue;
}
messages.add(new MailMessage(false, true, null, null, 0L, 0L, mailStr));
}
config.removeProperty("mail");
config.setExplicitList("mail", messages, new TypeToken<List<MailMessage>>() {}.getType());
config.blockingSave();
}
} catch (RuntimeException ex) {
LOGGER.log(Level.INFO, "File: " + file);
throw ex;
}
}
doneFile.setProperty("updateUsersMailList", true);
doneFile.save();
LOGGER.info("Done converting mail list.");
}
public void convertStupidCamelCaseUserdataKeys() { public void convertStupidCamelCaseUserdataKeys() {
if (doneFile.getBoolean("updateUsersLegacyPathNames", false)) { if (doneFile.getBoolean("updateUsersLegacyPathNames", false)) {
return; return;
@ -820,5 +862,6 @@ public class EssentialsUpgrade {
repairUserMap(); repairUserMap();
convertIgnoreList(); convertIgnoreList();
convertStupidCamelCaseUserdataKeys(); convertStupidCamelCaseUserdataKeys();
convertMailList();
} }
} }

View File

@ -18,6 +18,7 @@ import net.ess3.provider.SpawnerBlockProvider;
import net.ess3.provider.SpawnerItemProvider; import net.ess3.provider.SpawnerItemProvider;
import net.ess3.provider.SyncCommandsProvider; import net.ess3.provider.SyncCommandsProvider;
import net.essentialsx.api.v2.services.BalanceTop; import net.essentialsx.api.v2.services.BalanceTop;
import net.essentialsx.api.v2.services.mail.MailService;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.command.Command; import org.bukkit.command.Command;
@ -120,6 +121,8 @@ public interface IEssentials extends Plugin {
EssentialsTimer getTimer(); EssentialsTimer getTimer();
MailService getMail();
/** /**
* Get a list of players who are vanished. * Get a list of players who are vanished.
* *

View File

@ -6,12 +6,15 @@ import com.earth2me.essentials.config.entities.CommandCooldown;
import net.ess3.api.ITeleport; import net.ess3.api.ITeleport;
import net.ess3.api.MaxMoneyException; import net.ess3.api.MaxMoneyException;
import net.ess3.api.events.AfkStatusChangeEvent; import net.ess3.api.events.AfkStatusChangeEvent;
import net.essentialsx.api.v2.services.mail.MailMessage;
import net.essentialsx.api.v2.services.mail.MailSender;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -148,10 +151,22 @@ public interface IUser {
String getFormattedJailTime(); String getFormattedJailTime();
@Deprecated
List<String> getMails(); List<String> getMails();
@Deprecated
void addMail(String mail); void addMail(String mail);
void sendMail(MailSender sender, String message);
void sendMail(MailSender sender, String message, long expireAt);
ArrayList<MailMessage> getMailMessages();
void setMailList(ArrayList<MailMessage> messages);
int getMailAmount();
boolean isAfk(); boolean isAfk();
@Deprecated @Deprecated

View File

@ -0,0 +1,53 @@
package com.earth2me.essentials;
import net.ess3.api.IUser;
import net.essentialsx.api.v2.services.mail.MailService;
import net.essentialsx.api.v2.services.mail.MailMessage;
import net.essentialsx.api.v2.services.mail.MailSender;
import org.bukkit.plugin.ServicePriority;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import static com.earth2me.essentials.I18n.tl;
public class MailServiceImpl implements MailService {
private final transient ThreadLocal<SimpleDateFormat> df = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy/MM/dd HH:mm"));
public MailServiceImpl(IEssentials ess) {
ess.getServer().getServicesManager().register(MailService.class, this, ess, ServicePriority.Normal);
}
@Override
public void sendMail(IUser recipient, MailSender sender, String message) {
sendMail(recipient, sender, message, 0L);
}
@Override
public void sendMail(IUser recipient, MailSender sender, String message, long expireAt) {
sendMail(recipient, new MailMessage(false, false, sender.getName(), sender.getUUID(), System.currentTimeMillis(), expireAt, message));
}
@Override
public void sendLegacyMail(IUser recipient, String message) {
sendMail(recipient, new MailMessage(false, true, null, null, 0L, 0L, message));
}
private void sendMail(IUser recipient, MailMessage message) {
final ArrayList<MailMessage> messages = recipient.getMailMessages();
messages.add(0, message);
recipient.setMailList(messages);
}
@Override
public String getMailLine(MailMessage mail) {
final String message = mail.getMessage();
if (mail.isLegacy()) {
return tl("mailMessage", message);
}
final String expire = mail.getTimeExpire() != 0 ? "Timed" : "";
return tl((mail.isRead() ? "mailFormatNewRead" : "mailFormatNew") + expire, df.get().format(new Date(mail.getTimeSent())), mail.getSenderUsername(), message);
}
}

View File

@ -5,11 +5,11 @@ import com.earth2me.essentials.economy.EconomyLayer;
import com.earth2me.essentials.economy.EconomyLayers; import com.earth2me.essentials.economy.EconomyLayers;
import com.earth2me.essentials.messaging.IMessageRecipient; import com.earth2me.essentials.messaging.IMessageRecipient;
import com.earth2me.essentials.messaging.SimpleMessageRecipient; import com.earth2me.essentials.messaging.SimpleMessageRecipient;
import com.earth2me.essentials.utils.TriState;
import com.earth2me.essentials.utils.DateUtil; import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.EnumUtil; import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.FormatUtil; import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.NumberUtil; import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.TriState;
import com.earth2me.essentials.utils.VersionUtil; import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import net.ess3.api.IEssentials; import net.ess3.api.IEssentials;
@ -19,6 +19,7 @@ import net.ess3.api.events.JailStatusChangeEvent;
import net.ess3.api.events.MuteStatusChangeEvent; import net.ess3.api.events.MuteStatusChangeEvent;
import net.ess3.api.events.UserBalanceUpdateEvent; import net.ess3.api.events.UserBalanceUpdateEvent;
import net.essentialsx.api.v2.events.TransactionEvent; import net.essentialsx.api.v2.events.TransactionEvent;
import net.essentialsx.api.v2.services.mail.MailSender;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Statistic; import org.bukkit.Statistic;
@ -987,6 +988,11 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return this.getBase().getName(); return this.getBase().getName();
} }
@Override
public UUID getUUID() {
return getBase().getUniqueId();
}
@Override @Override
public boolean isReachable() { public boolean isReachable() {
return getBase().isOnline(); return getBase().isOnline();
@ -1054,12 +1060,28 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
} }
} }
@Override
public void sendMail(MailSender sender, String message) {
sendMail(sender, message, 0);
}
@Override
public void sendMail(MailSender sender, String message, long expireAt) {
ess.getMail().sendMail(this, sender, message, expireAt);
}
@Override
@Deprecated
public void addMail(String mail) {
ess.getMail().sendLegacyMail(this, mail);
}
public void notifyOfMail() { public void notifyOfMail() {
final List<String> mails = getMails(); final int unread = getUnreadMailAmount();
if (mails != null && !mails.isEmpty()) { if (unread != 0) {
final int notifyPlayerOfMailCooldown = ess.getSettings().getNotifyPlayerOfMailCooldown() * 1000; final int notifyPlayerOfMailCooldown = ess.getSettings().getNotifyPlayerOfMailCooldown() * 1000;
if (System.currentTimeMillis() - lastNotifiedAboutMailsMs >= notifyPlayerOfMailCooldown) { if (System.currentTimeMillis() - lastNotifiedAboutMailsMs >= notifyPlayerOfMailCooldown) {
sendMessage(tl("youHaveNewMail", mails.size())); sendMessage(tl("youHaveNewMail", unread));
lastNotifiedAboutMailsMs = System.currentTimeMillis(); lastNotifiedAboutMailsMs = System.currentTimeMillis();
} }
} }

View File

@ -10,6 +10,8 @@ import com.earth2me.essentials.utils.StringUtil;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import net.ess3.api.IEssentials; import net.ess3.api.IEssentials;
import net.ess3.api.MaxMoneyException; import net.ess3.api.MaxMoneyException;
import net.essentialsx.api.v2.services.mail.MailMessage;
import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -313,17 +315,59 @@ public abstract class UserData extends PlayerExtension implements IConf {
config.save(); config.save();
} }
/**
* @deprecated Mails are no longer just strings, this method is therefore misleading.
*/
@Deprecated
public List<String> getMails() { public List<String> getMails() {
return holder.mail(); final List<String> list = new ArrayList<>();
if (getMailAmount() != 0) {
for (MailMessage mail : getMailMessages()) {
// I hate this code btw
list.add(mail.isLegacy() ? mail.getMessage() : ChatColor.GOLD + "[" + ChatColor.RESET + mail.getSenderUsername() + ChatColor.GOLD + "] " + ChatColor.RESET + mail.getMessage());
}
}
return list;
} }
/**
* @deprecated This method does not support the new mail system and will fail at runtime.
*/
@Deprecated
public void setMails(List<String> mails) { public void setMails(List<String> mails) {
holder.mail(mails); throw new UnsupportedOperationException("UserData#setMails(List<String>) is deprecated and can no longer be used. Please tell the plugin author to update this!");
config.save();
} }
public void addMail(final String mail) { public int getMailAmount() {
holder.mail().add(mail); return holder.mail() == null ? 0 : holder.mail().size();
}
public int getUnreadMailAmount() {
if (holder.mail() == null || holder.mail().isEmpty()) {
return 0;
}
int unread = 0;
for (MailMessage element : holder.mail()) {
if (!element.isRead()) {
unread++;
}
}
return unread;
}
/**
* @deprecated This method does not support the new mail system and should not be used.
*/
@Deprecated
abstract void addMail(final String mail);
public ArrayList<MailMessage> getMailMessages() {
return new ArrayList<>(holder.mail());
}
public void setMailList(ArrayList<MailMessage> messages) {
holder.mail(messages);
config.save(); config.save();
} }

View File

@ -1,18 +1,23 @@
package com.earth2me.essentials.commands; package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource; import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Console;
import com.earth2me.essentials.User; import com.earth2me.essentials.User;
import com.earth2me.essentials.textreader.IText; import com.earth2me.essentials.messaging.IMessageRecipient;
import com.earth2me.essentials.textreader.SimpleTextInput; import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.textreader.TextPager; import com.earth2me.essentials.textreader.TextPager;
import com.earth2me.essentials.utils.DateUtil; import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.FormatUtil; import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil; import com.earth2me.essentials.utils.StringUtil;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import net.essentialsx.api.v2.services.mail.MailMessage;
import org.bukkit.Server; import org.bukkit.Server;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.ListIterator;
import java.util.UUID; import java.util.UUID;
import static com.earth2me.essentials.I18n.tl; import static com.earth2me.essentials.I18n.tl;
@ -28,17 +33,35 @@ public class Commandmail extends EssentialsCommand {
@Override @Override
public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception { public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
if (args.length >= 1 && "read".equalsIgnoreCase(args[0])) { if (args.length >= 1 && "read".equalsIgnoreCase(args[0])) {
final List<String> mail = user.getMails(); final ArrayList<MailMessage> mail = user.getMailMessages();
if (mail.isEmpty()) { if (mail == null || mail.size() == 0) {
user.sendMessage(tl("noMail"));
throw new NoChargeException();
}
final SimpleTextInput input = new SimpleTextInput();
final ListIterator<MailMessage> iterator = mail.listIterator();
while (iterator.hasNext()) {
final MailMessage mailObj = iterator.next();
if (mailObj.isExpired()) {
iterator.remove();
continue;
}
input.addLine(ess.getMail().getMailLine(mailObj));
iterator.set(new MailMessage(true, mailObj.isLegacy(), mailObj.getSenderUsername(),
mailObj.getSenderUUID(), mailObj.getTimeSent(), mailObj.getTimeExpire(), mailObj.getMessage()));
}
if (input.getLines().isEmpty()) {
user.sendMessage(tl("noMail")); user.sendMessage(tl("noMail"));
throw new NoChargeException(); throw new NoChargeException();
} }
final IText input = new SimpleTextInput(mail);
final TextPager pager = new TextPager(input); final TextPager pager = new TextPager(input);
pager.showPage(args.length > 1 ? args[1] : null, null, commandLabel + " " + args[0], user.getSource()); pager.showPage(args.length > 1 ? args[1] : null, null, commandLabel + " " + args[0], user.getSource());
user.sendMessage(tl("mailClear")); user.sendMessage(tl("mailClear"));
user.setMailList(mail);
return; return;
} }
if (args.length >= 3 && "send".equalsIgnoreCase(args[0])) { if (args.length >= 3 && "send".equalsIgnoreCase(args[0])) {
@ -61,8 +84,8 @@ public class Commandmail extends EssentialsCommand {
throw new Exception(tl("playerNeverOnServer", args[1])); throw new Exception(tl("playerNeverOnServer", args[1]));
} }
final String mail = tl("mailFormat", user.getName(), FormatUtil.formatMessage(user, "essentials.mail", StringUtil.sanitizeString(FormatUtil.stripFormat(getFinalArg(args, 2))))); final String msg = FormatUtil.formatMessage(user, "essentials.mail", StringUtil.sanitizeString(FormatUtil.stripFormat(getFinalArg(args, 2))));
if (mail.length() > 1000) { if (msg.length() > 1000) {
throw new Exception(tl("mailTooLong")); throw new Exception(tl("mailTooLong"));
} }
@ -75,29 +98,87 @@ public class Commandmail extends EssentialsCommand {
if (mailsPerMinute > ess.getSettings().getMailsPerMinute()) { if (mailsPerMinute > ess.getSettings().getMailsPerMinute()) {
throw new Exception(tl("mailDelay", ess.getSettings().getMailsPerMinute())); throw new Exception(tl("mailDelay", ess.getSettings().getMailsPerMinute()));
} }
u.addMail(tl("mailMessage", mail)); u.sendMail(user, msg);
} }
user.sendMessage(tl("mailSentTo", u.getDisplayName(), u.getName())); user.sendMessage(tl("mailSentTo", u.getDisplayName(), u.getName()));
user.sendMessage(mail); user.sendMessage(msg);
return;
}
if (args.length >= 4 && "sendtemp".equalsIgnoreCase(args[0])) {
if (!user.isAuthorized("essentials.mail.sendtemp")) {
throw new Exception(tl("noPerm", "essentials.mail.sendtemp"));
}
if (user.isMuted()) {
final String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReason", user.getMuteReason()) : tl("voiceSilenced"));
}
throw new Exception(user.hasMuteReason() ? tl("voiceSilencedReasonTime", dateDiff, user.getMuteReason()) : tl("voiceSilencedTime", dateDiff));
}
final User u;
try {
u = getPlayer(server, args[1], true, true);
} catch (final PlayerNotFoundException e) {
throw new Exception(tl("playerNeverOnServer", args[1]));
}
final long dateDiff = DateUtil.parseDateDiff(args[2], true);
final String msg = FormatUtil.formatMessage(user, "essentials.mail", StringUtil.sanitizeString(FormatUtil.stripFormat(getFinalArg(args, 3))));
if (msg.length() > 1000) {
throw new Exception(tl("mailTooLong"));
}
if (!u.isIgnoredPlayer(user)) {
if (Math.abs(System.currentTimeMillis() - timestamp) > 60000) {
timestamp = System.currentTimeMillis();
mailsPerMinute = 0;
}
mailsPerMinute++;
if (mailsPerMinute > ess.getSettings().getMailsPerMinute()) {
throw new Exception(tl("mailDelay", ess.getSettings().getMailsPerMinute()));
}
u.sendMail(user, msg, dateDiff);
}
user.sendMessage(tl("mailSentToExpire", u.getDisplayName(), DateUtil.formatDateDiff(dateDiff), u.getName()));
user.sendMessage(msg);
return; return;
} }
if (args.length > 1 && "sendall".equalsIgnoreCase(args[0])) { if (args.length > 1 && "sendall".equalsIgnoreCase(args[0])) {
if (!user.isAuthorized("essentials.mail.sendall")) { if (!user.isAuthorized("essentials.mail.sendall")) {
throw new Exception(tl("noPerm", "essentials.mail.sendall")); throw new Exception(tl("noPerm", "essentials.mail.sendall"));
} }
ess.runTaskAsynchronously(new SendAll(tl("mailFormat", user.getName(), ess.runTaskAsynchronously(new SendAll(user, FormatUtil.formatMessage(user, "essentials.mail", StringUtil.sanitizeString(FormatUtil.stripFormat(getFinalArg(args, 1))))));
FormatUtil.formatMessage(user, "essentials.mail", StringUtil.sanitizeString(FormatUtil.stripFormat(getFinalArg(args, 1)))))));
user.sendMessage(tl("mailSent")); user.sendMessage(tl("mailSent"));
return; return;
} }
if (args.length >= 1 && "clear".equalsIgnoreCase(args[0])) { if (args.length >= 1 && "clear".equalsIgnoreCase(args[0])) {
if (user.getMails() == null || user.getMails().isEmpty()) { final ArrayList<MailMessage> mails = user.getMailMessages();
if (mails == null || mails.size() == 0) {
user.sendMessage(tl("noMail")); user.sendMessage(tl("noMail"));
throw new NoChargeException(); throw new NoChargeException();
} }
user.setMails(null); if (args.length > 1) {
if (!NumberUtil.isPositiveInt(args[1])) {
throw new NotEnoughArgumentsException();
}
final int toRemove = Integer.parseInt(args[1]);
if (toRemove > mails.size()) {
user.sendMessage(tl("mailClearIndex", mails.size()));
return;
}
mails.remove(toRemove - 1);
user.setMailList(mails);
} else {
user.setMailList(null);
}
user.sendMessage(tl("mailCleared")); user.sendMessage(tl("mailCleared"));
return; return;
} }
@ -117,11 +198,22 @@ public class Commandmail extends EssentialsCommand {
} catch (final PlayerNotFoundException e) { } catch (final PlayerNotFoundException e) {
throw new Exception(tl("playerNeverOnServer", args[1])); throw new Exception(tl("playerNeverOnServer", args[1]));
} }
u.addMail(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 2)))); u.sendMail(Console.getInstance(), FormatUtil.replaceFormat(getFinalArg(args, 2)));
sender.sendMessage(tl("mailSent"));
return;
} else if (args.length >= 4 && "sendtemp".equalsIgnoreCase(args[0])) {
final User u;
try {
u = getPlayer(server, args[1], true, true);
} catch (final PlayerNotFoundException e) {
throw new Exception(tl("playerNeverOnServer", args[1]));
}
final long dateDiff = DateUtil.parseDateDiff(args[2], true);
u.sendMail(Console.getInstance(), FormatUtil.replaceFormat(getFinalArg(args, 3)), dateDiff);
sender.sendMessage(tl("mailSent")); sender.sendMessage(tl("mailSent"));
return; return;
} else if (args.length >= 2 && "sendall".equalsIgnoreCase(args[0])) { } else if (args.length >= 2 && "sendall".equalsIgnoreCase(args[0])) {
ess.runTaskAsynchronously(new SendAll(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 1))))); ess.runTaskAsynchronously(new SendAll(Console.getInstance(), FormatUtil.replaceFormat(getFinalArg(args, 1))));
sender.sendMessage(tl("mailSent")); sender.sendMessage(tl("mailSent"));
return; return;
} else if (args.length >= 2) { } else if (args.length >= 2) {
@ -132,13 +224,33 @@ public class Commandmail extends EssentialsCommand {
} catch (final PlayerNotFoundException e) { } catch (final PlayerNotFoundException e) {
throw new Exception(tl("playerNeverOnServer", args[0])); throw new Exception(tl("playerNeverOnServer", args[0]));
} }
u.addMail(tl("mailFormat", "Server", FormatUtil.replaceFormat(getFinalArg(args, 1)))); u.sendMail(Console.getInstance(), FormatUtil.replaceFormat(getFinalArg(args, 1)));
sender.sendMessage(tl("mailSent")); sender.sendMessage(tl("mailSent"));
return; return;
} }
throw new NotEnoughArgumentsException(); throw new NotEnoughArgumentsException();
} }
private class SendAll implements Runnable {
IMessageRecipient messageRecipient;
String message;
SendAll(IMessageRecipient messageRecipient, String message) {
this.messageRecipient = messageRecipient;
this.message = message;
}
@Override
public void run() {
for (UUID userid : ess.getUserMap().getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(userid);
if (user != null) {
user.sendMail(messageRecipient, message);
}
}
}
}
@Override @Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) { protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
if (args.length == 1) { if (args.length == 1) {
@ -146,15 +258,18 @@ public class Commandmail extends EssentialsCommand {
if (user.isAuthorized("essentials.mail.send")) { if (user.isAuthorized("essentials.mail.send")) {
options.add("send"); options.add("send");
} }
if (user.isAuthorized("essentials.mail.sendtemp")) {
options.add("sendtemp");
}
if (user.isAuthorized("essentials.mail.sendall")) { if (user.isAuthorized("essentials.mail.sendall")) {
options.add("sendall"); options.add("sendall");
} }
return options; return options;
} else if (args.length == 2 && args[0].equalsIgnoreCase("send") && user.isAuthorized("essentials.mail.send")) { } else if (args.length == 2 && ((args[0].equalsIgnoreCase("send") && user.isAuthorized("essentials.mail.send")) || (args[0].equalsIgnoreCase("sendtemp") && user.isAuthorized("essentials.mail.sendtemp")))) {
return getPlayers(server, user); return getPlayers(server, user);
} else if (args.length == 2 && args[0].equalsIgnoreCase("read")) { } else if (args.length == 2 && args[0].equalsIgnoreCase("read")) {
final List<String> mail = user.getMails(); final ArrayList<MailMessage> mail = user.getMailMessages();
final int pages = mail.size() / 9 + (mail.size() % 9 > 0 ? 1 : 0); final int pages = mail != null ? (mail.size() / 9 + (mail.size() % 9 > 0 ? 1 : 0)) : 0;
if (pages == 0) { if (pages == 0) {
return Lists.newArrayList("0"); return Lists.newArrayList("0");
} else { } else {
@ -164,8 +279,8 @@ public class Commandmail extends EssentialsCommand {
} }
return options; return options;
} }
} else if ((args.length > 2 && args[0].equalsIgnoreCase("send") && user.isAuthorized("essentials.mail.send")) || (args.length > 1 && args[0].equalsIgnoreCase("sendall") && user.isAuthorized("essentials.mail.sendall"))) { } else if (args.length == 3 && args[0].equalsIgnoreCase("sendtemp") && user.isAuthorized("essentials.mail.sendtemp")) {
return null; // Use vanilla handler return COMMON_DATE_DIFFS;
} else { } else {
return Collections.emptyList(); return Collections.emptyList();
} }
@ -175,30 +290,14 @@ public class Commandmail extends EssentialsCommand {
protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) { protected List<String> getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) {
if (args.length == 1) { if (args.length == 1) {
return Lists.newArrayList("send", "sendall"); return Lists.newArrayList("send", "sendall");
} else if (args.length == 2 && args[0].equalsIgnoreCase("send")) { } else if (args.length == 2 && (args[0].equalsIgnoreCase("send") || args[0].equalsIgnoreCase("sendtemp"))) {
return getPlayers(server, sender); return getPlayers(server, sender);
} else if (args.length == 3 && args[0].equalsIgnoreCase("sentemp")) {
return COMMON_DATE_DIFFS;
} else if ((args.length > 2 && args[0].equalsIgnoreCase("send")) || (args.length > 1 && args[0].equalsIgnoreCase("sendall"))) { } else if ((args.length > 2 && args[0].equalsIgnoreCase("send")) || (args.length > 1 && args[0].equalsIgnoreCase("sendall"))) {
return null; // Use vanilla handler return null; // Use vanilla handler
} else { } else {
return Collections.emptyList(); return Collections.emptyList();
} }
} }
private class SendAll implements Runnable {
final String message;
SendAll(final String message) {
this.message = message;
}
@Override
public void run() {
for (final UUID userid : ess.getUserMap().getAllUniqueUsers()) {
final User user = ess.getUserMap().getUser(userid);
if (user != null) {
user.addMail(message);
}
}
}
}
} }

View File

@ -9,8 +9,10 @@ import com.earth2me.essentials.config.processors.DeleteOnEmptyProcessor;
import com.earth2me.essentials.config.serializers.BigDecimalTypeSerializer; import com.earth2me.essentials.config.serializers.BigDecimalTypeSerializer;
import com.earth2me.essentials.config.serializers.CommandCooldownSerializer; import com.earth2me.essentials.config.serializers.CommandCooldownSerializer;
import com.earth2me.essentials.config.serializers.LocationTypeSerializer; import com.earth2me.essentials.config.serializers.LocationTypeSerializer;
import com.earth2me.essentials.config.serializers.MailMessageSerializer;
import com.earth2me.essentials.config.serializers.MaterialTypeSerializer; import com.earth2me.essentials.config.serializers.MaterialTypeSerializer;
import net.ess3.api.InvalidWorldException; import net.ess3.api.InvalidWorldException;
import net.essentialsx.api.v2.services.mail.MailMessage;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.spongepowered.configurate.CommentedConfigurationNode; import org.spongepowered.configurate.CommentedConfigurationNode;
@ -26,6 +28,7 @@ import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Type;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.ArrayList; import java.util.ArrayList;
@ -58,6 +61,7 @@ public class EssentialsConfiguration {
.register(LazyLocation.class, new LocationTypeSerializer()) .register(LazyLocation.class, new LocationTypeSerializer())
.register(Material.class, new MaterialTypeSerializer()) .register(Material.class, new MaterialTypeSerializer())
.register(CommandCooldown.class, new CommandCooldownSerializer()) .register(CommandCooldown.class, new CommandCooldownSerializer())
.register(MailMessage.class, new MailMessageSerializer())
.build(); .build();
private final AtomicInteger pendingWrites = new AtomicInteger(0); private final AtomicInteger pendingWrites = new AtomicInteger(0);
@ -139,6 +143,14 @@ public class EssentialsConfiguration {
setInternal(path, list); setInternal(path, list);
} }
public <T> void setExplicitList(final String path, final List<T> list, final Type type) {
try {
toSplitRoot(path, configurationNode).set(type, list);
} catch (SerializationException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
}
public <T> List<T> getList(final String path, Class<T> type) { public <T> List<T> getList(final String path, Class<T> type) {
final CommentedConfigurationNode node = getInternal(path); final CommentedConfigurationNode node = getInternal(path);
if (node == null) { if (node == null) {

View File

@ -4,6 +4,7 @@ import com.earth2me.essentials.config.annotations.DeleteIfIncomplete;
import com.earth2me.essentials.config.annotations.DeleteOnEmpty; import com.earth2me.essentials.config.annotations.DeleteOnEmpty;
import com.earth2me.essentials.config.entities.CommandCooldown; import com.earth2me.essentials.config.entities.CommandCooldown;
import com.earth2me.essentials.config.entities.LazyLocation; import com.earth2me.essentials.config.entities.LazyLocation;
import net.essentialsx.api.v2.services.mail.MailMessage;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@ -113,16 +114,16 @@ public class UserConfigHolder {
} }
@DeleteOnEmpty @DeleteOnEmpty
private @MonotonicNonNull List<String> mail; private @MonotonicNonNull ArrayList<MailMessage> mail;
public List<String> mail() { public ArrayList<MailMessage> mail() {
if (this.mail == null) { if (this.mail == null) {
this.mail = new ArrayList<>(); this.mail = new ArrayList<>();
} }
return this.mail; return this.mail;
} }
public void mail(final List<String> value) { public void mail(final ArrayList<MailMessage> value) {
this.mail = value; this.mail = value;
} }

View File

@ -0,0 +1,44 @@
package com.earth2me.essentials.config.serializers;
import net.essentialsx.api.v2.services.mail.MailMessage;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.UUID;
public class MailMessageSerializer implements TypeSerializer<MailMessage> {
@Override
public MailMessage deserialize(Type type, ConfigurationNode node) throws SerializationException {
final boolean legacy = !node.node("legacy").isNull() && node.node("legacy").getBoolean(false);
return new MailMessage(node.node("read").getBoolean(false),
legacy,
!legacy ? node.node("sender-name").getString() : null,
!legacy ? UUID.fromString(Objects.requireNonNull(node.node("sender-uuid").getString())) : null,
!legacy ? node.node("timestamp").getLong() : 0L,
!legacy ? node.node("expire").getLong() : 0L,
node.node("message").getString());
}
@Override
public void serialize(Type type, @Nullable MailMessage obj, ConfigurationNode node) throws SerializationException {
if (obj == null) {
node.raw(null);
return;
}
node.node("legacy").set(Boolean.class, obj.isLegacy());
node.node("read").set(Boolean.class, obj.isRead());
node.node("message").set(String.class, obj.getMessage());
if (!obj.isLegacy()) {
node.node("sender-name").set(String.class, obj.getSenderUsername());
node.node("sender-uuid").set(String.class, obj.getSenderUUID().toString());
node.node("timestamp").set(Long.class, obj.getTimeSent());
node.node("expire").set(Long.class, obj.getTimeExpire());
}
}
}

View File

@ -1,11 +1,12 @@
package com.earth2me.essentials.messaging; package com.earth2me.essentials.messaging;
import net.essentialsx.api.v2.services.mail.MailSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
/** /**
* Represents an interface for message recipients. * Represents an interface for message recipients.
*/ */
public interface IMessageRecipient { public interface IMessageRecipient extends MailSender {
/** /**
* Sends (prints) a message to this recipient. * Sends (prints) a message to this recipient.

View File

@ -8,6 +8,7 @@ import net.ess3.api.events.PrivateMessageSentEvent;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.UUID;
import static com.earth2me.essentials.I18n.tl; import static com.earth2me.essentials.I18n.tl;
@ -60,6 +61,11 @@ public class SimpleMessageRecipient implements IMessageRecipient {
return this.parent.getName(); return this.parent.getName();
} }
@Override
public UUID getUUID() {
return this.parent.getUUID();
}
@Override @Override
public String getDisplayName() { public String getDisplayName() {
return this.parent.getDisplayName(); return this.parent.getDisplayName();

View File

@ -2,8 +2,10 @@ package com.earth2me.essentials.signs;
import com.earth2me.essentials.User; import com.earth2me.essentials.User;
import net.ess3.api.IEssentials; import net.ess3.api.IEssentials;
import net.essentialsx.api.v2.services.mail.MailMessage;
import java.util.List; import java.util.ArrayList;
import java.util.ListIterator;
import static com.earth2me.essentials.I18n.tl; import static com.earth2me.essentials.I18n.tl;
@ -14,14 +16,28 @@ public class SignMail extends EssentialsSign {
@Override @Override
protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException { protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException {
final List<String> mail = player.getMails(); final ArrayList<MailMessage> mail = player.getMailMessages();
if (mail.isEmpty()) {
final ListIterator<MailMessage> iterator = mail.listIterator();
boolean hadMail = false;
while (iterator.hasNext()) {
final MailMessage mailObj = iterator.next();
if (mailObj.isExpired()) {
iterator.remove();
continue;
}
hadMail = true;
player.sendMessage(ess.getMail().getMailLine(mailObj));
iterator.set(new MailMessage(true, mailObj.isLegacy(), mailObj.getSenderUsername(),
mailObj.getSenderUUID(), mailObj.getTimeSent(), mailObj.getTimeExpire(), mailObj.getMessage()));
}
if (!hadMail) {
player.sendMessage(tl("noNewMail")); player.sendMessage(tl("noNewMail"));
return false; return false;
} }
for (final String s : mail) { player.setMailList(mail);
player.sendMessage(s);
}
player.sendMessage(tl("markMailAsRead")); player.sendMessage(tl("markMailAsRead"));
return true; return true;
} }

View File

@ -227,7 +227,7 @@ public class KeywordReplacer implements IText {
break; break;
case MAILS: case MAILS:
if (user != null) { if (user != null) {
replacer = Integer.toString(user.getMails().size()); replacer = Integer.toString(user.getMailAmount());
} }
break; break;
case PLAYTIME: case PLAYTIME:

View File

@ -20,6 +20,10 @@ public class SimpleTextInput implements IText {
public SimpleTextInput() { public SimpleTextInput() {
} }
public void addLine(String line) {
lines.add(line);
}
@Override @Override
public List<String> getLines() { public List<String> getLines() {
return lines; return lines;

View File

@ -0,0 +1,98 @@
package net.essentialsx.api.v2.services.mail;
import java.util.UUID;
/**
* An immutable representation of a message sent as mail.
*/
public class MailMessage {
private final boolean read;
private final boolean legacy;
private final String senderName;
private final UUID senderId;
private final long timestamp;
private final long expire;
private final String message;
public MailMessage(boolean read, boolean legacy, String sender, UUID uuid, long timestamp, long expire, String message) {
this.read = read;
this.legacy = legacy;
this.senderName = sender;
this.senderId = uuid;
this.timestamp = timestamp;
this.expire = expire;
this.message = message;
}
/**
* Checks if this message has been read by its recipient yet.
* @return true if this message has been read.
*/
public boolean isRead() {
return read;
}
/**
* Checks if this message was created via legacy api or converted from legacy format.
*
* A legacy messages only contains data for the read state and message.
* @see #isRead()
* @see #getMessage()
* @return true if this message is a legacy message.
*/
public boolean isLegacy() {
return legacy;
}
/**
* Gets the sender's username at the time of sending the message.
* @return The sender's username.
*/
public String getSenderUsername() {
return senderName;
}
/**
* Gets the sender's {@link UUID} or null if the sender does not have a UUID.
* @return The sender's {@link UUID} or null.
*/
public UUID getSenderUUID() {
return senderId;
}
/**
* Gets the millisecond epoch time when the message was sent.
* @return The epoch time when message was sent.
*/
public long getTimeSent() {
return timestamp;
}
/**
* Gets the millisecond epoch at which this message will expire and no longer been shown to the user.
* @return The epoch time when the message will expire.
*/
public long getTimeExpire() {
return expire;
}
/**
* Gets the message content for normal mail or the entire mail format for legacy mail.
* @see #isLegacy()
* @return The mail content or format.
*/
public String getMessage() {
return message;
}
/**
* Helper method to check if this mail has expired and should not been shown to the recipient.
* @return true if this mail has expired.
*/
public boolean isExpired() {
if (getTimeExpire() == 0L) {
return false;
}
return System.currentTimeMillis() >= getTimeExpire();
}
}

View File

@ -0,0 +1,22 @@
package net.essentialsx.api.v2.services.mail;
import java.util.UUID;
/**
* An entity which is allowed to send mail to an {@link net.ess3.api.IUser IUser}.
*
* In Essentials, IUser and Console are the entities that implement this interface.
*/
public interface MailSender {
/**
* Gets the username of this {@link MailSender}.
* @return The sender's username.
*/
String getName();
/**
* Gets the {@link UUID} of this {@link MailSender} or null if this sender doesn't have a UUID.
* @return The sender's {@link UUID} or null if N/A.
*/
UUID getUUID();
}

View File

@ -0,0 +1,43 @@
package net.essentialsx.api.v2.services.mail;
import net.ess3.api.IUser;
/**
* This interface provides access to core Essentials mailing functions, allowing API users to send messages to {@link IUser IUser's }.
*/
public interface MailService {
/**
* Sends a message from the specified {@link MailSender sender} to the specified {@link IUser recipient}.
* @param recipient The {@link IUser} which to send the message to.
* @param sender The {@link MailSender} which sent the message.
* @param message The message content.
*/
void sendMail(IUser recipient, MailSender sender, String message);
/**
* Sends a message from the specified {@link MailSender sender} to the specified {@link IUser recipient}.
* @param recipient The {@link IUser} which to send the message to.
* @param sender The {@link MailSender} which sent the message.
* @param message The message content.
* @param expireAt The millisecond epoch at which this message expires, or 0 if the message doesn't expire.
*/
void sendMail(IUser recipient, MailSender sender, String message, long expireAt);
/**
* Sends a legacy message to the user without any advanced features.
* @param recipient The {@link IUser} which to send the message to.
* @param message The message content.
* @see #sendMail(IUser, MailSender, String)
* @see #sendMail(IUser, MailSender, String, long)
* @deprecated This is only for maintaining backwards compatibility with old API, please use the newer {@link #sendMail(IUser, MailSender, String)} API.
*/
@Deprecated
void sendLegacyMail(IUser recipient, String message);
/**
* Generates the message sent to the recipient of the given {@link MailMessage}.
* @param message The {@link MailMessage} to generate the message for.
* @return The formatted message to be sent to the recipient.
*/
String getMailLine(MailMessage message);
}

View File

@ -647,21 +647,29 @@ loomCommandDescription=Opens up a loom.
loomCommandUsage=/<command> loomCommandUsage=/<command>
mailClear=\u00a76To clear your mail, type\u00a7c /mail clear\u00a76. mailClear=\u00a76To clear your mail, type\u00a7c /mail clear\u00a76.
mailCleared=\u00a76Mail cleared\! mailCleared=\u00a76Mail cleared\!
mailClearIndex=\u00a74You must specify a number between 1-{0}.
mailCommandDescription=Manages inter-player, intra-server mail. mailCommandDescription=Manages inter-player, intra-server mail.
mailCommandUsage=/<command> [read|clear|send [to] [message]|sendall [message]] mailCommandUsage=/<command> [read|clear|clear [number]|send [to] [message]|sendtemp [to] [expire time] [message]|sendall [message]]
mailCommandUsage1=/<command> read [page] mailCommandUsage1=/<command> read [page]
mailCommandUsage1Description=Reads the first (or specified) page of your mail mailCommandUsage1Description=Reads the first (or specified) page of your mail
mailCommandUsage2=/<command> clear mailCommandUsage2=/<command> clear [number]
mailCommandUsage2Description=Clears your mail mailCommandUsage2Description=Clears either all or the specified mail(s)
mailCommandUsage3=/<command> send <player> <message> mailCommandUsage3=/<command> send <player> <message>
mailCommandUsage3Description=Sends the specified player the given message mailCommandUsage3Description=Sends the specified player the given message
mailCommandUsage4=/<command> sendall <message> mailCommandUsage4=/<command> sendall <message>
mailCommandUsage4Description=Sends all players the given message mailCommandUsage4Description=Sends all players the given message
mailCommandUsage5=/<command> sendtemp <player> <expire time> <message>
mailCommandUsage5Description=Sends the specified player the given message which will expire in the specified time
mailDelay=Too many mails have been sent within the last minute. Maximum\: {0} mailDelay=Too many mails have been sent within the last minute. Maximum\: {0}
mailFormatNew=\u00a76[\u00a7r{0}\u00a76] \u00a76[\u00a7r{1}\u00a76] \u00a7r{2}
mailFormatNewTimed=\u00a76[\u00a7e\u26a0\u00a76] \u00a76[\u00a7r{0}\u00a76] \u00a76[\u00a7r{1}\u00a76] \u00a7r{2}
mailFormatNewRead=\u00a76[\u00a7r{0}\u00a76] \u00a76[\u00a7r{1}\u00a76] \u00a77\u00a7o{2}
mailFormatNewReadTimed=\u00a76[\u00a7e\u26a0\u00a76] \u00a76[\u00a7r{0}\u00a76] \u00a76[\u00a7r{1}\u00a76] \u00a77\u00a7o{2}
mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1}
mailMessage={0} mailMessage={0}
mailSent=\u00a76Mail sent\! mailSent=\u00a76Mail sent\!
mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\:
mailSentToExpire=\u00a7c{0}\u00a76 has been sent the following mail which will expire in \u00a7c{1}\u00a76\:
mailTooLong=\u00a74Mail message too long. Try to keep it below 1000 characters. mailTooLong=\u00a74Mail message too long. Try to keep it below 1000 characters.
markMailAsRead=\u00a76To mark your mail as read, type\u00a7c /mail clear\u00a76. markMailAsRead=\u00a76To mark your mail as read, type\u00a7c /mail clear\u00a76.
matchingIPAddress=\u00a76The following players previously logged in from that IP address\: matchingIPAddress=\u00a76The following players previously logged in from that IP address\:

View File

@ -286,7 +286,7 @@ commands:
aliases: [eloom] aliases: [eloom]
mail: mail:
description: Manages inter-player, intra-server mail. description: Manages inter-player, intra-server mail.
usage: /<command> [read|clear|send [to] [message]|sendall [message]] usage: /<command> [read|clear|clear [number]|send [to] [message]|sendtemp [to] [expire time] [message]|sendall [message]]
aliases: [email,eemail,memo,ememo] aliases: [email,eemail,memo,ememo]
me: me:
description: Describes an action in the context of the player. description: Describes an action in the context of the player.

View File

@ -5,6 +5,7 @@ import com.earth2me.essentials.utils.FormatUtil;
import net.essentialsx.api.v2.services.discord.InteractionMember; import net.essentialsx.api.v2.services.discord.InteractionMember;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import static com.earth2me.essentials.I18n.tl; import static com.earth2me.essentials.I18n.tl;
@ -48,6 +49,11 @@ public class DiscordMessageRecipient implements IMessageRecipient {
return member.getTag(); return member.getTag();
} }
@Override
public UUID getUUID() {
return null;
}
@Override @Override
public String getDisplayName() { public String getDisplayName() {
return member.getTag(); return member.getTag();