summaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/features
diff options
context:
space:
mode:
authorThunderblade73 <85900443+Thunderblade73@users.noreply.github.com>2024-06-23 20:06:17 +0200
committerGitHub <noreply@github.com>2024-06-23 20:06:17 +0200
commit6eb085f4e2ba69e98934ffa9489c8679ba23d244 (patch)
tree6f3f4abe26118a5c14ed84ce48408b17665be79f /src/main/java/at/hannibal2/skyhanni/features
parent78f5f7b94bdc48c3395ef17f30022b8cd653a776 (diff)
downloadskyhanni-6eb085f4e2ba69e98934ffa9489c8679ba23d244.tar.gz
skyhanni-6eb085f4e2ba69e98934ffa9489c8679ba23d244.tar.bz2
skyhanni-6eb085f4e2ba69e98934ffa9489c8679ba23d244.zip
Feature: Reforge helper (#1437)
Co-authored-by: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> Co-authored-by: hannibal2 <24389977+hannibal002@users.noreply.github.com> Co-authored-by: Cal <cwolfson58@gmail.com> Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/features')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/inventory/ReforgeHelper.kt432
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValue.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValueCalculator.kt13
3 files changed, 439 insertions, 10 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/ReforgeHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/ReforgeHelper.kt
new file mode 100644
index 000000000..d1826b481
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/ReforgeHelper.kt
@@ -0,0 +1,432 @@
+package at.hannibal2.skyhanni.features.inventory
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.api.ReforgeAPI
+import at.hannibal2.skyhanni.data.model.SkyblockStat
+import at.hannibal2.skyhanni.data.model.SkyblockStatList
+import at.hannibal2.skyhanni.events.GuiContainerEvent
+import at.hannibal2.skyhanni.events.GuiRenderEvent
+import at.hannibal2.skyhanni.events.InventoryCloseEvent
+import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent
+import at.hannibal2.skyhanni.events.LorenzChatEvent
+import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
+import at.hannibal2.skyhanni.utils.DelayedRun
+import at.hannibal2.skyhanni.utils.ItemUtils.cleanName
+import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName
+import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull
+import at.hannibal2.skyhanni.utils.ItemUtils.getItemRarityOrNull
+import at.hannibal2.skyhanni.utils.ItemUtils.name
+import at.hannibal2.skyhanni.utils.LorenzColor
+import at.hannibal2.skyhanni.utils.LorenzRarity
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.NumberUtil.toStringWithPlus
+import at.hannibal2.skyhanni.utils.RegexUtils.matches
+import at.hannibal2.skyhanni.utils.RenderUtils
+import at.hannibal2.skyhanni.utils.RenderUtils.drawSlotText
+import at.hannibal2.skyhanni.utils.RenderUtils.highlight
+import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables
+import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getReforgeName
+import at.hannibal2.skyhanni.utils.SoundUtils
+import at.hannibal2.skyhanni.utils.TimeUtils.ticks
+import at.hannibal2.skyhanni.utils.renderables.Renderable
+import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
+import net.minecraft.client.Minecraft
+import net.minecraft.init.Items
+import net.minecraft.inventory.Container
+import net.minecraft.item.ItemStack
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import java.awt.Color
+import java.util.concurrent.atomic.AtomicBoolean
+import at.hannibal2.skyhanni.utils.renderables.Renderable.Companion.string as renderableString
+
+@SkyHanniModule
+object ReforgeHelper {
+
+ private val config get() = SkyHanniMod.feature.inventory.helper.reforge
+
+ private val repoGroup = RepoPattern.group("reforge")
+
+ private val reforgeMenu by repoGroup.pattern(
+ "menu.blacksmith",
+ "Reforge Item",
+ )
+ private val reforgeHexMenu by repoGroup.pattern(
+ "menu.hex",
+ "The Hex ➜ Reforges",
+ )
+ private val reforgeChatMessage by repoGroup.pattern(
+ "chat.success",
+ "§aYou reforged your .* §r§ainto a .*!|§aYou applied a .* §r§ato your .*!",
+ )
+ private val reforgeChatFail by repoGroup.pattern(
+ "chat.fail",
+ "§cWait a moment before reforging again!|§cWhoa! Slow down there!",
+ )
+
+ private var isInReforgeMenu = false
+ private var isInHexReforgeMenu = false
+
+ private fun isReforgeMenu(chestName: String) = reforgeMenu.matches(chestName)
+ private fun isHexReforgeMenu(chestName: String) = reforgeHexMenu.matches(chestName)
+
+ private fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled && isInReforgeMenu
+
+ private var itemToReforge: ItemStack? = null
+ private var inventoryContainer: Container? = null
+
+ private var currentReforge: ReforgeAPI.Reforge? = null
+ private var reforgeToSearch: ReforgeAPI.Reforge? = null
+
+ private var hoveredReforge: ReforgeAPI.Reforge? = null
+
+ private val reforgeItem get() = if (isInHexReforgeMenu) 19 else 13
+ private val reforgeButton get() = if (isInHexReforgeMenu) 48 else 22
+
+ private const val HEX_REFORGE_NEXT_DOWN_BUTTON = 35
+ private const val HEX_REFORGE_NEXT_UP_BUTTON = 17
+
+ private const val EXIT_BUTTON = 40
+
+ private var waitForChat = AtomicBoolean(false)
+
+ /** Gatekeeps instant double switches of the state */
+ private var waitDelay = false
+
+ private var sortAfter: SkyblockStat? = null
+
+ private var display: List<Renderable> = generateDisplay()
+
+ private val hoverColor = LorenzColor.GOLD.addOpacity(50)
+ private val selectedColor = LorenzColor.BLUE.addOpacity(100)
+ private val finishedColor = LorenzColor.GREEN.addOpacity(75)
+
+ private fun itemUpdate() {
+ val newItem = inventoryContainer?.getSlot(reforgeItem)?.stack
+ if (newItem?.getInternalName() != itemToReforge?.getInternalName()) {
+ reforgeToSearch = null
+ }
+ itemToReforge = newItem
+ val newReforgeName = itemToReforge?.getReforgeName() ?: ""
+ if (newReforgeName == currentReforge?.lowercaseName) return
+ currentReforge = ReforgeAPI.reforgeList.firstOrNull { it.lowercaseName == newReforgeName }
+ updateDisplay()
+ }
+
+ @SubscribeEvent
+ fun onClick(event: GuiContainerEvent.SlotClickEvent) {
+ if (!isEnabled()) return
+ if (event.slot?.slotNumber == reforgeButton) {
+ if (event.slot.stack?.name == "§eReforge Item" || event.slot.stack?.name == "§cError!") return
+ if (handleReforgeButtonClick(event)) return
+ }
+
+ DelayedRun.runNextTick {
+ itemUpdate()
+ }
+ }
+
+ private fun handleReforgeButtonClick(event: GuiContainerEvent.SlotClickEvent): Boolean {
+ if (currentReforge == reforgeToSearch) {
+ event.cancel()
+ waitForChat.set(false)
+ SoundUtils.playBeepSound()
+ } else if (waitForChat.get()) {
+ waitDelay = true
+ event.cancel()
+ } else {
+ if (event.clickedButton == 2) return true
+ if (waitDelay) {
+ waitDelay = false
+ } else {
+ waitForChat.set(true)
+ }
+ }
+ return false
+ }
+
+ @SubscribeEvent
+ fun onChat(event: LorenzChatEvent) {
+ if (!isEnabled()) return
+ when {
+ reforgeChatMessage.matches(event.message) -> {
+ DelayedRun.runDelayed(2.ticks) {
+ itemUpdate()
+ waitForChat.set(false)
+ }
+ if (config?.hideChat == true) {
+ event.blockedReason = "reforge_hide"
+ }
+ }
+
+ reforgeChatFail.matches(event.message) -> {
+ DelayedRun.runDelayed(2.ticks) {
+ waitForChat.set(false)
+ }
+ if (config?.hideChat == true) {
+ event.blockedReason = "reforge_hide"
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onOpen(event: InventoryFullyOpenedEvent) {
+ if (!LorenzUtils.inSkyBlock) return
+ when {
+ isHexReforgeMenu(event.inventoryName) -> {
+ isInHexReforgeMenu = true
+ DelayedRun.runDelayed(2.ticks) {
+ itemUpdate() // update since an item must already be in place
+ }
+ }
+
+ isReforgeMenu(event.inventoryName) -> {
+ itemToReforge = null
+ currentReforge = null
+ }
+
+ else -> return
+ }
+ isInReforgeMenu = true
+ waitForChat.set(false)
+ DelayedRun.runNextTick {
+ inventoryContainer = Minecraft.getMinecraft().thePlayer.openContainer
+ }
+ }
+
+ @SubscribeEvent
+ fun onClose(event: InventoryCloseEvent) {
+ if (!isInReforgeMenu) return
+ isInReforgeMenu = false
+ isInHexReforgeMenu = false
+ reforgeToSearch = null
+ currentReforge = null
+ hoveredReforge = null
+ sortAfter = null
+ itemToReforge = null
+ display = emptyList()
+ }
+
+ private fun updateDisplay() {
+ display = generateDisplay()
+ }
+
+ private fun generateDisplay() = buildList<Renderable> {
+ this.add(renderableString("§6Reforge Overlay"))
+
+ val item = itemToReforge ?: run {
+ reforgeToSearch = null
+ return@buildList
+ }
+
+ val internalName = item.getInternalName()
+ val itemType = item.getItemCategoryOrNull()
+ val itemRarity = item.getItemRarityOrNull() ?: return@buildList
+
+ val rawReforgeList =
+ if (!isInHexReforgeMenu && config.reforgeStonesOnlyHex) ReforgeAPI.nonePowerStoneReforge else ReforgeAPI.reforgeList
+ val reforgeList = rawReforgeList.filter { it.isValid(itemType, internalName) }
+
+ val statTypes = reforgeList.mapNotNull { it.stats[itemRarity]?.keys }.flatten().toSet()
+
+ val statTypeButtons = (listOf(getStatButton(null)) + statTypes.map { getStatButton(it) }).chunked(9)
+ this.add(Renderable.table(statTypeButtons, xPadding = 3, yPadding = 2))
+
+ val list = reforgeList.sortedWith(getSortSelector(itemRarity, sortAfter)).map(getReforgeView(itemRarity))
+ this.addAll(list)
+ }
+
+ private fun getReforgeColour(reforge: ReforgeAPI.Reforge) = when {
+ currentReforge == reforge -> "§6"
+ reforgeToSearch == reforge -> "§3"
+ reforge.isReforgeStone -> "§9"
+ else -> "§7"
+ }
+
+ private fun getReforgeView(itemRarity: LorenzRarity): (ReforgeAPI.Reforge) -> Renderable = { reforge ->
+ val text = getReforgeColour(reforge) + reforge.name
+ val tips = getReforgeTips(reforge, itemRarity)
+ val onHover = if (!isInHexReforgeMenu) {
+ {}
+ } else {
+ { hoveredReforge = reforge }
+ }
+
+ Renderable.clickAndHover(
+ text, tips,
+ onClick = {
+ SoundUtils.playClickSound()
+ reforgeToSearch = reforge
+ updateDisplay()
+ },
+ onHover = onHover,
+ )
+ }
+
+ private fun getReforgeTips(
+ reforge: ReforgeAPI.Reforge,
+ itemRarity: LorenzRarity,
+ ): List<Renderable> {
+ val stats: List<Renderable>
+ val removedEffect: List<Renderable>
+ val addEffectText: String
+ val click: List<Renderable>
+ if (currentReforge == reforge) {
+ stats = currentReforge?.stats?.get(itemRarity)?.print() ?: emptyList()
+ removedEffect = emptyList()
+ addEffectText = "§aEffect:"
+ click = listOf(renderableString(""), renderableString("§3Reforge is currently applied!"))
+ } else {
+ stats = reforge.stats[itemRarity]?.print(currentReforge?.stats?.get(itemRarity)) ?: emptyList()
+ removedEffect = getReforgeEffect(
+ currentReforge,
+ itemRarity,
+ )?.let { listOf(renderableString("§cRemoves Effect:")) + it }?.takeIf { config.showDiff } ?: emptyList()
+ addEffectText = "§aAdds Effect:"
+ click = if (reforgeToSearch != reforge) {
+ listOf(renderableString(""), renderableString("§eClick to select!"))
+ } else emptyList()
+ }
+
+ val addedEffect = getReforgeEffect(reforge, itemRarity)?.let { listOf(renderableString(addEffectText)) + it } ?: emptyList()
+
+ return listOf(renderableString("§6Reforge Stats")) + stats + removedEffect + addedEffect + click
+ }
+
+ private fun getReforgeEffect(reforge: ReforgeAPI.Reforge?, rarity: LorenzRarity) =
+ reforge?.extraProperty?.get(rarity)?.let {
+ Renderable.wrappedString(
+ it,
+ 190,
+ color = LorenzColor.GRAY.toColor(),
+ )
+ }
+
+ private fun getSortSelector(
+ itemRarity: LorenzRarity,
+ sorting: SkyblockStat?,
+ ): Comparator<ReforgeAPI.Reforge> =
+ if (sorting != null) {
+ Comparator.comparing<ReforgeAPI.Reforge, Double> { it.stats[itemRarity]?.get(sorting) ?: 0.0 }.reversed()
+ } else {
+ Comparator.comparing { it.isReforgeStone }
+ }
+
+ private fun getStatButton(stat: SkyblockStat?): Renderable {
+ val icon: String
+ val tip: String
+ if (stat == null) {
+ icon = "§7D"
+ tip = "§7Default"
+ } else {
+ icon = stat.icon
+ tip = stat.iconWithName
+ }
+
+ val alreadySelected = sortAfter == stat
+ val fieldColor = if (alreadySelected) LorenzColor.GRAY else LorenzColor.DARK_GRAY
+
+
+ val tips = if (alreadySelected) {
+ listOf("§6Sort by", tip)
+ } else {
+ listOf("§6Sort by", tip, "", "§eClick to apply sorting!")
+ }
+ val sortField =
+ Renderable.drawInsideRoundedRect(
+ Renderable.hoverTips(
+ Renderable.fixedSizeLine(
+ renderableString(icon, horizontalAlign = RenderUtils.HorizontalAlignment.CENTER),
+ SkyblockStat.fontSizeOfLargestIcon,
+ ),
+ tips,
+ ),
+ fieldColor.toColor(), radius = 15, padding = 1,
+ )
+ return if (alreadySelected) {
+ sortField
+ } else {
+ Renderable.clickable(
+ sortField,
+ {
+ sortAfter = stat
+ updateDisplay()
+ },
+ )
+ }
+ }
+
+ @SubscribeEvent
+ fun onRender(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) {
+ if (!isEnabled()) return
+ config.position.renderRenderables(display, posLabel = "Reforge Overlay")
+ }
+
+ @SubscribeEvent
+ fun onForegroundDrawn(event: GuiContainerEvent.ForegroundDrawnEvent) {
+ if (!isEnabled()) return
+ if (currentReforge == null) return
+
+ inventoryContainer?.getSlot(reforgeItem)?.let {
+ event.drawSlotText(it.xDisplayPosition - 5, it.yDisplayPosition, "§e${currentReforge?.name}", 1f)
+ }
+ }
+
+ @SubscribeEvent
+ fun onGuiContainerBackgroundDrawn(event: GuiContainerEvent.BackgroundDrawnEvent) {
+ if (hoveredReforge != null && isInHexReforgeMenu) {
+ if (hoveredReforge != currentReforge) {
+ colorReforgeStone(hoverColor, hoveredReforge?.rawReforgeStoneName ?: "Random Basic Reforge")
+ } else {
+ inventoryContainer?.getSlot(reforgeItem)?.highlight(hoverColor)
+
+ //?.get(reforgeItem)?. = hoverColor
+ }
+ hoveredReforge = null
+ }
+
+ if (reforgeToSearch == null) return
+ if (reforgeToSearch != currentReforge) {
+ colorSelected()
+ } else {
+ inventoryContainer?.getSlot(reforgeItem)?.highlight(finishedColor)
+ }
+ }
+
+ private fun colorSelected() = if (reforgeToSearch?.isReforgeStone == true) {
+ if (isInHexReforgeMenu) {
+ colorReforgeStone(selectedColor, reforgeToSearch?.rawReforgeStoneName)
+ } else {
+ inventoryContainer?.getSlot(EXIT_BUTTON)?.highlight(selectedColor)
+ }
+ } else {
+ inventoryContainer?.getSlot(reforgeButton)?.highlight(selectedColor)
+ }
+
+ private fun colorReforgeStone(color: Color, reforgeStone: String?) {
+ val inventory = inventoryContainer?.inventorySlots ?: return
+ val slot = inventory.firstOrNull { it?.stack?.cleanName() == reforgeStone }
+ if (slot != null) {
+ slot highlight color
+ } else {
+ inventory[HEX_REFORGE_NEXT_DOWN_BUTTON]?.takeIf { it.stack.item == Items.skull }?.highlight(color)
+ inventory[HEX_REFORGE_NEXT_UP_BUTTON]?.takeIf { it.stack.item == Items.skull }?.highlight(color)
+ }
+ }
+
+ private fun SkyblockStatList.print(appliedReforge: SkyblockStatList? = null): List<Renderable> {
+ val diff = appliedReforge?.takeIf { config.showDiff }?.let { this - it }
+ val main = ((diff ?: this).mapNotNull {
+ val key = it.key
+ val value = this[key] ?: 0.0
+ buildList<Renderable> {
+ add(renderableString("§9${value.toStringWithPlus().removeSuffix(".0")}"))
+ diff?.get(key)?.let { add(renderableString((if (it < 0) "§c" else "§a") + it.toStringWithPlus().removeSuffix(".0"))) }
+ add(renderableString(key.iconWithName))
+ }
+ })
+ val table = Renderable.table(main, 5)
+ return listOf(table)
+ }
+}
+
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValue.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValue.kt
index 724583e20..dee0a6749 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValue.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValue.kt
@@ -4,7 +4,6 @@ import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.api.event.HandleEvent
import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator
import at.hannibal2.skyhanni.data.jsonobjects.repo.ItemsJson
-import at.hannibal2.skyhanni.data.jsonobjects.repo.neu.NeuReforgeStoneJson
import at.hannibal2.skyhanni.events.ConfigLoadEvent
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.events.InventoryCloseEvent
@@ -45,7 +44,6 @@ object EstimatedItemValue {
private val cache = mutableMapOf<ItemStack, List<List<Any>>>()
private var lastToolTipTime = 0L
var gemstoneUnlockCosts = HashMap<NEUInternalName, HashMap<String, List<String>>>()
- var reforges = mapOf<NEUInternalName, NeuReforgeStoneJson>()
var bookBundleAmount = mapOf<String, Int>()
private var currentlyShowing = false
@@ -55,8 +53,6 @@ object EstimatedItemValue {
fun onNeuRepoReload(event: NeuRepositoryReloadEvent) {
gemstoneUnlockCosts =
event.readConstant<HashMap<NEUInternalName, HashMap<String, List<String>>>>("gemstonecosts")
- reforges =
- event.readConstant<Map<NEUInternalName, NeuReforgeStoneJson>>("reforgestones")
}
@SubscribeEvent
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValueCalculator.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValueCalculator.kt
index e1619ad92..05d53fa65 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValueCalculator.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValueCalculator.kt
@@ -1,6 +1,7 @@
package at.hannibal2.skyhanni.features.misc.items
import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.api.ReforgeAPI
import at.hannibal2.skyhanni.test.command.ErrorManager
import at.hannibal2.skyhanni.utils.CollectionUtils.sortedDesc
import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName
@@ -130,7 +131,7 @@ object EstimatedItemValueCalculator {
)
if (price != null) {
val name = attributes[0].first.fixMending().allLettersFirstUppercase()
- list.add("§7Attribute §9$name ${attributes[0].second}§7: (§6${price.shortFormat()}§7)",)
+ list.add("§7Attribute §9$name ${attributes[0].second}§7: (§6${price.shortFormat()}§7)")
return price
}
}
@@ -214,15 +215,15 @@ object EstimatedItemValueCalculator {
private fun addReforgeStone(stack: ItemStack, list: MutableList<String>): Double {
val rawReforgeName = stack.getReforgeName() ?: return 0.0
- val reforge = EstimatedItemValue.reforges.values.firstOrNull {
- rawReforgeName == it.reforgeName.lowercase() || rawReforgeName == it.internalName.asString().lowercase()
+ val reforge = ReforgeAPI.onlyPowerStoneReforge.firstOrNull {
+ rawReforgeName == it.lowercaseName || rawReforgeName == it.reforgeStone?.asString()?.lowercase()
} ?: return 0.0
- val internalName = reforge.internalName.asString().asInternalName()
+ val internalName = reforge.reforgeStone ?: return 0.0
val reforgeStonePrice = internalName.getPrice()
val reforgeStoneName = internalName.itemName
- val applyCost = getReforgeStoneApplyCost(stack, reforge.reforgeCosts, internalName) ?: return 0.0
+ val applyCost = reforge.costs?.let { getReforgeStoneApplyCost(stack, it, internalName) } ?: return 0.0
- list.add("§7Reforge: §9${reforge.reforgeName}")
+ list.add("§7Reforge: §9${reforge.name}")
list.add(" §7Stone $reforgeStoneName §7(§6" + reforgeStonePrice.shortFormat() + "§7)")
list.add(" §7Apply cost: (§6" + applyCost.shortFormat() + "§7)")
return reforgeStonePrice + applyCost