From 46fd6258c3f147ed1dfd1ecf152f41b0b56d284f Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:33:16 +0300 Subject: SkyblockTime improvements. - Added skyblock hour - Added events for each time unit (year, season, month, day, hour) that are fired when the time unit changes value - Removed magic numbers and added constant fields holding the numbers --- .../de/hysky/skyblocker/utils/SkyblockTime.java | 116 ++++++++++++++++++--- 1 file changed, 103 insertions(+), 13 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java b/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java index ec3effaf..175156c0 100644 --- a/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java +++ b/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java @@ -1,6 +1,8 @@ package de.hysky.skyblocker.utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,39 +15,77 @@ public class SkyblockTime { public static final AtomicReference skyblockSeason = new AtomicReference<>(Season.SPRING); public static final AtomicReference skyblockMonth = new AtomicReference<>(Month.EARLY_SPRING); public static final AtomicInteger skyblockDay = new AtomicInteger(0); + public static final AtomicInteger skyblockHour = new AtomicInteger(0); private static final Logger LOGGER = LoggerFactory.getLogger("Skyblocker Time"); + //All time lengths are in milliseconds + public static final double HOUR_LENGTH = 50000; + public static final double DAY_LENGTH = HOUR_LENGTH * 24; + public static final double MONTH_LENGTH = DAY_LENGTH * 31; + public static final double SEASON_LENGTH = MONTH_LENGTH * 3; + public static final double YEAR_LENGTH = SEASON_LENGTH * 4; + private SkyblockTime() { } + /** + * Updates the time and schedules a cyclic scheduler which will update the time every hour, to be run on the next hour change. + */ public static void init() { updateTime(); - //ScheduleCyclic already runs the task upon scheduling, so there's no need to call updateTime() here - Scheduler.INSTANCE.schedule(() -> Scheduler.INSTANCE.scheduleCyclic(SkyblockTime::updateTime, 1200 * 20), (int) (1200000 - (getSkyblockMillis() % 1200000)) / 50); + //scheduleCyclic already runs the task upon scheduling, so there's no need to call updateTime() in the lambda as well + //The division by 50 is to convert the time to ticks + Scheduler.INSTANCE.schedule(() -> Scheduler.INSTANCE.scheduleCyclic(SkyblockTime::updateTime, (int) (HOUR_LENGTH / 50)), (int) (HOUR_LENGTH - (getSkyblockMillis() % HOUR_LENGTH)) / 50); } public static long getSkyblockMillis() { return System.currentTimeMillis() - SKYBLOCK_EPOCH; } - private static int getSkyblockYear() { - return (int) (Math.floor(getSkyblockMillis() / 446400000.0) + 1); + private static int calculateSkyblockYear() { + return (int) (Math.floor(getSkyblockMillis() / YEAR_LENGTH) + 1); + } + + private static int calculateSkyblockMonth() { + return (int) (Math.floor(getSkyblockMillis() / MONTH_LENGTH) % 12); } - private static int getSkyblockMonth() { - return (int) (Math.floor(getSkyblockMillis() / 37200000.0) % 12); + private static int calculateSkyblockDay() { + return (int) (Math.floor(getSkyblockMillis() / DAY_LENGTH) % 31 + 1); } - private static int getSkyblockDay() { - return (int) (Math.floor(getSkyblockMillis() / 1200000.0) % 31 + 1); + private static int calculateSkyblockHour() { + return (int) (Math.floor(getSkyblockMillis() / HOUR_LENGTH) % 24); } + //This could probably be compacted by abstracting the logic into a method that takes a Supplier and a Consumer, etc. but there's really no need private static void updateTime() { - skyblockYear.set(getSkyblockYear()); - skyblockSeason.set(Season.values()[getSkyblockMonth() / 3]); - skyblockMonth.set(Month.values()[getSkyblockMonth()]); - skyblockDay.set(getSkyblockDay()); - LOGGER.info("[Skyblocker Time] Skyblock time updated to Year {}, Season {}, Month {}, Day {}", skyblockYear.get(), skyblockSeason.get(), skyblockMonth.get(), skyblockDay.get()); + int year = calculateSkyblockYear(); + if (skyblockYear.get() != year) { + skyblockYear.set(year); + YEAR_CHANGE.invoker().onYearChange(year); + } + Season season = Season.values()[calculateSkyblockMonth() / 3]; + if (skyblockSeason.get() != season) { + skyblockSeason.set(season); + SEASON_CHANGE.invoker().onSeasonChange(season); + } + Month month = Month.values()[calculateSkyblockMonth()]; + if (skyblockMonth.get() != month) { + skyblockMonth.set(month); + MONTH_CHANGE.invoker().onMonthChange(month); + } + int day = calculateSkyblockDay(); + if (skyblockDay.get() != day) { + skyblockDay.set(day); + DAY_CHANGE.invoker().onDayChange(day); + } + int hour = calculateSkyblockHour(); + if (skyblockHour.get() != hour) { + skyblockHour.set(hour); + HOUR_CHANGE.invoker().onHourChange(hour); + } + LOGGER.info("[Skyblocker Time] Skyblock time updated to Year {}, Season {}, Month {}, Day {}, Hour {}", year, season, month, day, hour); } public enum Season { @@ -58,4 +98,54 @@ public class SkyblockTime { EARLY_FALL, FALL, LATE_FALL, EARLY_WINTER, WINTER, LATE_WINTER } + + public interface OnHourChange { + void onHourChange(int hour); + } + + public interface OnDayChange { + void onDayChange(int day); + } + + public interface OnMonthChange { + void onMonthChange(Month month); + } + + public interface OnSeasonChange { + void onSeasonChange(Season season); + } + + public interface OnYearChange { + void onYearChange(int year); + } + + public static final Event HOUR_CHANGE = EventFactory.createArrayBacked(OnHourChange.class, listeners -> hour -> { + for (OnHourChange listener : listeners) { + listener.onHourChange(hour); + } + }); + + public static final Event DAY_CHANGE = EventFactory.createArrayBacked(OnDayChange.class, listeners -> day -> { + for (OnDayChange listener : listeners) { + listener.onDayChange(day); + } + }); + + public static final Event MONTH_CHANGE = EventFactory.createArrayBacked(OnMonthChange.class, listeners -> month -> { + for (OnMonthChange listener : listeners) { + listener.onMonthChange(month); + } + }); + + public static final Event SEASON_CHANGE = EventFactory.createArrayBacked(OnSeasonChange.class, listeners -> season -> { + for (OnSeasonChange listener : listeners) { + listener.onSeasonChange(season); + } + }); + + public static final Event YEAR_CHANGE = EventFactory.createArrayBacked(OnYearChange.class, listeners -> year -> { + for (OnYearChange listener : listeners) { + listener.onYearChange(year); + } + }); } -- cgit From 9dcab1a19ceb27fb2cd6e6f553f58a3951ff9b0b Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:34:00 +0300 Subject: Add a method for concatenating block pos fields with spaces in between --- src/main/java/de/hysky/skyblocker/utils/PosUtils.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/utils/PosUtils.java b/src/main/java/de/hysky/skyblocker/utils/PosUtils.java index 4ca37a83..b6205088 100644 --- a/src/main/java/de/hysky/skyblocker/utils/PosUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/PosUtils.java @@ -25,4 +25,8 @@ public final class PosUtils { public static String getPosString(BlockPos blockPos) { return blockPos.getX() + "," + blockPos.getY() + "," + blockPos.getZ(); } + + public static String toSpaceSeparatedString(BlockPos blockPos) { + return blockPos.getX() + " " + blockPos.getY() + " " + blockPos.getZ(); + } } -- cgit From aacf590ee7e81ad3fbde3e904354e5a7382e109a Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:34:51 +0300 Subject: Add ray tracing to EggFinder to make it fairer --- .../skyblock/chocolatefactory/EggFinder.java | 55 +++++++++++++++------- 1 file changed, 39 insertions(+), 16 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java index 6926fda8..004579d0 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -12,6 +12,7 @@ import de.hysky.skyblocker.utils.scheduler.MessageScheduler; import de.hysky.skyblocker.utils.waypoint.Waypoint; import it.unimi.dsi.fastutil.objects.ObjectImmutableList; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; @@ -39,6 +40,7 @@ public class EggFinder { private static final Pattern eggFoundPattern = Pattern.compile("^(?:HOPPITY'S HUNT You found a Chocolate|You have already collected this Chocolate) (Breakfast|Lunch|Dinner)"); private static final Pattern newEggPattern = Pattern.compile("^HOPPITY'S HUNT A Chocolate (Breakfast|Lunch|Dinner) Egg has appeared!$"); private static final Logger logger = LoggerFactory.getLogger("Skyblocker Egg Finder"); + //This is most likely unnecessary with the addition of the location change packet, but it works fine and might be doing something so might as well keep it private static final LinkedList armorStandQueue = new LinkedList<>(); private static final Location[] possibleLocations = {Location.CRIMSON_ISLE, Location.CRYSTAL_HOLLOWS, Location.DUNGEON_HUB, Location.DWARVEN_MINES, Location.HUB, Location.THE_END, Location.THE_PARK, Location.GOLD_MINE, Location.DEEP_CAVERNS, Location.SPIDERS_DEN, Location.THE_FARMING_ISLAND}; private static boolean isLocationCorrect = false; @@ -51,6 +53,15 @@ public class EggFinder { SkyblockEvents.LOCATION_CHANGE.register(EggFinder::handleLocationChange); ClientReceiveMessageEvents.GAME.register(EggFinder::onChatMessage); WorldRenderEvents.AFTER_TRANSLUCENT.register(EggFinder::renderWaypoints); + ClientTickEvents.END_CLIENT_TICK.register(client -> { + if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder || client.player == null) return; + for (EggType type : EggType.entries) { + Egg egg = type.egg; + if (egg != null && !egg.seen && client.player.canSee(egg.entity)) { + type.setSeen(); + } + } + }); ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE) .then(literal("eggFinder") .then(literal("shareLocation") @@ -73,7 +84,6 @@ public class EggFinder { armorStandQueue.clear(); return; } - while (!armorStandQueue.isEmpty()) { handleArmorStand(armorStandQueue.poll()); } @@ -87,7 +97,7 @@ public class EggFinder { if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; if (SkyblockTime.skyblockSeason.get() != SkyblockTime.Season.SPRING) return; if (armorStand.hasCustomName() || !armorStand.isInvisible() || !armorStand.shouldHideBasePlate()) return; - if (Utils.getLocation() == Location.UNKNOWN) { //The location is unknown upon world change and will be changed via /locraw soon, so we can queue it for now + if (Utils.getLocation() == Location.UNKNOWN) { //The location is unknown upon world change and will be changed via location change packets soon, so we can queue it for now armorStandQueue.add(armorStand); return; } @@ -116,25 +126,14 @@ public class EggFinder { } private static void handleFoundEgg(ArmorStandEntity entity, EggType eggType) { - eggType.egg = new Egg(entity, new Waypoint(entity.getBlockPos().up(2), SkyblockerConfigManager.get().helpers.chocolateFactory.waypointType, ColorUtils.getFloatComponents(eggType.color))); - - if (!SkyblockerConfigManager.get().helpers.chocolateFactory.sendEggFoundMessages || System.currentTimeMillis() - eggType.messageLastSent < 1000) return; - eggType.messageLastSent = System.currentTimeMillis(); - MinecraftClient.getInstance().player.sendMessage( - Constants.PREFIX.get() - .append("Found a ") - .append(Text.literal("Chocolate " + eggType + " Egg") - .withColor(eggType.color)) - .append(" at " + entity.getBlockPos().up(2).toShortString() + "!") - .styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/skyblocker eggFinder shareLocation " + entity.getBlockX() + " " + (entity.getBlockY() + 2) + " " + entity.getBlockZ() + " " + eggType)) - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("Click to share the location in chat!").formatted(Formatting.GREEN))))); + eggType.egg = new Egg(entity, new Waypoint(entity.getBlockPos().up(2), SkyblockerConfigManager.get().helpers.chocolateFactory.waypointType, ColorUtils.getFloatComponents(eggType.color)), false); } private static void renderWaypoints(WorldRenderContext context) { if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; for (EggType type : EggType.entries) { Egg egg = type.egg; - if (egg != null && egg.waypoint.shouldRender()) egg.waypoint.render(context); + if (egg != null && egg.waypoint.shouldRender() && egg.seen) egg.waypoint.render(context); } } @@ -160,7 +159,17 @@ public class EggFinder { } } - record Egg(ArmorStandEntity entity, Waypoint waypoint) {} + static class Egg { + private final ArmorStandEntity entity; + private final Waypoint waypoint; + private boolean seen; + + Egg(ArmorStandEntity entity, Waypoint waypoint, boolean seen) { + this.entity = entity; + this.waypoint = waypoint; + this.seen = seen; + } + } @SuppressWarnings("DataFlowIssue") //Removes that pesky "unboxing of Integer might cause NPE" warning when we already know it's not null public enum EggType { @@ -188,6 +197,20 @@ public class EggFinder { this.texture = texture; } + public void setSeen() { + egg.seen = true; + if (!SkyblockerConfigManager.get().helpers.chocolateFactory.sendEggFoundMessages || System.currentTimeMillis() - messageLastSent < 1000) return; + messageLastSent = System.currentTimeMillis(); + MinecraftClient.getInstance().player.sendMessage( + Constants.PREFIX.get() + .append("Found a ") + .append(Text.literal("Chocolate " + this + " Egg") + .withColor(color)) + .append(" at " + egg.entity.getBlockPos().up(2).toShortString() + "!") + .styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/skyblocker eggFinder shareLocation " + PosUtils.toSpaceSeparatedString(egg.waypoint.pos) + " " + this)) + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("Click to share the location in chat!").formatted(Formatting.GREEN))))); + } + @Override @SuppressWarnings("deprecation") // It's either a new dependency or a deprecated method, and I'd rather use the deprecated method public String toString() { -- cgit From 714e3948501986ec23a62b01886643ebed6c66f3 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:45:05 +0300 Subject: Add apache commons text library to the project --- .../java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java index 004579d0..72de71d3 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -25,7 +25,7 @@ import net.minecraft.text.ClickEvent; import net.minecraft.text.HoverEvent; import net.minecraft.text.Text; import net.minecraft.util.Formatting; -import org.apache.commons.lang3.text.WordUtils; +import org.apache.commons.text.WordUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -212,7 +212,6 @@ public class EggFinder { } @Override - @SuppressWarnings("deprecation") // It's either a new dependency or a deprecated method, and I'd rather use the deprecated method public String toString() { return WordUtils.capitalizeFully(this.name()); } -- cgit From 0c183f6a183ffaa53eeaf301e7cc9bb34be28adf Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:45:23 +0300 Subject: Javadoc additions --- .../skyblocker/skyblock/chocolatefactory/EggFinder.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java index 72de71d3..e2e70653 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -42,7 +42,14 @@ public class EggFinder { private static final Logger logger = LoggerFactory.getLogger("Skyblocker Egg Finder"); //This is most likely unnecessary with the addition of the location change packet, but it works fine and might be doing something so might as well keep it private static final LinkedList armorStandQueue = new LinkedList<>(); + /** + * The locations that the egg finder should work while the player is in. + */ private static final Location[] possibleLocations = {Location.CRIMSON_ISLE, Location.CRYSTAL_HOLLOWS, Location.DUNGEON_HUB, Location.DWARVEN_MINES, Location.HUB, Location.THE_END, Location.THE_PARK, Location.GOLD_MINE, Location.DEEP_CAVERNS, Location.SPIDERS_DEN, Location.THE_FARMING_ISLAND}; + /** + * Whether the player is in a location where the egg finder should work. + * This is set to false upon world change and will be checked with the location change event afterward. + */ private static boolean isLocationCorrect = false; private EggFinder() { @@ -182,10 +189,12 @@ public class EggFinder { public final String texture; /* When a new egg spawns in the player's range, the order of packets/messages goes like this: - set_equipment -> new egg message -> set_entity_data + set_equipment → new egg message → set_entity_data We have to set the egg to null to prevent the highlight from staying where it was before the new egg spawned, - and doing so causes the found message to get sent twice. This is the reason for the existence of this field, so that we can not send the 2nd message. - This doesn't fix the field being set twice, but that's not an issue anyway. It'd be much harder to fix the highlight issue mentioned above if it wasn't being set twice. + and doing so causes the found message to get sent twice. + This is the reason for the existence of this field, so that we don't send the 2nd message. + This doesn't fix the field being set twice, but that's not an issue anyway. + It'd be much harder to fix the highlight issue mentioned above if it wasn't being set twice. */ private long messageLastSent = 0; -- cgit From eecce3d586317dea4c1adbdd16b51904c3e3d71d Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Mon, 15 Jul 2024 12:07:13 +0300 Subject: Don't highlight eggs if the same egg was found on another island --- .../skyblock/chocolatefactory/EggFinder.java | 45 +++++++++++----------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java index e2e70653..83d0c3ce 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -52,11 +52,10 @@ public class EggFinder { */ private static boolean isLocationCorrect = false; - private EggFinder() { - } + private EggFinder() {} public static void init() { - ClientPlayConnectionEvents.JOIN.register((ignored, ignored2, ignored3) -> invalidateState()); + ClientPlayConnectionEvents.JOIN.register((ignored, ignored2, ignored3) -> isLocationCorrect = false); SkyblockEvents.LOCATION_CHANGE.register(EggFinder::handleLocationChange); ClientReceiveMessageEvents.GAME.register(EggFinder::onChatMessage); WorldRenderEvents.AFTER_TRANSLUCENT.register(EggFinder::renderWaypoints); @@ -69,6 +68,11 @@ public class EggFinder { } } }); + SkyblockTime.HOUR_CHANGE.register(hour -> { + for (EggType type : EggType.entries) { + if (hour == type.resetHour) type.collected = false; + } + }); ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE) .then(literal("eggFinder") .then(literal("shareLocation") @@ -116,7 +120,7 @@ public class EggFinder { ItemUtils.getHeadTextureOptional(itemStack).ifPresent(texture -> { for (EggType type : EggType.entries) { //Compare blockPos rather than entity to avoid incorrect matches when the entity just moves rather than a new one being spawned elsewhere if (texture.equals(type.texture) && (type.egg == null || !type.egg.entity.getBlockPos().equals(armorStand.getBlockPos()))) { - handleFoundEgg(armorStand, type); + type.egg = new Egg(armorStand, new Waypoint(armorStand.getBlockPos().up(2), SkyblockerConfigManager.get().helpers.chocolateFactory.waypointType, ColorUtils.getFloatComponents(type.color)), false); return; } } @@ -124,18 +128,6 @@ public class EggFinder { } } - private static void invalidateState() { - if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; - isLocationCorrect = false; - for (EggType type : EggType.entries) { - type.egg = null; - } - } - - private static void handleFoundEgg(ArmorStandEntity entity, EggType eggType) { - eggType.egg = new Egg(entity, new Waypoint(entity.getBlockPos().up(2), SkyblockerConfigManager.get().helpers.chocolateFactory.waypointType, ColorUtils.getFloatComponents(eggType.color)), false); - } - private static void renderWaypoints(WorldRenderContext context) { if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; for (EggType type : EggType.entries) { @@ -149,7 +141,9 @@ public class EggFinder { Matcher matcher = eggFoundPattern.matcher(text.getString()); if (matcher.find()) { try { - Egg egg = EggType.valueOf(matcher.group(1).toUpperCase()).egg; + EggType eggType = EggType.valueOf(matcher.group(1).toUpperCase()); + eggType.collected = true; + Egg egg = eggType.egg; if (egg != null) egg.waypoint.setFound(); } catch (IllegalArgumentException e) { logger.error("[Skyblocker Egg Finder] Failed to find egg type for egg found message. Tried to match against: " + matcher.group(0), e); @@ -159,7 +153,7 @@ public class EggFinder { matcher.usePattern(newEggPattern); if (matcher.find()) { try { - EggType.valueOf(matcher.group(1).toUpperCase()).egg = null; + EggType.valueOf(matcher.group(1).toUpperCase()); } catch (IllegalArgumentException e) { logger.error("[Skyblocker Egg Finder] Failed to find egg type for egg spawn message. Tried to match against: " + matcher.group(0), e); } @@ -180,13 +174,15 @@ public class EggFinder { @SuppressWarnings("DataFlowIssue") //Removes that pesky "unboxing of Integer might cause NPE" warning when we already know it's not null public enum EggType { - LUNCH(Formatting.BLUE.getColorValue(), "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjU2ODExMiwKICAicHJvZmlsZUlkIiA6ICI3NzUwYzFhNTM5M2Q0ZWQ0Yjc2NmQ4ZGUwOWY4MjU0NiIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWVkcmVsIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdhZTZkMmQzMWQ4MTY3YmNhZjk1MjkzYjY4YTRhY2Q4NzJkNjZlNzUxZGI1YTM0ZjJjYmM2NzY2YTAzNTZkMGEiCiAgICB9CiAgfQp9"), - DINNER(Formatting.GREEN.getColorValue(), "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY0OTcwMSwKICAicHJvZmlsZUlkIiA6ICI3NGEwMzQxNWY1OTI0ZTA4YjMyMGM2MmU1NGE3ZjJhYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZXp6aXIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTVlMzYxNjU4MTlmZDI4NTBmOTg1NTJlZGNkNzYzZmY5ODYzMTMxMTkyODNjMTI2YWNlMGM0Y2M0OTVlNzZhOCIKICAgIH0KICB9Cn0"), - BREAKFAST(Formatting.GOLD.getColorValue(), "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY3MzE0OSwKICAicHJvZmlsZUlkIiA6ICJiN2I4ZTlhZjEwZGE0NjFmOTY2YTQxM2RmOWJiM2U4OCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbmFiYW5hbmFZZzciLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQ5MzMzZDg1YjhhMzE1ZDAzMzZlYjJkZjM3ZDhhNzE0Y2EyNGM1MWI4YzYwNzRmMWI1YjkyN2RlYjUxNmMyNCIKICAgIH0KICB9Cn0"); + LUNCH(Formatting.BLUE.getColorValue(), 14, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjU2ODExMiwKICAicHJvZmlsZUlkIiA6ICI3NzUwYzFhNTM5M2Q0ZWQ0Yjc2NmQ4ZGUwOWY4MjU0NiIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWVkcmVsIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdhZTZkMmQzMWQ4MTY3YmNhZjk1MjkzYjY4YTRhY2Q4NzJkNjZlNzUxZGI1YTM0ZjJjYmM2NzY2YTAzNTZkMGEiCiAgICB9CiAgfQp9"), + DINNER(Formatting.GREEN.getColorValue(), 21, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY0OTcwMSwKICAicHJvZmlsZUlkIiA6ICI3NGEwMzQxNWY1OTI0ZTA4YjMyMGM2MmU1NGE3ZjJhYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZXp6aXIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTVlMzYxNjU4MTlmZDI4NTBmOTg1NTJlZGNkNzYzZmY5ODYzMTMxMTkyODNjMTI2YWNlMGM0Y2M0OTVlNzZhOCIKICAgIH0KICB9Cn0"), + BREAKFAST(Formatting.GOLD.getColorValue(), 7, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY3MzE0OSwKICAicHJvZmlsZUlkIiA6ICJiN2I4ZTlhZjEwZGE0NjFmOTY2YTQxM2RmOWJiM2U4OCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbmFiYW5hbmFZZzciLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQ5MzMzZDg1YjhhMzE1ZDAzMzZlYjJkZjM3ZDhhNzE0Y2EyNGM1MWI4YzYwNzRmMWI1YjkyN2RlYjUxNmMyNCIKICAgIH0KICB9Cn0"); private Egg egg = null; public final int color; public final String texture; + public final int resetHour; + boolean collected = false; /* When a new egg spawns in the player's range, the order of packets/messages goes like this: set_equipment → new egg message → set_entity_data @@ -201,14 +197,19 @@ public class EggFinder { //This is to not create an array each time we iterate over the values public static final ObjectImmutableList entries = ObjectImmutableList.of(EggType.values()); - EggType(int color, String texture) { + EggType(int color, int resetHour, String texture) { this.color = color; + this.resetHour = resetHour; this.texture = texture; } public void setSeen() { egg.seen = true; if (!SkyblockerConfigManager.get().helpers.chocolateFactory.sendEggFoundMessages || System.currentTimeMillis() - messageLastSent < 1000) return; + if (collected) { + egg.waypoint.setFound(); + return; + } messageLastSent = System.currentTimeMillis(); MinecraftClient.getInstance().player.sendMessage( Constants.PREFIX.get() -- cgit From 1b66bf714c3c758c2c3c996f3b99eefd2ecc4fe6 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Mon, 15 Jul 2024 12:19:21 +0300 Subject: Add another SkyblockTime event for when the time changes, with all time variables --- src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java b/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java index 175156c0..300d902e 100644 --- a/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java +++ b/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java @@ -85,6 +85,7 @@ public class SkyblockTime { skyblockHour.set(hour); HOUR_CHANGE.invoker().onHourChange(hour); } + TIME_UPDATE.invoker().onTimeUpdate(year, season, month, day, hour); LOGGER.info("[Skyblocker Time] Skyblock time updated to Year {}, Season {}, Month {}, Day {}, Hour {}", year, season, month, day, hour); } @@ -119,6 +120,10 @@ public class SkyblockTime { void onYearChange(int year); } + public interface OnTimeUpdate { + void onTimeUpdate(int year, Season season, Month month, int day, int hour); + } + public static final Event HOUR_CHANGE = EventFactory.createArrayBacked(OnHourChange.class, listeners -> hour -> { for (OnHourChange listener : listeners) { listener.onHourChange(hour); @@ -148,4 +153,10 @@ public class SkyblockTime { listener.onYearChange(year); } }); + + public static final Event TIME_UPDATE = EventFactory.createArrayBacked(OnTimeUpdate.class, listeners -> (year, season, month, day, hour) -> { + for (OnTimeUpdate listener : listeners) { + listener.onTimeUpdate(year, season, month, day, hour); + } + }); } -- cgit From 95a14c80563a248ea302d3bcd112fc6a4b8d1e42 Mon Sep 17 00:00:00 2001 From: viciscat <51047087+viciscat@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:59:59 +0200 Subject: code the thing --- .../de/hysky/skyblocker/skyblock/ChestValue.java | 110 ++++++++++++++++++--- 1 file changed, 96 insertions(+), 14 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java b/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java index 908525e1..7d91ef2c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java @@ -1,25 +1,31 @@ package de.hysky.skyblocker.skyblock; -import com.google.gson.JsonObject; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.config.configs.DungeonsConfig; import de.hysky.skyblocker.config.configs.UIAndVisualsConfig; import de.hysky.skyblocker.mixins.accessors.HandledScreenAccessor; import de.hysky.skyblocker.mixins.accessors.ScreenAccessor; -import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.doubles.DoubleBooleanPair; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.fabricmc.fabric.api.client.screen.v1.Screens; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.TextWidget; import net.minecraft.item.ItemStack; import net.minecraft.screen.GenericContainerScreenHandler; import net.minecraft.screen.slot.Slot; +import net.minecraft.text.Style; import net.minecraft.text.Text; +import net.minecraft.util.Util; +import net.minecraft.util.math.MathHelper; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,6 +39,7 @@ public class ChestValue { private static final Logger LOGGER = LoggerFactory.getLogger(ChestValue.class); private static final Set DUNGEON_CHESTS = Set.of("Wood Chest", "Gold Chest", "Diamond Chest", "Emerald Chest", "Obsidian Chest", "Bedrock Chest"); private static final Pattern ESSENCE_PATTERN = Pattern.compile("(?[A-Za-z]+) Essence x(?[0-9]+)"); + private static final Pattern MINION_PATTERN = Pattern.compile("Minion (I|II|III|IV|V|VI|VII|VIII|IX|X|XI|XII)$"); private static final DecimalFormat FORMATTER = new DecimalFormat("#,###"); public static void init() { @@ -43,19 +50,28 @@ public class ChestValue { if (DUNGEON_CHESTS.contains(titleString)) { if (SkyblockerConfigManager.get().dungeons.dungeonChestProfit.enableProfitCalculator) { ScreenEvents.afterTick(screen).register(screen_ -> - ((ScreenAccessor) screen).setTitle(getDungeonChestProfit(genericContainerScreen.getScreenHandler(), title, titleString)) + { + Text dungeonChestProfit = getDungeonChestProfit(genericContainerScreen.getScreenHandler()); + if (dungeonChestProfit != null) addValueToContainer(genericContainerScreen, dungeonChestProfit, title); + } ); } } else if (SkyblockerConfigManager.get().uiAndVisuals.chestValue.enableChestValue && !titleString.equals("SkyBlock Menu")) { + boolean minion = MINION_PATTERN.matcher(title.getString().trim()).find(); Screens.getButtons(screen).add(ButtonWidget .builder(Text.literal("$"), buttonWidget -> { Screens.getButtons(screen).remove(buttonWidget); - ScreenEvents.afterTick(screen).register(screen_ -> - ((ScreenAccessor) screen).setTitle(getChestValue(genericContainerScreen.getScreenHandler(), title, titleString)) + ScreenEvents.afterTick(screen).register(screen_ -> { + Text chestValue = getChestValue(genericContainerScreen.getScreenHandler(), minion); + if (chestValue != null) { + addValueToContainer(genericContainerScreen, chestValue, title); + } + + } ); }) .dimensions(((HandledScreenAccessor) genericContainerScreen).getX() + ((HandledScreenAccessor) genericContainerScreen).getBackgroundWidth() - 16, ((HandledScreenAccessor) genericContainerScreen).getY() + 4, 12, 12) - .tooltip(Tooltip.of(Text.translatable("skyblocker.config.general.chestValue.@Tooltip"))) + .tooltip(minion ? Tooltip.of(Text.translatable("skyblocker.config.general.minionValue.@Tooltip")) : Tooltip.of(Text.translatable("skyblocker.config.general.chestValue.@Tooltip"))) .build() ); } @@ -63,14 +79,34 @@ public class ChestValue { }); } - private static Text getDungeonChestProfit(GenericContainerScreenHandler handler, Text title, String titleString) { + private static void addValueToContainer(GenericContainerScreen genericContainerScreen, Text chestValue, Text title) { + // If the contents get updated the widgets get added again, I have no idea why and I don't feel like debugging this. + Screens.getButtons(genericContainerScreen).removeIf(clickableWidget -> clickableWidget instanceof ScrollingTextWidget); + int backgroundWidth = ((HandledScreenAccessor) genericContainerScreen).getBackgroundWidth(); + int y = ((HandledScreenAccessor) genericContainerScreen).getY(); + int x = ((HandledScreenAccessor) genericContainerScreen).getX(); + ((ScreenAccessor) genericContainerScreen).setTitle(Text.empty()); + TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; + int chestValueWidth = Math.min(textRenderer.getWidth(chestValue), Math.max((backgroundWidth - 8) / 2 - 2, backgroundWidth - 8 - textRenderer.getWidth(title))); + + TextWidget chestValueWidget = new ScrollingTextWidget(chestValueWidth, textRenderer.fontHeight, chestValue, textRenderer); + chestValueWidget.setPosition(x + backgroundWidth - chestValueWidget.getWidth() - 4, y + 6); + Screens.getButtons(genericContainerScreen).add(chestValueWidget); + + ScrollingTextWidget chestTitleWidget = new ScrollingTextWidget(backgroundWidth - 8 - chestValueWidth - 2, textRenderer.fontHeight, title.copy().fillStyle(Style.EMPTY.withColor(4210752)), textRenderer); + chestTitleWidget.shadow = false; + chestTitleWidget.setPosition(x + 8, y + 6); + Screens.getButtons(genericContainerScreen).add(chestTitleWidget); + } + + private static @Nullable Text getDungeonChestProfit(GenericContainerScreenHandler handler) { try { double profit = 0; boolean hasIncompleteData = false, usedKismet = false; List slots = handler.slots.subList(0, handler.getRows() * 9); //If the item stack for the "Open Reward Chest" button or the kismet button hasn't been sent to the client yet - if (slots.get(31).getStack().isEmpty() || slots.get(50).getStack().isEmpty()) return title; + if (slots.get(31).getStack().isEmpty() || slots.get(50).getStack().isEmpty()) return null; for (Slot slot : slots) { ItemStack stack = slot.getStack(); @@ -138,19 +174,28 @@ public class ChestValue { profit -= kismetPriceData.leftDouble(); } - return Text.literal(titleString).append(getProfitText((long) profit, hasIncompleteData)); + return getProfitText((long) profit, hasIncompleteData); } catch (Exception e) { LOGGER.error("[Skyblocker Profit Calculator] Failed to calculate dungeon chest profit! ", e); } - return title; + return null; } - private static Text getChestValue(GenericContainerScreenHandler handler, Text title, String titleString) { + private static @Nullable Text getChestValue(GenericContainerScreenHandler handler, boolean minion) { try { double value = 0; boolean hasIncompleteData = false; - List slots = handler.slots.subList(0, handler.getRows() * 9); + List slots; + if (minion) { + slots = handler.slots.subList(0, handler.getRows() * 9).stream().filter(slot -> { + int x = slot.id % 9; + int y = slot.id / 9; + return x > 2 && x < 8 && y > 1 && y < 5; + }).toList(); + } else { + slots = handler.slots.subList(0, handler.getRows() * 9); + } for (Slot slot : slots) { ItemStack stack = slot.getStack(); @@ -169,12 +214,12 @@ public class ChestValue { } } - return Text.literal(titleString).append(getValueText((long) value, hasIncompleteData)); + return getValueText((long) value, hasIncompleteData); } catch (Exception e) { LOGGER.error("[Skyblocker Value Calculator] Failed to calculate dungeon chest value! ", e); } - return title; + return null; } /** @@ -193,4 +238,41 @@ public class ChestValue { UIAndVisualsConfig.ChestValue config = SkyblockerConfigManager.get().uiAndVisuals.chestValue; return Text.literal(' ' + FORMATTER.format(value) + " Coins").formatted(hasIncompleteData ? config.incompleteColor : config.color); } + + + + private static class ScrollingTextWidget extends TextWidget { + + public boolean shadow = true; + + public ScrollingTextWidget(int width, int height, Text message, TextRenderer textRenderer) { + super(width, height, message, textRenderer); + alignLeft(); + } + + @Override + public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { + draw(context, getTextRenderer(), getMessage(), getX(), getRight()); + } + + // Yoinked from ClickableWidget + protected void draw( + DrawContext context, TextRenderer textRenderer, Text text, int startX, int endX + ) { + int i = textRenderer.getWidth(text); + int k = endX - startX; + if (i > k) { + int l = i - k; + double d = (double) Util.getMeasuringTimeMs() / 600.0; + double e = Math.max((double)l * 0.5, 3.0); + double f = Math.sin((Math.PI / 2) * Math.cos((Math.PI * 2) * d / e)) / 2.0 + 0.5; + double g = MathHelper.lerp(f, 0.0, l); + context.enableScissor(startX, getY(), endX, getY() + textRenderer.fontHeight); + context.drawText(textRenderer, text, startX - (int)g, getY(), -1, shadow); + context.disableScissor(); + } else { + context.drawText(textRenderer, text, startX, getY(), -1, shadow); + } + } + } } -- cgit From b2387842f889bfc66dd2600171f01c8734aadbd2 Mon Sep 17 00:00:00 2001 From: viciscat <51047087+viciscat@users.noreply.github.com> Date: Mon, 22 Jul 2024 21:59:05 +0200 Subject: minion held coins and fix stupid --- .../de/hysky/skyblocker/skyblock/ChestValue.java | 36 +++++++++++++--------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java b/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java index 7d91ef2c..5cab28e7 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java @@ -18,6 +18,7 @@ import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.TextWidget; import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; import net.minecraft.screen.GenericContainerScreenHandler; import net.minecraft.screen.slot.Slot; import net.minecraft.text.Style; @@ -30,6 +31,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.DecimalFormat; +import java.text.ParseException; import java.util.List; import java.util.Set; import java.util.regex.Matcher; @@ -49,26 +51,18 @@ public class ChestValue { String titleString = title.getString(); if (DUNGEON_CHESTS.contains(titleString)) { if (SkyblockerConfigManager.get().dungeons.dungeonChestProfit.enableProfitCalculator) { - ScreenEvents.afterTick(screen).register(screen_ -> - { - Text dungeonChestProfit = getDungeonChestProfit(genericContainerScreen.getScreenHandler()); - if (dungeonChestProfit != null) addValueToContainer(genericContainerScreen, dungeonChestProfit, title); - } - ); + Text dungeonChestProfit = getDungeonChestProfit(genericContainerScreen.getScreenHandler()); + if (dungeonChestProfit != null) addValueToContainer(genericContainerScreen, dungeonChestProfit, title); } } else if (SkyblockerConfigManager.get().uiAndVisuals.chestValue.enableChestValue && !titleString.equals("SkyBlock Menu")) { boolean minion = MINION_PATTERN.matcher(title.getString().trim()).find(); Screens.getButtons(screen).add(ButtonWidget .builder(Text.literal("$"), buttonWidget -> { Screens.getButtons(screen).remove(buttonWidget); - ScreenEvents.afterTick(screen).register(screen_ -> { Text chestValue = getChestValue(genericContainerScreen.getScreenHandler(), minion); - if (chestValue != null) { - addValueToContainer(genericContainerScreen, chestValue, title); - } - - } - ); + if (chestValue != null) { + addValueToContainer(genericContainerScreen, chestValue, title); + } }) .dimensions(((HandledScreenAccessor) genericContainerScreen).getX() + ((HandledScreenAccessor) genericContainerScreen).getBackgroundWidth() - 16, ((HandledScreenAccessor) genericContainerScreen).getY() + 4, 12, 12) .tooltip(minion ? Tooltip.of(Text.translatable("skyblocker.config.general.minionValue.@Tooltip")) : Tooltip.of(Text.translatable("skyblocker.config.general.chestValue.@Tooltip"))) @@ -80,8 +74,6 @@ public class ChestValue { } private static void addValueToContainer(GenericContainerScreen genericContainerScreen, Text chestValue, Text title) { - // If the contents get updated the widgets get added again, I have no idea why and I don't feel like debugging this. - Screens.getButtons(genericContainerScreen).removeIf(clickableWidget -> clickableWidget instanceof ScrollingTextWidget); int backgroundWidth = ((HandledScreenAccessor) genericContainerScreen).getBackgroundWidth(); int y = ((HandledScreenAccessor) genericContainerScreen).getY(); int x = ((HandledScreenAccessor) genericContainerScreen).getX(); @@ -193,6 +185,20 @@ public class ChestValue { int y = slot.id / 9; return x > 2 && x < 8 && y > 1 && y < 5; }).toList(); + ItemStack stack; + String coinsLine; + if (handler.slots.size() > 28 && + (stack = handler.slots.get(28).getStack()).isOf(Items.HOPPER) && + (coinsLine = ItemUtils.getLoreLineIf(stack, s -> s.contains("Held Coins:"))) != null) { + + String source = coinsLine.split(":")[1]; + try { + value += DecimalFormat.getNumberInstance(java.util.Locale.US).parse(source.trim()).doubleValue(); + } catch (ParseException e) { + LOGGER.warn("[Skyblocker] Failed to parse {}", source); + } + + } } else { slots = handler.slots.subList(0, handler.getRows() * 9); } -- cgit From bc8864eeb2c4ba5a5f3d3709dc488089d77e4c98 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Thu, 11 Jul 2024 00:27:00 -0400 Subject: True HEX Display! Small change, major impact! --- .../skyblock/item/tooltip/TooltipManager.java | 1 + .../item/tooltip/adders/TrueHexDisplay.java | 42 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/TrueHexDisplay.java (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java index 3b4cb41c..40655bd1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java @@ -23,6 +23,7 @@ import java.util.List; public class TooltipManager { private static final TooltipAdder[] adders = new TooltipAdder[]{ new LineSmoothener(), // Applies before anything else + new TrueHexDisplay(), new SupercraftReminder(), ChocolateFactorySolver.INSTANCE, new ReorderHelper(), diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/TrueHexDisplay.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/TrueHexDisplay.java new file mode 100644 index 00000000..093e9de6 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/TrueHexDisplay.java @@ -0,0 +1,42 @@ +package de.hysky.skyblocker.skyblock.item.tooltip.adders; + +import java.util.List; +import java.util.regex.Pattern; + +import org.jetbrains.annotations.Nullable; + +import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; + +/** + * Changes the color of HEX colors codes on dye items to reflect their actual color + */ +public class TrueHexDisplay extends TooltipAdder { + private static final Pattern HEX_PATTERN = Pattern.compile("#[A-Fa-f0-9]{6}"); + + public TrueHexDisplay() { + super(Integer.MIN_VALUE); + } + + @Override + public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List lines) { + String itemId = stack.getSkyblockId(); + + //Nice job on item id consistency Hypixel + if (itemId != null && !itemId.isEmpty() && (itemId.startsWith("DYE_") || itemId.endsWith("_DYE"))) { + for (Text line : lines) { + //The hex part is inside of the siblings + for (Text text : line.getSiblings()) { + String stringified = text.getString(); + + if (HEX_PATTERN.matcher(stringified).matches()) { + ((MutableText) text).withColor(Integer.decode(stringified)); + } + } + } + } + } +} -- cgit From 9ddc3fe9a52efcbd32e7671a4070ea0a371b5570 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Thu, 11 Jul 2024 01:50:27 -0400 Subject: Exotic Tooltip Enhancements/Fixes --- .../skyblock/item/tooltip/adders/ColorTooltip.java | 57 +++++++++++++++++----- .../item/tooltip/adders/ObtainedDateTooltip.java | 18 +++++++ .../java/de/hysky/skyblocker/utils/Constants.java | 29 ++++++++++- 3 files changed, 89 insertions(+), 15 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ColorTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ColorTooltip.java index 8d9d8fbb..5b78e2cb 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ColorTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ColorTooltip.java @@ -20,6 +20,7 @@ import java.util.List; public class ColorTooltip extends SimpleTooltipAdder { private static final Logger LOGGER = LoggerFactory.getLogger(ColorTooltip.class); + private static final long WITHER_GLITCHED_AFTER_DATE = 1605830400000L; public ColorTooltip(int priority) { super(priority); @@ -45,25 +46,29 @@ public class ColorTooltip extends SimpleTooltipAdder { if (existingTooltip.startsWith("Color: ")) { correctLine = true; - addExoticTooltip(lines, internalID, ItemUtils.getCustomData(stack), colorHex, expectedHex, existingTooltip); + addExoticTooltip(lines, stack, internalID, colorHex, expectedHex, existingTooltip); break; } } if (!correctLine) { - addExoticTooltip(lines, internalID, ItemUtils.getCustomData(stack), colorHex, expectedHex, ""); + addExoticTooltip(lines, stack, internalID, colorHex, expectedHex, ""); } } } - private static void addExoticTooltip(List lines, String internalID, NbtCompound customData, String colorHex, String expectedHex, String existingTooltip) { - if (expectedHex != null && !colorHex.equalsIgnoreCase(expectedHex) && !isException(internalID, colorHex) && !intendedDyed(customData)) { - final DyeType type = checkDyeType(colorHex); - lines.add(1, Text.literal(existingTooltip + Formatting.DARK_GRAY + "(").append(type.getTranslatedText()).append(Formatting.DARK_GRAY + ")")); + private static void addExoticTooltip(List lines, ItemStack stack, String internalID, String colorHex, String expectedHex, String existingTooltip) { + if (expectedHex != null && !colorHex.equalsIgnoreCase(expectedHex) && !isException(internalID, colorHex) && !intendedDyed(ItemUtils.getCustomData(stack))) { + final DyeType type = checkDyeType(stack, colorHex); + lines.add(1, Text.literal(existingTooltip + Formatting.DARK_GRAY + "(") + .append(type.getTranslatedText()) + .append(Text.literal(" - ")) + .append(Text.literal("#" + colorHex).withColor(Integer.decode("0x" + colorHex))) + .append(Text.literal(")").formatted(Formatting.DARK_GRAY))); } } - public static String getExpectedHex(String id) { + private static String getExpectedHex(String id) { String color = TooltipInfoType.COLOR.getData().get(id).getAsString(); if (color != null) { String[] RGBValues = color.split(","); @@ -74,7 +79,7 @@ public class ColorTooltip extends SimpleTooltipAdder { } } - public static boolean isException(String id, String hex) { + private static boolean isException(String id, String hex) { return switch (id) { case String it when it.startsWith("LEATHER") || it.equals("GHOST_BOOTS") || Constants.SEYMOUR_IDS.contains(it) -> true; case String it when it.startsWith("RANCHER") -> Constants.RANCHERS.contains(hex); @@ -88,28 +93,54 @@ public class ColorTooltip extends SimpleTooltipAdder { }; } - public static DyeType checkDyeType(String hex) { + private static DyeType checkDyeType(ItemStack stack, String hex) { return switch (hex) { case String it when Constants.CRYSTAL_HEXES.contains(it) -> DyeType.CRYSTAL; case String it when Constants.FAIRY_HEXES.contains(it) -> DyeType.FAIRY; case String it when Constants.OG_FAIRY_HEXES.contains(it) -> DyeType.OG_FAIRY; - case String it when Constants.SPOOK.contains(it) -> DyeType.SPOOK; - case String it when Constants.GLITCHED.contains(it) -> DyeType.GLITCHED; + case String it when Constants.SPOOK.contains(it) && stack.getSkyblockId().startsWith("FAIRY_") -> DyeType.SPOOK; + case String it when Constants.GLITCHED.contains(it) && isGlitched(stack, hex) -> DyeType.GLITCHED; default -> DyeType.EXOTIC; }; } - public static boolean intendedDyed(NbtCompound customData) { + private static boolean intendedDyed(NbtCompound customData) { return customData.contains("dye_item"); } - public enum DyeType implements StringIdentifiable { + //Thanks to TGWaffles' guidance on how to make this more accurate + private static boolean isGlitched(ItemStack stack, String hex) { + String id = stack.getSkyblockId(); + + if (id.contains("WITHER")) { + return isWitherGlitched(id, hex, ObtainedDateTooltip.getLongTimestamp(stack)); + } + + String miscGlitchedId = Constants.MISC_GLITCHED_HEXES.get(hex); + + return miscGlitchedId != null && id.startsWith(miscGlitchedId); + } + + private static boolean isWitherGlitched(String id, String hex, long obtained) { + if (hex.equals("000000") && obtained < WITHER_GLITCHED_AFTER_DATE) return false; //Too old to be glitched + + return switch (id) { + case String it when it.contains("CHESTPLATE") -> Constants.WITHER_CHESTPLATE_HEXES.containsKey(hex) && Constants.WITHER_CHESTPLATE_HEXES.containsValue(it) && !Constants.WITHER_CHESTPLATE_HEXES.get(hex).equals(it); + case String it when it.contains("LEGGINGS") -> Constants.WITHER_LEGGINGS_HEXES.containsKey(hex) && Constants.WITHER_LEGGINGS_HEXES.containsValue(it) && !Constants.WITHER_LEGGINGS_HEXES.get(hex).equals(it); + case String it when it.contains("BOOTS") -> Constants.WITHER_BOOTS_HEXES.containsKey(hex) && Constants.WITHER_BOOTS_HEXES.containsValue(it) && !Constants.WITHER_BOOTS_HEXES.get(hex).equals(it); + + default -> false; + }; + } + + private enum DyeType implements StringIdentifiable { CRYSTAL("crystal", Formatting.AQUA), FAIRY("fairy", Formatting.LIGHT_PURPLE), OG_FAIRY("og_fairy", Formatting.DARK_PURPLE), SPOOK("spook", Formatting.RED), GLITCHED("glitched", Formatting.BLUE), EXOTIC("exotic", Formatting.GOLD); + private final String name; private final Formatting formatting; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java index 31aa3de4..e7e79966 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java @@ -72,4 +72,22 @@ public class ObtainedDateTooltip extends SimpleTooltipAdder { return ""; } + + /** + * @see #getTimestamp(ItemStack) + */ + public static long getLongTimestamp(ItemStack stack) { + NbtCompound customData = ItemUtils.getCustomData(stack); + + if (customData != null && customData.contains("timestamp", NbtElement.LONG_TYPE)) { + return customData.getLong("timestamp"); + } + + if (customData != null && customData.contains("timestamp", NbtElement.STRING_TYPE)) { + TemporalAccessor date = OLD_OBTAINED_DATE_FORMAT.parse(customData.getString("timestamp")); + return Instant.from(date).toEpochMilli(); + } + + return 0L; + } } diff --git a/src/main/java/de/hysky/skyblocker/utils/Constants.java b/src/main/java/de/hysky/skyblocker/utils/Constants.java index c002be57..50c79638 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Constants.java +++ b/src/main/java/de/hysky/skyblocker/utils/Constants.java @@ -6,6 +6,7 @@ import net.minecraft.util.Formatting; import java.time.LocalDate; import java.util.List; +import java.util.Map; import java.util.function.Supplier; /** @@ -62,11 +63,35 @@ public interface Constants { List OG_FAIRY_HEXES = List.of("FF99FF", "FFCCFF", "E5CCFF", "CC99FF", "CC00CC", "FF00FF", "FF33FF", "FF66FF", "B266FF", "9933FF", "7F00FF", "660066", "6600CC", "4C0099", "330066", "990099", "660033", "99004C", "CC0066", "660033", "99004C", "FFCCE5", "660033", "FFCCE5", "FF99CC", "FFCCE5", "FF99CC", "FF66B2"); - List GLITCHED = List.of("FFDC51", "F7DA33", "606060", "E7413C", "45413C", "4A14B7", "1793C4", "000000", "E75C3C", "65605A", - "5D2FB9", "17A8C4", "E76E3C", "88837E", "8969C8", "1CD4E4"); // Glitched through other means such as Shark Scale upgrade color List SPOOK = List.of("000000", "070008", "0E000F", "150017", "1B001F", "220027", "29002E", "300036", "37003E", "3E0046", "45004D", "4C0055", "52005D", "590065", "60006C", "670074", "6E007C", "750084", "7C008B", "830093", "89009B", "9000A3", "9700AA", "993399", "9E00B2"); + // Exotic - Glitched Hexes + Map MISC_GLITCHED_HEXES = Map.of( + "FFDC51", "SHARK_SCALE", + "F7DA33", "FROZEN_BLAZE", + "606060", "BAT_PERSON"); + Map WITHER_CHESTPLATE_HEXES = Map.of( + "E7413C", "POWER_WITHER_CHESTPLATE", + "45413C", "TANK_WITHER_CHESTPLATE", + "4A14B7", "SPEED_WITHER_CHESTPLATE", + "1793C4", "WISE_WITHER_CHESTPLATE", + "000000", "WITHER_CHESTPLATE"); + Map WITHER_LEGGINGS_HEXES = Map.of( + "E75C3C", "POWER_WITHER_LEGGINGS", + "65605A", "TANK_WITHER_LEGGINGS", + "5D2FB9", "SPEED_WITHER_LEGGINGS", + "17A8C4", "WISE_WITHER_LEGGINGS", + "000000", "WITHER_LEGGINGS"); + Map WITHER_BOOTS_HEXES = Map.of( + "E76E3C", "POWER_WITHER_BOOTS", + "88837E", "TANK_WITHER_BOOTS", + "8969C8", "SPEED_WITHER_BOOTS", + "1CD4E4", "WISE_WITHER_BOOTS", + "000000", "WITHER_BOOTS"); + //All glitched hexes + List GLITCHED = List.of("FFDC51", "F7DA33", "606060", "E7413C", "45413C", "4A14B7", "1793C4", "000000", "E75C3C", "65605A", + "5D2FB9", "17A8C4", "E76E3C", "88837E", "8969C8", "1CD4E4"); // Glitched through other means such as Shark Scale upgrade color // List of exceptions List RANCHERS = List.of("CC5500", "000000", "0"); -- cgit From 050e3c76ab1b86de365bbab8207cd02043963ad2 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Sat, 13 Jul 2024 15:27:06 -0400 Subject: Deduplicate timestamp code --- .../skyblock/item/tooltip/adders/ObtainedDateTooltip.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java index e7e79966..341ec0fe 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java @@ -12,6 +12,7 @@ import net.minecraft.util.Formatting; import org.jetbrains.annotations.Nullable; import java.time.Instant; +import java.time.LocalDate; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAccessor; @@ -77,17 +78,6 @@ public class ObtainedDateTooltip extends SimpleTooltipAdder { * @see #getTimestamp(ItemStack) */ public static long getLongTimestamp(ItemStack stack) { - NbtCompound customData = ItemUtils.getCustomData(stack); - - if (customData != null && customData.contains("timestamp", NbtElement.LONG_TYPE)) { - return customData.getLong("timestamp"); - } - - if (customData != null && customData.contains("timestamp", NbtElement.STRING_TYPE)) { - TemporalAccessor date = OLD_OBTAINED_DATE_FORMAT.parse(customData.getString("timestamp")); - return Instant.from(date).toEpochMilli(); - } - - return 0L; + return LocalDate.parse(getTimestamp(stack), OBTAINED_DATE_FORMATTER).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); } } -- cgit From 4c33da512d48a33cbc5a297ecdfe93906b3f037d Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Fri, 26 Jul 2024 00:59:29 -0400 Subject: Refactor obtained date methods --- .../item/tooltip/adders/ObtainedDateTooltip.java | 33 +++++++++++++--------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java index 341ec0fe..1cbff9d8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java @@ -12,7 +12,6 @@ import net.minecraft.util.Formatting; import org.jetbrains.annotations.Nullable; import java.time.Instant; -import java.time.LocalDate; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAccessor; @@ -42,6 +41,20 @@ public class ObtainedDateTooltip extends SimpleTooltipAdder { } } + private static TemporalAccessor getTimestampInternal(ItemStack stack) { + NbtCompound customData = ItemUtils.getCustomData(stack); + + if (customData != null && customData.contains("timestamp", NbtElement.LONG_TYPE)) { + return Instant.ofEpochMilli(customData.getLong("timestamp")); + } + + if (customData != null && customData.contains("timestamp", NbtElement.STRING_TYPE)) { + return OLD_OBTAINED_DATE_FORMAT.parse(customData.getString("timestamp")); + } + + return null; + } + /** * This method converts the "timestamp" variable into the same date format as Hypixel represents it in the museum. * Currently, there are two types of string timestamps the legacy which is built like this @@ -59,25 +72,17 @@ public class ObtainedDateTooltip extends SimpleTooltipAdder { * @return if the item have a "Timestamp" it will be shown formated on the tooltip */ public static String getTimestamp(ItemStack stack) { - NbtCompound customData = ItemUtils.getCustomData(stack); - - if (customData != null && customData.contains("timestamp", NbtElement.LONG_TYPE)) { - Instant date = Instant.ofEpochMilli(customData.getLong("timestamp")); - return OBTAINED_DATE_FORMATTER.format(date); - } + TemporalAccessor accessor = getTimestampInternal(stack); - if (customData != null && customData.contains("timestamp", NbtElement.STRING_TYPE)) { - TemporalAccessor date = OLD_OBTAINED_DATE_FORMAT.parse(customData.getString("timestamp")); - return OBTAINED_DATE_FORMATTER.format(date); - } - - return ""; + return accessor != null ? OBTAINED_DATE_FORMATTER.format(accessor) : ""; } /** * @see #getTimestamp(ItemStack) */ public static long getLongTimestamp(ItemStack stack) { - return LocalDate.parse(getTimestamp(stack), OBTAINED_DATE_FORMATTER).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + TemporalAccessor accessor = getTimestampInternal(stack); + + return accessor != null ? Instant.from(accessor).toEpochMilli() : 0; } } -- cgit From fd5a6a25f95fbcae256586943d6f89d562776c5a Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Fri, 26 Jul 2024 01:02:03 -0400 Subject: Update to new tooltip system --- .../skyblocker/skyblock/item/tooltip/adders/TrueHexDisplay.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/TrueHexDisplay.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/TrueHexDisplay.java index 093e9de6..3599b75d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/TrueHexDisplay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/TrueHexDisplay.java @@ -5,7 +5,7 @@ import java.util.regex.Pattern; import org.jetbrains.annotations.Nullable; -import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder; +import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder; import net.minecraft.item.ItemStack; import net.minecraft.screen.slot.Slot; import net.minecraft.text.MutableText; @@ -14,7 +14,7 @@ import net.minecraft.text.Text; /** * Changes the color of HEX colors codes on dye items to reflect their actual color */ -public class TrueHexDisplay extends TooltipAdder { +public class TrueHexDisplay extends SimpleTooltipAdder { private static final Pattern HEX_PATTERN = Pattern.compile("#[A-Fa-f0-9]{6}"); public TrueHexDisplay() { @@ -39,4 +39,9 @@ public class TrueHexDisplay extends TooltipAdder { } } } + + @Override + public boolean isEnabled() { + r