aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de/cowtipper/cowlection/command/MooCommand.java
diff options
context:
space:
mode:
authorCow <cow@volloeko.de>2020-08-01 15:06:47 +0200
committerCow <cow@volloeko.de>2020-08-01 15:06:47 +0200
commitc4e0e65b1d5106cb389e0371fe66ceccd08a3129 (patch)
tree6b94ed6a81e5be13fc99b01b2dd504e7097b0a5c /src/main/java/de/cowtipper/cowlection/command/MooCommand.java
parentf8659db5387750494b02c6f293c415c43a5a51c7 (diff)
downloadCowlection-c4e0e65b1d5106cb389e0371fe66ceccd08a3129.tar.gz
Cowlection-c4e0e65b1d5106cb389e0371fe66ceccd08a3129.tar.bz2
Cowlection-c4e0e65b1d5106cb389e0371fe66ceccd08a3129.zip
Reorganized /moo command
Diffstat (limited to 'src/main/java/de/cowtipper/cowlection/command/MooCommand.java')
-rw-r--r--src/main/java/de/cowtipper/cowlection/command/MooCommand.java605
1 files changed, 329 insertions, 276 deletions
diff --git a/src/main/java/de/cowtipper/cowlection/command/MooCommand.java b/src/main/java/de/cowtipper/cowlection/command/MooCommand.java
index 91d1932..9f5d004 100644
--- a/src/main/java/de/cowtipper/cowlection/command/MooCommand.java
+++ b/src/main/java/de/cowtipper/cowlection/command/MooCommand.java
@@ -14,6 +14,7 @@ import de.cowtipper.cowlection.handler.DungeonCache;
import de.cowtipper.cowlection.search.GuiSearch;
import de.cowtipper.cowlection.util.*;
import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiScreen;
import net.minecraft.command.*;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityArmorStand;
@@ -41,13 +42,28 @@ public class MooCommand extends CommandBase {
}
@Override
+ public String getCommandName() {
+ return "moo";
+ }
+
+ @Override
+ public List<String> getCommandAliases() {
+ return Collections.singletonList("m");
+ }
+
+ @Override
+ public String getCommandUsage(ICommandSender sender) {
+ return "/" + getCommandName() + " help";
+ }
+
+ @Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if (args.length == 0) {
main.getChatHelper().sendMessage(EnumChatFormatting.GOLD, "Tried to say " + EnumChatFormatting.YELLOW + getCommandName() + EnumChatFormatting.GOLD + "? Use " + EnumChatFormatting.YELLOW + getCommandName() + " say [optional text]" + EnumChatFormatting.GOLD + " instead.\n"
+ "Tried to use the command " + EnumChatFormatting.YELLOW + "/" + getCommandName() + EnumChatFormatting.GOLD + "? Use " + EnumChatFormatting.YELLOW + "/" + getCommandName() + " help" + EnumChatFormatting.GOLD + " for a list of available commands");
return;
}
- // sub commands: friends & other players
+ //region sub commands: Best friends, friends & other players
if (args[0].equalsIgnoreCase("say")) {
// work-around so you can still say 'moo' in chat without triggering the client-side command
String msg = CommandBase.buildString(args, 1);
@@ -55,115 +71,7 @@ public class MooCommand extends CommandBase {
} else if (args[0].equalsIgnoreCase("stalk")
|| args[0].equalsIgnoreCase("s")
|| args[0].equalsIgnoreCase("askPolitelyWhereTheyAre")) {
- if (args.length != 2) {
- throw new WrongUsageException("/" + getCommandName() + " stalk <playerName>");
- } else if (!Utils.isValidMcName(args[1])) {
- throw new InvalidPlayerNameException(args[1]);
- } else {
- handleStalking(args[1]);
- }
- } else if (args[0].equalsIgnoreCase("stalkskyblock") || args[0].equalsIgnoreCase("skyblockstalk")
- || args[0].equalsIgnoreCase("ss")
- || args[0].equalsIgnoreCase("stalksb") || args[0].equalsIgnoreCase("sbstalk")
- || args[0].equalsIgnoreCase("askPolitelyAboutTheirSkyBlockProgress")) {
- if (args.length != 2) {
- throw new WrongUsageException("/" + getCommandName() + " skyblockstalk <playerName>");
- } else if (!Utils.isValidMcName(args[1])) {
- throw new InvalidPlayerNameException(args[1]);
- } else {
- handleStalkingSkyBlock(args[1]);
- }
- } else if (args[0].equalsIgnoreCase("analyzeIsland")) {
- Map<String, String> minions = DataHelper.getMinions();
-
- Map<String, Integer> detectedMinions = new HashMap<>();
- Map<Integer, Integer> detectedMinionsWithSkin = new HashMap<>();
- int detectedMinionCount = 0;
- int minionsWithSkinCount = 0;
- entityLoop:
- for (Entity entity : sender.getEntityWorld().loadedEntityList) {
- if (entity instanceof EntityArmorStand) {
- EntityArmorStand minion = (EntityArmorStand) entity;
-
- if (minion.isInvisible() || !minion.isSmall() || minion.getHeldItem() == null) {
- // not a minion: invisible, or not small armor stand, or no item in hand (= minion in a minion chair)
- continue;
- }
- for (int slot = 0; slot < 4; slot++) {
- if (minion.getCurrentArmor(slot) == null) {
- // not a minion: missing equipment
- continue entityLoop;
- }
- }
- ItemStack skullItem = minion.getCurrentArmor(3); // head slot
- if (skullItem.getItem() instanceof ItemSkull && skullItem.getMetadata() == 3 && skullItem.hasTagCompound()) {
- // is a player head!
- if (skullItem.getTagCompound().hasKey("SkullOwner", Constants.NBT.TAG_COMPOUND)) {
- NBTTagCompound skullOwner = skullItem.getTagCompound().getCompoundTag("SkullOwner");
- String skullDataBase64 = skullOwner.getCompoundTag("Properties").getTagList("textures", Constants.NBT.TAG_COMPOUND).getCompoundTagAt(0).getString("Value");
- String skullData = new String(Base64.decodeBase64(skullDataBase64));
- String minionSkinId = StringUtils.substringBetween(skullData, "http://textures.minecraft.net/texture/", "\"");
- String detectedMinion = minions.get(minionSkinId);
- if (detectedMinion != null) {
- // minion head matches one know minion tier
- detectedMinions.put(detectedMinion, detectedMinions.getOrDefault(detectedMinion, 0) + 1);
- detectedMinionCount++;
- } else {
- int minionTier = ImageUtils.getTierFromTexture(minionSkinId);
- if (minionTier > 0) {
- detectedMinionsWithSkin.put(minionTier, detectedMinionsWithSkin.getOrDefault(minionTier, 0) + 1);
- minionsWithSkinCount++;
- } else {
- // looked like a minion but has no matching tier badge
- main.getLogger().info("[/moo analyzeIsland] Found an armor stand that could be a minion but it is missing a tier badge: " + minionSkinId + "\t\t\t" + minion.serializeNBT());
- }
- }
- }
- }
- }
- }
- StringBuilder analysisResults = new StringBuilder("Found ").append(EnumChatFormatting.GOLD).append(detectedMinionCount).append(EnumChatFormatting.YELLOW).append(" minions");
- if (minionsWithSkinCount > 0) {
- analysisResults.append(" + ").append(EnumChatFormatting.GOLD).append(minionsWithSkinCount).append(EnumChatFormatting.YELLOW).append(" unknown minions with skins");
- }
- analysisResults.append(" on this island");
- detectedMinions.entrySet().stream()
- .sorted(Map.Entry.comparingByKey()) // sort alphabetically by minion name and tier
- .forEach(minion -> {
- String minionWithTier = minion.getKey();
- int lastSpace = minionWithTier.lastIndexOf(' ');
-
- String tierRoman = minionWithTier.substring(lastSpace + 1);
-
- int tierArabic = Utils.convertRomanToArabic(tierRoman);
- EnumChatFormatting tierColor = Utils.getMinionTierColor(tierArabic);
-
- minionWithTier = minionWithTier.substring(0, lastSpace) + " " + tierColor + (MooConfig.useRomanNumerals() ? tierRoman : tierArabic);
- analysisResults.append("\n ").append(EnumChatFormatting.GOLD).append(minion.getValue()).append(minion.getValue() > 1 ? "✕ " : "⨉ ")
- .append(EnumChatFormatting.YELLOW).append(minionWithTier);
- });
- detectedMinionsWithSkin.entrySet().stream()
- .sorted(Map.Entry.comparingByKey()) // sort by tier
- .forEach(minionWithSkin -> {
- EnumChatFormatting tierColor = Utils.getMinionTierColor(minionWithSkin.getKey());
- String minionTier = MooConfig.useRomanNumerals() ? Utils.convertArabicToRoman(minionWithSkin.getKey()) : String.valueOf(minionWithSkin.getKey());
- analysisResults.append("\n ").append(EnumChatFormatting.GOLD).append(minionWithSkin.getValue()).append(minionWithSkin.getValue() > 1 ? "✕ " : "⨉ ")
- .append(EnumChatFormatting.RED).append("Unknown minion ").append(EnumChatFormatting.YELLOW).append("(new or with minion skin) ").append(tierColor).append(minionTier);
- });
- main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, analysisResults.toString());
- } else if (args[0].equalsIgnoreCase("dungeon") || args[0].equalsIgnoreCase("dung")) {
- DungeonCache dungeonCache = main.getDungeonCache();
- if (args.length == 2 && args[1].equalsIgnoreCase("gui")) {
- // edit dungeon gui
- new TickDelay(() -> Minecraft.getMinecraft().displayGuiScreen(new DungeonOverlayGuiConfig(main)), 1); // delay by 1 tick, because the chat closing would close the new gui instantly as well.
- } else if (dungeonCache.isInDungeon()) {
- dungeonCache.sendDungeonPerformance();
- } else {
- throw new MooCommandException(EnumChatFormatting.DARK_RED + "Looks like you're not in a dungeon... However, you can edit the Dungeon Performance overlay with " + EnumChatFormatting.RED + "/" + getCommandName() + " dungeon gui");
- }
- } else if (args[0].equalsIgnoreCase("dungeonGui") || args[0].equalsIgnoreCase("guiDungeon")
- || args[0].equalsIgnoreCase("guiDung") || args[0].equalsIgnoreCase("dungGui")) {
- new TickDelay(() -> Minecraft.getMinecraft().displayGuiScreen(new DungeonOverlayGuiConfig(main)), 1); // delay by 1 tick, because the chat closing would close the new gui instantly as well.
+ handleStalking(args);
} else if (args[0].equalsIgnoreCase("add")) {
handleBestFriendAdd(args);
} else if (args[0].equalsIgnoreCase("remove")) {
@@ -176,23 +84,30 @@ public class MooCommand extends CommandBase {
} else if (args[0].equalsIgnoreCase("nameChangeCheck")) {
handleNameChangeCheck(args);
}
- // sub-commands: miscellaneous
+ // + toggle (= alias for config)
+ //endregion
+ //region sub commands: SkyBlock
+ else if (args[0].equalsIgnoreCase("stalkskyblock") || args[0].equalsIgnoreCase("skyblockstalk")
+ || args[0].equalsIgnoreCase("ss")
+ || args[0].equalsIgnoreCase("stalksb") || args[0].equalsIgnoreCase("sbstalk")
+ || args[0].equalsIgnoreCase("askPolitelyAboutTheirSkyBlockProgress")) {
+ handleStalkingSkyBlock(args);
+ } else if (args[0].equalsIgnoreCase("analyzeIsland")) {
+ handleAnalyzeIsland(sender);
+ } else if (args[0].equalsIgnoreCase("dungeon") || args[0].equalsIgnoreCase("dung")) {
+ handleDungeon(args);
+ } else if (args[0].equalsIgnoreCase("dungeonGui") || args[0].equalsIgnoreCase("guiDungeon")
+ || args[0].equalsIgnoreCase("guiDung") || args[0].equalsIgnoreCase("dungGui")) {
+ displayGuiScreen(new DungeonOverlayGuiConfig(main));
+ }
+ //endregion
+ //region sub-commands: miscellaneous
else if (args[0].equalsIgnoreCase("config") || args[0].equalsIgnoreCase("toggle")) {
- new TickDelay(() -> Minecraft.getMinecraft().displayGuiScreen(new MooGuiConfig(null)), 1); // delay by 1 tick, because the chat closing would close the new gui instantly as well.
+ displayGuiScreen(new MooGuiConfig(null));
} else if (args[0].equalsIgnoreCase("search")) {
- new TickDelay(() -> Minecraft.getMinecraft().displayGuiScreen(new GuiSearch(main.getConfigDirectory())), 1); // delay by 1 tick, because the chat closing would close the new gui instantly as well.
+ displayGuiScreen(new GuiSearch(main.getConfigDirectory()));
} else if (args[0].equalsIgnoreCase("guiscale")) {
- int currentGuiScale = (Minecraft.getMinecraft()).gameSettings.guiScale;
- if (args.length == 1) {
- main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "\u279C Current GUI scale: " + EnumChatFormatting.DARK_GREEN + currentGuiScale);
- } else {
- int scale = MathHelper.parseIntWithDefault(args[1], -1);
- if (scale == -1 || scale > 10) {
- throw new NumberInvalidException(EnumChatFormatting.DARK_RED + args[1] + EnumChatFormatting.RED + " is an invalid GUI scale value. Valid values are integers below 10");
- }
- Minecraft.getMinecraft().gameSettings.guiScale = scale;
- main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "\u2714 New GUI scale: " + EnumChatFormatting.DARK_GREEN + scale + EnumChatFormatting.GREEN + " (previous: " + EnumChatFormatting.DARK_GREEN + currentGuiScale + EnumChatFormatting.GREEN + ")");
- }
+ handleGuiScale(args);
} else if (args[0].equalsIgnoreCase("rr")) {
Minecraft.getMinecraft().thePlayer.sendChatMessage("/r " + CommandBase.buildString(args, 1));
} else if (args[0].equalsIgnoreCase("shrug")) {
@@ -200,32 +115,12 @@ public class MooCommand extends CommandBase {
} else if (args[0].equalsIgnoreCase("apikey")) {
handleApiKey(args);
}
- // sub-commands: update mod
+ //endregion
+ //region sub-commands: update mod
else if (args[0].equalsIgnoreCase("update")) {
- boolean updateCheckStarted = main.getVersionChecker().runUpdateCheck(true);
-
- if (updateCheckStarted) {
- main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "\u279C Checking for a newer mod version...");
- // VersionChecker#handleVersionStatus will run with a 5 seconds delay
- } else {
- long nextUpdate = main.getVersionChecker().getNextCheck();
- String waitingTime = String.format("%02d:%02d",
- TimeUnit.MILLISECONDS.toMinutes(nextUpdate),
- TimeUnit.MILLISECONDS.toSeconds(nextUpdate) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(nextUpdate)));
- throw new MooCommandException("\u26A0 Update checker is on cooldown. Please wait " + EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + waitingTime + EnumChatFormatting.RESET + EnumChatFormatting.RED + " more minutes before checking again.");
- }
+ handleUpdate(args);
} else if (args[0].equalsIgnoreCase("updateHelp")) {
- main.getChatHelper().sendMessage(new ChatComponentText("\u279C Update instructions:").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(true))
- .appendSibling(new ChatComponentText("\n\u278A" + EnumChatFormatting.YELLOW + " download latest mod version").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(false)
- .setChatClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, main.getVersionChecker().getDownloadUrl()))
- .setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(EnumChatFormatting.YELLOW + "Download the latest version of " + Cowlection.MODNAME + "\n\u279C Click to download latest mod file")))))
- .appendSibling(new ChatComponentText("\n\u278B" + EnumChatFormatting.YELLOW + " exit Minecraft").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(false)
- .setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(EnumChatFormatting.GOLD + "\u278B" + EnumChatFormatting.YELLOW + " Without closing Minecraft first,\n" + EnumChatFormatting.YELLOW + "you can't delete the old .jar file!")))))
- .appendSibling(new ChatComponentText("\n\u278C" + EnumChatFormatting.YELLOW + " copy " + EnumChatFormatting.GOLD + Cowlection.MODNAME.replace(" ", "") + "-" + main.getVersionChecker().getNewVersion() + ".jar" + EnumChatFormatting.YELLOW + " into mods directory").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(false)
- .setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/moo directory"))
- .setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(EnumChatFormatting.YELLOW + "Open mods directory with command " + EnumChatFormatting.GOLD + "/moo directory\n\u279C Click to open mods directory")))))
- .appendSibling(new ChatComponentText("\n\u278D" + EnumChatFormatting.YELLOW + " delete old mod file " + EnumChatFormatting.GOLD + Cowlection.MODNAME.replace(" ", "") + "-" + Cowlection.VERSION + ".jar ").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(false)))
- .appendSibling(new ChatComponentText("\n\u278E" + EnumChatFormatting.YELLOW + " start Minecraft again").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(false))));
+ handleUpdateHelp();
} else if (args[0].equalsIgnoreCase("version")) {
main.getVersionChecker().handleVersionStatus(true);
} else if (args[0].equalsIgnoreCase("directory") || args[0].equalsIgnoreCase("folder")) {
@@ -235,7 +130,10 @@ public class MooCommand extends CommandBase {
e.printStackTrace();
throw new MooCommandException("\u2716 An error occurred trying to open the mod's directory. I guess you have to open it manually \u00af\\_(\u30c4)_/\u00af");
}
- } else if (args[0].equalsIgnoreCase("help")) {
+ }
+ //endregion
+ // help
+ else if (args[0].equalsIgnoreCase("help")) {
sendCommandUsage(sender);
}
// "catch-all" remaining sub-commands
@@ -244,55 +142,36 @@ public class MooCommand extends CommandBase {
}
}
- private void handleApiKey(String[] args) throws CommandException {
- if (args.length == 1) {
- String firstSentence;
- EnumChatFormatting color;
- EnumChatFormatting colorSecondary;
- if (Utils.isValidUuid(MooConfig.moo)) {
- firstSentence = "You already set your Hypixel API key.";
- color = EnumChatFormatting.GREEN;
- colorSecondary = EnumChatFormatting.DARK_GREEN;
- } else {
- firstSentence = "You haven't set your Hypixel API key yet.";
- color = EnumChatFormatting.RED;
- colorSecondary = EnumChatFormatting.DARK_RED;
- }
- main.getChatHelper().sendMessage(color, firstSentence + " Use " + colorSecondary + "/api new" + color + " to request a new API key from Hypixel or use " + colorSecondary + "/" + this.getCommandName() + " apikey <key>" + color + " to manually set your existing API key.");
- } else {
- String key = args[1];
- if (Utils.isValidUuid(key)) {
- MooConfig.moo = key;
- main.getConfig().syncFromFields();
- main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "Updated API key!");
- } else {
- throw new SyntaxErrorException("That doesn't look like a valid API key...");
- }
- }
- }
-
- private void handleStalking(String playerName) throws CommandException {
+ //region sub commands: Best friends, friends & other players
+ private void handleStalking(String[] args) throws CommandException {
if (!Utils.isValidUuid(MooConfig.moo)) {
throw new MooCommandException("You haven't set your Hypixel API key yet. Use " + EnumChatFormatting.DARK_RED + "/api new" + EnumChatFormatting.RED + " to request a new API key from Hypixel or use " + EnumChatFormatting.DARK_RED + "/" + this.getCommandName() + " apikey <key>" + EnumChatFormatting.RED + " to manually set your existing API key.");
}
- main.getChatHelper().sendMessage(EnumChatFormatting.GRAY, "Stalking " + EnumChatFormatting.WHITE + playerName + EnumChatFormatting.GRAY + ". This may take a few seconds.");
- boolean isBestFriend = main.getFriendsHandler().isBestFriend(playerName, true);
- if (isBestFriend) {
- Friend stalkedPlayer = main.getFriendsHandler().getBestFriend(playerName);
- // we have the uuid already, so stalk the player
- stalkPlayer(stalkedPlayer);
+ if (args.length != 2) {
+ throw new WrongUsageException("/" + getCommandName() + " stalk <playerName>");
+ } else if (!Utils.isValidMcName(args[1])) {
+ throw new InvalidPlayerNameException(args[1]);
} else {
- // fetch player uuid
- ApiUtils.fetchFriendData(playerName, stalkedPlayer -> {
- if (stalkedPlayer == null) {
- throw new ApiContactException("Mojang", "couldn't stalk " + EnumChatFormatting.DARK_RED + playerName);
- } else if (stalkedPlayer.equals(Friend.FRIEND_NOT_FOUND)) {
- throw new PlayerNotFoundException("There is no player with the name " + EnumChatFormatting.DARK_RED + playerName + EnumChatFormatting.RED + ".");
- } else {
- // ... then stalk the player
- stalkPlayer(stalkedPlayer);
- }
- });
+ String playerName = args[1];
+ main.getChatHelper().sendMessage(EnumChatFormatting.GRAY, "Stalking " + EnumChatFormatting.WHITE + playerName + EnumChatFormatting.GRAY + ". This may take a few seconds.");
+ boolean isBestFriend = main.getFriendsHandler().isBestFriend(playerName, true);
+ if (isBestFriend) {
+ Friend stalkedPlayer = main.getFriendsHandler().getBestFriend(playerName);
+ // we have the uuid already, so stalk the player
+ stalkPlayer(stalkedPlayer);
+ } else {
+ // fetch player uuid
+ ApiUtils.fetchFriendData(playerName, stalkedPlayer -> {
+ if (stalkedPlayer == null) {
+ throw new ApiContactException("Mojang", "couldn't stalk " + EnumChatFormatting.DARK_RED + playerName);
+ } else if (stalkedPlayer.equals(Friend.FRIEND_NOT_FOUND)) {
+ throw new PlayerNotFoundException("There is no player with the name " + EnumChatFormatting.DARK_RED + playerName + EnumChatFormatting.RED + ".");
+ } else {
+ // ... then stalk the player
+ stalkPlayer(stalkedPlayer);
+ }
+ });
+ }
}
}
@@ -344,28 +223,95 @@ public class MooCommand extends CommandBase {
});
}
- private void handleStalkingSkyBlock(String playerName) throws CommandException {
+ private void handleBestFriendAdd(String[] args) throws CommandException {
+ if (args.length != 2) {
+ throw new WrongUsageException("/" + getCommandName() + " add <playerName>");
+ } else if (!Utils.isValidMcName(args[1])) {
+ throw new InvalidPlayerNameException(args[1]);
+ } else if (main.getFriendsHandler().isBestFriend(args[1], true)) {
+ throw new MooCommandException(EnumChatFormatting.DARK_RED + args[1] + EnumChatFormatting.RED + " is a best friend already.");
+ } else if (main.getFriendsHandler().getBestFriends().size() >= 100) {
+ throw new MooCommandException(EnumChatFormatting.RED + "The best friends list is limited to 100 players. Remove some with " + EnumChatFormatting.WHITE + "/" + getCommandName() + " remove <name> " + EnumChatFormatting.RED + "first");
+ } else {
+ main.getChatHelper().sendMessage(EnumChatFormatting.GOLD, "Fetching " + EnumChatFormatting.YELLOW + args[1] + EnumChatFormatting.GOLD + "'s unique user id. This may take a few seconds...");
+ // add friend async
+ main.getFriendsHandler().addBestFriend(args[1]);
+ }
+ }
+
+ private void handleBestFriendRemove(String[] args) throws CommandException {
+ if (args.length != 2) {
+ throw new WrongUsageException("/" + getCommandName() + " remove <playerName>");
+ } else if (!Utils.isValidMcName(args[1])) {
+ throw new InvalidPlayerNameException(args[1]);
+ }
+ String username = args[1];
+ boolean removed = main.getFriendsHandler().removeBestFriend(username);
+ if (removed) {
+ main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "Removed " + EnumChatFormatting.DARK_GREEN + username + EnumChatFormatting.GREEN + " from best friends list.");
+ } else {
+ throw new MooCommandException(EnumChatFormatting.DARK_RED + username + EnumChatFormatting.RED + " isn't a best friend.");
+ }
+ }
+
+ private void handleListBestFriends() {
+ Set<String> bestFriends = main.getFriendsHandler().getBestFriends();
+
+ // TODO show fancy gui with list of best friends; maybe with buttons to delete them
+ main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "\u279C Best friends"
+ + (bestFriends.isEmpty() ? "" : " (" + EnumChatFormatting.DARK_GREEN + bestFriends.size() + EnumChatFormatting.GREEN + ")") + ": "
+ + ((bestFriends.isEmpty())
+ ? EnumChatFormatting.ITALIC + "none :c"
+ : EnumChatFormatting.DARK_GREEN + String.join(EnumChatFormatting.GREEN + ", " + EnumChatFormatting.DARK_GREEN, bestFriends)));
+ }
+
+ private void handleNameChangeCheck(String[] args) throws CommandException {
+ if (args.length != 2) {
+ throw new WrongUsageException("/" + getCommandName() + " nameChangeCheck <playerName>");
+ } else if (!Utils.isValidMcName(args[1])) {
+ throw new InvalidPlayerNameException(args[1]);
+ }
+ Friend bestFriend = main.getFriendsHandler().getBestFriend(args[1]);
+ if (bestFriend.equals(Friend.FRIEND_NOT_FOUND)) {
+ throw new MooCommandException(EnumChatFormatting.DARK_RED + args[1] + EnumChatFormatting.RED + " isn't a best friend.");
+ } else {
+ main.getChatHelper().sendMessage(EnumChatFormatting.GOLD, "Checking if " + bestFriend.getName() + " changed their name... This will take a few seconds...");
+ // check for name change async
+ main.getFriendsHandler().doBestFriendNameChangeCheck(bestFriend, true);
+ }
+ }
+ //endregion
+
+ //region sub commands: SkyBlock
+ private void handleStalkingSkyBlock(String[] args) throws CommandException {
if (!Utils.isValidUuid(MooConfig.moo)) {
throw new MooCommandException("You haven't set your Hypixel API key yet. Use " + EnumChatFormatting.DARK_RED + "/api new" + EnumChatFormatting.RED + " to request a new API key from Hypixel or use " + EnumChatFormatting.DARK_RED + "/" + this.getCommandName() + " apikey <key>" + EnumChatFormatting.RED + " to manually set your existing API key.");
}
- main.getChatHelper().sendMessage(EnumChatFormatting.GRAY, "Stalking " + EnumChatFormatting.WHITE + playerName + EnumChatFormatting.GRAY + "'s SkyBlock stats. This may take a few seconds.");
- boolean isBestFriend = main.getFriendsHandler().isBestFriend(playerName, true);
- if (isBestFriend) {
- Friend stalkedPlayer = main.getFriendsHandler().getBestFriend(playerName);
- // we have the uuid already, so stalk the player
- stalkSkyBlockStats(stalkedPlayer);
+ if (args.length != 2) {
+ throw new WrongUsageException("/" + getCommandName() + " skyblockstalk <playerName>");
+ } else if (!Utils.isValidMcName(args[1])) {
+ throw new InvalidPlayerNameException(args[1]);
} else {
- // fetch player uuid
- ApiUtils.fetchFriendData(playerName, stalkedPlayer -> {
- if (stalkedPlayer == null) {
- throw new ApiContactException("Mojang", "couldn't stalk " + EnumChatFormatting.DARK_RED + playerName);
- } else if (stalkedPlayer.equals(Friend.FRIEND_NOT_FOUND)) {
- throw new PlayerNotFoundException("There is no player with the name " + EnumChatFormatting.DARK_RED + playerName + EnumChatFormatting.RED + ".");
- } else {
- // ... then stalk the player
- stalkSkyBlockStats(stalkedPlayer);
- }
- });
+ String playerName = args[1];
+ main.getChatHelper().sendMessage(EnumChatFormatting.GRAY, "Stalking " + EnumChatFormatting.WHITE + playerName + EnumChatFormatting.GRAY + "'s SkyBlock stats. This may take a few seconds.");
+ boolean isBestFriend = main.getFriendsHandler().isBestFriend(playerName, true);
+ if (isBestFriend) {
+ Friend stalkedPlayer = main.getFriendsHandler().getBestFriend(playerName);
+ // we have the uuid already, so stalk the player
+ stalkSkyBlockStats(stalkedPlayer);
+ } else {
+ // fetch player uuid
+ ApiUtils.fetchFriendData(playerName, stalkedPlayer -> {
+ if (stalkedPlayer == null) {
+ throw new ApiContactException("Mojang", "couldn't stalk " + EnumChatFormatting.DARK_RED + playerName);
+ } else if (stalkedPlayer.equals(Friend.FRIEND_NOT_FOUND)) {
+ throw new PlayerNotFoundException("There is no player with the name " + EnumChatFormatting.DARK_RED + playerName + EnumChatFormatting.RED + ".");
+ } else {
+ // ... then stalk the player
+ stalkSkyBlockStats(stalkedPlayer);
+ }
+ });
+ }
}
}
@@ -521,100 +467,205 @@ public class MooCommand extends CommandBase {
});
}
- private void handleBestFriendAdd(String[] args) throws CommandException {
- if (args.length != 2) {
- throw new WrongUsageException("/" + getCommandName() + " add <playerName>");
- } else if (!Utils.isValidMcName(args[1])) {
- throw new InvalidPlayerNameException(args[1]);
- } else if (main.getFriendsHandler().isBestFriend(args[1], true)) {
- throw new MooCommandException(EnumChatFormatting.DARK_RED + args[1] + EnumChatFormatting.RED + " is a best friend already.");
- } else if (main.getFriendsHandler().getBestFriends().size() >= 100) {
- throw new MooCommandException(EnumChatFormatting.RED + "The best friends list is limited to 100 players. Remove some with " + EnumChatFormatting.WHITE + "/" + getCommandName() + " remove <name> " + EnumChatFormatting.RED + "first");
- } else {
- main.getChatHelper().sendMessage(EnumChatFormatting.GOLD, "Fetching " + EnumChatFormatting.YELLOW + args[1] + EnumChatFormatting.GOLD + "'s unique user id. This may take a few seconds...");
- // add friend async
- main.getFriendsHandler().addBestFriend(args[1]);
+ private void handleAnalyzeIsland(ICommandSender sender) {
+ Map<String, String> minions = DataHelper.getMinions();
+
+ Map<String, Integer> detectedMinions = new HashMap<>();
+ Map<Integer, Integer> detectedMinionsWithSkin = new HashMap<>();
+ int detectedMinionCount = 0;
+ int minionsWithSkinCount = 0;
+ entityLoop:
+ for (Entity entity : sender.getEntityWorld().loadedEntityList) {
+ if (entity instanceof EntityArmorStand) {
+ EntityArmorStand minion = (EntityArmorStand) entity;
+
+ if (minion.isInvisible() || !minion.isSmall() || minion.getHeldItem() == null) {
+ // not a minion: invisible, or not small armor stand, or no item in hand (= minion in a minion chair)
+ continue;
+ }
+ for (int slot = 0; slot < 4; slot++) {
+ if (minion.getCurrentArmor(slot) == null) {
+ // not a minion: missing equipment
+ continue entityLoop;
+ }
+ }
+ ItemStack skullItem = minion.getCurrentArmor(3); // head slot
+ if (skullItem.getItem() instanceof ItemSkull && skullItem.getMetadata() == 3 && skullItem.hasTagCompound()) {
+ // is a player head!
+ if (skullItem.getTagCompound().hasKey("SkullOwner", Constants.NBT.TAG_COMPOUND)) {
+ NBTTagCompound skullOwner = skullItem.getTagCompound().getCompoundTag("SkullOwner");
+ String skullDataBase64 = skullOwner.getCompoundTag("Properties").getTagList("textures", Constants.NBT.TAG_COMPOUND).getCompoundTagAt(0).getString("Value");
+ String skullData = new String(Base64.decodeBase64(skullDataBase64));
+ String minionSkinId = StringUtils.substringBetween(skullData, "http://textures.minecraft.net/texture/", "\"");
+ String detectedMinion = minions.get(minionSkinId);
+ if (detectedMinion != null) {
+ // minion head matches one know minion tier
+ detectedMinions.put(detectedMinion, detectedMinions.getOrDefault(detectedMinion, 0) + 1);
+ detectedMinionCount++;
+ } else {
+ int minionTier = ImageUtils.getTierFromTexture(minionSkinId);
+ if (minionTier > 0) {
+ detectedMinionsWithSkin.put(minionTier, detectedMinionsWithSkin.getOrDefault(minionTier, 0) + 1);
+ minionsWithSkinCount++;
+ } else {
+ // looked like a minion but has no matching tier badge
+ main.getLogger().info("[/moo analyzeIsland] Found an armor stand that could be a minion but it is missing a tier badge: " + minionSkinId + "\t\t\t" + minion.serializeNBT());
+ }
+ }
+ }
+ }
+ }
}
+ StringBuilder analysisResults = new StringBuilder("Found ").append(EnumChatFormatting.GOLD).append(detectedMinionCount).append(EnumChatFormatting.YELLOW).append(" minions");
+ if (minionsWithSkinCount > 0) {
+ analysisResults.append(" + ").append(EnumChatFormatting.GOLD).append(minionsWithSkinCount).append(EnumChatFormatting.YELLOW).append(" unknown minions with skins");
+ }
+ analysisResults.append(" on this island");
+ detectedMinions.entrySet().stream()
+ .sorted(Map.Entry.comparingByKey()) // sort alphabetically by minion name and tier
+ .forEach(minion -> {
+ String minionWithTier = minion.getKey();
+ int lastSpace = minionWithTier.lastIndexOf(' ');
+
+ String tierRoman = minionWithTier.substring(lastSpace + 1);
+
+ int tierArabic = Utils.convertRomanToArabic(tierRoman);
+ EnumChatFormatting tierColor = Utils.getMinionTierColor(tierArabic);
+
+ minionWithTier = minionWithTier.substring(0, lastSpace) + " " + tierColor + (MooConfig.useRomanNumerals() ? tierRoman : tierArabic);
+ analysisResults.append("\n ").append(EnumChatFormatting.GOLD).append(minion.getValue()).append(minion.getValue() > 1 ? "✕ " : "⨉ ")
+ .append(EnumChatFormatting.YELLOW).append(minionWithTier);
+ });
+ detectedMinionsWithSkin.entrySet().stream()
+ .sorted(Map.Entry.comparingByKey()) // sort by tier
+ .forEach(minionWithSkin -> {
+ EnumChatFormatting tierColor = Utils.getMinionTierColor(minionWithSkin.getKey());
+ String minionTier = MooConfig.useRomanNumerals() ? Utils.convertArabicToRoman(minionWithSkin.getKey()) : String.valueOf(minionWithSkin.getKey());
+ analysisResults.append("\n ").append(EnumChatFormatting.GOLD).append(minionWithSkin.getValue()).append(minionWithSkin.getValue() > 1 ? "✕ " : "⨉ ")
+ .append(EnumChatFormatting.RED).append("Unknown minion ").append(EnumChatFormatting.YELLOW).append("(new or with minion skin) ").append(tierColor).append(minionTier);
+ });
+ main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, analysisResults.toString());
}
- private void handleBestFriendRemove(String[] args) throws CommandException {
- if (args.length != 2) {
- throw new WrongUsageException("/" + getCommandName() + " remove <playerName>");
- } else if (!Utils.isValidMcName(args[1])) {
- throw new InvalidPlayerNameException(args[1]);
- }
- String username = args[1];
- boolean removed = main.getFriendsHandler().removeBestFriend(username);
- if (removed) {
- main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "Removed " + EnumChatFormatting.DARK_GREEN + username + EnumChatFormatting.GREEN + " from best friends list.");
+ private void handleDungeon(String[] args) throws MooCommandException {
+ DungeonCache dungeonCache = main.getDungeonCache();
+ if (args.length == 2 && args[1].equalsIgnoreCase("gui")) {
+ // edit dungeon gui
+ displayGuiScreen(new DungeonOverlayGuiConfig(main));
+ } else if (dungeonCache.isInDungeon()) {
+ dungeonCache.sendDungeonPerformance();
} else {
- throw new MooCommandException(EnumChatFormatting.DARK_RED + username + EnumChatFormatting.RED + " isn't a best friend.");
+ throw new MooCommandException(EnumChatFormatting.DARK_RED + "Looks like you're not in a dungeon... However, you can edit the Dungeon Performance overlay with " + EnumChatFormatting.RED + "/" + getCommandName() + " dungeon gui");
}
}
+ //endregion
- private void handleListBestFriends() {
- Set<String> bestFriends = main.getFriendsHandler().getBestFriends();
-
- // TODO show fancy gui with list of best friends; maybe with buttons to delete them
- main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "\u279C Best friends"
- + (bestFriends.isEmpty() ? "" : " (" + EnumChatFormatting.DARK_GREEN + bestFriends.size() + EnumChatFormatting.GREEN + ")") + ": "
- + ((bestFriends.isEmpty())
- ? EnumChatFormatting.ITALIC + "none :c"
- : EnumChatFormatting.DARK_GREEN + String.join(EnumChatFormatting.GREEN + ", " + EnumChatFormatting.DARK_GREEN, bestFriends)));
+ //region sub-commands: miscellaneous
+ private void handleGuiScale(String[] args) throws CommandException {
+ int currentGuiScale = (Minecraft.getMinecraft()).gameSettings.guiScale;
+ if (args.length == 1) {
+ main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "\u279C Current GUI scale: " + EnumChatFormatting.DARK_GREEN + currentGuiScale);
+ } else {
+ int scale = MathHelper.parseIntWithDefault(args[1], -1);
+ if (scale == -1 || scale > 10) {
+ throw new NumberInvalidException(EnumChatFormatting.DARK_RED + args[1] + EnumChatFormatting.RED + " is an invalid GUI scale value. Valid values are integers below 10");
+ }
+ Minecraft.getMinecraft().gameSettings.guiScale = scale;
+ main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "\u2714 New GUI scale: " + EnumChatFormatting.DARK_GREEN + scale + EnumChatFormatting.GREEN + " (previous: " + EnumChatFormatting.DARK_GREEN + currentGuiScale + EnumChatFormatting.GREEN + ")");
+ }
}
- private void handleNameChangeCheck(String[] args) throws CommandException {
- if (args.length != 2) {
- throw new WrongUsageException("/" + getCommandName() + " nameChangeCheck <playerName>");
- } else if (!Utils.isValidMcName(args[1])) {
- throw new InvalidPlayerNameException(args[1]);
- }
- Friend bestFriend = main.getFriendsHandler().getBestFriend(args[1]);
- if (bestFriend.equals(Friend.FRIEND_NOT_FOUND)) {
- throw new MooCommandException(EnumChatFormatting.DARK_RED + args[1] + EnumChatFormatting.RED + " isn't a best friend.");
+ private void handleApiKey(String[] args) throws CommandException {
+ if (args.length == 1) {
+ String firstSentence;
+ EnumChatFormatting color;
+ EnumChatFormatting colorSecondary;
+ if (Utils.isValidUuid(MooConfig.moo)) {
+ firstSentence = "You already set your Hypixel API key.";
+ color = EnumChatFormatting.GREEN;
+ colorSecondary = EnumChatFormatting.DARK_GREEN;
+ } else {
+ firstSentence = "You haven't set your Hypixel API key yet.";
+ color = EnumChatFormatting.RED;
+ colorSecondary = EnumChatFormatting.DARK_RED;
+ }
+ main.getChatHelper().sendMessage(color, firstSentence + " Use " + colorSecondary + "/api new" + color + " to request a new API key from Hypixel or use " + colorSecondary + "/" + this.getCommandName() + " apikey <key>" + color + " to manually set your existing API key.");
} else {
- main.getChatHelper().sendMessage(EnumChatFormatting.GOLD, "Checking if " + bestFriend.getName() + " changed their name... This will take a few seconds...");
- // check for name change async
- main.getFriendsHandler().doBestFriendNameChangeCheck(bestFriend, true);
+ String key = args[1];
+ if (Utils.isValidUuid(key)) {
+ MooConfig.moo = key;
+ main.getConfig().syncFromFields();
+ main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "Updated API key!");
+ } else {
+ throw new SyntaxErrorException("That doesn't look like a valid API key...");
+ }
}
}
+ //endregion
- @Override
- public String getCommandName() {
- return "moo";
+ //region sub-commands: update mod
+ private void handleUpdate(String[] args) throws MooCommandException {
+ if (args.length == 2 && args[1].equalsIgnoreCase("help")) {
+ handleUpdateHelp();
+ return;
+ }
+ boolean updateCheckStarted = main.getVersionChecker().runUpdateCheck(true);
+
+ if (updateCheckStarted) {
+ main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "\u279C Checking for a newer mod version...");
+ // VersionChecker#handleVersionStatus will run with a 5 seconds delay
+ } else {
+ long nextUpdate = main.getVersionChecker().getNextCheck();
+ String waitingTime = String.format("%02d:%02d",
+ TimeUnit.MILLISECONDS.toMinutes(nextUpdate),
+ TimeUnit.MILLISECONDS.toSeconds(nextUpdate) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(nextUpdate)));
+ throw new MooCommandException("\u26A0 Update checker is on cooldown. Please wait " + EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + waitingTime + EnumChatFormatting.RESET + EnumChatFormatting.RED + " more minutes before checking again.");
+ }
}
- @Override
- public List<String> getCommandAliases() {
- return Collections.singletonList("m");
+ private void handleUpdateHelp() {
+ main.getChatHelper().sendMessage(new ChatComponentText("\u279C Update instructions:").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(true))
+ .appendSibling(new ChatComponentText("\n\u278A" + EnumChatFormatting.YELLOW + " download latest mod version").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(false)
+ .setChatClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, main.getVersionChecker().getDownloadUrl()))
+ .setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(EnumChatFormatting.YELLOW + "Download the latest version of " + Cowlection.MODNAME + "\n\u279C Click to download latest mod file")))))
+ .appendSibling(new ChatComponentText("\n\u278B" + EnumChatFormatting.YELLOW + " exit Minecraft").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(false)
+ .setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(EnumChatFormatting.GOLD + "\u278B" + EnumChatFormatting.YELLOW + " Without closing Minecraft first,\n" + EnumChatFormatting.YELLOW + "you can't delete the old .jar file!")))))
+ .appendSibling(new ChatComponentText("\n\u278C" + EnumChatFormatting.YELLOW + " copy " + EnumChatFormatting.GOLD + Cowlection.MODNAME.replace(" ", "") + "-" + main.getVersionChecker().getNewVersion() + ".jar" + EnumChatFormatting.YELLOW + " into mods directory").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(false)
+ .setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/moo directory"))
+ .setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(EnumChatFormatting.YELLOW + "Open mods directory with command " + EnumChatFormatting.GOLD + "/moo directory\n\u279C Click to open mods directory")))))
+ .appendSibling(new ChatComponentText("\n\u278D" + EnumChatFormatting.YELLOW + " delete old mod file " + EnumChatFormatting.GOLD + Cowlection.MODNAME.replace(" ", "") + "-" + Cowlection.VERSION + ".jar ").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(false)))
+ .appendSibling(new ChatComponentText("\n\u278E" + EnumChatFormatting.YELLOW + " start Minecraft again").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD).setBold(false))));
}
+ //endregion
- @Override
- public String getCommandUsage(ICommandSender sender) {
- return "/" + getCommandName() + " help";
+ // other helper methods:
+ private void displayGuiScreen(GuiScreen gui) {
+ // delay by 1 tick, because the chat closing would close the new gui instantly as well.
+ new TickDelay(() -> Minecraft.getMinecraft().displayGuiScreen(gui), 1);
}
private void sendCommandUsage(ICommandSender sender) {
IChatComponent usage = new MooChatComponent("\u279C " + Cowlection.MODNAME + " commands:").gold().bold()
- .appendSibling(createCmdHelpSection(1, "Friends & other players"))
+ .appendSibling(createCmdHelpSection(1, "Best friends, friends & other players"))
.appendSibling(createCmdHelpEntry("stalk", "Get info of player's status"))
- .appendSibling(createCmdHelpEntry("stalkskyblock", "Get info of player's SkyBlock stats"))
- .appendSibling(createCmdHelpEntry("analyzeIsland", "Analyze a SkyBlock private island"))
- .appendSibling(createCmdHelpEntry("dungeon", "SkyBlock Dungeons: display current dungeon performance"))
- .appendSibling(createCmdHelpEntry("dungeonGui", "SkyBlock Dungeons: edit dungeon performance GUI"))
.appendSibling(createCmdHelpEntry("add", "Add best friends"))
.appendSibling(createCmdHelpEntry("remove", "Remove best friends"))
.appendSibling(createCmdHelpEntry("list", "View list of best friends"))
.appendSibling(createCmdHelpEntry("online", "View list of best friends that are currently online"))
- .appendSibling(createCmdHelpEntry("nameChangeCheck", "Force a scan for a changed name of a best friend"))
+ .appendSibling(createCmdHelpEntry("nameChangeCheck", "Force a scan for a changed name of a best friend (is done automatically as well)"))
.appendSibling(createCmdHelpEntry("toggle", "Toggle join/leave notifications"))
- .appendSibling(createCmdHelpSection(2, "Miscellaneous"))
+ .appendSibling(createCmdHelpSection(2, "SkyBlock"))
+ .appendSibling(createCmdHelpEntry("stalkskyblock", "Get info of player's SkyBlock stats"))
+ .appendSibling(createCmdHelpEntry("analyzeIsland", "Analyze a SkyBlock private island"))
+ .appendSibling(createCmdHelpEntry("dungeon", "SkyBlock Dungeons: display current dungeon performance"))
+ .appendSibling(createCmdHelpEntry("dungeonGui", "SkyBlock Dungeons: edit dungeon performance GUI"))
+ .appendSibling(createCmdHelpSection(3, "Miscellaneous"))
.appendSibling(createCmdHelpEntry("config", "Open mod's configuration"))
.appendSibling(createCmdHelpEntry("search", "Open Minecraft log search"))
.appendSibling(createCmdHelpEntry("guiScale", "Change GUI scale"))
.appendSibling(createCmdHelpEntry("rr", "Alias for /r without auto-replacement to /msg"))
.appendSibling(createCmdHelpEntry("shrug", "\u00AF\\_(\u30C4)_/\u00AF")) // ¯\_(ツ)_/¯
- .appendSibling(createCmdHelpSection(3, "Update mod"))
+ .appendSibling(createCmdHelpSection(4, "Update mod"))
.appendSibling(createCmdHelpEntry("update", "Check for new mod updates"))
.appendSibling(createCmdHelpEntry("updateHelp", "Show mod update instructions"))
.appendSibling(createCmdHelpEntry("version", "View results of last mod update check"))
@@ -642,10 +693,12 @@ public class MooCommand extends CommandBase {
public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {
if (args.length == 1) {
return getListOfStringsMatchingLastWord(args,
- /* friends & other players */ "stalk", "askPolitelyWhereTheyAre", "stalkskyblock", "skyblockstalk", "askPolitelyAboutTheirSkyBlockProgress", "analyzeIsland", "dungeon", "dungeonGui", "guiDungeon", "add", "remove", "list", "online", "nameChangeCheck", "toggle",
+ /* Best friends, friends & other players */ "stalk", "add", "remove", "list", "online", "nameChangeCheck", "toggle",
+ /* SkyBlock */ "stalkskyblock", "skyblockstalk", "analyzeIsland", "dungeon", "dungeonGui", "guiDungeon",
/* miscellaneous */ "config", "search", "guiscale", "rr", "shrug", "apikey",
/* update mod */ "update", "updateHelp", "version", "directory",
- /* help */ "help");
+ /* help */ "help",
+ /* rarely used aliases */ "askPolitelyWhereTheyAre", "askPolitelyAboutTheirSkyBlockProgress");
} else if (args.length == 2 && args[0].equalsIgnoreCase("remove")) {
return getListOfStringsMatchingLastWord(args, main.getFriendsHandler().getBestFriends());
}