diff options
author | Cow <cow@volloeko.de> | 2020-04-28 12:44:09 +0200 |
---|---|---|
committer | Cow <cow@volloeko.de> | 2020-04-28 12:44:09 +0200 |
commit | 38cd6cc98ba320e54754a270c889549b793b6b90 (patch) | |
tree | afee59b68a33f9ca183fc48c9d58e5fdf0dda95b /src | |
parent | 35553dceb9c683000095ce1a62b4e094234304bc (diff) | |
download | Cowlection-38cd6cc98ba320e54754a270c889549b793b6b90.tar.gz Cowlection-38cd6cc98ba320e54754a270c889549b793b6b90.tar.bz2 Cowlection-38cd6cc98ba320e54754a270c889549b793b6b90.zip |
Added Tab-completable usernames for various commands
- use /tabcompletablecommand for a full list of valid commands (e.g. party, msg, boop, ...)
- list of supported commands can be modified via config
Diffstat (limited to 'src')
8 files changed, 201 insertions, 12 deletions
diff --git a/src/main/java/eu/olli/cowmoonication/Cowmoonication.java b/src/main/java/eu/olli/cowmoonication/Cowmoonication.java index 748883a..30ac662 100644 --- a/src/main/java/eu/olli/cowmoonication/Cowmoonication.java +++ b/src/main/java/eu/olli/cowmoonication/Cowmoonication.java @@ -2,11 +2,13 @@ package eu.olli.cowmoonication; import eu.olli.cowmoonication.command.MooCommand; import eu.olli.cowmoonication.command.ShrugCommand; +import eu.olli.cowmoonication.command.TabCompletableCommand; import eu.olli.cowmoonication.config.MooConfig; import eu.olli.cowmoonication.friends.Friends; import eu.olli.cowmoonication.listener.ChatListener; import eu.olli.cowmoonication.listener.PlayerListener; import eu.olli.cowmoonication.util.ChatHelper; +import eu.olli.cowmoonication.util.PlayerCache; import eu.olli.cowmoonication.util.VersionChecker; import net.minecraftforge.client.ClientCommandHandler; import net.minecraftforge.common.MinecraftForge; @@ -33,6 +35,7 @@ public class Cowmoonication { private Friends friends; private VersionChecker versionChecker; private ChatHelper chatHelper; + private PlayerCache playerCache; private Logger logger; @Mod.EventHandler @@ -45,7 +48,7 @@ public class Cowmoonication { } friends = new Friends(this, new File(modDir, "friends.json")); - config = new MooConfig(new Configuration(new File(modDir, MODID + ".cfg"))); + config = new MooConfig(this, new Configuration(new File(modDir, MODID + ".cfg"))); chatHelper = new ChatHelper(); modsDir = e.getSourceFile().getParentFile(); @@ -57,11 +60,13 @@ public class Cowmoonication { MinecraftForge.EVENT_BUS.register(new PlayerListener(this)); ClientCommandHandler.instance.registerCommand(new MooCommand(this)); ClientCommandHandler.instance.registerCommand(new ShrugCommand(this)); + ClientCommandHandler.instance.registerCommand(new TabCompletableCommand(this)); } @EventHandler public void postInit(FMLPostInitializationEvent e) { versionChecker = new VersionChecker(this); + playerCache = new PlayerCache(this); } public MooConfig getConfig() { @@ -80,6 +85,10 @@ public class Cowmoonication { return chatHelper; } + public PlayerCache getPlayerCache() { + return playerCache; + } + public File getModsFolder() { return modsDir; } diff --git a/src/main/java/eu/olli/cowmoonication/command/MooCommand.java b/src/main/java/eu/olli/cowmoonication/command/MooCommand.java index 58d01a5..c1a8318 100644 --- a/src/main/java/eu/olli/cowmoonication/command/MooCommand.java +++ b/src/main/java/eu/olli/cowmoonication/command/MooCommand.java @@ -302,6 +302,10 @@ public class MooCommand extends CommandBase { /* miscellaneous */ "config", "guiscale", "shrug", "apikey", /* update mod */ "update", "updateHelp", "version", "folder", /* help */ "help"); + } else if (args.length == 2 && args[0].equalsIgnoreCase("remove")) { + return getListOfStringsMatchingLastWord(args, main.getFriends().getBestFriends()); + } else if (args.length == 2 && args[0].equalsIgnoreCase("stalk")) { + return getListOfStringsMatchingLastWord(args, main.getPlayerCache().getAllNamesSorted()); } return null; } diff --git a/src/main/java/eu/olli/cowmoonication/command/TabCompletableCommand.java b/src/main/java/eu/olli/cowmoonication/command/TabCompletableCommand.java new file mode 100644 index 0000000..b1ffa33 --- /dev/null +++ b/src/main/java/eu/olli/cowmoonication/command/TabCompletableCommand.java @@ -0,0 +1,81 @@ +package eu.olli.cowmoonication.command; + +import com.mojang.realmsclient.util.Pair; +import eu.olli.cowmoonication.Cowmoonication; +import eu.olli.cowmoonication.config.MooConfig; +import net.minecraft.client.Minecraft; +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.util.BlockPos; +import net.minecraft.util.EnumChatFormatting; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.List; + +public class TabCompletableCommand extends CommandBase { + private final Cowmoonication main; + + public TabCompletableCommand(Cowmoonication main) { + this.main = main; + } + + @Override + public String getCommandName() { + return "tabcompletablecommand"; + } + + @Override + public String getCommandUsage(ICommandSender sender) { + return EnumChatFormatting.YELLOW + "Commands where player names can be Tab-completed: " + EnumChatFormatting.GOLD + StringUtils.join(getCommandAliases(), EnumChatFormatting.YELLOW + ", " + EnumChatFormatting.GOLD) + + EnumChatFormatting.YELLOW + ". Use " + EnumChatFormatting.GOLD + "/moo config " + EnumChatFormatting.YELLOW + " to edit the list of commands with tab-completable usernames."; + } + + @Override + public void processCommand(ICommandSender sender, String[] args) throws CommandException { + Pair<String, String> lastCommand = getLastCommand(); + if (lastCommand == null) { + main.getChatHelper().sendMessage(EnumChatFormatting.RED, "Something went wrong trying to process this command."); + } else if (lastCommand.first().equalsIgnoreCase(getCommandName())) { + main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, getCommandUsage(sender)); + } else { + Minecraft.getMinecraft().thePlayer.sendChatMessage(lastCommand.second()); + } + } + + /** + * Work-around to get last used command name or alias (by default it's impossible to detect the used alias) + * + * @return 1st: last command used by thePlayer, 2nd: (full) last message sent thePlayer; or null if no command was sent as the last message + */ + private Pair<String, String> getLastCommand() { + List<String> sentMessages = Minecraft.getMinecraft().ingameGUI.getChatGUI().getSentMessages(); + String lastMessage = sentMessages.get(sentMessages.size() - 1); + if (lastMessage.startsWith("/")) { + int endOfCommandName = lastMessage.indexOf(" "); + return Pair.of(lastMessage.substring(1, endOfCommandName == -1 ? lastMessage.length() : endOfCommandName), + lastMessage); + } + return null; + } + + @Override + public int getRequiredPermissionLevel() { + return 0; + } + + @Override + public List<String> getCommandAliases() { + // list of commands that require a player name as one their 1st or 2nd argument + return Arrays.asList(MooConfig.tabCompletableNamesCommands); + } + + @Override + public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) { + if (args.length == 1 || args.length == 2) { + return getListOfStringsMatchingLastWord(args, main.getPlayerCache().getAllNamesSorted()); + } + return null; + } +} diff --git a/src/main/java/eu/olli/cowmoonication/config/MooConfig.java b/src/main/java/eu/olli/cowmoonication/config/MooConfig.java index 41cec89..cb852a7 100644 --- a/src/main/java/eu/olli/cowmoonication/config/MooConfig.java +++ b/src/main/java/eu/olli/cowmoonication/config/MooConfig.java @@ -2,6 +2,8 @@ package eu.olli.cowmoonication.config; import eu.olli.cowmoonication.Cowmoonication; import eu.olli.cowmoonication.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.config.Configuration; import net.minecraftforge.common.config.Property; @@ -10,18 +12,23 @@ import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.regex.Pattern; public class MooConfig { public static boolean doUpdateCheck; public static boolean showBestFriendNotifications; public static boolean showFriendNotifications; public static boolean showGuildNotifications; + public static String[] tabCompletableNamesCommands; public static String moo; private static Configuration cfg = null; + private final Cowmoonication main; private List<String> propOrderGeneral; - public MooConfig(Configuration configuration) { + public MooConfig(Cowmoonication main, Configuration configuration) { + this.main = main; cfg = configuration; initConfig(); } @@ -79,26 +86,42 @@ public class MooConfig { "showFriendNotifications", false, "Set to true to receive friends' login/logout messages, set to false hide them."), true); Property propShowGuildNotifications = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, "showGuildNotifications", false, "Set to true to receive guild members' login/logout messages, set to false hide them."), true); + Property propTabCompletableNamesCommands = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, + "tabCompletableNamesCommands", new String[]{"party", "p", "invite", "visit", "ignore", "msg", "tell", "w", "boop", "profile"}, "List of commands with a Tab-completable username argument."), true) + .setValidationPattern(Pattern.compile("^[A-Za-z]+$")); Property propMoo = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, "moo", "", "The answer to life the universe and everything. Don't edit this entry manually!", Utils.VALID_UUID_PATTERN), false); cfg.setCategoryPropertyOrder(Configuration.CATEGORY_CLIENT, propOrderGeneral); + // 'manual' replacement for propTabCompletableNamesCommands.hasChanged() + boolean modifiedTabCompletableCommandsList = false; + String[] tabCompletableCommandsPreChange = tabCompletableNamesCommands != null ? tabCompletableNamesCommands.clone() : null; + if (readFieldsFromConfig) { doUpdateCheck = propDoUpdateCheck.getBoolean(); showBestFriendNotifications = propShowBestFriendNotifications.getBoolean(); showFriendNotifications = propShowFriendNotifications.getBoolean(); showGuildNotifications = propShowGuildNotifications.getBoolean(); + tabCompletableNamesCommands = propTabCompletableNamesCommands.getStringList(); moo = propMoo.getString(); + + if (!Arrays.equals(tabCompletableCommandsPreChange, tabCompletableNamesCommands)) { + modifiedTabCompletableCommandsList = true; + } } propDoUpdateCheck.set(doUpdateCheck); propShowBestFriendNotifications.set(showBestFriendNotifications); propShowFriendNotifications.set(showFriendNotifications); propShowGuildNotifications.set(showGuildNotifications); + propTabCompletableNamesCommands.set(tabCompletableNamesCommands); propMoo.set(moo); if (cfg.hasChanged()) { + if (modifiedTabCompletableCommandsList && Minecraft.getMinecraft().thePlayer != null) { + main.getChatHelper().sendMessage(EnumChatFormatting.RED, "Added or removed commands with tab-completable usernames take effect after a game restart!"); + } cfg.save(); } } diff --git a/src/main/java/eu/olli/cowmoonication/listener/ChatListener.java b/src/main/java/eu/olli/cowmoonication/listener/ChatListener.java index cf0f794..3c8847b 100644 --- a/src/main/java/eu/olli/cowmoonication/listener/ChatListener.java +++ b/src/main/java/eu/olli/cowmoonication/listener/ChatListener.java @@ -28,7 +28,8 @@ public class ChatListener { * - §aFriend > §r§aNAME §r§eleft.§r * - §2Guild > §r§aNAME §r§eleft.§r */ - private static final Pattern LOGIN_LOGOUT_NOTIFICATION = Pattern.compile("^(?<type>§aFriend|§2Guild) > §r(?<rank>§[0-9a-f])(?<playerName>[\\w]+)(?<joinLeave> §r§e(?:joined|left)\\.)§r$"); + private static final Pattern LOGIN_LOGOUT_NOTIFICATION = Pattern.compile("^(?<type>§aFriend|§2Guild) > §r(?<rank>§[0-9a-f])(?<playerName>[\\w]+)(?<joinLeaveSuffix> §r§e(?<joinedLeft>joined|left)\\.)§r$"); + private static final Pattern CHAT_MESSAGE_RECEIVED_PATTERN = Pattern.compile("^(?:Party|Guild) > (?:\\[.*?] )?(?<playerName>\\w+)(?: \\[.*?])?: "); private static final Pattern PRIVATE_MESSAGE_RECEIVED_PATTERN = Pattern.compile("^From (?:\\[.*?] )?(\\w+): "); private final Cowmoonication main; private String lastTypedChars = ""; @@ -51,13 +52,23 @@ public class ChatListener { String type = notificationMatcher.group("type"); String rank = notificationMatcher.group("rank"); String playerName = notificationMatcher.group("playerName"); - String joinLeave = notificationMatcher.group("joinLeave"); + String joinLeaveSuffix = notificationMatcher.group("joinLeaveSuffix"); + String joinedLeft = notificationMatcher.group("joinedLeft"); - if (MooConfig.showBestFriendNotifications) { - boolean isBestFriend = main.getFriends().isBestFriend(playerName, false); - if (isBestFriend) { + + boolean isBestFriend = main.getFriends().isBestFriend(playerName, false); + if (isBestFriend) { + switch (joinedLeft) { + case "joined": + main.getPlayerCache().addBestFriend(playerName); + break; + case "left": + main.getPlayerCache().removeBestFriend(playerName); + break; + } + if (MooConfig.showBestFriendNotifications) { // replace default (friend/guild) notification with best friend notification - main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, "" + EnumChatFormatting.DARK_GREEN + EnumChatFormatting.BOLD + "Best friend" + EnumChatFormatting.DARK_GREEN + " > " + EnumChatFormatting.RESET + rank + playerName + joinLeave); + main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, "" + EnumChatFormatting.DARK_GREEN + EnumChatFormatting.BOLD + "Best friend" + EnumChatFormatting.DARK_GREEN + " > " + EnumChatFormatting.RESET + rank + playerName + joinLeaveSuffix); e.setCanceled(true); return; } @@ -125,11 +136,23 @@ public class ChatListener { } @SubscribeEvent - public void onPrivateMsgReceive(ClientChatReceivedEvent e) { + public void onChatMsgReceive(ClientChatReceivedEvent e) { if (e.type != 2) { - Matcher matcher = PRIVATE_MESSAGE_RECEIVED_PATTERN.matcher(e.message.getUnformattedText()); - if (matcher.find()) { - this.lastPMSender = matcher.group(1); + String messageSender = null; + + String message = EnumChatFormatting.getTextWithoutFormattingCodes(e.message.getUnformattedText()); + + Matcher privateMessageMatcher = PRIVATE_MESSAGE_RECEIVED_PATTERN.matcher(message); + Matcher chatMessageMatcher = CHAT_MESSAGE_RECEIVED_PATTERN.matcher(message); + if (privateMessageMatcher.find()) { + messageSender = privateMessageMatcher.group(1); + this.lastPMSender = messageSender; + } else if (chatMessageMatcher.find()) { + messageSender = chatMessageMatcher.group("playerName"); + } + + if (messageSender != null) { + main.getPlayerCache().add(messageSender); } } } diff --git a/src/main/java/eu/olli/cowmoonication/listener/PlayerListener.java b/src/main/java/eu/olli/cowmoonication/listener/PlayerListener.java index 304806d..95c35c6 100644 --- a/src/main/java/eu/olli/cowmoonication/listener/PlayerListener.java +++ b/src/main/java/eu/olli/cowmoonication/listener/PlayerListener.java @@ -21,5 +21,6 @@ public class PlayerListener { @SubscribeEvent public void onServerLeave(FMLNetworkEvent.ClientDisconnectionFromServerEvent e) { main.getFriends().saveBestFriends(); + main.getPlayerCache().clearAllCaches(); } } diff --git a/src/main/java/eu/olli/cowmoonication/util/PlayerCache.java b/src/main/java/eu/olli/cowmoonication/util/PlayerCache.java new file mode 100644 index 0000000..1b5251a --- /dev/null +++ b/src/main/java/eu/olli/cowmoonication/util/PlayerCache.java @@ -0,0 +1,46 @@ +package eu.olli.cowmoonication.util; + +import com.google.common.collect.EvictingQueue; +import eu.olli.cowmoonication.Cowmoonication; + +import java.util.Set; +import java.util.TreeSet; + +public class PlayerCache { + @SuppressWarnings("UnstableApiUsage") + private final EvictingQueue<String> nameCache = EvictingQueue.create(50); + @SuppressWarnings("UnstableApiUsage") + private final EvictingQueue<String> bestFriendCache = EvictingQueue.create(50); + private final Cowmoonication main; + + public PlayerCache(Cowmoonication main) { + this.main = main; + } + + public void add(String name) { + // remove old entry (if exists) to 'push' name to the end of the queue + nameCache.remove(name); + nameCache.add(name); + } + + public void addBestFriend(String name) { + // remove old entry (if exists) to 'push' name to the end of the queue + bestFriendCache.remove(name); + bestFriendCache.add(name); + } + + public void removeBestFriend(String name) { + bestFriendCache.remove(name); + } + + public Set<String> getAllNamesSorted() { + Set<String> nameList = new TreeSet<>(bestFriendCache); + nameList.addAll(nameCache); + return nameList; + } + + public void clearAllCaches() { + nameCache.clear(); + bestFriendCache.clear(); + } +} diff --git a/src/main/resources/assets/cowmoonication/lang/en_US.lang b/src/main/resources/assets/cowmoonication/lang/en_US.lang index ad103b6..05cfc43 100644 --- a/src/main/resources/assets/cowmoonication/lang/en_US.lang +++ b/src/main/resources/assets/cowmoonication/lang/en_US.lang @@ -6,3 +6,5 @@ cowmoonication.config.showFriendNotifications=Show friend notifications cowmoonication.config.showFriendNotifications.tooltip=Set to true to receive friends' login/logout messages, set to false hide them. cowmoonication.config.showGuildNotifications=Show guild notifications cowmoonication.config.showGuildNotifications.tooltip=Set to true to receive guild members' login/logout messages, set to false hide them. +cowmoonication.config.tabCompletableNamesCommands=Commands with Tab-completable usernames +cowmoonication.config.tabCompletableNamesCommands.tooltip=List of commands with a username argument that should be Tab-completable.\nRequires game restart to take effect! |