From f359c490fdaa9a056d05e2e3ca9aadc185534c0d Mon Sep 17 00:00:00 2001 From: Moritz <59416038+Morazzer@users.noreply.github.com> Date: Thu, 26 Dec 2024 11:10:30 +0100 Subject: [PATCH] feat: add croesus helper (#220) --- .../datagen/lang/EnglishLanguageProvider.java | 4 + .../cabcb80d088276cffde41e74584028f1c00b99b8 | 4 +- .../assets/cookies-mod/lang/en_us.json | 8 +- .../mod/config/categories/DungeonConfig.java | 12 ++ .../mixins/ItemBackgroundRenderMixin.java | 28 +++++ .../mod/features/dungeons/CroesusHelper.java | 75 +++++++++++ .../features/dungeons/DungeonFeatures.java | 3 + .../dungeons/chests/CroesusChestHelper.java | 119 ++++++++++++++++++ .../mod/translations/TranslationKeys.java | 4 + .../items/CookiesDataComponentTypes.java | 4 + .../cookies/mod/utils/items/ItemUtils.java | 19 +++ 11 files changed, 277 insertions(+), 3 deletions(-) create mode 100644 src/main/java/codes/cookies/mod/features/dungeons/CroesusHelper.java create mode 100644 src/main/java/codes/cookies/mod/features/dungeons/chests/CroesusChestHelper.java diff --git a/src/datagen/java/codes/cookies/mod/datagen/lang/EnglishLanguageProvider.java b/src/datagen/java/codes/cookies/mod/datagen/lang/EnglishLanguageProvider.java index 25fddd14..8c88ae44 100644 --- a/src/datagen/java/codes/cookies/mod/datagen/lang/EnglishLanguageProvider.java +++ b/src/datagen/java/codes/cookies/mod/datagen/lang/EnglishLanguageProvider.java @@ -688,5 +688,9 @@ private void addDungeonConfig(CookiesTranslationBuilder translationBuilder) { Furthermore thank you to drek1984, Jade and bonsai which where helping Desco1 with the original and as well skytils for parts of the original solver."""); + + translationBuilder.addConfig(CONFIG_DUNGEON_CROESUS, "Croesus", "Adds features to the croesus npc."); + translationBuilder.addConfig(CONFIG_DUNGEON_CROESUS_HIGHLIGHT_UNCLAIMED, "Highlight unclaimed", "Highlights unclaimed chests in the croesus npc."); + translationBuilder.addConfig(CONFIG_DUNGEON_CROESUS_REPLACE_ITEM, "Replace chest item", "Replaces the chest item with the highest rarity item in the chest, this MAY not be the most valuable item in the chest."); } } diff --git a/src/main/generated/.cache/cabcb80d088276cffde41e74584028f1c00b99b8 b/src/main/generated/.cache/cabcb80d088276cffde41e74584028f1c00b99b8 index 08a5164d..e14a09a4 100644 --- a/src/main/generated/.cache/cabcb80d088276cffde41e74584028f1c00b99b8 +++ b/src/main/generated/.cache/cabcb80d088276cffde41e74584028f1c00b99b8 @@ -1,2 +1,2 @@ -// 1.21.3 2024-12-11T11:17:47.4766913 cookies-mod/Language (en_us) -b8e506abeadfabc1b260c9088e803802d2607fc9 assets\cookies-mod\lang\en_us.json +// 1.21.3 2024-12-26T09:18:51.409229 cookies-mod/Language (en_us) +fecd8a32a589755601eeacf43fc4ab7a03efe92a assets/cookies-mod/lang/en_us.json diff --git a/src/main/generated/assets/cookies-mod/lang/en_us.json b/src/main/generated/assets/cookies-mod/lang/en_us.json index 2351fb3d..2c273cca 100644 --- a/src/main/generated/assets/cookies-mod/lang/en_us.json +++ b/src/main/generated/assets/cookies-mod/lang/en_us.json @@ -89,6 +89,12 @@ "cookies.config.dev.show_plot_price_breakdown.name": "Plot price breakdown", "cookies.config.dev.show_plot_price_breakdown.tooltip": "Shows a breakdown of how much compost you need to unlock all plots.", "cookies.config.dev.tooltip": "Development related config entries.", + "cookies.config.dungeon.croesus.highlight_unclaimed.name": "Highlight unclaimed", + "cookies.config.dungeon.croesus.highlight_unclaimed.tooltip": "Highlights unclaimed chests in the croesus npc.", + "cookies.config.dungeon.croesus.name": "Croesus", + "cookies.config.dungeon.croesus.replace_item.name": "Replace chest item", + "cookies.config.dungeon.croesus.replace_item.tooltip": "Replaces the chest item with the highest rarity item in the chest, this MAY not be the most valuable item in the chest.", + "cookies.config.dungeon.croesus.tooltip": "Adds features to the croesus npc.", "cookies.config.dungeon.name": "Dungeon Config", "cookies.config.dungeon.player_glow_by_class_color.name": "Class based glow color", "cookies.config.dungeon.player_glow_by_class_color.tooltip": "Overrides the default hypixel glowing by rank to glow by class color.", @@ -480,4 +486,4 @@ "cookies.unexpected_error": "An unexpected error occurred while executing the command!", "cookies.update_available": "Your version of the mod isn't up-to-date!", "cookies.update_modrinth": "(Click here to open modrinth)" -} +} \ No newline at end of file diff --git a/src/main/java/codes/cookies/mod/config/categories/DungeonConfig.java b/src/main/java/codes/cookies/mod/config/categories/DungeonConfig.java index a342b9f7..b0b30ed4 100644 --- a/src/main/java/codes/cookies/mod/config/categories/DungeonConfig.java +++ b/src/main/java/codes/cookies/mod/config/categories/DungeonConfig.java @@ -45,6 +45,7 @@ public DungeonConfig() { public SpiritLeapFoldable spiritLeapFoldable = new SpiritLeapFoldable(); public PuzzleFoldable puzzleFoldable = new PuzzleFoldable(); public ClassColorFoldable classColorFoldable = new ClassColorFoldable(); + public CroesusFoldable croesusFoldable = new CroesusFoldable(); public BooleanOption glowClassColor = new BooleanOption(CONFIG_DUNGEON_GLOW_CLASS_COLOR, true); public TextDisplayOption render = new TextDisplayOption(CONFIG_DUNGEON_RENDER); @@ -165,4 +166,15 @@ public String getName() { } } + public static class CroesusFoldable extends Foldable { + + public BooleanOption highlightUnclaimedChests = new BooleanOption(CONFIG_DUNGEON_CROESUS_HIGHLIGHT_UNCLAIMED, false); + public BooleanOption replaceChestItemWithHighestRarityItem = new BooleanOption(CONFIG_DUNGEON_CROESUS_REPLACE_ITEM, false); + + @Override + public String getName() { + return CONFIG_DUNGEON_CROESUS; + } + } + } diff --git a/src/main/java/codes/cookies/mod/events/mixins/ItemBackgroundRenderMixin.java b/src/main/java/codes/cookies/mod/events/mixins/ItemBackgroundRenderMixin.java index 683ceb12..b9284d71 100644 --- a/src/main/java/codes/cookies/mod/events/mixins/ItemBackgroundRenderMixin.java +++ b/src/main/java/codes/cookies/mod/events/mixins/ItemBackgroundRenderMixin.java @@ -51,6 +51,15 @@ private void renderBackground(DrawContext context, Slot slot, CallbackInfo ci) { if (stack == null) { return; } + if (stack.contains(CookiesDataComponentTypes.BACKGROUND_ITEM)) { + final ItemStack itemStack = stack.get(CookiesDataComponentTypes.BACKGROUND_ITEM); + context.getMatrices().push(); + context.getMatrices().translate(0,0,-100); + context.drawItem(itemStack, slot.x, slot.y); + context.getMatrices().pop(); + return; + } + final Integer data = ItemUtils.getData(stack, CookiesDataComponentTypes.ITEM_BACKGROUND_COLOR); if (data == null) { return; @@ -64,6 +73,25 @@ private void renderBackground(DrawContext context, Slot slot, CallbackInfo ci) { ); } + @Inject( + method = "drawSlot", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/gui/DrawContext;drawItem(Lnet/minecraft/item/ItemStack;III)V", + shift = At.Shift.AFTER + ) + ) + private void renderForeground(DrawContext context, Slot slot, CallbackInfo ci) { + final ItemStack stack = slot.getStack(); + if (stack == null) { + return; + } + if (stack.contains(CookiesDataComponentTypes.FOREGROUND_ITEM)) { + final ItemStack itemStack = stack.get(CookiesDataComponentTypes.FOREGROUND_ITEM); + context.drawItem(itemStack, slot.x, slot.y); + } + } + /** * Called when a screen is opened or resized. * diff --git a/src/main/java/codes/cookies/mod/features/dungeons/CroesusHelper.java b/src/main/java/codes/cookies/mod/features/dungeons/CroesusHelper.java new file mode 100644 index 00000000..78dc420d --- /dev/null +++ b/src/main/java/codes/cookies/mod/features/dungeons/CroesusHelper.java @@ -0,0 +1,75 @@ +package codes.cookies.mod.features.dungeons; + +import java.util.List; +import java.util.Optional; + +import codes.cookies.mod.config.categories.DungeonConfig; +import codes.cookies.mod.events.InventoryEvents; +import codes.cookies.mod.events.api.InventoryContentUpdateEvent; +import codes.cookies.mod.utils.cookies.CookiesUtils; +import codes.cookies.mod.utils.items.CookiesDataComponentTypes; +import codes.cookies.mod.utils.items.ItemUtils; +import codes.cookies.mod.utils.skyblock.LocationUtils; +import com.google.common.base.Predicates; + +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.screen.slot.Slot; + +public class CroesusHelper { + + public CroesusHelper(HandledScreen handledScreen) { + InventoryContentUpdateEvent.registerSlot(handledScreen.getScreenHandler(), this::update); + } + + public static void init() { + InventoryEvents.beforeInit( + "Croesus", Predicates.>alwaysTrue() + .and(o -> LocationUtils.Island.DUNGEON_HUB.isActive()), + CroesusHelper::open); + } + + private static void open(HandledScreen handledScreen) { + if (!DungeonConfig.getInstance().croesusFoldable.highlightUnclaimedChests.getValue()) { + return; + } + new CroesusHelper(handledScreen); + } + + private void update(Slot slot) { + final ItemStack stack = slot.getStack(); + + if (!stack.isOf(Items.PLAYER_HEAD)) { + return; + } + + final String literalStackName = CookiesUtils.stripColor(stack.getName().getString()); + if (!this.isCatacombsOrMasterModeMame(literalStackName)) { + return; + } + + final Optional> optionalLore = ItemUtils.getLore(stack); + if (optionalLore.isEmpty()) { + return; + } + + final List lore = optionalLore.get().stream().map(String::trim).toList(); + final boolean hasntOpenedChests = lore.contains("No Chests Opened!"); + + final Item backgroundStackItem; + if (hasntOpenedChests) { + backgroundStackItem = Items.LIME_STAINED_GLASS_PANE; + } else { + backgroundStackItem = Items.GRAY_STAINED_GLASS_PANE; + } + + stack.set(CookiesDataComponentTypes.BACKGROUND_ITEM, new ItemStack(backgroundStackItem)); + } + + private boolean isCatacombsOrMasterModeMame(String name) { + return name.equalsIgnoreCase("Master Mode The Catacombs") || name.equalsIgnoreCase("The Catacombs"); + } + +} diff --git a/src/main/java/codes/cookies/mod/features/dungeons/DungeonFeatures.java b/src/main/java/codes/cookies/mod/features/dungeons/DungeonFeatures.java index 3fd867fe..ad3c860c 100644 --- a/src/main/java/codes/cookies/mod/features/dungeons/DungeonFeatures.java +++ b/src/main/java/codes/cookies/mod/features/dungeons/DungeonFeatures.java @@ -1,5 +1,6 @@ package codes.cookies.mod.features.dungeons; +import codes.cookies.mod.features.dungeons.chests.CroesusChestHelper; import codes.cookies.mod.features.dungeons.map.DungeonMapHud; import codes.cookies.mod.render.hud.HudManager; import com.google.common.cache.Cache; @@ -74,6 +75,8 @@ public DungeonFeatures() { new CorrectAllThePanesTerminalSolver(); new ChangeAllToSameColorTerminalSolver(); SpiritLeapOverlay.init(this); + CroesusHelper.init(); + CroesusChestHelper.init(); HudManager.register(DungeonMapHud.getInstance()); } diff --git a/src/main/java/codes/cookies/mod/features/dungeons/chests/CroesusChestHelper.java b/src/main/java/codes/cookies/mod/features/dungeons/chests/CroesusChestHelper.java new file mode 100644 index 00000000..116c714f --- /dev/null +++ b/src/main/java/codes/cookies/mod/features/dungeons/chests/CroesusChestHelper.java @@ -0,0 +1,119 @@ +package codes.cookies.mod.features.dungeons.chests; + +import codes.cookies.mod.config.categories.DungeonConfig; +import codes.cookies.mod.events.InventoryEvents; +import codes.cookies.mod.events.api.InventoryContentUpdateEvent; +import codes.cookies.mod.repository.RepositoryItem; +import codes.cookies.mod.utils.items.CookiesDataComponentTypes; +import codes.cookies.mod.utils.items.ItemUtils; +import codes.cookies.mod.utils.skyblock.LocationUtils; +import com.google.common.base.Predicates; + +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.screen.slot.Slot; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class CroesusChestHelper { + + private final List chestsNames = List.of("Wood Chest", "Gold Chest", "Diamond Chest", "Emerald Chest", "Obsidian Chest", "Bedrock Chest"); + + public CroesusChestHelper(HandledScreen handledScreen) { + InventoryContentUpdateEvent.registerSlot(handledScreen.getScreenHandler(), this::update); + } + + private void update(Slot slot) { + final ItemStack stack = slot.getStack(); + + if (!stack.isOf(Items.PLAYER_HEAD)) { + return; + } + + final String literalStackName = stack.getName().getString(); + + if (!isChestName(literalStackName)) { + return; + } + + final Optional stackForChest = this.getStackForChest(stack); + stackForChest.ifPresent(itemStack -> this.modifyItem(stack, itemStack)); + } + + private void modifyItem(ItemStack originalStack, @NotNull ItemStack overrideStack) { + ItemUtils.copy(DataComponentTypes.LORE, originalStack, overrideStack); + ItemUtils.copy(DataComponentTypes.CUSTOM_NAME, originalStack, overrideStack); + ItemUtils.copy(DataComponentTypes.ITEM_NAME, originalStack, overrideStack); + + if (overrideStack.isOf(Items.PLAYER_HEAD)) { + originalStack.set(CookiesDataComponentTypes.FOREGROUND_ITEM, overrideStack); + } else { + originalStack.set(CookiesDataComponentTypes.OVERRIDE_RENDER_ITEM, overrideStack); + } + } + + private boolean isChestName(String name) { + return chestsNames.contains(name); + } + + public static void init() { + InventoryEvents.beforeInit( + "cookies-regex:Master Mode The Catacombs - F.*", Predicates.>alwaysTrue() + .and(o -> LocationUtils.Island.DUNGEON_HUB.isActive()), + CroesusChestHelper::open); + InventoryEvents.beforeInit( + "cookies-regex:The Catacombs - F.*", Predicates.>alwaysTrue() + .and(o -> LocationUtils.Island.DUNGEON_HUB.isActive()), + CroesusChestHelper::open); + } + + private static void open(HandledScreen handledScreen) { + if (!DungeonConfig.getInstance().croesusFoldable.replaceChestItemWithHighestRarityItem.getValue()) { + return; + } + new CroesusChestHelper(handledScreen); + } + + private Optional getStackForChest(ItemStack chest) { + final Optional> optionalLore = ItemUtils.getLore(chest); + + if (optionalLore.isEmpty()) { + return Optional.empty(); + } + + final List lore = optionalLore.get(); + + final List contents = lore.stream().skip(1).takeWhile(line -> !line.isEmpty()).collect(Collectors.toList()); + contents.removeIf(string -> string.contains("Essence")); + + final List items = new ArrayList<>(); + boolean containsEnchantedBooks = false; + for (String content : contents) { + if (content.startsWith("Enchanted Book")) { + containsEnchantedBooks = true; + } + + RepositoryItem.ofName(content).ifPresent(items::add); + } + + items.sort(Comparator.comparingInt(item -> item.getTier().ordinal())); + + if (!items.isEmpty()) { + return Optional.ofNullable(items.getFirst().constructItemStack()); + } + + if (containsEnchantedBooks) { + return Optional.of(new ItemStack(Items.ENCHANTED_BOOK)); + } + + return Optional.empty(); + } +} diff --git a/src/main/java/codes/cookies/mod/translations/TranslationKeys.java b/src/main/java/codes/cookies/mod/translations/TranslationKeys.java index 88a73bfe..08d518f9 100644 --- a/src/main/java/codes/cookies/mod/translations/TranslationKeys.java +++ b/src/main/java/codes/cookies/mod/translations/TranslationKeys.java @@ -426,6 +426,10 @@ public interface TranslationKeys { String CONFIG_DUNGEON_PUZZLE_WATER_BOARD_SOLVER = CONFIG_DUNGEON_PUZZLE + ".water_board"; String CONFIG_DUNGEON_PUZZLE_WATER_BOARD_CREDITS = CONFIG_DUNGEON_PUZZLE_WATER_BOARD_SOLVER + ".credits"; + String CONFIG_DUNGEON_CROESUS = CONFIG_DUNGEON + ".croesus"; + String CONFIG_DUNGEON_CROESUS_HIGHLIGHT_UNCLAIMED = CONFIG_DUNGEON_CROESUS + ".highlight_unclaimed"; + String CONFIG_DUNGEON_CROESUS_REPLACE_ITEM = CONFIG_DUNGEON_CROESUS + ".replace_item"; + // // internal diff --git a/src/main/java/codes/cookies/mod/utils/items/CookiesDataComponentTypes.java b/src/main/java/codes/cookies/mod/utils/items/CookiesDataComponentTypes.java index 39ee5667..eeb0c22c 100644 --- a/src/main/java/codes/cookies/mod/utils/items/CookiesDataComponentTypes.java +++ b/src/main/java/codes/cookies/mod/utils/items/CookiesDataComponentTypes.java @@ -78,6 +78,8 @@ public class CookiesDataComponentTypes { public static final ComponentType ITEM_BACKGROUND_COLOR; public static final ComponentType> CUSTOM_LORE; public static final ComponentType LORE_ITEMS; + public static final ComponentType BACKGROUND_ITEM; + public static final ComponentType FOREGROUND_ITEM; private static final List> list = new ArrayList<>(); @Getter @@ -216,6 +218,8 @@ public class CookiesDataComponentTypes { ITEM_BACKGROUND_COLOR = new CookiesDataComponent<>(Identifier.of("cookies:item_background_color")); CUSTOM_LORE = new CookiesDataComponent<>(Identifier.of("cookies:custom_lore")); LORE_ITEMS = new CookiesDataComponent<>(Identifier.of("cookies:lore_items")); + BACKGROUND_ITEM = new CookiesDataComponent<>(Identifier.of("cookies:background_item")); + FOREGROUND_ITEM = new CookiesDataComponent<>(Identifier.of("cookies:foreground_item")); ON_ITEM_CLICK_RUNNABLE = new CookiesDataComponent<>(Identifier.of("cookies:on_item_click_runnable")); } diff --git a/src/main/java/codes/cookies/mod/utils/items/ItemUtils.java b/src/main/java/codes/cookies/mod/utils/items/ItemUtils.java index b291cd92..eb85014a 100644 --- a/src/main/java/codes/cookies/mod/utils/items/ItemUtils.java +++ b/src/main/java/codes/cookies/mod/utils/items/ItemUtils.java @@ -2,14 +2,23 @@ import codes.cookies.mod.data.profile.items.Item; +import codes.cookies.mod.utils.cookies.CookiesUtils; + import net.minecraft.client.MinecraftClient; import net.minecraft.component.ComponentType; import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.LoreComponent; import net.minecraft.component.type.NbtComponent; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; +import net.minecraft.text.Text; + import org.jetbrains.annotations.NotNull; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + /** * Item related utility methods. */ @@ -81,4 +90,14 @@ public static String getId(Item item) { } return item.itemStack().get(CookiesDataComponentTypes.SKYBLOCK_ID); } + + public static Optional> getLore(ItemStack stack) { + return Optional.ofNullable(stack.get(DataComponentTypes.LORE)) + .map(LoreComponent::lines) + .map(ItemUtils::mapTextListToString); + } + + private static List mapTextListToString(@NotNull List texts) { + return texts.stream().map(Text::getString).map(CookiesUtils::stripColor).collect(Collectors.toList()); + } }