summaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/features/items
diff options
context:
space:
mode:
authorLorenz <lo.scherf@gmail.com>2022-08-17 03:05:34 +0200
committerLorenz <lo.scherf@gmail.com>2022-08-17 03:05:34 +0200
commitef58a94bf31868c4b53218474f0be04c1cd93d97 (patch)
treecb56d5969f8bebf586298475a61c521229663fda /src/main/java/at/hannibal2/skyhanni/features/items
parent5669dbf6f68e7cacb2df6a4e37d703df8635353e (diff)
downloadskyhanni-ef58a94bf31868c4b53218474f0be04c1cd93d97.tar.gz
skyhanni-ef58a94bf31868c4b53218474f0be04c1cd93d97.tar.bz2
skyhanni-ef58a94bf31868c4b53218474f0be04c1cd93d97.zip
moving packets around
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/features/items')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/items/HideNotClickableItems.kt416
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/items/ItemDisplayOverlayFeatures.kt121
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/items/VanillaItemManager.kt53
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/items/abilitycooldown/ItemAbilityCooldown.kt215
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/items/abilitycooldown/WitherImpactDetection.kt74
5 files changed, 879 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/features/items/HideNotClickableItems.kt b/src/main/java/at/hannibal2/skyhanni/features/items/HideNotClickableItems.kt
new file mode 100644
index 000000000..c3b4a398d
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/items/HideNotClickableItems.kt
@@ -0,0 +1,416 @@
+package at.hannibal2.skyhanni.features.items
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.data.ItemRenderBackground.Companion.background
+import at.hannibal2.skyhanni.events.GuiContainerEvent
+import at.hannibal2.skyhanni.events.RepositoryReloadEvent
+import at.hannibal2.skyhanni.features.bazaar.BazaarApi
+import at.hannibal2.skyhanni.utils.*
+import at.hannibal2.skyhanni.utils.ItemUtils.cleanName
+import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName
+import at.hannibal2.skyhanni.utils.ItemUtils.getLore
+import at.hannibal2.skyhanni.utils.LorenzUtils.removeColor
+import com.google.gson.JsonObject
+import net.minecraft.client.Minecraft
+import net.minecraft.client.gui.inventory.GuiChest
+import net.minecraft.inventory.ContainerChest
+import net.minecraft.item.ItemStack
+import net.minecraftforge.event.entity.player.ItemTooltipEvent
+import net.minecraftforge.fml.common.eventhandler.EventPriority
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+
+class HideNotClickableItems {
+
+ private var hideReason = ""
+
+ private var lastClickTime = 0L
+ private var bypassUntil = 0L
+
+ private val hideNpcSellFilter = MultiFilter()
+ private val hideInStorageFilter = MultiFilter()
+ private val tradeNpcFilter = MultiFilter()
+ private val itemsToSalvage = mutableListOf<String>()
+ private val hidePlayerTradeFilter = MultiFilter()
+ private val notAuctionableFilter = MultiFilter()
+
+ @SubscribeEvent
+ fun onRepoReload(event: RepositoryReloadEvent) {
+ try {
+ val hideNotClickableItems = event.getConstant("HideNotClickableItems")!!
+ hideNpcSellFilter.load(hideNotClickableItems["hide_npc_sell"].asJsonObject)
+ hideInStorageFilter.load(hideNotClickableItems["hide_in_storage"].asJsonObject)
+ tradeNpcFilter.load(event.getConstant("TradeNpcs")!!)
+ updateSalvageList(hideNotClickableItems)
+ hidePlayerTradeFilter.load(hideNotClickableItems["hide_player_trade"].asJsonObject)
+ notAuctionableFilter.load(hideNotClickableItems["not_auctionable"].asJsonObject)
+
+ } catch (e: Exception) {
+ e.printStackTrace()
+ LorenzUtils.error("error in RepositoryReloadEvent")
+ }
+ }
+
+ private fun updateSalvageList(hideNotClickableItems: JsonObject) {
+ itemsToSalvage.clear()
+ val salvage = hideNotClickableItems["salvage"].asJsonObject
+ itemsToSalvage.addAll(salvage.asJsonObject["items"].asJsonArray.map { it.asString })
+ for (armor in salvage.asJsonObject["armor"].asJsonArray.map { it.asString }) {
+ itemsToSalvage.add("$armor Helmet")
+ itemsToSalvage.add("$armor Chestplate")
+ itemsToSalvage.add("$armor Leggings")
+ itemsToSalvage.add("$armor Boots")
+ }
+ }
+
+ @SubscribeEvent
+ fun onBackgroundDrawn(event: GuiContainerEvent.BackgroundDrawnEvent) {
+ if (!LorenzUtils.inSkyblock) return
+ if (isDisabled()) return
+ if (event.gui !is GuiChest) return
+ val guiChest = event.gui
+ val chest = guiChest.inventorySlots as ContainerChest
+ val chestName = chest.lowerChestInventory.displayName.unformattedText.trim()
+
+ for (slot in chest.inventorySlots) {
+ if (slot == null) continue
+
+ if (slot.slotNumber == slot.slotIndex) continue
+ if (slot.stack == null) continue
+
+ if (hide(chestName, slot.stack)) {
+ val color = LorenzColor.DARK_GRAY.addOpacity(160)
+ slot.stack.background = color.rgb
+ }
+ }
+ }
+
+ @SubscribeEvent(priority = EventPriority.LOWEST)
+ fun onTooltip(event: ItemTooltipEvent) {
+ if (isDisabled()) return
+ if (event.toolTip == null) return
+ val guiChest = Minecraft.getMinecraft().currentScreen
+ if (guiChest !is GuiChest) return
+ val chest = guiChest.inventorySlots as ContainerChest
+ val chestName = chest.lowerChestInventory.displayName.unformattedText.trim()
+
+ val stack = event.itemStack
+ if (ItemUtils.getItemsInOpenChest().contains(stack)) return
+ if (!ItemUtils.getItemsInInventory().contains(stack)) return
+
+ if (hide(chestName, stack)) {
+ val first = event.toolTip[0]
+ event.toolTip.clear()
+ event.toolTip.add("§7" + first.removeColor())
+ event.toolTip.add("")
+ if (hideReason == "") {
+ event.toolTip.add("§4No hide reason!")
+ LorenzUtils.warning("Not hide reason for not clickable item!")
+ } else {
+ event.toolTip.add("§c$hideReason")
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onSlotClick(event: GuiContainerEvent.SlotClickEvent) {
+ if (isDisabled()) return
+ if (event.gui !is GuiChest) return
+ val guiChest = event.gui
+ val chest = guiChest.inventorySlots as ContainerChest
+ val chestName = chest.lowerChestInventory.displayName.unformattedText.trim()
+
+ val slot = event.slot ?: return
+
+ if (slot.slotNumber == slot.slotIndex) return
+ if (slot.stack == null) return
+
+ val stack = slot.stack
+
+ if (hide(chestName, stack)) {
+ event.isCanceled = true
+
+ if (System.currentTimeMillis() > lastClickTime + 5_000) {
+ lastClickTime = System.currentTimeMillis()
+ }
+ return
+ }
+ }
+
+ private fun isDisabled(): Boolean {
+ if (bypassUntil > System.currentTimeMillis()) return true
+
+ return !SkyHanniMod.feature.inventory.hideNotClickableItems
+ }
+
+ private fun hide(chestName: String, stack: ItemStack): Boolean {
+ hideReason = ""
+ return when {
+ hideNpcSell(chestName, stack) -> true
+ hideInStorage(chestName, stack) -> true
+ hideSalvage(chestName, stack) -> true
+ hidePlayerTrade(chestName, stack) -> true
+ hideBazaarOrAH(chestName, stack) -> true
+ hideAccessoryBag(chestName, stack) -> true
+ hideSackOfSacks(chestName, stack) -> true
+ hideFishingBag(chestName, stack) -> true
+ hidePotionBag(chestName, stack) -> true
+ hidePrivateIslandChest(chestName, stack) -> true
+ hideAttributeFusion(chestName, stack) -> true
+ hideYourEquipment(chestName, stack) -> true
+ else -> false
+ }
+ }
+
+ private fun hideYourEquipment(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.startsWith("Your Equipment")) return false
+
+ val list = listOf(
+ "HELMET",
+ "CHESTPLATE",
+ "LEGGINGS",
+ "BOOTS",
+
+ "NECKLACE",
+ "CLOAK",
+ "BELT",
+ "GLOVES",
+ "BRACELET"
+ )
+ for (type in list) {
+ if (stack.getLore().any { it.contains("§l") && it.contains(type) }) {//todo use item api
+ return false
+ }
+ }
+
+ if (isSkyBlockMenuItem(stack)) {
+ hideReason = "The SkyBlock Menu cannot be put into the potion bag!"
+ return true
+ }
+
+ hideReason = "This item cannot be put into your equipment!"
+ return true
+ }
+
+ private fun hideAttributeFusion(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.startsWith("Attribute Fusion")) return false
+
+ if (ItemUtils.hasAttributes(stack)) return false
+
+ hideReason = "This item has no attributes!"
+ return true
+ }
+
+ private fun hidePrivateIslandChest(chestName: String, stack: ItemStack): Boolean {
+ if (chestName != "Chest" && chestName != "Large Chest") return false
+ //TODO make check if player is on private island
+
+ if (!ItemUtils.isSoulBound(stack)) return false
+
+ hideReason = "This item cannot be stored into a chest!"
+ return true
+ }
+
+ private fun hidePotionBag(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.startsWith("Potion Bag")) return false
+
+ if (isSkyBlockMenuItem(stack)) {
+ hideReason = "The SkyBlock Menu cannot be put into the potion bag!"
+ return true
+ }
+
+ if (stack.cleanName().endsWith(" Potion")) return false
+
+ hideReason = "This item is not a potion!"
+ return true
+ }
+
+ private fun hideFishingBag(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.startsWith("Fishing Bag")) return false
+
+ if (isSkyBlockMenuItem(stack)) {
+ hideReason = "The SkyBlock Menu cannot be put into the fishing bag!"
+ return true
+ }
+
+ if (stack.getLore().any { it.removeColor() == "Fishing Bait" }) {
+ return false
+ }
+ hideReason = "This item is not a fishing bait!"
+ return true
+ }
+
+ private fun hideSackOfSacks(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.startsWith("Sack of Sacks")) return false
+
+ val name = stack.cleanName()
+ if (ItemUtils.isSack(name)) return false
+ if (isSkyBlockMenuItem(stack)) return false
+
+ hideReason = "This item is not a sack!"
+ return true
+ }
+
+ private fun hideAccessoryBag(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.startsWith("Accessory Bag")) return false
+
+ if (stack.getLore().any { it.contains("ACCESSORY") }) return false
+ if (isSkyBlockMenuItem(stack)) return false
+
+ hideReason = "This item is not an accessory!"
+ return true
+ }
+
+ private fun hidePlayerTrade(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.startsWith("You ")) return false
+
+ if (ItemUtils.isCoopSoulBound(stack)) {
+ hideReason = "Soulbound items cannot be traded!"
+ return true
+ }
+
+ if (isSkyBlockMenuItem(stack)) {
+ hideReason = "The SkyBlock Menu cannot be traded!"
+ return true
+ }
+
+ val name = stack.cleanName()
+
+ if (ItemUtils.isSack(name)) {
+ hideReason = "Sacks cannot be traded!"
+ return true
+ }
+
+ val result = hidePlayerTradeFilter.match(name)
+ LorenzDebug.log("hidePlayerTradeList filter result for '$name': $result")
+
+ if (result) hideReason = "This item cannot be traded!"
+ return result
+ }
+
+ private fun hideNpcSell(chestName: String, stack: ItemStack): Boolean {
+ if (!tradeNpcFilter.match(chestName)) return false
+
+ var name = stack.cleanName()
+ val size = stack.stackSize
+ val amountText = " x$size"
+ if (name.endsWith(amountText)) {
+ name = name.substring(0, name.length - amountText.length)
+ }
+
+ if (isSkyBlockMenuItem(stack)) {
+ hideReason = "The SkyBlock Menu cannot be sold at the NPC!"
+ return true
+ }
+
+ if (!ItemUtils.isRecombobulated(stack)) {
+ if (hideNpcSellFilter.match(name)) return false
+
+ val id = stack.getInternalName()
+ if (VanillaItemManager.isVanillaItem(id) && !stack.isItemEnchanted) {
+ return false
+ }
+ }
+
+ hideReason = "This item should not be sold at the NPC!"
+ return true
+ }
+
+ private fun hideInStorage(chestName: String, stack: ItemStack): Boolean {
+ if (!chestName.contains("Ender Chest") && !chestName.contains("Backpack") && chestName != "Storage") return false
+
+ if (isSkyBlockMenuItem(stack)) {
+ hideReason = "The SkyBlock Menu cannot be put into the storage!"
+ return true
+ }
+
+ val name = stack.cleanName()
+
+ if (ItemUtils.isSack(name)) {
+ hideReason = "Sacks cannot be put into the storage!"
+ return true
+ }
+
+ val result = hideInStorageFilter.match(name)
+
+ if (result) hideReason = "Bags cannot be put into the storage!"
+ return result
+ }
+
+ private fun hideSalvage(chestName: String, stack: ItemStack): Boolean {
+ if (chestName != "Salvage Item") return false
+
+ if (ItemUtils.isRecombobulated(stack)) {
+ hideReason = "This item should not be salvaged! (Recombobulated)"
+ return true
+ }
+ for (line in stack.getLore()) {
+ if (line.contains("LEGENDARY DUNGEON")) {
+ hideReason = "This item should not be salvaged! (Legendary)"
+ return true
+ }
+ }
+
+ if (isSkyBlockMenuItem(stack)) {
+ hideReason = "The SkyBlock Menu cannot be salvaged!"
+ return true
+ }
+
+ val name = stack.cleanName()
+ for (item in itemsToSalvage) {
+ if (name.endsWith(item)) {
+ return false
+ }
+ }
+
+ hideReason = "This item cannot be salvaged!"
+ return true
+ }
+
+ private fun hideBazaarOrAH(chestName: String, stack: ItemStack): Boolean {
+ val bazaarInventory = BazaarApi.isBazaarInventory(chestName)
+
+ val auctionHouseInventory =
+ chestName == "Co-op Auction House" || chestName == "Auction House" || chestName == "Create BIN Auction" || chestName == "Create Auction"
+ if (!bazaarInventory && !auctionHouseInventory) return false
+
+
+
+ if (isSkyBlockMenuItem(stack)) {
+ if (bazaarInventory) hideReason = "The SkyBlock Menu is not a Bazaar Product!"
+ if (auctionHouseInventory) hideReason = "The SkyBlock Menu cannot be auctioned!"
+ return true
+ }
+
+ val displayName = stack.displayName
+ if (bazaarInventory != BazaarApi.isBazaarItem(displayName)) {
+ if (bazaarInventory) hideReason = "This item is not a Bazaar Product!"
+ if (auctionHouseInventory) hideReason = "Bazaar Products cannot be auctioned!"
+
+ return true
+ }
+
+ if (isNotAuctionable(stack)) return true
+
+ return false
+ }
+
+ private fun isNotAuctionable(stack: ItemStack): Boolean {
+ if (ItemUtils.isCoopSoulBound(stack)) {
+ hideReason = "Soulbound items cannot be auctioned!"
+ return true
+ }
+
+ val name = stack.cleanName()
+
+ if (ItemUtils.isSack(name)) {
+ hideReason = "Sacks cannot be auctioned!"
+ return true
+ }
+
+ val result = notAuctionableFilter.match(name)
+ if (result) hideReason = "This item cannot be auctioned!"
+ return result
+ }
+
+ private fun isSkyBlockMenuItem(stack: ItemStack): Boolean = stack.getInternalName() == "SKYBLOCK_MENU"
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/items/ItemDisplayOverlayFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/items/ItemDisplayOverlayFeatures.kt
new file mode 100644
index 000000000..1ad9aa39b
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/items/ItemDisplayOverlayFeatures.kt
@@ -0,0 +1,121 @@
+package at.hannibal2.skyhanni.features.items
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.events.GuiRenderItemEvent
+import at.hannibal2.skyhanni.utils.ItemUtils
+import at.hannibal2.skyhanni.utils.ItemUtils.cleanName
+import at.hannibal2.skyhanni.utils.ItemUtils.getLore
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.between
+import at.hannibal2.skyhanni.utils.LorenzUtils.matchRegex
+import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimal
+import net.minecraft.client.renderer.GlStateManager
+import net.minecraft.item.ItemStack
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+
+class ItemDisplayOverlayFeatures {
+
+ @SubscribeEvent
+ fun onRenderItemOverlayPost(event: GuiRenderItemEvent.RenderOverlayEvent.Post) {
+ val item = event.stack ?: return
+
+ if (!LorenzUtils.inSkyblock || item.stackSize != 1) return
+
+ val stackTip = getStackTip(item)
+
+ if (stackTip.isNotEmpty()) {
+ GlStateManager.disableLighting()
+ GlStateManager.disableDepth()
+ GlStateManager.disableBlend()
+ event.fontRenderer.drawStringWithShadow(
+ stackTip,
+ (event.x + 17 - event.fontRenderer.getStringWidth(stackTip)).toFloat(),
+ (event.y + 9).toFloat(),
+ 16777215
+ )
+ GlStateManager.enableLighting()
+ GlStateManager.enableDepth()
+ }
+
+ }
+
+ private fun getStackTip(item: ItemStack): String {
+ val name = item.cleanName()
+
+ if (SkyHanniMod.feature.inventory.itemNumberAsStackSize.contains(0)) {
+ when (name) {
+ "First Master Star" -> return "1"
+ "Second Master Star" -> return "2"
+ "Third Master Star" -> return "3"
+ "Fourth Master Star" -> return "4"
+ "Fifth Master Star" -> return "5"
+ }
+ }
+
+ if (SkyHanniMod.feature.inventory.itemNumberAsStackSize.contains(1)) {
+ if (name.matchRegex("(.*)Master Skull - Tier .")) {
+ return name.substring(name.length - 1)
+ }
+ }
+
+ if (SkyHanniMod.feature.inventory.itemNumberAsStackSize.contains(2)) {
+ if (name.contains("Golden ") || name.contains("Diamond ")) {
+ when {
+ name.contains("Bonzo") -> return "1"
+ name.contains("Scarf") -> return "2"
+ name.contains("Professor") -> return "3"
+ name.contains("Thorn") -> return "4"
+ name.contains("Livid") -> return "5"
+ name.contains("Sadan") -> return "6"
+ name.contains("Necron") -> return "7"
+ }
+ }
+ }
+
+ if (SkyHanniMod.feature.inventory.itemNumberAsStackSize.contains(3)) {
+ if (name.startsWith("New Year Cake (")) {
+ return "§b" + name.between("(Year ", ")")
+ }
+ }
+
+ if (SkyHanniMod.feature.inventory.itemNumberAsStackSize.contains(4)) {
+ if (ItemUtils.isPet(name)) {
+ val level = name.between("Lvl ", "] ").toInt()
+ if (level != ItemUtils.maxPetLevel(name)) {
+ return "$level"
+ }
+ }
+ }
+
+ if (SkyHanniMod.feature.inventory.itemNumberAsStackSize.contains(5)) {
+ if (name.contains(" Minion ")) {
+ if (item.getLore().any { it.contains("Place this minion") }) {
+ val array = name.split(" ")
+ val last = array[array.size - 1]
+ return last.romanToDecimal().toString()
+ }
+ }
+ }
+
+ if (SkyHanniMod.feature.inventory.displaySackName) {
+ if (ItemUtils.isSack(name)) {
+ //TODO fix this and replace other
+// val sackName = grabSackName(name)
+ val split = name.split(" ")
+ val sackName = split[split.size - 2]
+ return (if (name.contains("Enchanted")) "§5" else "") + sackName.substring(0, 2)
+ }
+ }
+
+ return ""
+ }
+
+// private fun grabSackName(name: String): String {
+// val split = name.split(" ")
+// val text = split[0]
+// for (line in arrayOf("Large", "Medium", "Small", "Enchanted")) {
+// if (text == line) return grabSackName(name.substring(text.length + 1))
+// }
+// return text
+// }
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/features/items/VanillaItemManager.kt b/src/main/java/at/hannibal2/skyhanni/features/items/VanillaItemManager.kt
new file mode 100644
index 000000000..f138d9c23
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/items/VanillaItemManager.kt
@@ -0,0 +1,53 @@
+package at.hannibal2.skyhanni.features.items
+
+import com.google.gson.GsonBuilder
+import com.google.gson.JsonObject
+import java.io.BufferedReader
+import java.io.File
+import java.io.FileInputStream
+import java.io.InputStreamReader
+import java.nio.charset.StandardCharsets
+
+class VanillaItemManager {
+ private val gson = GsonBuilder().setPrettyPrinting().create()
+
+ companion object {
+ private val vanillaItems: MutableList<String> = ArrayList()
+
+ fun isVanillaItem(internalName: String): Boolean {
+ return vanillaItems.contains(internalName)
+ }
+ }
+
+ init {
+ load()
+ }
+
+ private fun load() {
+ vanillaItems.clear()
+ val itemDirectory = File("config/notenoughupdates/repo/items")
+ if (!itemDirectory.isDirectory) return
+ val files = itemDirectory.listFiles() ?: return
+ for (file in files) {
+ val jsonObject = getJsonFromFile(file)
+ if (jsonObject != null) {
+ if (jsonObject.has("vanilla") && jsonObject["vanilla"].asBoolean) {
+ val name = file.name
+ val internalName = name.split(".")[0]
+ vanillaItems.add(internalName)
+ }
+ }
+ }
+
+ }
+
+ private fun getJsonFromFile(file: File): JsonObject? {
+ try {
+ BufferedReader(InputStreamReader(FileInputStream(file),
+ StandardCharsets.UTF_8
+ )).use { reader -> return gson.fromJson(reader, JsonObject::class.java) }
+ } catch (e: Exception) {
+ return null
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/features/items/abilitycooldown/ItemAbilityCooldown.kt b/src/main/java/at/hannibal2/skyhanni/features/items/abilitycooldown/ItemAbilityCooldown.kt
new file mode 100644
index 000000000..0d094c4b4
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/items/abilitycooldown/ItemAbilityCooldown.kt
@@ -0,0 +1,215 @@
+package at.hannibal2.skyhanni.features.items.abilitycooldown
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.data.ItemRenderBackground.Companion.background
+import at.hannibal2.skyhanni.events.GuiRenderItemEvent
+import at.hannibal2.skyhanni.events.LorenzActionBarEvent
+import at.hannibal2.skyhanni.utils.ItemUtils
+import at.hannibal2.skyhanni.utils.ItemUtils.cleanName
+import at.hannibal2.skyhanni.utils.LorenzColor
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.between
+import net.minecraft.client.Minecraft
+import net.minecraft.client.renderer.GlStateManager
+import net.minecraft.item.ItemStack
+import net.minecraftforge.common.MinecraftForge
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import net.minecraftforge.fml.common.gameevent.TickEvent
+
+class ItemAbilityCooldown {
+
+ var lastAbility = ""
+ var tick = 0
+ val items = mutableMapOf<ItemStack, ItemText>()
+ val witherImpactDetection = WitherImpactDetection(this)
+
+ init {
+ MinecraftForge.EVENT_BUS.register(witherImpactDetection)
+ }
+
+ fun clickWitherImpact() {
+ Ability.WITHER_IMPACT.click()
+ }
+
+ @SubscribeEvent
+ fun onActionBar(event: LorenzActionBarEvent) {
+ if (!isEnabled()) return
+
+ val message: String = event.message
+ if (message.contains(" (§6")) {
+ if (message.contains("§b) ")) {
+ val name: String = message.between(" (§6", "§b) ")
+ if (name == lastAbility) return
+ lastAbility = name
+ for (ability in Ability.values()) {
+ if (ability.abilityName == name) {
+ click(ability)
+ return
+ }
+ }
+ return
+ }
+ }
+ lastAbility = ""
+ }
+
+ private fun isEnabled(): Boolean {
+ return LorenzUtils.inSkyblock && SkyHanniMod.feature.abilities.itemAbilityCooldown
+ }
+
+ private fun click(ability: Ability) {
+// if (ability.isActive()) return
+ if (!ability.actionBarDetection) return
+ ability.click()
+ }
+
+ @SubscribeEvent
+ fun onTick(event: TickEvent.ClientTickEvent) {
+ if (!isEnabled()) return
+
+ tick++
+ if (tick % 2 == 0) {
+ checkHotbar()
+ }
+ }
+
+ private fun checkHotbar() {
+ items.clear()
+ for ((stack, slot) in ItemUtils.getItemsInInventoryWithSlots(true)) {
+// val inHotbar = slot in 36..43
+
+ val itemName: String = stack.cleanName()
+ val ability = hasAbility(itemName)
+ if (ability != null) {
+
+ if (ability.isOnCooldown()) {
+ val duration: Long = ability.lastClick + ability.getCooldown() - System.currentTimeMillis()
+ val color = if (duration < 600) LorenzColor.RED else LorenzColor.YELLOW
+ items[stack] = ItemText(color, ability.getDurationText(), true)
+ } else {
+ items[stack] = ItemText(LorenzColor.GREEN, "R", false)
+ }
+ }
+ }
+
+ }
+
+ @SubscribeEvent
+ fun onRenderItemOverlayPost(event: GuiRenderItemEvent.RenderOverlayEvent.Post) {
+ if (!isEnabled()) return
+
+ val item = event.stack ?: return
+ if (item.stackSize != 1) return
+
+ var stackTip = ""
+
+ val guiOpen = Minecraft.getMinecraft().currentScreen != null
+ val itemText = items.filter { it.key == item }
+ .firstNotNullOfOrNull { it.value } ?: return
+ if (guiOpen && !itemText.onCooldown) return
+
+ val color = itemText.color
+ stackTip = color.getChatColor() + itemText.text
+
+ if (SkyHanniMod.feature.abilities.itemAbilityCooldownBackground) {
+ var opacity = 130
+ if (color == LorenzColor.GREEN) {
+ opacity = 80
+ }
+ item.background = color.addOpacity(opacity).rgb
+ }
+
+ if (stackTip.isNotEmpty()) {
+ GlStateManager.disableLighting()
+ GlStateManager.disableDepth()
+ GlStateManager.disableBlend()
+ //TODO add option to change the size
+ event.fontRenderer.drawStringWithShadow(
+ stackTip,
+ (event.x + 17 - event.fontRenderer.getStringWidth(stackTip)).toFloat(),
+ (event.y + 9).toFloat(),
+ 16777215
+ )
+ GlStateManager.enableLighting()
+ GlStateManager.enableDepth()
+ }
+ }
+
+ private fun hasAbility(itemName: String): Ability? {
+ for (ability in Ability.values()) {
+ for (name in ability.itemNames) {
+ if (itemName.contains(name)) {
+ return ability
+ }
+ }
+ }
+ return null
+ }
+
+ enum class Ability(
+ val abilityName: String,
+ val cooldownInSeconds: Long,
+ vararg val itemNames: String,
+ var lastClick: Long = 0L,
+ val actionBarDetection: Boolean = true,
+ ) {
+ //TODO add into repo
+ ATOMSPLIT("Soulcry", 4, "Atomsplit Katana", "Vorpal Katana", "Voidedge Katana"),
+ WITHER_IMPACT("Wither Impact", 5, "Hyperion", "Scylla", "Valkyrie", "Astrea", actionBarDetection = false),
+
+ HEAL_1("Small Heal", 7, "Wand of Healing"),
+ HEAL_2("Medium Heal", 7, "Wand of Mending"),
+ HEAL_3("Big Heal", 7, "Wand of Restoration"),
+ HEAL_4("Huge Heal", 7, "Wand of Atonement"),
+
+ ICE_SPRAY("Ice Spray", 5, "Ice Spray Wand"),
+ GYRO("Gravity Storm", 30, "Gyrokinetic Wand"),
+ GIANTS_SWORD("Giant's Slam", 30, "Giant's Sword"),
+
+ STAR_FALL("Starfall", 2, "Starlight Wand"),
+ VODOO_DOLL("Acupuncture", 5, "Voodoo Doll"),
+ INK_WAND("Ink Bomb", 30, "Ink Wand"),
+ GOLEM_SWORD("Iron Punch", 3, "Golem Sword"),
+ EMBER_ROD("Fire Blast", 30, "Ember Rod"),
+ ENDER_BOW("Ender Warp", 30, "Ender Bow"),
+
+ LIVID_DAGGER("Throw", 5, "Livid Dagger"),
+ WEIRD_TUBA("Howl", 20, "Weird Tuba"),
+
+ ENDSTONE_SWORD("Extreme Focus", 5, "End Stone Sword"),
+ PIGMAN_SWORD("Burning Souls", 5, "Pigman Sword"),
+
+ SOULWARD("Soulward", 20, "Soul Esoward"),
+ ECHO("Echo", 3, "Ancestral Spade"),
+
+ FIRE_VEIL("Fire Veil", 5, "Fire Veil Wand"),
+ //TODO add new crimson isle weapons
+
+ ;
+
+ fun click() {
+ lastClick = System.currentTimeMillis()
+ }
+
+ fun isOnCooldown(): Boolean = lastClick + getCooldown() > System.currentTimeMillis()
+
+ fun getCooldown(): Long = cooldownInSeconds * 1000
+
+ fun getDurationText(): String {
+ var duration: Long = lastClick + getCooldown() - System.currentTimeMillis()
+ return if (duration < 1600) {
+ duration /= 100
+ var d = duration.toDouble()
+ d /= 10.0
+ LorenzUtils.formatDouble(d)
+ } else {
+ duration /= 1000
+ duration++
+ LorenzUtils.formatInteger(duration.toInt())
+ }
+ }
+
+ }
+
+ class ItemText(val color: LorenzColor, val text: String, val onCooldown: Boolean)
+} \ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/features/items/abilitycooldown/WitherImpactDetection.kt b/src/main/java/at/hannibal2/skyhanni/features/items/abilitycooldown/WitherImpactDetection.kt
new file mode 100644
index 000000000..da0d5068c
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/items/abilitycooldown/WitherImpactDetection.kt
@@ -0,0 +1,74 @@
+package at.hannibal2.skyhanni.features.items.abilitycooldown
+
+import at.hannibal2.skyhanni.events.PacketEvent
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import net.minecraft.client.Minecraft
+import net.minecraft.init.Items
+import net.minecraft.item.ItemStack
+import net.minecraft.nbt.NBTTagCompound
+import net.minecraft.nbt.NBTTagList
+import net.minecraft.network.play.client.C08PacketPlayerBlockPlacement
+import net.minecraft.network.play.server.S1CPacketEntityMetadata
+import net.minecraft.network.play.server.S2APacketParticles
+import net.minecraft.util.EnumParticleTypes
+import net.minecraftforge.common.util.Constants
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import net.minecraftforge.fml.common.gameevent.TickEvent
+
+/**
+ * Taken from Skytils under AGPL 3.0
+ * Modified
+ * https://github.com/Skytils/SkytilsMod/blob/1.x/LICENSE.md
+ * @author Skytils
+ */
+class WitherImpactDetection(private val itemAbilityCooldown: ItemAbilityCooldown) {
+
+ val S2APacketParticles.type: EnumParticleTypes
+ get() = this.particleType
+ var lastShieldUse = -1L
+ var lastShieldClick = 0L
+
+ @SubscribeEvent
+ fun onReceivePacket(event: PacketEvent.ReceiveEvent) {
+ val mc = Minecraft.getMinecraft()
+ if (!LorenzUtils.inSkyblock || mc.theWorld == null) return
+
+ event.packet.apply {
+
+ if (this is S1CPacketEntityMetadata && lastShieldClick != -1L && entityId == mc.thePlayer?.entityId && System.currentTimeMillis() - lastShieldClick <= 500 && func_149376_c()?.any { it.dataValueId == 17 } == true) {
+ lastShieldUse = System.currentTimeMillis()
+ lastShieldClick = -1
+ itemAbilityCooldown.clickWitherImpact()
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onSendPacket(event: PacketEvent.SendEvent) {
+ val mc = Minecraft.getMinecraft()
+ if (!LorenzUtils.inSkyblock || lastShieldUse != -1L || mc.thePlayer?.heldItem == null) return
+ if (event.packet is C08PacketPlayerBlockPlacement && mc.thePlayer.heldItem.item == Items.iron_sword && getExtraAttributes(
+ mc.thePlayer.heldItem
+ )?.getTagList("ability_scroll", Constants.NBT.TAG_STRING)?.asStringSet()
+ ?.contains("WITHER_SHIELD_SCROLL") == true
+ ) {
+ lastShieldClick = System.currentTimeMillis()
+ }
+ }
+
+ @SubscribeEvent
+ fun onTick(event: TickEvent.ClientTickEvent) {
+ if (lastShieldUse != -1L) {
+ val diff = ((lastShieldUse + 5000 - System.currentTimeMillis()) / 1000f)
+ if (diff < 0) lastShieldUse = -1
+ }
+ }
+
+ private fun getExtraAttributes(item: ItemStack?): NBTTagCompound? {
+ return if (item == null || !item.hasTagCompound()) {
+ null
+ } else item.getSubCompound("ExtraAttributes", false)
+ }
+
+ private fun NBTTagList.asStringSet() = (0..tagCount()).mapTo(hashSetOf()) { getStringTagAt(it) }
+} \ No newline at end of file