From a54f518faf6d79be4bfd5ec218d251734bb123f1 Mon Sep 17 00:00:00 2001 From: Cow Date: Wed, 1 Jul 2020 02:14:58 +0200 Subject: Added item age tooltips --- .../eu/olli/cowmoonication/command/MooCommand.java | 4 +- .../olli/cowmoonication/data/HySkyBlockStats.java | 2 +- .../cowmoonication/listener/PlayerListener.java | 51 +++++++++++++++++++++- .../java/eu/olli/cowmoonication/util/Utils.java | 29 +++++++++++- 4 files changed, 80 insertions(+), 6 deletions(-) (limited to 'src/main/java/eu') diff --git a/src/main/java/eu/olli/cowmoonication/command/MooCommand.java b/src/main/java/eu/olli/cowmoonication/command/MooCommand.java index c926939..4467167 100644 --- a/src/main/java/eu/olli/cowmoonication/command/MooCommand.java +++ b/src/main/java/eu/olli/cowmoonication/command/MooCommand.java @@ -290,12 +290,12 @@ public class MooCommand extends CommandBase { .setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(EnumChatFormatting.YELLOW + "Run " + EnumChatFormatting.GOLD + "/profile " + slothStalking.getPlayerName()))))) .appendSibling(new ChatComponentText(" while you're in a lobby (tooltip of the player head on the top left).").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.YELLOW)))); } else if (slothStalking.hasNeverLoggedOut()) { - Pair lastOnline = Utils.getLastOnlineWords(slothStalking.getLastLogin()); + Pair lastOnline = Utils.getDurationAsWords(slothStalking.getLastLogin()); main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, slothStalking.getPlayerNameFormatted() + EnumChatFormatting.YELLOW + " was last online " + EnumChatFormatting.GOLD + lastOnline.first() + EnumChatFormatting.YELLOW + " ago" + (lastOnline.second() != null ? " (" + EnumChatFormatting.GOLD + lastOnline.second() + EnumChatFormatting.YELLOW + ")" : "") + "."); } else { - Pair lastOnline = Utils.getLastOnlineWords(slothStalking.getLastLogout()); + Pair lastOnline = Utils.getDurationAsWords(slothStalking.getLastLogout()); main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, slothStalking.getPlayerNameFormatted() + EnumChatFormatting.YELLOW + " is " + EnumChatFormatting.GOLD + "offline" + EnumChatFormatting.YELLOW + " for " + EnumChatFormatting.GOLD + lastOnline.first() + EnumChatFormatting.YELLOW + ((lastOnline.second() != null || slothStalking.getLastGame() != null) ? (" (" diff --git a/src/main/java/eu/olli/cowmoonication/data/HySkyBlockStats.java b/src/main/java/eu/olli/cowmoonication/data/HySkyBlockStats.java index a9735c3..21e1f89 100644 --- a/src/main/java/eu/olli/cowmoonication/data/HySkyBlockStats.java +++ b/src/main/java/eu/olli/cowmoonication/data/HySkyBlockStats.java @@ -123,7 +123,7 @@ public class HySkyBlockStats { } public Pair getFancyFirstJoined() { - return Utils.getLastOnlineWords(first_join); + return Utils.getDurationAsWords(first_join); } public double getCoinPurse() { diff --git a/src/main/java/eu/olli/cowmoonication/listener/PlayerListener.java b/src/main/java/eu/olli/cowmoonication/listener/PlayerListener.java index 3c8dd87..afa6c31 100644 --- a/src/main/java/eu/olli/cowmoonication/listener/PlayerListener.java +++ b/src/main/java/eu/olli/cowmoonication/listener/PlayerListener.java @@ -9,20 +9,32 @@ 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.util.EnumChatFormatting; import net.minecraftforge.event.entity.player.ItemTooltipEvent; 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 Cowmoonication 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)$"); public PlayerListener(Cowmoonication main) { this.main = main; @@ -32,11 +44,34 @@ public class PlayerListener { @SubscribeEvent public void onItemTooltip(ItemTooltipEvent e) { - if (!MooConfig.showAdvancedTooltips) { + 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) { - // for auction house: show price for each item if multiple items are sold at once 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! @@ -79,6 +114,18 @@ public class PlayerListener { } } + 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"))); diff --git a/src/main/java/eu/olli/cowmoonication/util/Utils.java b/src/main/java/eu/olli/cowmoonication/util/Utils.java index 22f32d3..8d846f3 100644 --- a/src/main/java/eu/olli/cowmoonication/util/Utils.java +++ b/src/main/java/eu/olli/cowmoonication/util/Utils.java @@ -9,6 +9,7 @@ import org.apache.commons.lang3.time.DurationFormatUtils; import java.io.File; import java.io.IOException; import java.nio.file.Path; +import java.text.DecimalFormat; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; @@ -38,7 +39,7 @@ public final class Utils { * @param timestamp last login/logout * @return 1st: duration between timestamp and now in words; 2nd: formatted date if time differences is >24h, otherwise null */ - public static Pair getLastOnlineWords(long timestamp) { + public static Pair getDurationAsWords(long timestamp) { long duration = System.currentTimeMillis() - timestamp; long daysPast = TimeUnit.MILLISECONDS.toDays(duration); @@ -58,6 +59,32 @@ public final class Utils { } } + public static String getDurationAsWord(long timestamp) { + long duration = System.currentTimeMillis() - timestamp; + long secondsPast = TimeUnit.MILLISECONDS.toSeconds(duration); + if (secondsPast < 60) { + return secondsPast + " second" + (secondsPast > 1 ? "s" : ""); + } + long minutesPast = TimeUnit.SECONDS.toMinutes(secondsPast); + if (minutesPast < 60) { + return minutesPast + " minute" + (minutesPast > 1 ? "s" : ""); + } + long hoursPast = TimeUnit.MINUTES.toHours(minutesPast); + if (hoursPast < 24) { + return hoursPast + " hour" + (hoursPast > 1 ? "s" : ""); + } + long daysPast = TimeUnit.HOURS.toDays(hoursPast); + if (daysPast < 31) { + return daysPast + " day" + (daysPast > 1 ? "s" : ""); + } + double monthsPast = daysPast / 30.5d; + if (monthsPast < 12) { + return new DecimalFormat("0.#").format(monthsPast) + " month" + (monthsPast >= 2 ? "s" : ""); + } + double yearsPast = monthsPast / 12d; + return new DecimalFormat("0.#").format(yearsPast) + " year" + (yearsPast >= 2 ? "s" : ""); + } + public static String toRealPath(Path path) { try { return path.toRealPath().toString(); -- cgit