diff options
Diffstat (limited to 'src/main/java')
15 files changed, 547 insertions, 211 deletions
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/CrimsonIsleCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/CrimsonIsleCategory.java index 1e35db1e..242bfd24 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/CrimsonIsleCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/CrimsonIsleCategory.java @@ -80,6 +80,22 @@ public class CrimsonIsleCategory { newValue -> config.crimsonIsle.kuudra.arrowPoisonThreshold = newValue) .controller(IntegerFieldControllerBuilder::create) .build()) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("skyblocker.config.crimsonIsle.kuudra.kuudraGlow")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.crimsonIsle.kuudra.kuudraGlow.@Tooltip"))) + .binding(defaults.crimsonIsle.kuudra.kuudraGlow, + () -> config.crimsonIsle.kuudra.kuudraGlow, + newValue -> config.crimsonIsle.kuudra.kuudraGlow = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("skyblocker.config.crimsonIsle.kuudra.dangerWarning")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.crimsonIsle.kuudra.dangerWarning.@Tooltip"))) + .binding(defaults.crimsonIsle.kuudra.dangerWarning, + () -> config.crimsonIsle.kuudra.dangerWarning, + newValue -> config.crimsonIsle.kuudra.dangerWarning = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) .build()) //dojo .group(OptionGroup.createBuilder() diff --git a/src/main/java/de/hysky/skyblocker/config/configs/CrimsonIsleConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/CrimsonIsleConfig.java index 6645b88d..9c087baf 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/CrimsonIsleConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/CrimsonIsleConfig.java @@ -38,6 +38,12 @@ public class CrimsonIsleConfig { @SerialEntry public int arrowPoisonThreshold = 32; + + @SerialEntry + public boolean kuudraGlow = true; + + @SerialEntry + public boolean dangerWarning = true; } public static class Dojo { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java b/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java index c997cda0..67928b07 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java @@ -10,18 +10,29 @@ 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.item.Items; 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.NotNull; +import org.jetbrains.annotations.Nullable; 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; @@ -31,6 +42,7 @@ public class ChestValue { private static final Logger LOGGER = LoggerFactory.getLogger(ChestValue.class); private static final Set<String> DUNGEON_CHESTS = Set.of("Wood Chest", "Gold Chest", "Diamond Chest", "Emerald Chest", "Obsidian Chest", "Bedrock Chest"); private static final Pattern ESSENCE_PATTERN = Pattern.compile("(?<type>[A-Za-z]+) Essence x(?<amount>[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() { @@ -40,20 +52,27 @@ public class ChestValue { String titleString = title.getString(); if (DUNGEON_CHESTS.contains(titleString)) { if (SkyblockerConfigManager.get().dungeons.dungeonChestProfit.enableProfitCalculator) { - ScreenEvents.afterTick(screen).register(screen_ -> - ((ScreenAccessor) screen).setTitle(getDungeonChestProfit(genericContainerScreen.getScreenHandler(), title, titleString)) - ); + ScreenEvents.afterTick(screen).register(ignored -> { + 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(ignored -> { + 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() ); } @@ -61,14 +80,14 @@ public class ChestValue { }); } - private static Text getDungeonChestProfit(GenericContainerScreenHandler handler, Text title, String titleString) { + private static @Nullable Text getDungeonChestProfit(GenericContainerScreenHandler handler) { try { double profit = 0; boolean hasIncompleteData = false, usedKismet = false; List<Slot> 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(); @@ -136,25 +155,35 @@ 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<Slot> slots = handler.slots.subList(0, handler.getRows() * 9); + List<Slot> slots = minion ? getMinionSlots(handler) : handler.slots.subList(0, handler.getRows() * 9); for (Slot slot : slots) { ItemStack stack = slot.getStack(); if (stack.isEmpty()) { continue; } + String coinsLine; + if (minion && slot.id == 28 && stack.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); + } + continue; + } String id = stack.getSkyblockApiId(); @@ -167,12 +196,20 @@ 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; + } + + private static @NotNull List<Slot> getMinionSlots(GenericContainerScreenHandler handler) { + return 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 || slot.id == 28; + }).toList(); } /** @@ -191,4 +228,58 @@ 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 void addValueToContainer(GenericContainerScreen genericContainerScreen, Text chestValue, Text title) { + Screens.getButtons(genericContainerScreen).removeIf(clickableWidget -> clickableWidget instanceof ChestValueTextWidget); + 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 ChestValueTextWidget(chestValueWidth, textRenderer.fontHeight, chestValue, textRenderer); + chestValueWidget.setPosition(x + backgroundWidth - chestValueWidget.getWidth() - 4, y + 6); + Screens.getButtons(genericContainerScreen).add(chestValueWidget); + + ChestValueTextWidget chestTitleWidget = new ChestValueTextWidget(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 class ChestValueTextWidget extends TextWidget { + + public boolean shadow = true; + + public ChestValueTextWidget(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); + } + } + } } 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..6d390039 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; @@ -24,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; @@ -39,18 +40,40 @@ 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<ArmorStandEntity> 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() { - } + 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); + ClientTickEvents.END_CLIENT_TICK.register(client -> { + if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder || client.player == null) return; + if (!isLocationCorrect || SkyblockTime.skyblockSeason.get() != SkyblockTime.Season.SPRING) return; + for (EggType type : EggType.entries) { + Egg egg = type.egg; + if (egg != null && !egg.seen && client.player.canSee(egg.entity)) { + type.setSeen(); + } + } + }); + 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") @@ -73,7 +96,6 @@ public class EggFinder { armorStandQueue.clear(); return; } - while (!armorStandQueue.isEmpty()) { handleArmorStand(armorStandQueue.poll()); } @@ -87,7 +109,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; } @@ -99,7 +121,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; } } @@ -107,34 +129,11 @@ 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))); - - 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))))); - } - 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); } } @@ -143,7 +142,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); @@ -153,43 +154,75 @@ 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); } } } - 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 { - 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 + 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; //This is to not create an array each time we iterate over the values public static final ObjectImmutableList<EggType> 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() + .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() { return WordUtils.capitalizeFully(this.name()); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/ArrowPoisonWarning.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/ArrowPoisonWarning.java index 7c3c634a..c0d371de 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/ArrowPoisonWarning.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/ArrowPoisonWarning.java @@ -2,7 +2,6 @@ package de.hysky.skyblocker.skyblock.crimson.kuudra; import java.util.function.Supplier; -import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.config.configs.CrimsonIsleConfig; import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra.KuudraPhase; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/DangerWarning.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/DangerWarning.java new file mode 100644 index 00000000..feaa1a11 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/DangerWarning.java @@ -0,0 +1,69 @@ +package de.hysky.skyblocker.skyblock.crimson.kuudra; + +import java.util.function.Supplier; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.render.title.Title; +import de.hysky.skyblocker.utils.render.title.TitleContainer; +import de.hysky.skyblocker.utils.scheduler.Scheduler; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.client.MinecraftClient; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.DyeColor; +import net.minecraft.util.math.BlockPos; + +public class DangerWarning { + private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); + private static final Supplier<MutableText> DANGER_TEXT = () -> Text.translatable("skyblocker.crimson.kuudra.danger"); + private static final Title TITLE = new Title(DANGER_TEXT.get()); + + static void init() { + Scheduler.INSTANCE.scheduleCyclic(DangerWarning::updateIndicator, 5); + ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> reset()); + } + + private static void updateIndicator() { + if (Utils.isInKuudra() && SkyblockerConfigManager.get().crimsonIsle.kuudra.dangerWarning && CLIENT.player != null && CLIENT.world != null) { + for (int i = 1; i <= 5; i++) { + BlockPos under = CLIENT.player.getBlockPos().down(i); + Title title = getDangerTitle(under); + + if (title != null) { + RenderHelper.displayInTitleContainerAndPlaySound(title); + + return; + } else if (i == 5) { //Prevent removing the title prematurely + TitleContainer.removeTitle(TITLE); + } + } + } + } + + private static Title getDangerTitle(BlockPos pos) { + BlockState state = CLIENT.world.getBlockState(pos); + Block block = state.getBlock(); + + int argb = switch (block) { + case Block b when b == Blocks.GREEN_TERRACOTTA -> DyeColor.GREEN.getEntityColor(); + case Block b when b == Blocks.LIME_TERRACOTTA -> DyeColor.LIME.getEntityColor(); + case Block b when b == Blocks.YELLOW_TERRACOTTA -> DyeColor.YELLOW.getEntityColor(); + case Block b when b == Blocks.ORANGE_TERRACOTTA -> DyeColor.ORANGE.getEntityColor(); + case Block b when b == Blocks.PINK_TERRACOTTA -> DyeColor.PINK.getEntityColor(); + case Block b when b == Blocks.RED_TERRACOTTA -> DyeColor.RED.getEntityColor(); + + default -> 0; + }; + + return argb != 0 ? TITLE.setText(DANGER_TEXT.get().withColor(argb & 0x00FFFFFF)) : null; + } + + private static void reset() { + TitleContainer.removeTitle(TITLE); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java index 5bc98894..626905a5 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java @@ -1,23 +1,22 @@ package de.hysky.skyblocker.skyblock.crimson.kuudra; import de.hysky.skyblocker.utils.Utils; -import de.hysky.skyblocker.utils.scheduler.Scheduler; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; 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.WorldRenderEvents; import net.minecraft.text.Text; import net.minecraft.util.Formatting; -public class Kuudra { +public class Kuudra { + public static final int KUUDRA_MAGMA_CUBE_SIZE = 30; + static KuudraPhase phase = KuudraPhase.OTHER; public static void init() { - WorldRenderEvents.AFTER_TRANSLUCENT.register(KuudraWaypoints::render); - ClientLifecycleEvents.CLIENT_STARTED.register(KuudraWaypoints::load); + KuudraWaypoints.init(); + DangerWarning.init(); + ClientPlayConnectionEvents.JOIN.register((_handler, _sender, _client) -> reset()); ClientReceiveMessageEvents.GAME.register(Kuudra::onMessage); - Scheduler.INSTANCE.scheduleCyclic(KuudraWaypoints::tick, 20); } private static void onMessage(Text text, boolean overlay) { @@ -35,6 +34,10 @@ public class Kuudra { if (message.equals("[NPC] Elle: POW! SURELY THAT'S IT! I don't think he has any more in him!")) { phase = KuudraPhase.OTHER; } + + if (message.equals("[NPC] Elle: What just happened!? Is this Kuudra's real lair?")) { + phase = KuudraPhase.KUUDRA_LAIR; + } } } @@ -45,6 +48,7 @@ public class Kuudra { enum KuudraPhase { OTHER, RETRIEVE_SUPPLIES, - DPS; + DPS, + KUUDRA_LAIR; //Infernal Only } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/KuudraWaypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/KuudraWaypoints.java index dbf7409a..ba2e6695 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/KuudraWaypoints.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/KuudraWaypoints.java @@ -20,10 +20,13 @@ import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.PosUtils; import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.scheduler.Scheduler; import de.hysky.skyblocker.utils. |
