From 8de53239f61c0f424dab6cf2ae83f45feb4d232b Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Thu, 2 Mar 2023 02:00:00 +0100 Subject: bingo card small reworks for current bingo event, made craft minion helper feature bingo only. --- .../java/at/hannibal2/skyhanni/SkyHanniMod.java | 2 +- .../at/hannibal2/skyhanni/config/Features.java | 2 +- .../hannibal2/skyhanni/config/features/Bingo.java | 30 ++- .../skyhanni/config/features/Minions.java | 16 -- .../skyhanni/features/bingo/BingoCardDisplay.kt | 34 ++- .../skyhanni/features/bingo/BingoNextStepHelper.kt | 39 ++- .../skyhanni/features/bingo/MinionCraftHelper.kt | 276 +++++++++++++++++++++ .../skyhanni/features/minion/MinionCraftHelper.kt | 276 --------------------- 8 files changed, 356 insertions(+), 319 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/features/bingo/MinionCraftHelper.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/minion/MinionCraftHelper.kt (limited to 'src/main/java') diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java index 9392bb7a1..9502b300b 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java @@ -11,6 +11,7 @@ import at.hannibal2.skyhanni.features.bazaar.*; import at.hannibal2.skyhanni.features.bingo.BingoCardDisplay; import at.hannibal2.skyhanni.features.bingo.BingoNextStepHelper; import at.hannibal2.skyhanni.features.bingo.CompactBingoChat; +import at.hannibal2.skyhanni.features.bingo.MinionCraftHelper; import at.hannibal2.skyhanni.features.chat.ChatFilter; import at.hannibal2.skyhanni.features.chat.PlayerDeathMessages; import at.hannibal2.skyhanni.features.chat.playerchat.PlayerChatFilter; @@ -27,7 +28,6 @@ import at.hannibal2.skyhanni.features.garden.*; import at.hannibal2.skyhanni.features.inventory.*; import at.hannibal2.skyhanni.features.itemabilities.FireVeilWandParticles; import at.hannibal2.skyhanni.features.itemabilities.abilitycooldown.ItemAbilityCooldown; -import at.hannibal2.skyhanni.features.minion.MinionCraftHelper; import at.hannibal2.skyhanni.features.minion.MinionFeatures; import at.hannibal2.skyhanni.features.misc.*; import at.hannibal2.skyhanni.features.misc.tiarelay.TiaRelayHelper; diff --git a/src/main/java/at/hannibal2/skyhanni/config/Features.java b/src/main/java/at/hannibal2/skyhanni/config/Features.java index 489a52f7c..abed49281 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/Features.java +++ b/src/main/java/at/hannibal2/skyhanni/config/Features.java @@ -128,7 +128,7 @@ public class Features extends Config { } if (runnableId.equals("minionCraftHelper")) { - editOverlay(activeConfigCategory, 200, 16, minions.minionCraftHelperPos); + editOverlay(activeConfigCategory, 200, 16, bingo.minionCraftHelperPos); return; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Bingo.java b/src/main/java/at/hannibal2/skyhanni/config/features/Bingo.java index aa202849b..4b4610d75 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/Bingo.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/Bingo.java @@ -1,9 +1,7 @@ package at.hannibal2.skyhanni.config.features; import at.hannibal2.skyhanni.config.core.config.Position; -import at.hannibal2.skyhanni.config.core.config.annotations.ConfigEditorBoolean; -import at.hannibal2.skyhanni.config.core.config.annotations.ConfigEditorButton; -import at.hannibal2.skyhanni.config.core.config.annotations.ConfigOption; +import at.hannibal2.skyhanni.config.core.config.annotations.*; import com.google.gson.annotations.Expose; public class Bingo { @@ -15,12 +13,34 @@ public class Bingo { public boolean compactChatMessages = true; @Expose - @ConfigOption(name = "Bingo Card", desc = "Show the bingo card.") + @ConfigOption(name = "Bingo Card View", desc = "Simply showing the bingo card. Toggle by sneaking with skyblock menu in hand.") @ConfigEditorBoolean - public boolean bingoCard = false; + public boolean cardDisplay = true; + + @Expose + @ConfigOption(name = "Bingo Steps", desc = "Show help with the next step in bingo instead of the bingo card. " + + "§cThis feature is in early development. Expect bugs and missing goals.") + @ConfigEditorBoolean + public boolean stepHelper = false; @Expose @ConfigOption(name = "Bingo Card Position", desc = "") @ConfigEditorButton(runnableId = "bingoCard", buttonText = "Edit") public Position bingoCardPos = new Position(10, 10, false, true); + + @ConfigOption(name = "Minion Craft Helper", desc = "") + @ConfigEditorAccordion(id = 0) + public boolean minionCraftHelper = false; + + @Expose + @ConfigOption(name = "Minion Craft Helper", desc = "Show how many more items you need to upgrade the minion in your inventory. Especially useful for bingo.") + @ConfigEditorBoolean + @ConfigAccordionId(id = 0) + public boolean minionCraftHelperEnabled = true; + + @Expose + @ConfigOption(name = "Minion Craft Helper Position", desc = "") + @ConfigEditorButton(runnableId = "minionCraftHelper", buttonText = "Edit") + @ConfigAccordionId(id = 0) + public Position minionCraftHelperPos = new Position(10, 10, false, true); } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Minions.java b/src/main/java/at/hannibal2/skyhanni/config/features/Minions.java index 8d2963ea8..d29eb45bd 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/Minions.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/Minions.java @@ -82,22 +82,6 @@ public class Minions { @ConfigAccordionId(id = 2) public Position hopperProfitPos = new Position(10, 10, false, true); - @ConfigOption(name = "Minion Craft Helper", desc = "") - @ConfigEditorAccordion(id = 3) - public boolean minionCraftHelper = false; - - @Expose - @ConfigOption(name = "Minion Craft Helper", desc = "Show how many more items you need to upgrade the minion in your inventory. Especially useful for bingo.") - @ConfigEditorBoolean - @ConfigAccordionId(id = 3) - public boolean minionCraftHelperEnabled = false; - - @Expose - @ConfigOption(name = "Minion Craft Helper Position", desc = "") - @ConfigEditorButton(runnableId = "minionCraftHelper", buttonText = "Edit") - @ConfigAccordionId(id = 3) - public Position minionCraftHelperPos = new Position(10, 10, false, true); - @Expose @ConfigOption(name = "Hide Mob Nametag", desc = "Hiding the nametag of mobs close to minions") @ConfigEditorBoolean diff --git a/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoCardDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoCardDisplay.kt index f1c87bf15..824fd7942 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoCardDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoCardDisplay.kt @@ -27,6 +27,11 @@ class BingoCardDisplay { private var tick = 0 private val display = mutableListOf() + private val config get() = SkyHanniMod.feature.bingo + + init { + update() + } companion object { val personalGoals = mutableListOf() @@ -48,6 +53,7 @@ class BingoCardDisplay { @SubscribeEvent fun onTick(event: TickEvent.ClientTickEvent) { if (!LorenzUtils.isBingoProfile) return + if (!config.cardDisplay) return if (event.phase != TickEvent.Phase.START) return tick++ @@ -117,13 +123,17 @@ class BingoCardDisplay { display.clear() display.add("Community Goals") - communityGoals.mapTo(display) { " " + it.description + if (it.done) " §aDONE" else "" } - - val todo = personalGoals.filter { !it.done } - val done = MAX_PERSONAL_GOALS - todo.size - display.add(" ") - display.add("Personal Goals: ($done/$MAX_PERSONAL_GOALS done)") - todo.mapTo(display) { " " + it.description } + if (communityGoals.isEmpty()) { + display.add("§7Open the §e/bingo §7card.") + } else { + communityGoals.mapTo(display) { " " + it.description + if (it.done) " §aDONE" else "" } + + val todo = personalGoals.filter { !it.done } + val done = MAX_PERSONAL_GOALS - todo.size + display.add(" ") + display.add("Personal Goals: ($done/$MAX_PERSONAL_GOALS done)") + todo.mapTo(display) { " " + it.description } + } } private var lastSneak = false @@ -132,7 +142,7 @@ class BingoCardDisplay { @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { if (!LorenzUtils.isBingoProfile) return - if (!SkyHanniMod.feature.bingo.bingoCard) return + if (!config.cardDisplay) return val stack = Minecraft.getMinecraft().thePlayer.heldItem //TODO into ItemUtils or InventoryUtils if (ItemUtils.isSkyBlockMenuItem(stack)) { @@ -147,18 +157,22 @@ class BingoCardDisplay { } } } + if (!config.stepHelper && displayMode == 1) { + displayMode = 0 + } if (displayMode == 0) { if (Minecraft.getMinecraft().currentScreen !is GuiChat) { - SkyHanniMod.feature.bingo.bingoCardPos.renderStrings(display) + config.bingoCardPos.renderStrings(display) } } else if (displayMode == 1) { - SkyHanniMod.feature.bingo.bingoCardPos.renderStrings(BingoNextStepHelper.currentHelp) + config.bingoCardPos.renderStrings(BingoNextStepHelper.currentHelp) } } @SubscribeEvent fun onChat(event: LorenzChatEvent) { if (!LorenzUtils.isBingoProfile) return + if (!config.cardDisplay) return val message = event.message //§6§lBINGO GOAL COMPLETE! §r§eRaw Salmon Collector diff --git a/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoNextStepHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoNextStepHelper.kt index b0ec44f02..91b5b9bd6 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoNextStepHelper.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoNextStepHelper.kt @@ -1,5 +1,6 @@ package at.hannibal2.skyhanni.features.bingo +import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.data.SkillExperience import at.hannibal2.skyhanni.events.LorenzChatEvent @@ -20,6 +21,8 @@ class BingoNextStepHelper { private val itemIslandRequired = mutableMapOf() private val itemRequired = mutableMapOf() private val islands = mutableMapOf() + private val collectionPattern = Pattern.compile("Reach ([0-9]+(?:,\\d+)*) (.*) Collection\\.") + private val crystalPattern = Pattern.compile("Obtain a (\\w+) Crystal in the Crystal Hollows\\.") companion object { private val finalSteps = mutableListOf() @@ -39,7 +42,12 @@ class BingoNextStepHelper { } currentHelp.clear() - currentHelp.add("Bingo Helper:") + currentHelp.add("Bingo Step Helper:") + + if (currentSteps.isEmpty()) { + currentHelp.add("§7Open the §e/bingo §7card.") + } + for (currentStep in currentSteps) { val text = getName(currentStep) currentHelp.add(" §7$text") @@ -92,6 +100,7 @@ class BingoNextStepHelper { @SubscribeEvent fun onTick(event: TickEvent.ClientTickEvent) { if (!LorenzUtils.isBingoProfile) return + if (!SkyHanniMod.feature.bingo.cardDisplay) return if (event.phase != TickEvent.Phase.START) return tick++ @@ -106,7 +115,8 @@ class BingoNextStepHelper { @SubscribeEvent fun onChat(event: LorenzChatEvent) { - if (!LorenzUtils.inSkyBlock) return + if (!LorenzUtils.isBingoProfile) return + if (!SkyHanniMod.feature.bingo.cardDisplay) return //TODO add thys message // if (event.message == "thys message") { @@ -148,7 +158,9 @@ class BingoNextStepHelper { done = true updateResult() if (!silent) { - LorenzUtils.chat("§e[SkyHanni] A bingo goal step is done! ($displayName)") + if (SkyHanniMod.feature.bingo.stepHelper) { + LorenzUtils.chat("§e[SkyHanni] A bingo goal step is done! ($displayName)") + } } } @@ -177,11 +189,10 @@ class BingoNextStepHelper { for (goal in personalGoals) { val description = goal.description.removeColor() - val pattern = Pattern.compile("Reach ([0-9]+(?:,\\d+)*) (.*) Collection\\.") - val matcher = pattern.matcher(description) - if (matcher.matches()) { - val amount = matcher.group(1).replace(",", "").toInt() - val name = matcher.group(2) + val collectionMatcher = collectionPattern.matcher(description) + if (collectionMatcher.matches()) { + val amount = collectionMatcher.group(1).replace(",", "").toInt() + val name = collectionMatcher.group(2) val collectionStep = CollectionStep(name, amount).apply { finalSteps.add(this) } createItemIslandRequirement(name, collectionStep) @@ -201,7 +212,12 @@ class BingoNextStepHelper { "Jacob's Ticket", 32, mapOf("Jacob's Ticket" to 1) - ).apply { this requires IslandType.HUB.getStep() }.addItemRequirements() + ).apply { this requires IslandType.GARDEN.getStep() }.addItemRequirements() + } + val crystalMatcher = crystalPattern.matcher(description) + if (crystalMatcher.matches()) { + val crystal = crystalMatcher.group(1) + ChatMessageStep("Obtain a $crystal Crystal").apply { finalSteps.add(this) } requires IslandType.CRYSTAL_HOLLOWS.getStep() } println("No help for goal: '$description'") @@ -269,11 +285,14 @@ class BingoNextStepHelper { IslandType.DWARVEN_MINES.getStep() requires SkillLevelStep("Mining", 12) IslandType.CRYSTAL_HOLLOWS.getStep() requires IslandType.DWARVEN_MINES.getStep() + // TODO add skyblock level requirement +// IslandType.GARDEN.getStep() requires SkyBlockLevelStep(6) + IslandType.GARDEN.getStep() requires IslandType.HUB.getStep() + val farmingContest = ChatMessageStep("Farming Contest") farmingContest requires SkillLevelStep("Farming", 10) itemRequired["Jacob's Ticket"] = farmingContest - // enchantedCharcoal(7) // compactor(7) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/bingo/MinionCraftHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/bingo/MinionCraftHelper.kt new file mode 100644 index 000000000..c0ae5d6fa --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/bingo/MinionCraftHelper.kt @@ -0,0 +1,276 @@ +package at.hannibal2.skyhanni.features.bingo + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.SendTitleHelper +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.ProfileJoinEvent +import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName +import at.hannibal2.skyhanni.utils.ItemUtils.name +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NEUItems +import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimalIfNeeded +import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import io.github.moulberry.notenoughupdates.NotEnoughUpdates +import io.github.moulberry.notenoughupdates.recipes.CraftingRecipe +import io.github.moulberry.notenoughupdates.recipes.NeuRecipe +import net.minecraft.client.Minecraft +import net.minecraft.item.ItemStack +import net.minecraftforge.event.world.WorldEvent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent +import java.util.regex.Pattern + +class MinionCraftHelper { + + private var minionNamePattern = Pattern.compile("(.*) Minion (.*)") + private var tick = 0 + private var display = mutableListOf() + private var hasMinionInInventory = false + private var hasItemsForMinion = false + private val tierOneMinions = mutableListOf() + private val tierOneMinionsDone = mutableListOf() + private val allIngredients = mutableListOf() + private val alreadyNotified = mutableListOf() + private val recipesCache = mutableMapOf>() + private var multiplierCache = mutableMapOf>() + + @SubscribeEvent + fun onWorldChange(event: WorldEvent.Load) { + alreadyNotified.clear() + recipesCache.clear() + } + + @SubscribeEvent + fun onTick(event: TickEvent.ClientTickEvent) { + if (event.phase != TickEvent.Phase.START) return + if (!LorenzUtils.isBingoProfile) return + if (!SkyHanniMod.feature.bingo.minionCraftHelperEnabled) return + + tick++ + + if (tick % 10 == 0) { + val mainInventory = Minecraft.getMinecraft()?.thePlayer?.inventory?.mainInventory ?: return + hasMinionInInventory = mainInventory + .mapNotNull { it?.name?.removeColor() } + .any { it.contains(" Minion ") } + } + + if (tick % (60 * 2) == 0) { + val mainInventory = Minecraft.getMinecraft()?.thePlayer?.inventory?.mainInventory ?: return + hasItemsForMinion = loadFromInventory(mainInventory).first.isNotEmpty() + } + + if (!hasMinionInInventory && !hasItemsForMinion) { + display.clear() + return + } + + if (tick % 3 != 0) return +// if (tick % 60 != 0) return + + val mainInventory = Minecraft.getMinecraft()?.thePlayer?.inventory?.mainInventory ?: return + + val (minions, otherItems) = loadFromInventory(mainInventory) + + display.clear() + for ((minionName, minionId) in minions) { + val matcher = minionNamePattern.matcher(minionName) + if (!matcher.matches()) return + val cleanName = matcher.group(1).removeColor() + val number = matcher.group(2).romanToDecimalIfNeeded() + addMinion(cleanName, number, minionId, otherItems) + } + } + + @SubscribeEvent + fun onProfileJoin(event: ProfileJoinEvent) { + tierOneMinionsDone.clear() + } + + private fun loadFromInventory(mainInventory: Array): Pair, MutableMap> { + init() + + val minions = mutableMapOf() + val otherItems = mutableMapOf() + + for (item in mainInventory) { + val name = item?.name?.removeColor() ?: continue + val rawId = item.getInternalName() + if (name.contains(" Minion ")) { + minions[name] = rawId + } else { + if (!allIngredients.contains(rawId)) continue + val (itemId, multiplier) = getMultiplier(rawId) + val old = otherItems.getOrDefault(itemId, 0) + otherItems[itemId] = old + item.stackSize * multiplier + } + } + firstMinionTier(otherItems, minions) + return Pair(minions, otherItems) + } + + private fun init() { + if (tierOneMinions.isNotEmpty()) return + + allIngredients.clear() + + for (internalId in NotEnoughUpdates.INSTANCE.manager.itemInformation.keys) { + if (internalId.endsWith("_GENERATOR_1")) { + tierOneMinions.add(internalId) + } + + if (internalId.contains("_GENERATOR_")) { + for (recipe in getRecipes(internalId)) { + if (recipe !is CraftingRecipe) continue + + for (ingredient in recipe.ingredients) { + val id = ingredient.internalItemId + if (!id.contains("_GENERATOR_")) { + if (!allIngredients.contains(id)) { + allIngredients.add(id) + } + } + } + } + } + } + } + + private fun firstMinionTier(otherItems: Map, minions: MutableMap) { + val help = otherItems.filter { !it.key.startsWith("WOOD_") } + val tierOneMinionsFiltered = tierOneMinions.filter { it !in tierOneMinionsDone } + for (minionId in tierOneMinionsFiltered) { + val prefix = minionId.dropLast(1) + if (minions.any { it.value.startsWith(prefix) }) { + tierOneMinionsDone.add(minionId) + } + } + for (minionId in tierOneMinionsFiltered) { + + for (recipe in getRecipes(minionId)) { + if (recipe !is CraftingRecipe) continue + if (recipe.ingredients.any { help.contains(it.internalItemId) }) { + val name = recipe.output.itemStack.name!!.removeColor() + val abc = name.replace(" I", " 0") + minions[abc] = minionId.replace("_1", "_0") + } + } + } + } + + private fun addMinion(name: String, minionTier: Int, minionId: String, otherItems: MutableMap) { + val nextTier = minionTier + 1 + val minionName = "§9$name Minion $nextTier" + display.add(minionName) + val nextMinionId = minionId.addOneToId() + val recipes: List = getRecipes(nextMinionId) + for (recipe in recipes) { + if (recipe !is CraftingRecipe) continue + val output = recipe.output + val internalItemId = output.internalItemId + if (!internalItemId.contains("_GENERATOR_")) continue + val map = mutableMapOf() + for (input in recipe.inputs) { + val itemId = input.internalItemId + if (minionId != itemId) { + val count = input.count.toInt() + val old = map.getOrDefault(itemId, 0) + map[itemId] = old + count + } + } + var allDone = true + for ((rawId, need) in map) { + val (itemId, multiplier) = getMultiplier(rawId) + val needAmount = need * multiplier + val have = otherItems.getOrDefault(itemId, 0) + val percentage = have.toDouble() / needAmount + val itemName = NEUItems.getItemStack(rawId).name ?: "§cName??§f" + if (percentage >= 1) { + display.add(" $itemName§8: §aDONE") + otherItems[itemId] = have - needAmount + } else { + val format = LorenzUtils.formatPercentage(percentage) + val haveFormat = LorenzUtils.formatInteger(have) + val needFormat = LorenzUtils.formatInteger(needAmount) + display.add("$itemName§8: §e$format §8(§7$haveFormat§8/§7$needFormat§8)") + allDone = false + } + } + display.add(" ") + if (allDone) { + addMinion(name, nextTier, nextMinionId, otherItems) + notify(minionName) + } + } + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { + if (!LorenzUtils.isBingoProfile) return + if (!SkyHanniMod.feature.bingo.minionCraftHelperEnabled) return + + SkyHanniMod.feature.bingo.minionCraftHelperPos.renderStrings(display, center = true) + } + + private fun getRecipes(minionId: String): List { + if (recipesCache.contains(minionId)) { + return recipesCache[minionId]!! + } + val recipes = NEUItems.manager.getAvailableRecipesFor(minionId) + recipesCache[minionId] = recipes + return recipes + } + + private fun notify(minionName: String) { + if (alreadyNotified.contains(minionName)) return + + SendTitleHelper.sendTitle("Can craft $minionName", 3_000) + alreadyNotified.add(minionName) + } + + private fun String.addOneToId(): String { + val lastText = split("_").last() + val next = lastText.toInt() + 1 + return replace(lastText, "" + next) + } + + + private fun getMultiplier(rawId: String, tryCount: Int = 0, parent: String? = null): Pair { + if (multiplierCache.contains(rawId)) { + return multiplierCache[rawId]!! + } + if (tryCount == 10) { + val message = "Error reading getMultiplier for item '$rawId'" + Error(message).printStackTrace() + LorenzUtils.error(message) + return Pair(rawId, 1) + } + for (recipe in getRecipes(rawId)) { + if (recipe !is CraftingRecipe) continue + + val map = mutableMapOf() + for (ingredient in recipe.ingredients) { + val count = ingredient.count.toInt() + val internalItemId = ingredient.internalItemId + val old = map.getOrDefault(internalItemId, 0) + map[internalItemId] = old + count + } + if (map.size != 1) continue + val current = map.iterator().next().toPair() + val id = current.first + return if (id != parent) { + val child = getMultiplier(id, tryCount + 1, rawId) + val result = Pair(child.first, child.second * current.second) + multiplierCache[rawId] = result + result + } else { + Pair(parent, 1) + } + } + + val result = Pair(rawId, 1) + multiplierCache[rawId] = result + return result + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/minion/MinionCraftHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/minion/MinionCraftHelper.kt deleted file mode 100644 index 52b38e742..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/minion/MinionCraftHelper.kt +++ /dev/null @@ -1,276 +0,0 @@ -package at.hannibal2.skyhanni.features.minion - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.data.SendTitleHelper -import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.events.ProfileJoinEvent -import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName -import at.hannibal2.skyhanni.utils.ItemUtils.name -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.NEUItems -import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimalIfNeeded -import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings -import at.hannibal2.skyhanni.utils.StringUtils.removeColor -import io.github.moulberry.notenoughupdates.NotEnoughUpdates -import io.github.moulberry.notenoughupdates.recipes.CraftingRecipe -import io.github.moulberry.notenoughupdates.recipes.NeuRecipe -import net.minecraft.client.Minecraft -import net.minecraft.item.ItemStack -import net.minecraftforge.event.world.WorldEvent -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import net.minecraftforge.fml.common.gameevent.TickEvent -import java.util.regex.Pattern - -class MinionCraftHelper { - - private var minionNamePattern = Pattern.compile("(.*) Minion (.*)") - private var tick = 0 - private var display = mutableListOf() - private var hasMinionInInventory = false - private var hasItemsForMinion = false - private val tierOneMinions = mutableListOf() - private val tierOneMinionsDone = mutableListOf() - private val allIngredients = mutableListOf() - private val alreadyNotified = mutableListOf() - private val recipesCache = mutableMapOf>() - private var multiplierCache = mutableMapOf>() - - @SubscribeEvent - fun onWorldChange(event: WorldEvent.Load) { - alreadyNotified.clear() - recipesCache.clear() - } - - @SubscribeEvent - fun onTick(event: TickEvent.ClientTickEvent) { - if (event.phase != TickEvent.Phase.START) return - if (!LorenzUtils.inSkyBlock) return - if (!SkyHanniMod.feature.minions.minionCraftHelperEnabled) return - - tick++ - - if (tick % 10 == 0) { - val mainInventory = Minecraft.getMinecraft()?.thePlayer?.inventory?.mainInventory ?: return - hasMinionInInventory = mainInventory - .mapNotNull { it?.name?.removeColor() } - .any { it.contains(" Minion ") } - } - - if (tick % (60 * 2) == 0) { - val mainInventory = Minecraft.getMinecraft()?.thePlayer?.inventory?.mainInventory ?: return - hasItemsForMinion = loadFromInventory(mainInventory).first.isNotEmpty() - } - - if (!hasMinionInInventory && !hasItemsForMinion) { - display.clear() - return - } - - if (tick % 3 != 0) return -// if (tick % 60 != 0) return - - val mainInventory = Minecraft.getMinecraft()?.thePlayer?.inventory?.mainInventory ?: return - - val (minions, otherItems) = loadFromInventory(mainInventory) - - display.clear() - for ((minionName, minionId) in minions) { - val matcher = minionNamePattern.matcher(minionName) - if (!matcher.matches()) return - val cleanName = matcher.group(1).removeColor() - val number = matcher.group(2).romanToDecimalIfNeeded() - addMinion(cleanName, number, minionId, otherItems) - } - } - - @SubscribeEvent - fun onProfileJoin(event: ProfileJoinEvent) { - tierOneMinionsDone.clear() - } - - private fun loadFromInventory(mainInventory: Array): Pair, MutableMap> { - init() - - val minions = mutableMapOf() - val otherItems = mutableMapOf() - - for (item in mainInventory) { - val name = item?.name?.removeColor() ?: continue - val rawId = item.getInternalName() - if (name.contains(" Minion ")) { - minions[name] = rawId - } else { - if (!allIngredients.contains(rawId)) continue - val (itemId, multiplier) = getMultiplier(rawId) - val old = otherItems.getOrDefault(itemId, 0) - otherItems[itemId] = old + item.stackSize * multiplier - } - } - firstMinionTier(otherItems, minions) - return Pair(minions, otherItems) - } - - private fun init() { - if (tierOneMinions.isNotEmpty()) return - - allIngredients.clear() - - for (internalId in NotEnoughUpdates.INSTANCE.manager.itemInformation.keys) { - if (internalId.endsWith("_GENERATOR_1")) { - tierOneMinions.add(internalId) - } - - if (internalId.contains("_GENERATOR_")) { - for (recipe in getRecipes(internalId)) { - if (recipe !is CraftingRecipe) continue - - for (ingredient in recipe.ingredients) { - val id = ingredient.internalItemId - if (!id.contains("_GENERATOR_")) { - if (!allIngredients.contains(id)) { - allIngredients.add(id) - } - } - } - } - } - } - } - - private fun firstMinionTier(otherItems: Map, minions: MutableMap) { - val help = otherItems.filter { !it.key.startsWith("WOOD_") } - val tierOneMinionsFiltered = tierOneMinions.filter { it !in tierOneMinionsDone } - for (minionId in tierOneMinionsFiltered) { - val prefix = minionId.dropLast(1) - if (minions.any { it.value.startsWith(prefix) }) { - tierOneMinionsDone.add(minionId) - } - } - for (minionId in tierOneMinionsFiltered) { - - for (recipe in getRecipes(minionId)) { - if (recipe !is CraftingRecipe) continue - if (recipe.ingredients.any { help.contains(it.internalItemId) }) { - val name = recipe.output.itemStack.name!!.removeColor() - val abc = name.replace(" I", " 0") - minions[abc] = minionId.replace("_1", "_0") - } - } - } - } - - private fun addMinion(name: String, minionTier: Int, minionId: String, otherItems: MutableMap) { - val nextTier = minionTier + 1 - val minionName = "§9$name Minion $nextTier" - display.add(minionName) - val nextMinionId = minionId.addOneToId() - val recipes: List = getRecipes(nextMinionId) - for (recipe in recipes) { - if (recipe !is CraftingRecipe) continue - val output = recipe.output - val internalItemId = output.internalItemId - if (!internalItemId.contains("_GENERATOR_")) continue - val map = mutableMapOf() - for (input in recipe.inputs) { - val itemId = input.internalItemId - if (minionId != itemId) { - val count = input.count.toInt() - val old = map.getOrDefault(itemId, 0) - map[itemId] = old + count - } - } - var allDone = true - for ((rawId, need) in map) { - val (itemId, multiplier) = getMultiplier(rawId) - val needAmount = need * multiplier - val have = otherItems.getOrDefault(itemId, 0) - val percentage = have.toDouble() / needAmount - val itemName = NEUItems.getItemStack(rawId).name ?: "§cName??§f" - if (percentage >= 1) { - display.add(" $itemName§8: §aDONE") - otherItems[itemId] = have - needAmount - } else { - val format = LorenzUtils.formatPercentage(percentage) - val haveFormat = LorenzUtils.formatInteger(have) - val needFormat = LorenzUtils.formatInteger(needAmount) - display.add("$itemName§8: §e$format §8(§7$haveFormat§8/§7$needFormat§8)") - allDone = false - } - } - display.add(" ") - if (allDone) { - addMinion(name, nextTier, nextMinionId, otherItems) - notify(minionName) - } - } - } - - @SubscribeEvent - fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { - if (!LorenzUtils.inSkyBlock) return - if (!SkyHanniMod.feature.minions.minionCraftHelperEnabled) return - - SkyHanniMod.feature.minions.minionCraftHelperPos.renderStrings(display, center = true) - } - - private fun getRecipes(minionId: String): List { - if (recipesCache.contains(minionId)) { - return recipesCache[minionId]!! - } - val recipes = NEUItems.manager.getAvailableRecipesFor(minionId) - recipesCache[minionId] = recipes - return recipes - } - - private fun notify(minionName: String) { - if (alreadyNotified.contains(minionName)) return - - SendTitleHelper.sendTitle("Can craft $minionName", 3_000) - alreadyNotified.add(minionName) - } - - private fun String.addOneToId(): String { - val lastText = split("_").last() - val next = lastText.toInt() + 1 - return replace(lastText, "" + next) - } - - - private fun getMultiplier(rawId: String, tryCount: Int = 0, parent: String? = null): Pair { - if (multiplierCache.contains(rawId)) { - return multiplierCache[rawId]!! - } - if (tryCount == 10) { - val message = "Error reading getMultiplier for item '$rawId'" - Error(message).printStackTrace() - LorenzUtils.error(message) - return Pair(rawId, 1) - } - for (recipe in getRecipes(rawId)) { - if (recipe !is CraftingRecipe) continue - - val map = mutableMapOf() - for (ingredient in recipe.ingredients) { - val count = ingredient.count.toInt() - val internalItemId = ingredient.internalItemId - val old = map.getOrDefault(internalItemId, 0) - map[internalItemId] = old + count - } - if (map.size != 1) continue - val current = map.iterator().next().toPair() - val id = current.first - return if (id != parent) { - val child = getMultiplier(id, tryCount + 1, rawId) - val result = Pair(child.first, child.second * current.second) - multiplierCache[rawId] = result - result - } else { - Pair(parent, 1) - } - } - - val result = Pair(rawId, 1) - multiplierCache[rawId] = result - return result - } -} -- cgit