diff options
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/main/java/eu/olli/cowlection/Cowlection.java | 11 | ||||
-rw-r--r-- | src/main/java/eu/olli/cowlection/listener/PlayerListener.java | 193 | ||||
-rw-r--r-- | src/main/java/eu/olli/cowlection/listener/skyblock/DungeonsListener.java (renamed from src/main/java/eu/olli/cowlection/listener/DungeonsListener.java) | 2 | ||||
-rw-r--r-- | src/main/java/eu/olli/cowlection/listener/skyblock/SkyBlockListener.java | 162 |
5 files changed, 224 insertions, 146 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index f19d93b..83686aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Added `/moo say [optional text]`: You can say `moo` again without triggering the command `/moo` 🎉 ### Changed +- SkyBlock related event listeners now only run while on SkyBlock, otherwise they are disabled + - Fixes e.g. removal of enchantments in non-SkyBlock gamemodes - Tab-completable player names now include names from: - party or game (duels) invites - Dungeon party finder: player joins group diff --git a/src/main/java/eu/olli/cowlection/Cowlection.java b/src/main/java/eu/olli/cowlection/Cowlection.java index ab538ee..9ce14c3 100644 --- a/src/main/java/eu/olli/cowlection/Cowlection.java +++ b/src/main/java/eu/olli/cowlection/Cowlection.java @@ -7,7 +7,6 @@ import eu.olli.cowlection.config.MooConfig; import eu.olli.cowlection.handler.FriendsHandler; import eu.olli.cowlection.handler.PlayerCache; import eu.olli.cowlection.listener.ChatListener; -import eu.olli.cowlection.listener.DungeonsListener; import eu.olli.cowlection.listener.PlayerListener; import eu.olli.cowlection.util.ChatHelper; import eu.olli.cowlection.util.VersionChecker; @@ -40,6 +39,7 @@ public class Cowlection { private VersionChecker versionChecker; private ChatHelper chatHelper; private PlayerCache playerCache; + private boolean isOnSkyBlock; private Logger logger; @Mod.EventHandler @@ -62,7 +62,6 @@ public class Cowlection { @EventHandler public void init(FMLInitializationEvent e) { MinecraftForge.EVENT_BUS.register(new ChatListener(this)); - MinecraftForge.EVENT_BUS.register(new DungeonsListener(this)); MinecraftForge.EVENT_BUS.register(new PlayerListener(this)); ClientCommandHandler.instance.registerCommand(new MooCommand(this)); ClientCommandHandler.instance.registerCommand(new ShrugCommand(this)); @@ -109,6 +108,14 @@ public class Cowlection { return logger; } + public boolean isOnSkyBlock() { + return isOnSkyBlock; + } + + public void setIsOnSkyBlock(boolean isOnSkyBlock) { + this.isOnSkyBlock = isOnSkyBlock; + } + /** * Get mod's instance; instead of this method use dependency injection where possible */ diff --git a/src/main/java/eu/olli/cowlection/listener/PlayerListener.java b/src/main/java/eu/olli/cowlection/listener/PlayerListener.java index 1c7710d..fe15a4f 100644 --- a/src/main/java/eu/olli/cowlection/listener/PlayerListener.java +++ b/src/main/java/eu/olli/cowlection/listener/PlayerListener.java @@ -1,171 +1,35 @@ package eu.olli.cowlection.listener; import eu.olli.cowlection.Cowlection; -import eu.olli.cowlection.config.MooConfig; +import eu.olli.cowlection.listener.skyblock.DungeonsListener; +import eu.olli.cowlection.listener.skyblock.SkyBlockListener; import eu.olli.cowlection.util.GsonUtils; import eu.olli.cowlection.util.TickDelay; -import eu.olli.cowlection.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.inventory.GuiChest; import net.minecraft.client.gui.inventory.GuiInventory; -import net.minecraft.enchantment.Enchantment; -import net.minecraft.init.Blocks; -import net.minecraft.init.Items; import net.minecraft.inventory.ContainerChest; import net.minecraft.inventory.IInventory; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; +import net.minecraft.scoreboard.ScoreObjective; import net.minecraft.util.EnumChatFormatting; -import net.minecraft.util.StatCollector; import net.minecraftforge.client.event.GuiScreenEvent; -import net.minecraftforge.common.util.Constants; -import net.minecraftforge.event.entity.player.ItemTooltipEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.PlayerSetSpawnEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.network.FMLNetworkEvent; -import org.apache.commons.lang3.StringUtils; import org.lwjgl.input.Keyboard; -import java.text.NumberFormat; -import java.text.ParseException; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.List; -import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - public class PlayerListener { private final Cowlection main; - private final NumberFormat numberFormatter; - /** - * timestamp example: 4/20/20 4:20 AM - */ - private final Pattern SB_TIMESTAMP_PATTERN = Pattern.compile("^(\\d{1,2})/(\\d{1,2})/(\\d{2}) (\\d{1,2}):(\\d{2}) (AM|PM)$"); + private DungeonsListener dungeonsListener; + private SkyBlockListener skyBlockListener; public PlayerListener(Cowlection main) { this.main = main; - numberFormatter = NumberFormat.getNumberInstance(Locale.US); - numberFormatter.setMaximumFractionDigits(0); - } - - @SubscribeEvent - public void onItemTooltip(ItemTooltipEvent e) { - if (e.itemStack == null || e.toolTip == null) { - return; - } - // remove unnecessary tooltip entries: dyed leather armor - NBTTagCompound nbtDisplay = e.itemStack.getSubCompound("display", false); - if (nbtDisplay != null && nbtDisplay.hasKey("color", Constants.NBT.TAG_INT)) { - if (Minecraft.getMinecraft().gameSettings.advancedItemTooltips) { - e.toolTip.removeIf(line -> line.startsWith("Color: #")); - } else { - e.toolTip.removeIf(line -> line.equals(EnumChatFormatting.ITALIC + StatCollector.translateToLocal("item.dyed"))); - } - } - - // remove unnecessary tooltip entries: enchantments (already added via lore) - NBTTagList enchantments = e.itemStack.getEnchantmentTagList(); - if (enchantments != null) { - for (int enchantmentNr = 0; enchantmentNr < enchantments.tagCount(); ++enchantmentNr) { - int enchantmentId = enchantments.getCompoundTagAt(enchantmentNr).getShort("id"); - int enchantmentLevel = enchantments.getCompoundTagAt(enchantmentNr).getShort("lvl"); - - if (Enchantment.getEnchantmentById(enchantmentId) != null) { - e.toolTip.remove(Enchantment.getEnchantmentById(enchantmentId).getTranslatedName(enchantmentLevel)); - } - } - } - - if (!MooConfig.showAdvancedTooltips && !Keyboard.isKeyDown(Keyboard.KEY_LMENU)) { - return; - } - // add item age to tooltip - NBTTagCompound extraAttributes = e.itemStack.getSubCompound("ExtraAttributes", false); - if (extraAttributes != null && extraAttributes.hasKey("timestamp")) { - String rawTimestamp = extraAttributes.getString("timestamp"); - Matcher sbTimestampMatcher = SB_TIMESTAMP_PATTERN.matcher(rawTimestamp); - if (sbTimestampMatcher.matches()) { - // Timezone = America/Toronto! headquarter is in Val-des-Monts, Quebec, Canada; timezone can also be confirmed by looking at the timestamps of New Year Cakes - ZonedDateTime dateTime = getDateTimeWithZone(sbTimestampMatcher, ZoneId.of("America/Toronto")); // EDT/EST - String dateTimeFormatted = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm zzz")); - - int index = Math.max(0, e.toolTip.size() - (e.showAdvancedItemTooltips ? /* item name & nbt info */ 2 : 0)); - - if (Keyboard.isKeyDown(Keyboard.KEY_LMENU)) { - // full tooltip - e.toolTip.add(index, "Timestamp: " + EnumChatFormatting.DARK_GRAY + dateTimeFormatted); - e.toolTip.add(index, "Item age: " + EnumChatFormatting.DARK_GRAY + Utils.getDurationAsWords(dateTime.toEpochSecond() * 1000).first()); - } else { - // abbreviated tooltip - e.toolTip.add(index, "Item age: " + EnumChatFormatting.DARK_GRAY + Utils.getDurationAsWord(dateTime.toEpochSecond() * 1000)); - } - } - } - - // for auction house: show price for each item if multiple items are sold at once - if (e.entityPlayer != null && e.entityPlayer.openContainer instanceof ContainerChest) { - int stackSize = e.itemStack.stackSize; - if ((stackSize == 1 && !isSubmitBidItem(e.itemStack)) || e.toolTip.size() < 4) { - // only 1 item or irrelevant tooltip - nothing to do here, abort! - return; - } - - if (isSubmitBidItem(e.itemStack)) { - // special case: "place bid on an item" interface ("Auction View") - ItemStack auctionedItem = e.entityPlayer.openContainer.getInventory().get(13); - stackSize = auctionedItem.stackSize; - if (stackSize == 1) { - // still only 1 item, abort! - return; - } - } - - List<String> toolTip = e.toolTip; - - // starting with i=1 because first line is never the one we're looking for - for (int i = 1; i < toolTip.size(); i++) { - String toolTipLineUnformatted = EnumChatFormatting.getTextWithoutFormattingCodes(toolTip.get(i)); - if (toolTipLineUnformatted.startsWith("Top bid: ") - || toolTipLineUnformatted.startsWith("Starting bid: ") - || toolTipLineUnformatted.startsWith("Buy it now: ") - || toolTipLineUnformatted.startsWith("Sold for: ") - || toolTipLineUnformatted.startsWith("New bid: ") /* special case: 'Submit Bid' item */) { - - try { - long price = numberFormatter.parse(StringUtils.substringBetween(toolTipLineUnformatted, ": ", " coins")).longValue(); - double priceEach = price / (double) stackSize; - String formattedPriceEach = priceEach < 5000 ? numberFormatter.format(priceEach) : Utils.formatNumberWithAbbreviations(priceEach); - String pricePerItem = EnumChatFormatting.YELLOW + " (" + formattedPriceEach + " each)"; - toolTip.set(i, toolTip.get(i) + pricePerItem); - return; - } catch (ParseException ex) { - return; - } - } - } - } - } - - private ZonedDateTime getDateTimeWithZone(Matcher sbTimestampMatcher, ZoneId zoneId) { - int year = 2000 + Integer.parseInt(sbTimestampMatcher.group(3)); - int month = Integer.parseInt(sbTimestampMatcher.group(1)); - int day = Integer.parseInt(sbTimestampMatcher.group(2)); - int hour = (Integer.parseInt(sbTimestampMatcher.group(4)) + (sbTimestampMatcher.group(6).equals("PM") ? 12 : 0)) % 24; - int minute = Integer.parseInt(sbTimestampMatcher.group(5)); - - LocalDateTime localDateTime = LocalDateTime.of(year, month, day, hour, minute); - - return ZonedDateTime.of(localDateTime, zoneId); - } - - private boolean isSubmitBidItem(ItemStack itemStack) { - return (itemStack.getItem().equals(Items.gold_nugget) || itemStack.getItem().equals(Item.getItemFromBlock(Blocks.gold_block))) - && (itemStack.hasDisplayName() && (itemStack.getDisplayName().endsWith("Submit Bid") || itemStack.getDisplayName().endsWith("Collect Auction"))); } @SubscribeEvent @@ -207,11 +71,54 @@ public class PlayerListener { public void onServerJoin(FMLNetworkEvent.ClientConnectedToServerEvent e) { main.getVersionChecker().runUpdateCheck(false); new TickDelay(() -> main.getChatHelper().sendOfflineMessages(), 6 * 20); + main.setIsOnSkyBlock(false); + } + + @SubscribeEvent + public void onWorldEnter(PlayerSetSpawnEvent e) { + // check if player is on SkyBlock or on another gamemode + new TickDelay(() -> { + ScoreObjective scoreboardSidebar = e.entityPlayer.worldObj.getScoreboard().getObjectiveInDisplaySlot(1); + boolean wasOnSkyBlock = main.isOnSkyBlock(); + main.setIsOnSkyBlock(scoreboardSidebar != null && EnumChatFormatting.getTextWithoutFormattingCodes(scoreboardSidebar.getDisplayName()).startsWith("SKYBLOCK")); + + if (!wasOnSkyBlock && main.isOnSkyBlock()) { + // player wasn't on SkyBlock before but now is on SkyBlock + main.getLogger().info("Entered SkyBlock! Registering SkyBlock listeners"); + registerSkyBlockListeners(); + } else if (wasOnSkyBlock && !main.isOnSkyBlock()) { + // player was on SkyBlock before and is now in another gamemode + unregisterSkyBlockListeners(); + main.getLogger().info("Leaving SkyBlock! Un-registering SkyBlock listeners"); + } + }, 20); // 1 second delay, making sure scoreboard got sent + } + + private void registerSkyBlockListeners() { + if (dungeonsListener == null) { + MinecraftForge.EVENT_BUS.register(dungeonsListener = new DungeonsListener(main)); + } + if (skyBlockListener == null) { + MinecraftForge.EVENT_BUS.register(skyBlockListener = new SkyBlockListener(main)); + } + } + + private void unregisterSkyBlockListeners() { + if (dungeonsListener != null) { + MinecraftForge.EVENT_BUS.unregister(dungeonsListener); + dungeonsListener = null; + } + if (skyBlockListener != null) { + MinecraftForge.EVENT_BUS.unregister(skyBlockListener); + skyBlockListener = null; + } } @SubscribeEvent public void onServerLeave(FMLNetworkEvent.ClientDisconnectionFromServerEvent e) { + main.setIsOnSkyBlock(false); main.getFriendsHandler().saveBestFriends(); main.getPlayerCache().clearAllCaches(); + unregisterSkyBlockListeners(); } } diff --git a/src/main/java/eu/olli/cowlection/listener/DungeonsListener.java b/src/main/java/eu/olli/cowlection/listener/skyblock/DungeonsListener.java index cbc45c9..eedd0b7 100644 --- a/src/main/java/eu/olli/cowlection/listener/DungeonsListener.java +++ b/src/main/java/eu/olli/cowlection/listener/skyblock/DungeonsListener.java @@ -1,4 +1,4 @@ -package eu.olli.cowlection.listener; +package eu.olli.cowlection.listener.skyblock; import eu.olli.cowlection.Cowlection; import eu.olli.cowlection.config.MooConfig; diff --git a/src/main/java/eu/olli/cowlection/listener/skyblock/SkyBlockListener.java b/src/main/java/eu/olli/cowlection/listener/skyblock/SkyBlockListener.java new file mode 100644 index 0000000..9722fb5 --- /dev/null +++ b/src/main/java/eu/olli/cowlection/listener/skyblock/SkyBlockListener.java @@ -0,0 +1,162 @@ +package eu.olli.cowlection.listener.skyblock; + +import eu.olli.cowlection.Cowlection; +import eu.olli.cowlection.config.MooConfig; +import eu.olli.cowlection.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.event.entity.player.ItemTooltipEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.apache.commons.lang3.StringUtils; +import org.lwjgl.input.Keyboard; + +import java.text.NumberFormat; +import java.text.ParseException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SkyBlockListener { + private final Cowlection main; + /** + * timestamp example: 4/20/20 4:20 AM + */ + private final Pattern SB_TIMESTAMP_PATTERN = Pattern.compile("^(\\d{1,2})/(\\d{1,2})/(\\d{2}) (\\d{1,2}):(\\d{2}) (AM|PM)$"); + private final NumberFormat numberFormatter; + + public SkyBlockListener(Cowlection main) { + this.main = main; + numberFormatter = NumberFormat.getNumberInstance(Locale.US); + numberFormatter.setMaximumFractionDigits(0); + } + + @SubscribeEvent + public void onItemTooltip(ItemTooltipEvent e) { + if (e.itemStack == null || e.toolTip == null) { + return; + } + // remove unnecessary tooltip entries: dyed leather armor + NBTTagCompound nbtDisplay = e.itemStack.getSubCompound("display", false); + if (nbtDisplay != null && nbtDisplay.hasKey("color", Constants.NBT.TAG_INT)) { + if (Minecraft.getMinecraft().gameSettings.advancedItemTooltips) { + e.toolTip.removeIf(line -> line.startsWith("Color: #")); + } else { + e.toolTip.removeIf(line -> line.equals(EnumChatFormatting.ITALIC + StatCollector.translateToLocal("item.dyed"))); + } + } + + // remove unnecessary tooltip entries: enchantments (already added via lore) + NBTTagList enchantments = e.itemStack.getEnchantmentTagList(); + if (enchantments != null) { + for (int enchantmentNr = 0; enchantmentNr < enchantments.tagCount(); ++enchantmentNr) { + int enchantmentId = enchantments.getCompoundTagAt(enchantmentNr).getShort("id"); + int enchantmentLevel = enchantments.getCompoundTagAt(enchantmentNr).getShort("lvl"); + + if (Enchantment.getEnchantmentById(enchantmentId) != null) { + e.toolTip.remove(Enchantment.getEnchantmentById(enchantmentId).getTranslatedName(enchantmentLevel)); + } + } + } + + if (!MooConfig.showAdvancedTooltips && !Keyboard.isKeyDown(Keyboard.KEY_LMENU)) { + return; + } + // add item age to tooltip + NBTTagCompound extraAttributes = e.itemStack.getSubCompound("ExtraAttributes", false); + if (extraAttributes != null && extraAttributes.hasKey("timestamp")) { + String rawTimestamp = extraAttributes.getString("timestamp"); + Matcher sbTimestampMatcher = SB_TIMESTAMP_PATTERN.matcher(rawTimestamp); + if (sbTimestampMatcher.matches()) { + // Timezone = America/Toronto! headquarter is in Val-des-Monts, Quebec, Canada; timezone can also be confirmed by looking at the timestamps of New Year Cakes + ZonedDateTime dateTime = getDateTimeWithZone(sbTimestampMatcher, ZoneId.of("America/Toronto")); // EDT/EST + String dateTimeFormatted = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm zzz")); + + int index = Math.max(0, e.toolTip.size() - (e.showAdvancedItemTooltips ? /* item name & nbt info */ 2 : 0)); + + if (Keyboard.isKeyDown(Keyboard.KEY_LMENU)) { + // full tooltip + e.toolTip.add(index, "Timestamp: " + EnumChatFormatting.DARK_GRAY + dateTimeFormatted); + e.toolTip.add(index, "Item age: " + EnumChatFormatting.DARK_GRAY + Utils.getDurationAsWords(dateTime.toEpochSecond() * 1000).first()); + } else { + // abbreviated tooltip + e.toolTip.add(index, "Item age: " + EnumChatFormatting.DARK_GRAY + Utils.getDurationAsWord(dateTime.toEpochSecond() * 1000)); + } + } + } + + // for auction house: show price for each item if multiple items are sold at once + if (e.entityPlayer != null && e.entityPlayer.openContainer instanceof ContainerChest) { + int stackSize = e.itemStack.stackSize; + if ((stackSize == 1 && !isSubmitBidItem(e.itemStack)) || e.toolTip.size() < 4) { + // only 1 item or irrelevant tooltip - nothing to do here, abort! + return; + } + + if (isSubmitBidItem(e.itemStack)) { + // special case: "place bid on an item" interface ("Auction View") + ItemStack auctionedItem = e.entityPlayer.openContainer.getInventory().get(13); + stackSize = auctionedItem.stackSize; + if (stackSize == 1) { + // still only 1 item, abort! + return; + } + } + + List<String> toolTip = e.toolTip; + + // starting with i=1 because first line is never the one we're looking for + for (int i = 1; i < toolTip.size(); i++) { + String toolTipLineUnformatted = EnumChatFormatting.getTextWithoutFormattingCodes(toolTip.get(i)); + if (toolTipLineUnformatted.startsWith("Top bid: ") + || toolTipLineUnformatted.startsWith("Starting bid: ") + || toolTipLineUnformatted.startsWith("Buy it now: ") + || toolTipLineUnformatted.startsWith("Sold for: ") + || toolTipLineUnformatted.startsWith("New bid: ") /* special case: 'Submit Bid' item */) { + + try { + long price = numberFormatter.parse(StringUtils.substringBetween(toolTipLineUnformatted, ": ", " coins")).longValue(); + double priceEach = price / (double) stackSize; + String formattedPriceEach = priceEach < 5000 ? numberFormatter.format(priceEach) : Utils.formatNumberWithAbbreviations(priceEach); + String pricePerItem = EnumChatFormatting.YELLOW + " (" + formattedPriceEach + " each)"; + toolTip.set(i, toolTip.get(i) + pricePerItem); + return; + } catch (ParseException ex) { + return; + } + } + } + } + } + + private ZonedDateTime getDateTimeWithZone(Matcher sbTimestampMatcher, ZoneId zoneId) { + int year = 2000 + Integer.parseInt(sbTimestampMatcher.group(3)); + int month = Integer.parseInt(sbTimestampMatcher.group(1)); + int day = Integer.parseInt(sbTimestampMatcher.group(2)); + int hour = (Integer.parseInt(sbTimestampMatcher.group(4)) + (sbTimestampMatcher.group(6).equals("PM") ? 12 : 0)) % 24; + int minute = Integer.parseInt(sbTimestampMatcher.group(5)); + + LocalDateTime localDateTime = LocalDateTime.of(year, month, day, hour, minute); + + return ZonedDateTime.of(localDateTime, zoneId); + } + + private boolean isSubmitBidItem(ItemStack itemStack) { + return (itemStack.getItem().equals(Items.gold_nugget) || itemStack.getItem().equals(Item.getItemFromBlock(Blocks.gold_block))) + && (itemStack.hasDisplayName() && (itemStack.getDisplayName().endsWith("Submit Bid") || itemStack.getDisplayName().endsWith("Collect Auction"))); + } +} |