From 5ffe5dab3973b540a4e0cd1b57f13d0be77e3f84 Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Thu, 16 Mar 2023 19:13:08 +0100 Subject: Added jacob farming contest features --- CHANGELOG.md | 4 + FEATURES.md | 3 + .../java/at/hannibal2/skyhanni/SkyHanniMod.java | 2 + .../at/hannibal2/skyhanni/api/CollectionAPI.kt | 17 ++- .../skyhanni/config/features/Inventory.java | 23 +++ .../at/hannibal2/skyhanni/data/InventoryData.kt | 34 ++++- .../java/at/hannibal2/skyhanni/data/ToolTipData.kt | 21 +++ .../skyhanni/events/InventoryOpenEvent.kt | 9 +- .../skyhanni/events/LorenzToolTipEvent.kt | 6 + .../inventory/JacobFarmingContestsInventory.kt | 162 +++++++++++++++++++++ .../mixins/transformers/gui/MixinGuiContainer.java | 6 + 11 files changed, 275 insertions(+), 12 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/data/ToolTipData.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/events/LorenzToolTipEvent.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/inventory/JacobFarmingContestsInventory.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 816907c31..67ed61cdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ + Added support for tier 1 minions and title send for the minion craft helper. + Added Chicken head Timer. + Added **rancher boots** speed display. ++ Added **Unclaimed Rewards** - Highlight contests with unclaimed rewards in the jacob inventory. ++ Added **Duplicate Hider** - Hides duplicate farming contests in the inventory. ++ Added **Contest Time** - Adds the real time format to the farming contest description. ### Garden Features + Added **Copper Price** - Show copper to coin prices inside the Sky Mart inventory. @@ -33,6 +36,7 @@ + Added **Warn When Close** - Warn with title and sound when the next crop milestone upgrade happens in 5 seconds. Useful for switching to a different pet for leveling. + Added **Money per Hour** - Displays the money per hour YOU get with YOUR crop/minute value when selling the items to bazaar. + ### Features from other Mods > *The following features are only there because I want them when testing SkyHanni features without other mods present.* + Added Hide explosions. diff --git a/FEATURES.md b/FEATURES.md index 29f7e8881..f5c0a42b0 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -58,6 +58,9 @@ + Highlight depleted Bonzo's Masks in your inventory. + Highlight stuff that is missing in the skyblock level guide inventory. + **Auction Highlighter** - Highlight own items that are sold in green and that are expired in red. ++ **Unclaimed Rewards** - Highlight contests with unclaimed rewards in the jacob inventory. ++ **Duplicate Hider** - Hides duplicate farming contests in the inventory. ++ **Contest Time** - Adds the real time format to the farming contest description. ## Item Abilities - Show the cooldown of items in the inventory. diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java index f594e9c98..cf7c89c0f 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java @@ -115,6 +115,7 @@ public class SkyHanniMod { loadModule(new RenderGuiData()); loadModule(new GardenCropMilestones()); loadModule(new OwnInventoryData()); + loadModule(new ToolTipData()); // APIs loadModule(new BazaarApi()); @@ -220,6 +221,7 @@ public class SkyHanniMod { loadModule(new EliteFarmingWeight()); loadModule(new DicerRngDropCounter()); loadModule(new CropMoneyDisplay()); + loadModule(new JacobFarmingContestsInventory()); Commands.INSTANCE.init(); diff --git a/src/main/java/at/hannibal2/skyhanni/api/CollectionAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CollectionAPI.kt index 0a8fc7a80..f86819895 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CollectionAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CollectionAPI.kt @@ -7,6 +7,7 @@ import at.hannibal2.skyhanni.events.ProfileJoinEvent import at.hannibal2.skyhanni.features.bazaar.BazaarApi import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.name +import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.StringUtils.removeColor import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import java.util.regex.Pattern @@ -15,6 +16,13 @@ class CollectionAPI { private val counterPattern = Pattern.compile("(?:.*) §e(.*)§6\\/(?:.*)") private val singleCounterPattern = Pattern.compile("§7Total Collected: §e(.*)") + private val hypixelApiHasWrongItems = listOf( + "WOOL", + "CORRUPTED_FRAGMENT", + "EGG", + "POISONOUS_POTATO", + ) + @SubscribeEvent fun onProfileDataLoad(event: ProfileApiDataLoadedEvent) { val profileData = event.profileData @@ -32,12 +40,13 @@ class CollectionAPI { if (rawName == "GEMSTONE_COLLECTION") { itemName = "Gemstone" } + // Hypixel moment - if (rawName == "WOOL" || rawName == "CORRUPTED_FRAGMENT") { - continue - } + if (hypixelApiHasWrongItems.contains(rawName)) continue + if (itemName == null) { - println("collection name is null for '$rawName'") + LorenzUtils.debug("collection name is null for '$rawName'") + println() continue } collectionValue[itemName] = counter diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Inventory.java b/src/main/java/at/hannibal2/skyhanni/config/features/Inventory.java index 0e3fa3ba6..65ad96900 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/Inventory.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/Inventory.java @@ -88,6 +88,29 @@ public class Inventory { @ConfigAccordionId(id = 2) public boolean statsTuningTemplateStats = true; + @Expose + @ConfigOption(name = "Jacob Farming Contest", desc = "") + @ConfigEditorAccordion(id = 3) + public boolean jacobFarmingContest = false; + + @Expose + @ConfigOption(name = "Unclaimed Rewards", desc = "Highlight contests with unclaimed rewards in the jacob inventory.") + @ConfigEditorBoolean + @ConfigAccordionId(id = 3) + public boolean jacobFarmingContestHighlightRewards = true; + + @Expose + @ConfigOption(name = "Duplicate Hider", desc = "Hides duplicate farming contests in the inventory.") + @ConfigEditorBoolean + @ConfigAccordionId(id = 3) + public boolean jacobFarmingContestHideDuplicates = true; + + @Expose + @ConfigOption(name = "Contest Time", desc = "Adds the real time format to the contest description.") + @ConfigEditorBoolean + @ConfigAccordionId(id = 3) + public boolean jacobFarmingContestRealTime = true; + @Expose @ConfigOption( name = "Item number", diff --git a/src/main/java/at/hannibal2/skyhanni/data/InventoryData.kt b/src/main/java/at/hannibal2/skyhanni/data/InventoryData.kt index 0f372269a..d3630c159 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/InventoryData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/InventoryData.kt @@ -1,17 +1,16 @@ package at.hannibal2.skyhanni.data -import at.hannibal2.skyhanni.events.GuiContainerEvent -import at.hannibal2.skyhanni.events.InventoryCloseEvent -import at.hannibal2.skyhanni.events.InventoryOpenEvent -import at.hannibal2.skyhanni.events.PacketEvent +import at.hannibal2.skyhanni.events.* import net.minecraft.item.ItemStack import net.minecraft.network.play.server.S2DPacketOpenWindow import net.minecraft.network.play.server.S2FPacketSetSlot import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent class InventoryData { private var currentInventory: Inventory? = null private var acceptItems = false + private var lateEvent: LateInventoryOpenEvent? = null @SubscribeEvent fun onCloseWindow(event: GuiContainerEvent.CloseWindowEvent) { @@ -25,6 +24,15 @@ class InventoryData { } } + @SubscribeEvent + fun onTick(event: TickEvent.ClientTickEvent) { + if (event.phase != TickEvent.Phase.START) return + lateEvent?.let { + it.postAndCatch() + lateEvent = null + } + } + @SubscribeEvent fun onChatPacket(event: PacketEvent.ReceiveEvent) { val packet = event.packet @@ -40,7 +48,21 @@ class InventoryData { } if (packet is S2FPacketSetSlot) { - if (!acceptItems) return + if (!acceptItems) { + currentInventory?.let { + if (it.windowId != packet.func_149175_c()) return + + val slot = packet.func_149173_d() + if (slot < it.slotCount) { + val itemStack = packet.func_149174_e() + if (itemStack != null) { + it.items[slot] = itemStack + lateEvent = LateInventoryOpenEvent(it) + } + } + } + return + } currentInventory?.let { if (it.windowId != packet.func_149175_c()) return @@ -71,6 +93,6 @@ class InventoryData { val windowId: Int, val title: String, val slotCount: Int, - val items: MutableMap = mutableMapOf() + val items: MutableMap = mutableMapOf(), ) } \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/data/ToolTipData.kt b/src/main/java/at/hannibal2/skyhanni/data/ToolTipData.kt new file mode 100644 index 000000000..70ed2ead6 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/ToolTipData.kt @@ -0,0 +1,21 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.events.LorenzToolTipEvent +import net.minecraft.inventory.Slot +import net.minecraftforge.event.entity.player.ItemTooltipEvent +import net.minecraftforge.fml.common.eventhandler.EventPriority +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +class ToolTipData { + + @SubscribeEvent(priority = EventPriority.LOWEST) + fun onTooltip(event: ItemTooltipEvent) { + val toolTip = event.toolTip ?: return + val slot = lastSlot ?: return + LorenzToolTipEvent(slot, event.itemStack, toolTip).postAndCatch() + } + + companion object { + var lastSlot: Slot? = null + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/events/InventoryOpenEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/InventoryOpenEvent.kt index 135159106..aec3e6542 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/InventoryOpenEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/InventoryOpenEvent.kt @@ -3,9 +3,14 @@ package at.hannibal2.skyhanni.events import at.hannibal2.skyhanni.data.InventoryData import net.minecraft.item.ItemStack -class InventoryOpenEvent(inventory: InventoryData.Inventory): LorenzEvent() { +open class BaseInventoryOpenEvent(inventory: InventoryData.Inventory): LorenzEvent() { val inventoryId: Int by lazy { inventory.windowId } val inventoryName: String by lazy {inventory.title } val inventorySize: Int by lazy {inventory.slotCount } val inventoryItems: MutableMap by lazy {inventory.items } -} \ No newline at end of file +} + +class InventoryOpenEvent(inventory: InventoryData.Inventory): BaseInventoryOpenEvent(inventory) + +// Firing with items that are added later +class LateInventoryOpenEvent(inventory: InventoryData.Inventory): BaseInventoryOpenEvent(inventory) \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/events/LorenzToolTipEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/LorenzToolTipEvent.kt new file mode 100644 index 000000000..992edd78d --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/LorenzToolTipEvent.kt @@ -0,0 +1,6 @@ +package at.hannibal2.skyhanni.events + +import net.minecraft.inventory.Slot +import net.minecraft.item.ItemStack + +class LorenzToolTipEvent(val slot: Slot, val itemStack: ItemStack, var toolTip: MutableList): LorenzEvent() \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/JacobFarmingContestsInventory.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/JacobFarmingContestsInventory.kt new file mode 100644 index 000000000..c4da66bcc --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/JacobFarmingContestsInventory.kt @@ -0,0 +1,162 @@ +package at.hannibal2.skyhanni.features.inventory + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.GuiContainerEvent +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.events.LateInventoryOpenEvent +import at.hannibal2.skyhanni.events.LorenzToolTipEvent +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.ItemUtils.name +import at.hannibal2.skyhanni.utils.LorenzColor +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.RenderUtils.highlight +import io.github.moulberry.notenoughupdates.util.SkyBlockTime +import net.minecraft.client.gui.inventory.GuiChest +import net.minecraft.inventory.ContainerChest +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.text.SimpleDateFormat +import java.util.* +import java.util.regex.Pattern + +class JacobFarmingContestsInventory { + + private val duplicateSlots = mutableListOf() + private val realTime = mutableMapOf() + + private val formatDay = SimpleDateFormat("dd MMMM yyyy", Locale.getDefault()) + private val formatTime = SimpleDateFormat("HH:mm", Locale.getDefault()) + private val pattern = Pattern.compile("§a(.*) (.*)(?:rd|st|nd|th), Year (.*)") + private val config get() = SkyHanniMod.feature.inventory + + // Render the contests a tick delayed to feel smoother + private var hideEverything = true + + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + duplicateSlots.clear() + realTime.clear() + hideEverything = true + } + + @SubscribeEvent + fun onLateInventoryOpen(event: LateInventoryOpenEvent) { + if (!LorenzUtils.inSkyBlock) return + if (event.inventoryName != "Your Contests") return + + duplicateSlots.clear() + realTime.clear() + + val foundEvents = mutableListOf() + for ((slot, item) in event.inventoryItems) { + if (!item.getLore().any { it.startsWith("§7Your score: §e") }) continue + + val name = item.name!! + + if (foundEvents.contains(name)) { + if (config.jacobFarmingContestHideDuplicates) { + duplicateSlots.add(slot) + } + } else { + foundEvents.add(name) + } + if (config.jacobFarmingContestRealTime) { + readRealTime(name, slot) + } + } + hideEverything = false + } + + private fun readRealTime(name: String, slot: Int) { + val matcher = pattern.matcher(name) + if (!matcher.matches()) return + + val month = matcher.group(1) + val day = matcher.group(2).toInt() + val year = matcher.group(3).toInt() + + var monthNr = 0 + for (i in 1..12) { + val monthName = SkyBlockTime.monthName(i) + if (month == monthName) { + monthNr = i + } + } + val time = SkyBlockTime(year, monthNr, day, 0, 0, 0) + val toMillis = time.toMillis() + val dayFormat = formatDay.format(toMillis) + val startTimeFormat = formatTime.format(toMillis) + val endTimeFormat = formatTime.format(toMillis + 1000 * 60 * 20) + realTime[slot] = "$dayFormat $startTimeFormat-$endTimeFormat" + } + + @SubscribeEvent + fun onBackgroundDrawn(event: GuiContainerEvent.BackgroundDrawnEvent) { + if (!LorenzUtils.inSkyBlock) return + if (!InventoryUtils.openInventoryName().contains("Your Contests")) return + if (!config.jacobFarmingContestHighlightRewards) return + + // hide green border for a tick + if (config.jacobFarmingContestHideDuplicates && hideEverything) return + + if (event.gui !is GuiChest) return + val guiChest = event.gui + val chest = guiChest.inventorySlots as ContainerChest + + for (slot in chest.inventorySlots) { + if (slot == null) continue + if (slot.slotNumber != slot.slotIndex) continue + if (duplicateSlots.contains(slot.slotNumber)) continue + val stack = slot.stack ?: continue + if (stack.getLore().any { it == "§eClick to claim reward!" }) { + slot highlight LorenzColor.GREEN + } + } + } + + @SubscribeEvent + fun onDrawSlot(event: GuiContainerEvent.DrawSlotEvent.GuiContainerDrawSlotPre) { + if (!LorenzUtils.inSkyBlock) return + if (!config.jacobFarmingContestHideDuplicates) return + if (!InventoryUtils.openInventoryName().contains("Your Contests")) return + + if (hideEverything) { + val slot = event.slot + val number = slot.slotNumber + if (number in 10..43) { + event.isCanceled = true + return + } + + } + + val slot = event.slot.slotNumber + if (!duplicateSlots.contains(slot)) return + event.isCanceled = true + } + + @SubscribeEvent + fun onTooltip(event: LorenzToolTipEvent) { + if (!LorenzUtils.inSkyBlock) return + if (!InventoryUtils.openInventoryName().contains("Your Contests")) return + + val slot = event.slot.slotNumber + + if (config.jacobFarmingContestHideDuplicates) { + if (duplicateSlots.contains(slot)) { + event.toolTip.clear() + event.toolTip.add("§7Duplicate contest!") + return + } + } + + if (config.jacobFarmingContestRealTime) { + realTime[slot]?.let { + val toolTip = event.toolTip + if (toolTip.size > 1) { + toolTip.add(1, it) + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiContainer.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiContainer.java index a7fc852e5..2096841bf 100644 --- a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiContainer.java +++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiContainer.java @@ -1,10 +1,12 @@ package at.hannibal2.skyhanni.mixins.transformers.gui; +import at.hannibal2.skyhanni.data.ToolTipData; import at.hannibal2.skyhanni.mixins.hooks.GuiContainerHook; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.inventory.Slot; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -16,6 +18,9 @@ public abstract class MixinGuiContainer extends GuiScreen { @Unique private final GuiContainerHook hook = new GuiContainerHook(this); + @Shadow + private Slot theSlot; + @Inject(method = "keyTyped", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/entity/EntityPlayerSP;closeScreen()V", shift = At.Shift.BEFORE), cancellable = true) private void closeWindowPressed(CallbackInfo ci) { hook.closeWindowPressed(ci); @@ -55,5 +60,6 @@ public abstract class MixinGuiContainer extends GuiScreen { ) public void drawScreen_after(int mouseX, int mouseY, float partialTicks, CallbackInfo ci) { hook.onDrawScreenAfter(mouseX, mouseY, ci); + ToolTipData.Companion.setLastSlot(theSlot); } } -- cgit