From 43c07a3b0eba764b48f184e04391cf74a5aee1d7 Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Fri, 14 Apr 2023 16:07:59 +0200 Subject: Moved garden features into different packages --- .../java/at/hannibal2/skyhanni/SkyHanniMod.java | 8 + .../hannibal2/skyhanni/config/commands/Commands.kt | 2 +- .../skyhanni/features/garden/AnitaMedalProfit.kt | 1 + .../skyhanni/features/garden/CropMoneyDisplay.kt | 251 ---------- .../skyhanni/features/garden/CropSpeedMeter.kt | 141 ------ .../features/garden/DicerRngDropCounter.kt | 127 ----- .../skyhanni/features/garden/EliteFarmingWeight.kt | 323 ------------ .../skyhanni/features/garden/FarmingArmorDrops.kt | 107 ---- .../skyhanni/features/garden/GardenBestCropTime.kt | 106 ---- .../features/garden/GardenCropMilestoneDisplay.kt | 385 -------------- .../features/garden/GardenCustomKeybinds.kt | 107 ---- .../skyhanni/features/garden/GardenDeskInSBMenu.kt | 51 -- .../features/garden/GardenInventoryNumbers.kt | 53 -- .../features/garden/GardenNextPlotPrice.kt | 46 -- .../features/garden/GardenVisitorColorNames.kt | 55 -- .../features/garden/GardenVisitorFeatures.kt | 549 -------------------- .../skyhanni/features/garden/GardenVisitorTimer.kt | 69 --- .../skyhanni/features/garden/SkyMartCopperPrice.kt | 86 ---- .../features/garden/WrongFungiCutterWarning.kt | 82 --- .../features/garden/farming/CropMoneyDisplay.kt | 254 ++++++++++ .../features/garden/farming/CropSpeedMeter.kt | 143 ++++++ .../features/garden/farming/DicerRngDropCounter.kt | 129 +++++ .../features/garden/farming/EliteFarmingWeight.kt | 325 ++++++++++++ .../features/garden/farming/FarmingArmorDrops.kt | 108 ++++ .../features/garden/farming/GardenBestCropTime.kt | 108 ++++ .../garden/farming/GardenCropMilestoneDisplay.kt | 387 +++++++++++++++ .../garden/farming/GardenCustomKeybinds.kt | 108 ++++ .../garden/farming/WrongFungiCutterWarning.kt | 83 ++++ .../garden/inventory/GardenDeskInSBMenu.kt | 52 ++ .../garden/inventory/GardenInventoryNumbers.kt | 54 ++ .../garden/inventory/GardenNextPlotPrice.kt | 47 ++ .../garden/inventory/SkyMartCopperPrice.kt | 87 ++++ .../garden/visitor/GardenVisitorColorNames.kt | 55 ++ .../garden/visitor/GardenVisitorFeatures.kt | 551 +++++++++++++++++++++ .../features/garden/visitor/GardenVisitorTimer.kt | 70 +++ .../features/inventory/HideNotClickableItems.kt | 2 +- .../java/at/hannibal2/skyhanni/test/LorenzTest.kt | 2 +- 37 files changed, 2573 insertions(+), 2541 deletions(-) delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/CropMoneyDisplay.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/CropSpeedMeter.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/DicerRngDropCounter.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/EliteFarmingWeight.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/FarmingArmorDrops.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/GardenBestCropTime.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/GardenCropMilestoneDisplay.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/GardenCustomKeybinds.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/GardenDeskInSBMenu.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/GardenInventoryNumbers.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextPlotPrice.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorColorNames.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorFeatures.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorTimer.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/SkyMartCopperPrice.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/WrongFungiCutterWarning.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropMoneyDisplay.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropSpeedMeter.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/farming/DicerRngDropCounter.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/farming/EliteFarmingWeight.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingArmorDrops.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenBestCropTime.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCustomKeybinds.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/farming/WrongFungiCutterWarning.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenDeskInSBMenu.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryNumbers.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenNextPlotPrice.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/inventory/SkyMartCopperPrice.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorColorNames.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorTimer.kt (limited to 'src/main/java/at/hannibal2') diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java index 4b24f51fd..06c19a8a8 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java @@ -28,6 +28,14 @@ import at.hannibal2.skyhanni.features.garden.*; import at.hannibal2.skyhanni.features.garden.composter.ComposterDisplay; import at.hannibal2.skyhanni.features.garden.composter.ComposterInventoryNumbers; import at.hannibal2.skyhanni.features.garden.composter.GardenComposterInventoryFeatures; +import at.hannibal2.skyhanni.features.garden.farming.*; +import at.hannibal2.skyhanni.features.garden.inventory.GardenDeskInSBMenu; +import at.hannibal2.skyhanni.features.garden.inventory.GardenInventoryNumbers; +import at.hannibal2.skyhanni.features.garden.inventory.GardenNextPlotPrice; +import at.hannibal2.skyhanni.features.garden.inventory.SkyMartCopperPrice; +import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorColorNames; +import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorFeatures; +import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorTimer; import at.hannibal2.skyhanni.features.inventory.*; import at.hannibal2.skyhanni.features.itemabilities.FireVeilWandParticles; import at.hannibal2.skyhanni.features.itemabilities.abilitycooldown.ItemAbilityCooldown; diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt index f45c8a035..f09836a5b 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt @@ -9,7 +9,7 @@ import at.hannibal2.skyhanni.features.bazaar.BazaarDataGrabber import at.hannibal2.skyhanni.features.bingo.BingoCardDisplay import at.hannibal2.skyhanni.features.bingo.BingoNextStepHelper import at.hannibal2.skyhanni.features.event.diana.BurrowWarpHelper -import at.hannibal2.skyhanni.features.garden.CropSpeedMeter +import at.hannibal2.skyhanni.features.garden.farming.CropSpeedMeter import at.hannibal2.skyhanni.features.misc.CollectionCounter import at.hannibal2.skyhanni.features.misc.MarkedPlayerManager import at.hannibal2.skyhanni.test.LorenzTest diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/AnitaMedalProfit.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/AnitaMedalProfit.kt index 0f51e65aa..ed95ee8b4 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/AnitaMedalProfit.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/AnitaMedalProfit.kt @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryOpenEvent +import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorFeatures import at.hannibal2.skyhanni.utils.ItemUtils import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.ItemUtils.getLore diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/CropMoneyDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/CropMoneyDisplay.kt deleted file mode 100644 index 2bb43af93..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/CropMoneyDisplay.kt +++ /dev/null @@ -1,251 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.events.GardenToolChangeEvent -import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.features.bazaar.BazaarApi -import at.hannibal2.skyhanni.features.bazaar.BazaarData -import at.hannibal2.skyhanni.features.garden.GardenAPI.getSpeed -import at.hannibal2.skyhanni.utils.ItemUtils.name -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList -import at.hannibal2.skyhanni.utils.LorenzUtils.sortedDesc -import at.hannibal2.skyhanni.utils.NEUItems -import at.hannibal2.skyhanni.utils.NumberUtil -import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems -import at.hannibal2.skyhanni.utils.StringUtils.removeColor -import io.github.moulberry.notenoughupdates.NotEnoughUpdates -import kotlinx.coroutines.launch -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import net.minecraftforge.fml.common.gameevent.TickEvent - -class CropMoneyDisplay { - private var display = mutableListOf>() - private val config get() = SkyHanniMod.feature.garden - private var tick = 0 - private var loaded = false - private var ready = false - private val multipliers = mutableMapOf() - private val cropNames = mutableMapOf() // internalName -> cropName - private var hasCropInHand = false - - @SubscribeEvent - fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { - if (!isEnabled()) return - - config.moneyPerHourPos.renderStringsAndItems(display, posLabel = "Garden Crop Money Per Hour") - } - - @SubscribeEvent - fun onGardenToolChange(event: GardenToolChangeEvent) { - hasCropInHand = event.crop != null - update() - } - - @SubscribeEvent - fun onTick(event: TickEvent.ClientTickEvent) { - if (!isEnabled()) return - if (tick++ % (20 * 5) != 0) return - if (!hasCropInHand && !config.moneyPerHourAlwaysOn) return - - update() - } - - private fun update() { - init() - - display = drawDisplay() - } - - private fun drawDisplay(): MutableList> { - val newDisplay = mutableListOf>() - - val title = if (config.moneyPerHourCompact) { - "§7Money/Hour:" - } else { - "§7Money per Hour when selling:" - } - - if (!ready) { - newDisplay.addAsSingletonList(title) - newDisplay.addAsSingletonList("§eLoading...") - return newDisplay - } - - if (!hasCropInHand && !config.moneyPerHourAlwaysOn) return newDisplay - - newDisplay.addAsSingletonList(fullTitle(title)) - - if (!config.cropMilestoneProgress) { - newDisplay.addAsSingletonList("§cCrop Milestone Progress Display is disabled!") - return newDisplay - } - - val moneyPerHourData = calculateMoneyPerHour() - if (moneyPerHourData.isEmpty()) { - if (!GardenAPI.isSpeedDataEmpty()) { - val message = "money/hr empty but speed data not empty, retry" - LorenzUtils.debug(message) - println(message) - newDisplay.addAsSingletonList("§eStill Loading...") - ready = false - loaded = false - return newDisplay - } - newDisplay.addAsSingletonList("§cFarm crops to add them to this list!") - return newDisplay - } - - var number = 0 - val help = moneyPerHourData.mapValues { (_, value) -> value.max() } - for (internalName in help.sortedDesc().keys) { - number++ - val cropName = cropNames[internalName]!! - val isCurrent = cropName == GardenAPI.cropInHand - if (number > config.moneyPerHourShowOnlyBest && !isCurrent) continue - - val list = mutableListOf() - if (!config.moneyPerHourCompact) { - list.add("§7$number# ") - } - - try { - list.add(NEUItems.getItemStack(internalName)) - } catch (e: NullPointerException) { - e.printStackTrace() - } - - if (!config.moneyPerHourCompact) { - val itemName = NEUItems.getItemStack(internalName).name?.removeColor() ?: continue - val currentColor = if (isCurrent) "§e" else "§7" - val contestFormat = if (GardenNextJacobContest.isNextCrop(cropName)) "§n" else "" - list.add("$currentColor$contestFormat$itemName§7: ") - } - - val coinsColor = if (isCurrent && config.moneyPerHourCompact) "§e" else "§6" - val moneyArray = moneyPerHourData[internalName]!! - - for (price in moneyArray) { - val format = format(price) - list.add("$coinsColor$format") - list.add("§7/") - } - list.removeLast() - - newDisplay.add(list) - } - - return newDisplay - } - - private fun fullTitle(title: String): String { - val titleText: String - val nameList = mutableListOf() - if (config.moneyPerHourUseCustomFormat) { - val map = mapOf( - 0 to "Sell Offer", - 1 to "Instant Sell", - 2 to "NPC Price", - ) - val list = mutableListOf() - for (index in config.moneyPerHourCustomFormat) { - map[index]?.let { - list.add(it) - } - } - for (line in list) { - nameList.add("§e$line") - nameList.add("§7/") - } - nameList.removeLast() - titleText = nameList.joinToString("") - } else { - titleText = if (LorenzUtils.noTradeMode) "§eNPC Price" else "§eSell Offer" - } - return "$title §7($titleText§7)" - } - - private fun format(moneyPerHour: Double) = if (config.moneyPerHourCompactPrice) { - NumberUtil.format(moneyPerHour) - } else { - LorenzUtils.formatInteger(moneyPerHour.toLong()) - } - - private fun calculateMoneyPerHour(): Map> { - val moneyPerHours = mutableMapOf>() - for ((internalName, amount) in multipliers) { - val crop = cropNames[internalName]!! - val speed = crop.getSpeed() - // No speed data for item in hand - if (speed == -1) continue - - val speedPerHr = speed.toDouble() * 60 * 60 - val blocksPerHour = speedPerHr / amount.toDouble() - - val bazaarData = BazaarApi.getBazaarDataForInternalName(internalName) ?: continue - moneyPerHours[internalName] = formatNumbers(bazaarData, blocksPerHour) - } - return moneyPerHours - } - - private fun formatNumbers(bazaarData: BazaarData, blocksPerHour: Double): Array { - val npcPrice = bazaarData.npcPrice * blocksPerHour - val sellOffer = bazaarData.buyPrice * blocksPerHour - val instantSell = bazaarData.sellPrice * blocksPerHour - - return if (config.moneyPerHourUseCustomFormat) { - val map = mapOf( - 0 to sellOffer, - 1 to instantSell, - 2 to npcPrice, - ) - val newList = mutableListOf() - for (index in config.moneyPerHourCustomFormat) { - map[index]?.let { - newList.add(it) - } - } - newList.toTypedArray() - } else { - if (LorenzUtils.noTradeMode) { - arrayOf(npcPrice) - } else { - arrayOf(sellOffer) - } - } - } - - private fun init() { - if (loaded) return - - if (BazaarApi.bazaarMap.isEmpty()) { - LorenzUtils.debug("bz not ready for money/time!") - return - } - - loaded = true - - SkyHanniMod.coroutineScope.launch { - - for ((internalName, _) in NotEnoughUpdates.INSTANCE.manager.itemInformation) { - if (!BazaarApi.isBazaarItem(internalName)) continue - if (internalName == "ENCHANTED_PAPER") continue - - val (newId, amount) = NEUItems.getMultiplier(internalName) - if (amount < 10) continue - val itemName = NEUItems.getItemStack(newId).name?.removeColor() ?: continue - val crop = CropType.getByItemName(itemName) - crop?.let { - multipliers[internalName] = amount - cropNames[internalName] = it - } - } - - - ready = true - update() - } - } - - private fun isEnabled() = GardenAPI.inGarden() && config.moneyPerHourDisplay -} diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/CropSpeedMeter.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/CropSpeedMeter.kt deleted file mode 100644 index 9db52fe7c..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/CropSpeedMeter.kt +++ /dev/null @@ -1,141 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.data.GardenCropMilestones.Companion.getCounter -import at.hannibal2.skyhanni.events.BlockClickEvent -import at.hannibal2.skyhanni.events.CropMilestoneUpdateEvent -import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.features.garden.CropType.Companion.getCropType -import at.hannibal2.skyhanni.utils.BlockUtils.isBabyCrop -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round -import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators -import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import net.minecraftforge.fml.common.gameevent.TickEvent - -class CropSpeedMeter { - private var display = listOf() - private var currentCrop: CropType? = null - private var currentBlocks = 0 - private var tick = 0 - private var snapshot = listOf() - - @SubscribeEvent - fun onBlockBreak(event: BlockClickEvent) { - if (!isEnabled()) return - if (startCrops.isEmpty()) return - - val blockState = event.getBlockState - val cropBroken = blockState.getCropType() ?: return - if (cropBroken.multiplier == 1) { - if (blockState.isBabyCrop()) return - } - - if (currentCrop != cropBroken) { - currentCrop = cropBroken - currentBlocks = 0 - snapshot = emptyList() - } - breakBlock() - } - - @SubscribeEvent - fun onTick(event: TickEvent.ClientTickEvent) { - if (!isEnabled()) return - if (tick++ % 30 != 0) return - - updateDisplay() - } - - private fun updateDisplay() { - display = renderDisplay() - } - - private fun renderDisplay(): MutableList { - val list = mutableListOf() - list.add("§7Crop Speed Meter") - if (startCrops.isEmpty()) { - list.add("§cOpen §e/cropmilestones §cto start!") - return list - } - - if (currentCrop == null) { - list.add("§cStart breaking blocks!") - return list - } - currentCrop?.let { - list.add(" §7Current ${it.cropName} counter: §e${currentBlocks.addSeparators()}") - } - - if (snapshot.isNotEmpty()) { - list += snapshot - } else { - list.add("§cOpen §e/cropmilestones §cagain to calculate!") - } - - return list - } - - @SubscribeEvent - fun onCropMilestoneUpdate(event: CropMilestoneUpdateEvent) { - if (!isEnabled()) return - val counters = mutableMapOf() - for (cropType in CropType.values()) { - counters[cropType] = cropType.getCounter() - } - if (startCrops.isEmpty()) { - startCrops = counters - currentCrop = null - snapshot = emptyList() - } else { - currentCrop?.let { - val crops = it.getCounter() - startCrops[it]!! - val blocks = currentBlocks - val cropsPerBlocks = (crops.toDouble() / blocks.toDouble()).round(3) - - val list = mutableListOf() - list.add("") - list.add("§6Calculation results") - list.add(" §7Crops collected: " + crops.addSeparators()) - list.add(" §7Blocks broken: " + blocks.addSeparators()) - list.add(" §7Crops per Block: " + cropsPerBlocks.addSeparators()) - - val baseDrops = it.baseDrops - val farmingFortune = (cropsPerBlocks * 100 / baseDrops).round(3) - - - list.add(" §7Calculated farming Fortune: §e" + farmingFortune.addSeparators()) - list.add("§cOpen /cropmilestones again to recalculate!") - - snapshot = list - updateDisplay() - } - } - } - - private fun breakBlock() { - currentBlocks++ - } - - companion object { - var enabled = false - private var startCrops = mapOf() - - fun toggle() { - enabled = !enabled - LorenzUtils.chat("§e[SkyHanni] Crop Speed Meter " + if (enabled) "§aEnabled" else "§cDisabled") - startCrops = emptyMap() - - } - } - - @SubscribeEvent - fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { - if (!isEnabled()) return - - SkyHanniMod.feature.garden.cropSpeedMeterPos.renderStrings(display, posLabel = "Crop Speed Meter") - } - - fun isEnabled() = enabled && GardenAPI.inGarden() -} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/DicerRngDropCounter.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/DicerRngDropCounter.kt deleted file mode 100644 index 7f2facf4f..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/DicerRngDropCounter.kt +++ /dev/null @@ -1,127 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.events.ConfigLoadEvent -import at.hannibal2.skyhanni.events.GardenToolChangeEvent -import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.events.LorenzChatEvent -import at.hannibal2.skyhanni.utils.ItemUtils.name -import at.hannibal2.skyhanni.utils.LorenzUtils.sortedDesc -import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators -import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent - -class DicerRngDropCounter { - private var display = listOf() - private val drops = mutableMapOf>() - private val itemDrops = mutableListOf() - private val config get() = SkyHanniMod.feature.garden - - init { - drops[CropType.MELON] = mutableMapOf() - drops[CropType.PUMPKIN] = mutableMapOf() - - itemDrops.add(ItemDrop(CropType.MELON, DropRarity.UNCOMMON, "§a§lUNCOMMON DROP! §r§eDicer dropped §r§a1x §r§aEnchanted Melon§r§e!")) - itemDrops.add(ItemDrop(CropType.MELON, DropRarity.RARE, "§9§lRARE DROP! §r§eDicer dropped §r§a5x §r§aEnchanted Melon§r§e!")) - itemDrops.add(ItemDrop(CropType.MELON, DropRarity.CRAZY_RARE, "§d§lCRAZY RARE DROP! §r§eDicer dropped §r§a50x §r§aEnchanted Melon§r§e!")) - itemDrops.add(ItemDrop(CropType.MELON, DropRarity.PRAY_TO_RNGESUS, "§5§lPRAY TO RNGESUS DROP! §r§eDicer dropped §r§92x §r§9Enchanted Melon Block§r§e!")) - - itemDrops.add(ItemDrop(CropType.PUMPKIN, DropRarity.UNCOMMON, "§a§lUNCOMMON DROP! §r§eDicer dropped §r§f64x §r§fPumpkin§r§e!")) - itemDrops.add(ItemDrop(CropType.PUMPKIN, DropRarity.RARE, "§9§lRARE DROP! §r§eDicer dropped §r§a1x §r§aEnchanted Pumpkin§r§e!")) - itemDrops.add(ItemDrop(CropType.PUMPKIN, DropRarity.CRAZY_RARE, "§d§lCRAZY RARE DROP! §r§eDicer dropped §r§a10x §r§aEnchanted Pumpkin§r§e!")) - itemDrops.add(ItemDrop(CropType.PUMPKIN, DropRarity.PRAY_TO_RNGESUS, "§5§lPRAY TO RNGESUS DROP! §r§eDicer dropped §r§a64x §r§aEnchanted Pumpkin§r§e!")) - } - - enum class DropRarity(val displayName: String) { - UNCOMMON("§a§lUNCOMMON DROP"), - RARE("§9§lRARE DROP"), - CRAZY_RARE("§d§lCRAZY RARE DROP"), - PRAY_TO_RNGESUS("§5§lPRAY TO RNGESUS DROP"), - } - - @SubscribeEvent - fun onChat(event: LorenzChatEvent) { - if (!isEnabled()) return - - val message = event.message - for (drop in itemDrops) { - if (message == drop.message) { - addDrop(drop.crop, drop.rarity) - saveConfig() - update() - if (config.dicerCounterHideChat) { - event.blockedReason = "dicer_rng_drop_counter" - } - return - } - } - } - - private fun update() { - display = drawDisplay() - } - - private fun drawDisplay(): List { - val help = mutableListOf() - val items = drops[cropInHand] ?: return help - help.add("§7RNG Drops for $toolName§7:") - for ((rarity, amount) in items.sortedDesc()) { - val displayName = rarity.displayName - help.add(" §7- §e${amount.addSeparators()}x $displayName") - } - - return help - } - - private var cropInHand: CropType? = null - private var toolName = "" - - @SubscribeEvent - fun onGardenToolChange(event: GardenToolChangeEvent) { - val crop = event.crop - cropInHand = if (crop == CropType.MELON || crop == CropType.PUMPKIN) crop else null - if (cropInHand != null) { - toolName = event.toolItem!!.name!! - } - update() - } - - private fun addDrop(crop: CropType, rarity: DropRarity) { - val map = drops[crop]!! - val old = map[rarity] ?: 0 - map[rarity] = old + 1 - } - - @SubscribeEvent - fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { - if (isEnabled()) { - config.dicerCounterPos.renderStrings(display, posLabel = "Dicer Counter") - } - } - - class ItemDrop(val crop: CropType, val rarity: DropRarity, val message: String) - - private fun saveConfig() { - val map = SkyHanniMod.feature.hidden.gardenDicerRngDrops - map.clear() - for (drop in drops) { - val crop = drop.key - for ((rarity, amount) in drop.value) { - map[crop.cropName + "." + rarity.name] = amount - } - } - } - - @SubscribeEvent - fun onConfigLoad(event: ConfigLoadEvent) { - for ((internalName, amount) in SkyHanniMod.feature.hidden.gardenDicerRngDrops) { - val split = internalName.split(".") - val crop = CropType.getByNameNoNull(split[0]) - val rarityName = split[1] - val rarity = DropRarity.valueOf(rarityName) - drops[crop]!![rarity] = amount - } - } - - fun isEnabled() = GardenAPI.inGarden() && config.dicerCounterDisplay -} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/EliteFarmingWeight.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/EliteFarmingWeight.kt deleted file mode 100644 index bbcdd13dc..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/EliteFarmingWeight.kt +++ /dev/null @@ -1,323 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.data.HypixelData -import at.hannibal2.skyhanni.events.GardenToolChangeEvent -import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.features.garden.GardenAPI.getSpeed -import at.hannibal2.skyhanni.utils.APIUtil -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round -import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings -import at.hannibal2.skyhanni.utils.TimeUtils -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import net.minecraftforge.event.world.WorldEvent -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import net.minecraftforge.fml.common.gameevent.TickEvent -import java.util.* - -class EliteFarmingWeight { - - @SubscribeEvent - fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { - if (isEnabled()) { - config.eliteFarmingWeightPos.renderStrings(display, posLabel = "Elite Farming Weight") - } - } - - @SubscribeEvent - fun onGardenToolChange(event: GardenToolChangeEvent) { - // Reset speed - weightPerSecond = -1.0 - } - - @SubscribeEvent - fun onWorldChange(event: WorldEvent.Load) { - // We want to try to connect to the api again after a world switch. - apiError = false - // We ask both api endpoints after every world switch - weight = -1.0 - weightPerSecond = -1.0 - - leaderboardPosition = -1 - dirtyCropWeight = true - lastLeaderboardUpdate = 0 - nextPlayerWeight = 0.0 - nextPlayerName = "" - hasPassedNext = false - } - - var tick = 0 - - @SubscribeEvent - fun onTick(event: TickEvent.ClientTickEvent) { - if (!isEnabled()) return - if (tick++ % 5 != 0) return - update() - } - - companion object { - private val config get() = SkyHanniMod.feature.garden - private val localCounter = mutableMapOf() - - private var display = listOf() - private var profileId = "" - private var lastLeaderboardUpdate = 0L - private var apiError = false - private var leaderboardPosition = -1 - private var weight = -2.0 - private var localWeight = 0.0 - private var weightPerSecond = -1.0 - private var dirtyCropWeight = false - private var isLoadingWeight = false - private var isLoadingLeaderboard = false - - private var nextPlayerName = "" - private var nextPlayerWeight = 0.0 - private var hasPassedNext = false - - private fun update() { - if (!GardenAPI.inGarden()) return - if (apiError) { - display = listOf( - "§6Farming Weight§7: §cError!", - "§cCannot load data from Elite Farmers!", - "§eRejoin garden to try again." - ) - return - } - if (weight == -2.0) { - display = Collections.singletonList("§6Farming Weight§7: §eLoading..") - return - } - - if (weight == -1.0) { - if (!isLoadingWeight) { - val localProfile = HypixelData.profileName - if (localProfile == "") return - - isLoadingWeight = true - SkyHanniMod.coroutineScope.launch { - loadWeight(localProfile) - isLoadingWeight = false - } - } - return - } - - val weight = getWeight() - val leaderboard = getLeaderboard() - - val list = mutableListOf() - list.add("§6Farming Weight§7: $weight$leaderboard") - - if (isEtaEnabled() && (weightPerSecond != -1.0 || config.eliteFarmingWeightOvertakeETAAlways)) { - list.add(getETA()) - } - display = list - } - - private fun getLeaderboard(): String { - if (!config.eliteFarmingWeightLeaderboard) return "" - - // Fetching new leaderboard position every 10 minutes - if (System.currentTimeMillis() > lastLeaderboardUpdate + 600_000) { - if (!isLoadingLeaderboard) { - isLoadingLeaderboard = true - SkyHanniMod.coroutineScope.launch { - leaderboardPosition = loadLeaderboardPosition() - lastLeaderboardUpdate = System.currentTimeMillis() - isLoadingLeaderboard = false - } - } - } - - return if (leaderboardPosition != -1) { - val format = LorenzUtils.formatInteger(leaderboardPosition) - " §7[§b#$format§7]" - } else { - if (isLoadingLeaderboard) { - " §7[§b#?§7]" - } else "" - } - } - - private fun getWeight(): String { - if (dirtyCropWeight) { - val values = calculateCollectionWeight().values - if (values.isNotEmpty()) { - localWeight = values.sum() - dirtyCropWeight = false - } - } - - val totalWeight = (localWeight + weight) - return "§e" + LorenzUtils.formatDouble(totalWeight, 2) - } - - private fun getETA(): String { - if (weight < 0) return "" - val nextName = if (leaderboardPosition == -1) "#1000" else nextPlayerName - - val totalWeight = (localWeight + weight) - val weightUntilOvertake = nextPlayerWeight - totalWeight - if (weightUntilOvertake < 0) { - if (!hasPassedNext) { - if (weightPerSecond > 0) { - LorenzUtils.debug("weightPerSecond: '$weightPerSecond'") - LorenzUtils.chat("§e[SkyHanni] You passed §b$nextName §ein the Farming Weight Leaderboard!") - } - if (leaderboardPosition == -1) { - leaderboardPosition = 1000 - } else { - leaderboardPosition-- - } - hasPassedNext = true - } - return "§cWaiting for leaderboard update..." - } - - if (nextPlayerWeight == 0.0) { - return "§cRejoin the garden to show ETA!" - } - val timeFormat = if (weightPerSecond != -1.0) { - val timeTillOvertake = (weightUntilOvertake / weightPerSecond) * 1000 - val format = TimeUtils.formatDuration(timeTillOvertake.toLong()) - " §7(§b$format§7)" - } else "" - - val weightFormat = LorenzUtils.formatDouble(weightUntilOvertake, 2) - return "§e$weightFormat$timeFormat §7behind §b$nextName" - } - - private fun isEnabled() = GardenAPI.inGarden() && config.eliteFarmingWeightDisplay - private fun isEtaEnabled() = config.eliteFarmingWeightOvertakeETA - - fun addCrop(crop: CropType, addedCounter: Int) { - val before = getExactWeight() - localCounter[crop] = crop.getLocalCounter() + addedCounter - val after = getExactWeight() - - updateWeightPerSecond(crop, before, after, addedCounter) - - dirtyCropWeight = true - } - - private fun updateWeightPerSecond(crop: CropType, before: Double, after: Double, diff: Int) { - val speed = crop.getSpeed() - if (speed != -1) { - val weightDiff = (after - before) * 1000 - weightPerSecond = weightDiff / diff * speed / 1000 - } - } - - private fun getExactWeight(): Double { - val values = calculateCollectionWeight(false).values - return if (values.isNotEmpty()) { - values.sum() - } else 0.0 - } - - private suspend fun loadLeaderboardPosition() = try { - val uuid = LorenzUtils.getPlayerUuid() - val showNext = if (isEtaEnabled()) "?showNext=true" else "" - val url = "https://elitebot.dev/api/leaderboard/rank/weight/farming/$uuid/$profileId$showNext" - val result = withContext(Dispatchers.IO) { APIUtil.getJSONResponse(url) }.asJsonObject - - if (isEtaEnabled()) { - result["next"]?.asJsonObject?.let { - nextPlayerName = it["ign"].asString - nextPlayerWeight = it["amount"].asDouble - } - } - - result["rank"].asInt - } catch (e: Exception) { - error() - e.printStackTrace() - -1 - } - - private suspend fun loadWeight(localProfile: String) { - val uuid = LorenzUtils.getPlayerUuid() - val url = "https://elitebot.dev/api/weight/$uuid" - - try { - val result = withContext(Dispatchers.IO) { APIUtil.getJSONResponse(url) }.asJsonObject - for (profileEntry in result["profiles"].asJsonObject.entrySet()) { - val profile = profileEntry.value.asJsonObject - val profileName = profile["cute_name"].asString.lowercase() - if (profileName == localProfile) { - profileId = profileEntry.key - weight = profile["farming"].asJsonObject["total"].asDouble - - localCounter.clear() - dirtyCropWeight = true - - return - } - } - println("localProfile: '$localProfile'") - println("url: '$url'") - println("result: '$result'") - } catch (e: Exception) { - println("url: '$url'") - e.printStackTrace() - } - error() - } - - private fun error() { - apiError = true - LorenzUtils.error("[SkyHanni] Loading the farming weight data from elitebot.dev failed!") - LorenzUtils.chat("§eYou can re-enter the garden to try to fix the problem. If this message repeats itself, please report it on Discord!") - } - - private fun calculateCollectionWeight(round: Boolean = true): MutableMap { - val weightPerCrop = mutableMapOf() - var totalWeight = 0.0 - for (crop in CropType.values()) { - val weight = crop.getLocalCounter() / crop.getFactor() - val roundedWeight = weight.let { if (round) it.round(2) else it } - weightPerCrop[crop] = roundedWeight - totalWeight += roundedWeight - } - if (totalWeight > 0) { - weightPerCrop[CropType.MUSHROOM] = specialMushroomWeight(weightPerCrop, totalWeight) - } - return weightPerCrop - } - - private fun specialMushroomWeight(weightPerCrop: MutableMap, totalWeight: Double): Double { - val cactusWeight = weightPerCrop[CropType.CACTUS]!! - val sugarCaneWeight = weightPerCrop[CropType.SUGAR_CANE]!! - val doubleBreakRatio = (cactusWeight + sugarCaneWeight) / totalWeight; - val normalRatio = (totalWeight - cactusWeight - sugarCaneWeight) / totalWeight; - - val mushroomFactor = CropType.MUSHROOM.getFactor() - val mushroomCollection = CropType.MUSHROOM.getLocalCounter() - return doubleBreakRatio * (mushroomCollection / (2 * mushroomFactor)) + normalRatio * (mushroomCollection / mushroomFactor) - } - - private fun CropType.getLocalCounter() = localCounter[this] ?: 0L - - private fun CropType.getFactor() = factorPerCrop[this]!! - - private val factorPerCrop by lazy { - mapOf( - CropType.WHEAT to 100_000.0, - CropType.CARROT to 300_000.0, - CropType.POTATO to 300_000.0, - CropType.SUGAR_CANE to 200_000.0, - CropType.NETHER_WART to 250_000.0, - CropType.PUMPKIN to 90_066.27, - CropType.MELON to 450_324.6, - CropType.MUSHROOM to 90_178.06, - CropType.COCOA_BEANS to 267_174.04, - CropType.CACTUS to 177_254.45, - ) - } - } -} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingArmorDrops.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingArmorDrops.kt deleted file mode 100644 index c56347122..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingArmorDrops.kt +++ /dev/null @@ -1,107 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.events.ConfigLoadEvent -import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.events.LorenzChatEvent -import at.hannibal2.skyhanni.utils.InventoryUtils -import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName -import at.hannibal2.skyhanni.utils.LorenzUtils.sortedDesc -import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators -import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import net.minecraftforge.fml.common.gameevent.TickEvent -import java.util.regex.Pattern - -class FarmingArmorDrops { - private var display = listOf() - private val drops = mutableMapOf() - private var hasArmor = false - private var tick = 0 - private val armorPattern = Pattern.compile("(FERMENTO|CROPIE|SQUASH|MELON)_(LEGGINGS|CHESTPLATE|BOOTS|HELMET)") - private val config get() = SkyHanniMod.feature.garden - - enum class ArmorDropType(val dropName: String, val chatMessage: String) { - CROPIE("§9Cropie", "§6§lRARE CROP! §r§f§r§9Cropie §r§b(Armor Set Bonus)"), - SQUASH("§5Squash", "§6§lRARE CROP! §r§f§r§5Squash §r§b(Armor Set Bonus)"), - FERMENTO("§6Fermento", "§6§lRARE CROP! §r§f§r§6Fermento §r§b(Armor Set Bonus)"), - } - - @SubscribeEvent - fun onChat(event: LorenzChatEvent) { - for (dropType in ArmorDropType.values()) { - if (dropType.chatMessage == event.message) { - addDrop(dropType) - if (config.farmingArmorDropsEnabled && config.farmingArmorDropsHideChat) { - event.blockedReason = "farming_armor_drops" - } - } - } - } - - private fun addDrop(drop: ArmorDropType) { - val old = drops[drop] ?: 0 - drops[drop] = old + 1 - saveConfig() - update() - } - - private fun update() { - display = drawDisplay() - } - - private fun drawDisplay(): List { - val help = mutableListOf() - help.add("§7RNG Drops for Farming Armor:") - for ((drop, amount) in drops.sortedDesc()) { - val dropName = drop.dropName - help.add(" §7- §e${amount.addSeparators()}x $dropName") - } - - return help - } - - private fun saveConfig() { - val map = SkyHanniMod.feature.hidden.gardenFarmingArmorDrops - map.clear() - for ((drop, amount) in drops) { - map[drop.toString()] = amount - } - } - - @SubscribeEvent - fun onConfigLoad(event: ConfigLoadEvent) { - for ((rawName, amount) in SkyHanniMod.feature.hidden.gardenFarmingArmorDrops) { - drops[ArmorDropType.valueOf(rawName)] = amount - } - update() - } - - @SubscribeEvent - fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { - if (!GardenAPI.inGarden()) return - if (!config.farmingArmorDropsEnabled) return - if (!hasArmor) return - - config.farmingArmorDropsPos.renderStrings(display, posLabel = "Farming Armor Drops") - } - - @SubscribeEvent - fun onTick(event: TickEvent.ClientTickEvent) { - if (event.phase != TickEvent.Phase.START) return - if (!GardenAPI.inGarden()) return - if (!config.farmingArmorDropsEnabled) return - - tick++ - if (tick % 30 == 0) { - checkArmor() - } - } - - private fun checkArmor() { - val armorPieces = InventoryUtils.getArmor() - .mapNotNull { it?.getInternalName() } - .count { armorPattern.matcher(it).matches() } - hasArmor = armorPieces > 1 - } -} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenBestCropTime.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenBestCropTime.kt deleted file mode 100644 index 049ef2552..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenBestCropTime.kt +++ /dev/null @@ -1,106 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.data.GardenCropMilestones -import at.hannibal2.skyhanni.data.GardenCropMilestones.Companion.getCounter -import at.hannibal2.skyhanni.features.garden.GardenAPI.addCropIcon -import at.hannibal2.skyhanni.features.garden.GardenAPI.getSpeed -import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList -import at.hannibal2.skyhanni.utils.LorenzUtils.sorted -import at.hannibal2.skyhanni.utils.TimeUtils - -class GardenBestCropTime { - var display = listOf>() - val timeTillNextCrop = mutableMapOf() - private val config get() = SkyHanniMod.feature.garden - - fun drawBestDisplay(currentCrop: CropType?): List> { - val newList = mutableListOf>() - if (timeTillNextCrop.size < CropType.values().size) { - updateTimeTillNextCrop() - } - - val gardenExp = config.cropMilestoneBestType == 0 - val sorted = if (gardenExp) { - val helpMap = mutableMapOf() - for ((cropName, time) in timeTillNextCrop) { - val currentTier = GardenCropMilestones.getTierForCrops(cropName.getCounter()) - val gardenExpForTier = getGardenExpForTier(currentTier + 1) - val fakeTime = time / gardenExpForTier - helpMap[cropName] = fakeTime - } - helpMap.sorted() - } else { - timeTillNextCrop.sorted() - } - - val title = if (gardenExp) "§2Garden Experience" else "§bSkyBlock Level" - if (config.cropMilestoneBestCompact) { - newList.addAsSingletonList("§eBest Crop Time") - } else { - newList.addAsSingletonList("§eBest Crop Time §7($title§7)") - } - - if (!config.cropMilestoneProgress) { - newList.addAsSingletonList("§cCrop Milestone Progress Display is disabled!") - return newList - } - - if (sorted.isEmpty()) { - newList.addAsSingletonList("§cFarm crops to add them to this list!") - return newList - } - - var number = 0 - for (crop in sorted.keys) { - val millis = timeTillNextCrop[crop]!! - val duration = TimeUtils.formatDuration(millis, maxUnits = 2) - val isCurrent = crop == currentCrop - number++ - if (number > config.cropMilestoneShowOnlyBest && !isCurrent) continue - - val list = mutableListOf() - list.add("§7$number# ") - list.addCropIcon(crop) - - val color = if (isCurrent) "§e" else "§7" - val contestFormat = if (GardenNextJacobContest.isNextCrop(crop)) "§n" else "" - val nextTier = GardenCropMilestones.getTierForCrops(crop.getCounter()) + 1 - - val cropName = if (!config.cropMilestoneBestCompact) crop.cropName + " " else "" - val cropNameDisplay = "$color$contestFormat$cropName$nextTier§r" - list.add("$cropNameDisplay §b$duration") - - if (gardenExp && !config.cropMilestoneBestCompact) { - val gardenExpForTier = getGardenExpForTier(nextTier) - list.add(" §7(§2$gardenExpForTier §7Exp)") - } - newList.add(list) - } - return newList - } - - private fun getGardenExpForTier(gardenLevel: Int) = if (gardenLevel > 30) 300 else gardenLevel * 10 - - fun updateTimeTillNextCrop() { - for (crop in CropType.values()) { - val speed = crop.getSpeed() - if (speed == -1) continue - - val counter = crop.getCounter() - val currentTier = GardenCropMilestones.getTierForCrops(counter) - - val cropsForCurrentTier = GardenCropMilestones.getCropsForTier(currentTier) - val nextTier = currentTier + 1 - val cropsForNextTier = GardenCropMilestones.getCropsForTier(nextTier) - - val have = counter - cropsForCurrentTier - val need = cropsForNextTier - cropsForCurrentTier - - val missing = need - have - val missingTimeSeconds = missing / speed - val millis = missingTimeSeconds * 1000 - timeTillNextCrop[crop] = millis - } - } -} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenCropMilestoneDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenCropMilestoneDisplay.kt deleted file mode 100644 index 9e4013088..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenCropMilestoneDisplay.kt +++ /dev/null @@ -1,385 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.data.ClickType -import at.hannibal2.skyhanni.data.GardenCropMilestones -import at.hannibal2.skyhanni.data.GardenCropMilestones.Companion.getCounter -import at.hannibal2.skyhanni.data.GardenCropMilestones.Companion.setCounter -import at.hannibal2.skyhanni.data.MayorElectionData -import at.hannibal2.skyhanni.data.TitleUtils -import at.hannibal2.skyhanni.events.* -import at.hannibal2.skyhanni.features.garden.CropType.Companion.getCropType -import at.hannibal2.skyhanni.features.garden.GardenAPI.addCropIcon -import at.hannibal2.skyhanni.features.garden.GardenAPI.getCropType -import at.hannibal2.skyhanni.features.garden.GardenAPI.setSpeed -import at.hannibal2.skyhanni.utils.BlockUtils.isBabyCrop -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList -import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems -import at.hannibal2.skyhanni.utils.SoundUtils -import at.hannibal2.skyhanni.utils.TimeUtils -import net.minecraft.item.ItemStack -import net.minecraftforge.fml.common.eventhandler.EventPriority -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import java.util.* -import kotlin.concurrent.fixedRateTimer - -class GardenCropMilestoneDisplay { - private var progressDisplay = listOf>() - private var mushroomCowPerkDisplay = listOf>() - private val cultivatingData = mutableMapOf() - private val config get() = SkyHanniMod.feature.garden - private val bestCropTime = GardenBestCropTime() -// val cropMilestoneLevelUpPattern = Pattern.compile(" §r§b§lGARDEN MILESTONE §3(.*) §8XXIII➜§3(.*)") - - private var lastPlaySoundTime = 0L - - private var needsInventory = false - - private var mushroom_cow_nether_warts = true - - @SubscribeEvent - fun onRepoReload(event: RepositoryReloadEvent) { - try { - val constant = event.getConstant("DisabledFeatures") - mushroom_cow_nether_warts = if (constant != null) { - if (constant.has("mushroom_cow_nether_warts")) { - constant["mushroom_cow_nether_warts"].asBoolean - } else false - } else false - } catch (e: Exception) { - e.printStackTrace() - } - } - - @SubscribeEvent - fun onChatMessage(event: LorenzChatEvent) { - if (!isEnabled()) return - // TODO remove this once hypixel counts 64x pumpkin drops to cultivating - if (event.message == "§a§lUNCOMMON DROP! §r§eDicer dropped §r§f64x §r§fPumpkin§r§e!") { - CropType.PUMPKIN.setCounter(CropType.PUMPKIN.getCounter() + 64) - } -// if (config.cropMilestoneWarnClose) { -// val matcher = cropMilestoneLevelUpPattern.matcher(event.message) -// if (matcher.matches()) { -// val cropType = matcher.group(1) -// val newLevel = matcher.group(2).romanToDecimalIfNeeded() -// LorenzUtils.debug("found milestone messsage!") -// SendTitleHelper.sendTitle("§b$cropType $newLevel", 1_500) -// } -// } - } - - @SubscribeEvent - fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { - if (!isEnabled()) return - - config.cropMilestoneProgressDisplayPos.renderStringsAndItems( - progressDisplay, - posLabel = "Crop Milestone Progress" - ) - - if (config.cropMilestoneMushroomPetPerkEnabled) { - config.cropMilestoneMushroomPetPerkPos.renderStringsAndItems( - mushroomCowPerkDisplay, - posLabel = "Mushroom Cow Perk" - ) - } - - if (config.cropMilestoneBestDisplay) { - config.cropMilestoneNextDisplayPos.renderStringsAndItems(bestCropTime.display, posLabel = "Best Crop Time") - } - } - - @SubscribeEvent(priority = EventPriority.LOW) - fun onProfileJoin(event: ProfileJoinEvent) { - if (GardenCropMilestones.cropCounter.values.sum() == 0L) { - needsInventory = true - } - } - - @SubscribeEvent - fun onCropMilestoneUpdate(event: CropMilestoneUpdateEvent) { - needsInventory = false - bestCropTime.updateTimeTillNextCrop() - update() - } - - @SubscribeEvent - fun onOwnInventoryItemUpdate(event: OwnInventorItemUpdateEvent) { - if (!GardenAPI.inGarden()) return - - try { - val item = event.itemStack - val counter = GardenAPI.readCounter(item) - if (counter == -1) return - val crop = item.getCropType() ?: return - if (cultivatingData.containsKey(crop)) { - val old = cultivatingData[crop]!! - val addedCounter = counter - old - - if (GardenCropMilestones.cropCounter.isEmpty()) { - for (innerCrop in CropType.values()) { - innerCrop.setCounter(0) - } - } - if (GardenAPI.isSpeedDataEmpty()) { - for (cropType in CropType.values()) { - cropType.setSpeed(-1) - } - } - if (!finneganPerkActive()) { - crop.setCounter(crop.getCounter() + addedCounter) - } - EliteFarmingWeight.addCrop(crop, addedCounter) - if (currentCrop == crop) { - calculateSpeed(addedCounter) - update() - } - } - cultivatingData[crop] = counter - } catch (e: Throwable) { - LorenzUtils.error("[SkyHanni] Error in OwnInventorItemUpdateEvent") - e.printStackTrace() - } - } - - private fun finneganPerkActive(): Boolean { - val forcefullyEnabledAlwaysFinnegan = config.forcefullyEnabledAlwaysFinnegan - val perkActive = MayorElectionData.isPerkActive("Finnegan", "Farming Simulator") - MayorElectionData.currentCandidate?.let { - - } - return forcefullyEnabledAlwaysFinnegan || perkActive - } - - @SubscribeEvent - fun onBlockClick(event: BlockClickEvent) { - if (!isEnabled()) return - if (event.clickType != ClickType.LEFT_CLICK) return - - val blockState = event.getBlockState - - val cropType = blockState.getCropType() ?: return - val multiplier = cropType.multiplier - if (multiplier == 1) { - if (blockState.isBabyCrop()) return - } - blocksBroken += multiplier - } - - private var currentSpeed = 0 - private var averageSpeedPerSecond = 0 - private var countInLastSecond = 0 - private val allCounters = mutableListOf() - private var lastItemInHand: ItemStack? = null - private var currentCrop: CropType? = null - private var blocksBroken = 0 - private var lastBlocksPerSecond = 0 - - private fun resetSpeed() { - currentSpeed = 0 - averageSpeedPerSecond = 0 - countInLastSecond = 0 - allCounters.clear() - } - - init { - fixedRateTimer(name = "skyhanni-crop-milestone-speed", period = 1000L) { - if (GardenAPI.inGarden() && GardenAPI.mushroomCowPet) { - CropType.MUSHROOM.setCounter(CropType.MUSHROOM.getCounter() + blocksBroken) - update() - } - if (isEnabled()) { - checkSpeed() - } - } - } - - private fun checkSpeed() { - if (finneganPerkActive()) { - currentSpeed = (currentSpeed.toDouble() * 0.8).toInt() - } - - if (countInLastSecond > 8) { - allCounters.add(currentSpeed) - while (allCounters.size > 30) { - allCounters.removeFirst() - } - averageSpeedPerSecond = allCounters.average().toInt() - } - countInLastSecond = 0 - - if (finneganPerkActive()) { - currentCrop?.let { - it.setCounter(it.getCounter() + currentSpeed) - } - } - currentSpeed = 0 - - lastBlocksPerSecond = blocksBroken - blocksBroken = 0 - } - - - private fun calculateSpeed(addedCounter: Int) { - currentSpeed += addedCounter - countInLastSecond++ - } - - @SubscribeEvent - fun onGardenToolChange(event: GardenToolChangeEvent) { - lastItemInHand = event.toolItem - currentCrop = event.crop - - if (isEnabled()) { - resetSpeed() - update() - } - } - - private fun update() { - progressDisplay = emptyList() - mushroomCowPerkDisplay = emptyList() - bestCropTime.display = emptyList() - currentCrop?.let { - progressDisplay = drawProgressDisplay(it, it.getCounter()) - if (config.cropMilestoneBestDisplay) { - bestCropTime.display = bestCropTime.drawBestDisplay(it) - } - } - if (config.cropMilestoneBestAlwaysOn) { - if (currentCrop == null) { - bestCropTime.display = bestCropTime.drawBestDisplay(null) - } - } - } - - private fun drawProgressDisplay(crop: CropType, counter: Long): MutableList> { - val lineMap = HashMap>() - lineMap[0] = Collections.singletonList("§6Crop Milestones") - - val currentTier = GardenCropMilestones.getTierForCrops(counter) - val nextTier = currentTier + 1 - - val list = mutableListOf() - list.addCropIcon(crop) - list.add("§7" + crop.cropName + " Tier $nextTier") - lineMap[1] = list - - val cropsForCurrentTier = GardenCropMilestones.getCropsForTier(currentTier) - val cropsForNextTier = GardenCropMilestones.getCropsForTier(nextTier) - - val have = counter - cropsForCurrentTier - val need = cropsForNextTier - cropsForCurrentTier - - val haveFormat = LorenzUtils.formatInteger(have) - val needFormat = LorenzUtils.formatInteger(need) - lineMap[2] = Collections.singletonList("§e$haveFormat§8/§e$needFormat") - - lastItemInHand?.let { - if (GardenAPI.readCounter(it) == -1) { - lineMap[3] = Collections.singletonList("§cWarning: You need Cultivating!") - return formatDisplay(lineMap) - } - } - - if (averageSpeedPerSecond != 0) { - crop.setSpeed(averageSpeedPerSecond) - val missing = need - have - val missingTimeSeconds = missing / averageSpeedPerSecond - val millis = missingTimeSeconds * 1000 - bestCropTime.timeTillNextCrop[crop] = millis - val duration = TimeUtils.formatDuration(millis) - if (config.cropMilestoneWarnClose) { - if (millis < 5_900) { - if (System.currentTimeMillis() > lastPlaySoundTime + 1_000) { - lastPlaySoundTime = System.currentTimeMillis() - SoundUtils.playBeepSound() - } - TitleUtils.sendTitle("§b${crop.cropName} $nextTier in $duration", 1_500) - } - } - lineMap[3] = Collections.singletonList("§7In §b$duration") - - val format = LorenzUtils.formatInteger(averageSpeedPerSecond * 60) - lineMap[4] = Collections.singletonList("§7Crops/Minute§8: §e$format") - lineMap[5] = Collections.singletonList("§7Blocks/Second§8: §e$lastBlocksPerSecond") - } - - if (GardenAPI.mushroomCowPet && crop != CropType.MUSHROOM) { - if (mushroom_cow_nether_warts && crop == CropType.NETHER_WART) { - mushroomCowPerkDisplay = listOf( - listOf("§6Mooshroom Cow Perk"), - listOf("§cNether Warts don't give mushrooms."), - listOf("§7(Hypixel please fix this)") - ) - } else { - addMushroomCowData() - } - } - - return formatDisplay(lineMap) - } - - private fun formatDisplay(lineMap: HashMap>): MutableList> { - val newList = mutableListOf>() - for (index in config.cropMilestoneText) { - lineMap[index]?.let { - newList.add(it) - } - } - - if (needsInventory) { - newList.addAsSingletonList("§cOpen §e/cropmilestones §cto update!") - } - - return newList - } - - private fun addMushroomCowData() { - val lineMap = HashMap>() - val counter = CropType.MUSHROOM.getCounter() - - val currentTier = GardenCropMilestones.getTierForCrops(counter) - val nextTier = currentTier + 1 - - val cropsForCurrentTier = GardenCropMilestones.getCropsForTier(currentTier) - val cropsForNextTier = GardenCropMilestones.getCropsForTier(nextTier) - - val have = counter - cropsForCurrentTier - val need = cropsForNextTier - cropsForCurrentTier - - val haveFormat = LorenzUtils.formatInteger(have) - val needFormat = LorenzUtils.formatInteger(need) - - val missing = need - have - - // We assume perfect 20 blocks per seconds - val blocksPerSecond = 20 * (currentCrop?.multiplier ?: 1) - - val missingTimeSeconds = missing / blocksPerSecond - val millis = missingTimeSeconds * 1000 - val duration = TimeUtils.formatDuration(millis) - - lineMap[0] = Collections.singletonList("§6Mooshroom Cow Perk") - - val list = mutableListOf() - list.addCropIcon(CropType.MUSHROOM) - list.add("§7Mushroom Tier $nextTier") - lineMap[1] = list - - lineMap[2] = Collections.singletonList("§e$haveFormat§8/§e$needFormat") - lineMap[3] = Collections.singletonList("§7In §b$duration") - - val newList = mutableListOf>() - for (index in config.cropMilestoneMushroomPetPerkText) { - lineMap[index]?.let { - newList.add(it) - } - } - mushroomCowPerkDisplay = newList - } - - private fun isEnabled() = GardenAPI.inGarden() && config.cropMilestoneProgress -} diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenCustomKeybinds.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenCustomKeybinds.kt deleted file mode 100644 index 4e24cf988..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenCustomKeybinds.kt +++ /dev/null @@ -1,107 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.config.features.Garden -import at.hannibal2.skyhanni.events.GardenToolChangeEvent -import at.hannibal2.skyhanni.mixins.transformers.AccessorKeyBinding -import io.github.moulberry.moulconfig.internal.KeybindHelper -import net.minecraft.client.Minecraft -import net.minecraft.client.settings.KeyBinding -import net.minecraftforge.event.world.WorldEvent -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent - -class GardenCustomKeybinds { - private val shConfig: Garden get() = SkyHanniMod.feature.garden - private val mcSettings get() = Minecraft.getMinecraft().gameSettings - - private val cache = mutableMapOf() - private val map = mutableMapOf Int>() - - init { - map[mcSettings.keyBindAttack] = { shConfig.keyBindAttack } - map[mcSettings.keyBindLeft] = { shConfig.keyBindLeft } - map[mcSettings.keyBindRight] = { shConfig.keyBindRight } - map[mcSettings.keyBindForward] = { shConfig.keyBindForward } - map[mcSettings.keyBindBack] = { shConfig.keyBindBack } - map[mcSettings.keyBindJump] = { shConfig.keyBindJump } - map[mcSettings.keyBindSneak] = { shConfig.keyBindSneak } - - Runtime.getRuntime().addShutdownHook(Thread { reset() }) - } - - @SubscribeEvent - fun onGardenToolChange(event: GardenToolChangeEvent) { - update() - } - - private fun update() { - if (isEnabled() && GardenAPI.toolInHand != null) { - applyCustomKeybinds() - } else { - reset() - } - } - - @SubscribeEvent - fun onWorldChange(event: WorldEvent.Load) { - reset() - } - - private fun applyCustomKeybinds() { - val alreadyBoundedKeys = mutableListOf() - var counter = 0 - for ((mcBinding, skyHanniBinding) in map) { - val newKeyCode = skyHanniBinding() - if (newKeyCode == mcBinding.keyCode) continue - - disableAlreadyExistingKeybinds(newKeyCode, alreadyBoundedKeys) - - if (!cache.containsKey(mcBinding)) { - cache[mcBinding] = mcBinding.keyCode - mcBinding.unpressKeyIfDown() - } - - mcBinding.keyCode = newKeyCode - alreadyBoundedKeys.add(mcBinding.keyCodeDefault) - counter++ - } - - if (counter > 0) { - KeyBinding.resetKeyBindingArrayAndHash() - } - } - - private fun disableAlreadyExistingKeybinds(newKeyCode: Int, alreadyBoundedKeys: MutableList) { - if (newKeyCode == 0) return - for (keyBinding in mcSettings.keyBindings) { - if (keyBinding.keyCode != newKeyCode) continue - if (alreadyBoundedKeys.contains(keyBinding.keyCodeDefault)) continue - keyBinding.unpressKeyIfDown() - cache[keyBinding] = keyBinding.keyCode - keyBinding.keyCode = 0 - } - } - - private fun reset() { - var counter = 0 - for ((key, keyCode) in cache) { - if (key.keyCode != keyCode) { - key.unpressKeyIfDown() - counter++ - key.keyCode = keyCode - } - } - cache.clear() - if (counter > 0) { - KeyBinding.resetKeyBindingArrayAndHash() - } - } - - private fun KeyBinding.unpressKeyIfDown() { - if (KeybindHelper.isKeyDown(keyCode)) { - (this as AccessorKeyBinding).skyhanni_unpressKey() - } - } - - private fun isEnabled() = GardenAPI.inGarden() && shConfig.keyBindEnabled -} diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenDeskInSBMenu.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenDeskInSBMenu.kt deleted file mode 100644 index f84e9fa44..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenDeskInSBMenu.kt +++ /dev/null @@ -1,51 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.events.InventoryCloseEvent -import at.hannibal2.skyhanni.events.InventoryOpenEvent -import at.hannibal2.skyhanni.utils.NEUItems -import io.github.moulberry.notenoughupdates.events.ReplaceItemEvent -import io.github.moulberry.notenoughupdates.events.SlotClickEvent -import io.github.moulberry.notenoughupdates.util.Utils -import net.minecraft.client.Minecraft -import net.minecraft.client.player.inventory.ContainerLocalMenu -import net.minecraftforge.fml.common.eventhandler.EventPriority -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent - -class GardenDeskInSBMenu { - - private val config get() = SkyHanniMod.feature.garden - private var showItem = false - - private val item by lazy { - val neuItem = NEUItems.getItemStack("DOUBLE_PLANT") - Utils.createItemStack(neuItem.item, "§bDesk", "§7Click here to", "§7run §e/desk") - } - - - @SubscribeEvent - fun onInventoryOpen(event: InventoryOpenEvent) { - showItem = GardenAPI.inGarden() && config.deskInSkyBlockMenu && event.inventoryName == "SkyBlock Menu" - } - - @SubscribeEvent - fun onInventoryClose(event: InventoryCloseEvent) { - showItem = false - } - - @SubscribeEvent - fun replaceItem(event: ReplaceItemEvent) { - if (event.inventory is ContainerLocalMenu && showItem && event.slotNumber == 10) { - event.replaceWith(item) - } - } - - @SubscribeEvent(priority = EventPriority.HIGH) - fun onStackClick(event: SlotClickEvent) { - if (showItem && event.slotId == 10) { - event.isCanceled = true - val thePlayer = Minecraft.getMinecraft().thePlayer - thePlayer.sendChatMessage("/desk") - } - } -} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenInventoryNumbers.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenInventoryNumbers.kt deleted file mode 100644 index 53815205c..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenInventoryNumbers.kt +++ /dev/null @@ -1,53 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.data.model.ComposterUpgrade -import at.hannibal2.skyhanni.events.RenderItemTipEvent -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.NumberUtil.romanToDecimalIfNeeded -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import java.util.regex.Pattern - -class GardenInventoryNumbers { - private var patternTierProgress = Pattern.compile("§7Progress to Tier (.*): §e(?:.*)") - private var patternUpgradeTier = Pattern.compile("§7Current Tier: §[ea](.*)§7/§a.*") - - @SubscribeEvent - fun onRenderItemTip(event: RenderItemTipEvent) { - if (!GardenAPI.inGarden()) return - - if (InventoryUtils.openInventoryName() == "Crop Milestones") { - if (!SkyHanniMod.feature.garden.numberCropMilestone) return - - event.stack.getLore() - .map { patternTierProgress.matcher(it) } - .filter { it.matches() } - .map { it.group(1).romanToDecimalIfNeeded() - 1 } - .forEach { event.stackTip = "" + it } - } - - if (InventoryUtils.openInventoryName() == "Crop Upgrades") { - if (!SkyHanniMod.feature.garden.numberCropUpgrades) return - - event.stack.getLore() - .map { patternUpgradeTier.matcher(it) } - .filter { it.matches() } - .map { it.group(1) } - .forEach { event.stackTip = "" + it } - } - - if (InventoryUtils.openInventoryName() == "Composter Upgrades") { - if (!SkyHanniMod.feature.garden.numberComposterUpgrades) return - - event.stack.name?.let { - val matcher = ComposterUpgrade.regex.matcher(it) - if (matcher.matches()) { - val level = matcher.group("level")?.romanToDecimalIfNeeded() ?: 0 - event.stackTip = "$level" - } - } - } - } -} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextPlotPrice.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextPlotPrice.kt deleted file mode 100644 index 85b61db60..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextPlotPrice.kt +++ /dev/null @@ -1,46 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.utils.* -import at.hannibal2.skyhanni.utils.ItemUtils.name -import net.minecraftforge.event.entity.player.ItemTooltipEvent -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent - -class GardenNextPlotPrice { - - @SubscribeEvent - fun onTooltip(event: ItemTooltipEvent) { - if (!GardenAPI.inGarden()) return - if (!SkyHanniMod.feature.garden.plotPrice) return - - if (InventoryUtils.openInventoryName() != "Configure Plots") return - - val name = event.itemStack.name ?: return - if (!name.startsWith("§ePlot")) return - - var next = false - val list = event.toolTip - var i = -1 - for (l in list) { - i++ - val line = l.substring(4) - if (line.contains("Cost")) { - next = true - continue - } - - if (next) { - val (itemName, amount) = ItemUtils.readItemAmount(line) - if (itemName != null) { - val lowestBin = NEUItems.getPrice(NEUItems.getInternalName(itemName)) - val price = lowestBin * amount - val format = NumberUtil.format(price) - list[i] = list[i] + " §7(§6$format§7)" - } else { - LorenzUtils.error("§c[SkyHanni] Could not read item '$line'") - } - break - } - } - } -} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorColorNames.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorColorNames.kt deleted file mode 100644 index cf0df59e8..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorColorNames.kt +++ /dev/null @@ -1,55 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.events.RepositoryReloadEvent -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.StringUtils.removeColor -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent - -class GardenVisitorColorNames { - - @SubscribeEvent - fun onRepoReload(event: RepositoryReloadEvent) { - try { - val mapColor = mutableMapOf() - val mapItems = mutableMapOf>() - val garden = event.getConstant("Garden")!! - for ((name, element) in garden["visitors"].asJsonObject.entrySet()) { - val jsonObject = element.asJsonObject - val rarity = jsonObject["rarity"].asString - mapColor[name] = getColor(rarity) - mapItems[name] = jsonObject["need_items"].asJsonArray.map { it.asString } - - } - visitorColor = mapColor - visitorItems = mapItems - - } catch (e: Exception) { - e.printStackTrace() - LorenzUtils.error("error in RepositoryReloadEvent") - } - } - - companion object { - private var visitorColor = mapOf() // name -> color code - var visitorItems = mapOf>() - - fun getColoredName(name: String): String { - if (!SkyHanniMod.feature.garden.visitorColoredName) return name - - val cleanName = name.removeColor() - val color = visitorColor[cleanName] ?: return name - return color + cleanName - } - } - - - private fun getColor(rarity: String) = when (rarity) { - "uncommon" -> "§a" - "rare" -> "§9" - "legendary" -> "§6" - "special" -> "§c" - - else -> throw RuntimeException("Unknown rarity for '$rarity'") - } -} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorFeatures.kt deleted file mode 100644 index 2b7f12539..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorFeatures.kt +++ /dev/null @@ -1,549 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.data.TitleUtils -import at.hannibal2.skyhanni.events.* -import at.hannibal2.skyhanni.features.garden.GardenAPI.getSpeed -import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper -import at.hannibal2.skyhanni.utils.* -import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName -import at.hannibal2.skyhanni.utils.ItemUtils.getLore -import at.hannibal2.skyhanni.utils.ItemUtils.name -import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList -import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators -import at.hannibal2.skyhanni.utils.RenderUtils.drawString -import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems -import at.hannibal2.skyhanni.utils.StringUtils.removeColor -import io.github.moulberry.notenoughupdates.events.SlotClickEvent -import io.github.moulberry.notenoughupdates.util.SBInfo -import net.minecraft.client.Minecraft -import net.minecraft.entity.EntityLivingBase -import net.minecraft.entity.item.EntityArmorStand -import net.minecraft.network.play.client.C02PacketUseEntity -import net.minecraftforge.client.event.RenderLivingEvent -import net.minecraftforge.client.event.RenderWorldLastEvent -import net.minecraftforge.event.entity.player.ItemTooltipEvent -import net.minecraftforge.fml.common.eventhandler.EventPriority -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import net.minecraftforge.fml.common.gameevent.TickEvent -import java.util.regex.Pattern - -class GardenVisitorFeatures { - private val visitors = mutableMapOf() - private var display = listOf>() - private var lastClickedNpc = 0 - private var tick = 0 - private val copperPattern = Pattern.compile(" §8\\+§c(.*) Copper") - private val gardenExperiencePattern = Pattern.compile(" §8\\+§2(.*) §7Garden Experience") - private val offerAcceptedPattern = Pattern.compile("§6§lOFFER ACCEPTED §r§8with §r(.*) §r.*") - private val config get() = SkyHanniMod.feature.garden - - companion object { - var inVisitorInventory = false - } - - @SubscribeEvent - fun onInventoryOpen(event: InventoryOpenEvent) { - inVisitorInventory = false - - if (!GardenAPI.inGarden()) return - val npcItem = event.inventoryItems[13] ?: return - val lore = npcItem.getLore() - var isVisitor = false - if (lore.size == 4) { - val line = lore[3] - if (line.startsWith("§7Offers Accepted: §a")) { - isVisitor = true - } - } - if (!isVisitor) return - - val offerItem = event.inventoryItems[29] ?: return - if (offerItem.name != "§aAccept Offer") return - inVisitorInventory = true - - if (!config.visitorNeedsDisplay && config.visitorHighlightStatus == 3) return - - var name = npcItem.name ?: return - if (name.length == name.removeColor().length + 4) { - name = name.substring(2) - } - val visitor = visitors[name]!! - visitor.entityId = lastClickedNpc - for (line in offerItem.getLore()) { - if (line == "§7Items Required:") continue - if (line.isEmpty()) break - - val (itemName, amount) = ItemUtils.readItemAmount(line) - if (itemName == null) { - LorenzUtils.error("§c[SkyHanni] Could not read item '$line'") - continue - } - val internalName = NEUItems.getInternalName(itemName) - visitor.items[internalName] = amount - } - if (visitor.status == VisitorStatus.NEW) { - oldStatus(visitor) - visitor.status = VisitorStatus.WAITING - statusChange(visitor) - } - - update() - } - - private fun updateDisplay() { - display = drawDisplay() - } - - private fun drawDisplay(): List> { - val newDisplay = mutableListOf>() - if (!config.visitorNeedsDisplay) return newDisplay - - val requiredItems = mutableMapOf() - val newVisitors = mutableListOf() - for ((visitorName, visitor) in visitors) { - if (visitor.status != VisitorStatus.WAITING && visitor.status != VisitorStatus.NEW) continue - - val items = visitor.items - if (items.isEmpty()) { - newVisitors.add(visitorName) - } - for ((internalName, amount) in items) { - val old = requiredItems.getOrDefault(internalName, 0) - requiredItems[internalName] = old + amount - } - } - if (requiredItems.isNotEmpty()) { - newDisplay.addAsSingletonList("§7Visitor items needed:") - for ((internalName, amount) in requiredItems) { - val name = NEUItems.getItemStack(internalName).name!! - val itemStack = NEUItems.getItemStack(internalName) - - val list = mutableListOf() - list.add(" §7- ") - list.add(itemStack) - list.add("$name §8x${amount.addSeparators()}") - - if (config.visitorNeedsShowPrice) { - val price = NEUItems.getPrice(internalName) * amount - val format = NumberUtil.format(price) - list.add(" §7(§6$format§7)") - } - - newDisplay.add(list) - } - } - if (newVisitors.isNotEmpty()) { - if (requiredItems.isNotEmpty()) { - newDisplay.addAsSingletonList("") - } - val amount = newVisitors.size - val visitorLabel = if (amount == 1) "visitor" else "visitors" - newDisplay.addAsSingletonList("§e$amount §7new $visitorLabel:") - for (visitor in newVisitors) { - val displayName = GardenVisitorColorNames.getColoredName(visitor) - - val list = mutableListOf() - list.add(" §7- $displayName") - - if (config.visitorItemPreview) { - val items = GardenVisitorColorNames.visitorItems[visitor.removeColor()] - if (items == null) { - LorenzUtils.debug("Visitor '$visitor' has no items in repo!") - list.add(" §7(§c?§7)") - continue - } - list.add(" ") - if (items.isEmpty()) { - list.add("§7(§fAny§7)") - } else { - for (item in items) { - try { - val internalName = NEUItems.getInternalName(item) - list.add(NEUItems.getItemStack(internalName)) - } catch (e: Exception) { - list.add(" '$item' ") - } - } - } - } - - newDisplay.add(list) - } - } - - return newDisplay - } - - @SubscribeEvent(priority = EventPriority.HIGH) - fun onStackClick(event: SlotClickEvent) { - if (!inVisitorInventory) return - if (event.slot.stack?.name != "§cRefuse Offer") return - if (event.slotId != 33) return - - getVisitor(lastClickedNpc)?.let { - oldStatus(it) - it.status = VisitorStatus.REFUSED - statusChange(it) - update() - } - } - - private fun getVisitor(id: Int) = visitors.map { it.value }.find { it.entityId == id } - - @SubscribeEvent - fun onCheckRender(event: CheckRenderEntityEvent<*>) { - if (!GardenAPI.inGarden()) return - if (!GardenAPI.onBarnPlot) return - if (config.visitorHighlightStatus != 1 && config.visitorHighlightStatus != 2) return - - val entity = event.entity - if (entity is EntityArmorStand) { - if (entity.name == "§e§lCLICK") { - event.isCanceled = true - } - } - } - - @SubscribeEvent - fun onRenderWorld(event: RenderWorldLastEvent) { - if (!GardenAPI.inGarden()) return - if (!GardenAPI.onBarnPlot) return - if (config.visitorHighlightStatus != 1 && config.visitorHighlightStatus != 2) return - - for (visitor in visitors.values) { - visitor.getEntity()?.let { - val location = it.getLorenzVec().add(0.0, 2.2, 0.0) - val text = visitor.status.displayName - event.drawString(location, text) - } - } - } - - @SubscribeEvent(priority = EventPriority.HIGH) - fun onTooltip(event: ItemTooltipEvent) { - if (!GardenAPI.inGarden()) return - if (!inVisitorInventory) return - val name = event.itemStack.name ?: return - if (name != "§aAccept Offer") return - - val list = event.toolTip - var totalPrice = 0.0 - var itemsCounter = 0 - var itemsWithSpeedCounter = 0 - var endReached = false - for ((i, l) in list.toMutableList().withIndex()) { - if (l.length < 4) continue - - val line = l.substring(4) - if (line == "") { - if (!endReached) { - if (config.visitorShowPrice) { - if (itemsCounter > 1) { - val format = NumberUtil.format(totalPrice) - list[1] = list[1] + "$line §7(§6Total §6$format§7)" - } - } - endReached = true - } - } - - // Items Required - if (i > 1 && !endReached) { - val (itemName, amount) = ItemUtils.readItemAmount(line) - if (itemName != null) { - var internalName: String - try { - internalName = NEUItems.getInternalName(itemName) - } catch (e: NullPointerException) { - val message = "internal name is null: '$itemName'" - println(message) - LorenzUtils.error(message) - e.printStackTrace() - return - } - val price = NEUItems.getPrice(internalName) * amount - totalPrice += price - if (config.visitorShowPrice) { - val format = NumberUtil.format(price) - list[i + itemsWithSpeedCounter] = "$line §7(§6$format§7)" - } - itemsCounter++ - - if (config.visitorExactAmountAndTime) { - val multiplier = NEUItems.getMultiplier(internalName) - val rawName = NEUItems.getItemStack(multiplier.first).name?.removeColor() ?: continue - CropType.getByItemName(rawName)?.let { - val speed = it.getSpeed() - val cropAmount = multiplier.second.toLong() * amount - val formatAmount = LorenzUtils.formatInteger(cropAmount) - val formatName = "§e$formatAmount§7x ${it.cropName} " - val formatSpeed = if (speed != -1) { - val missingTimeSeconds = cropAmount / speed - val duration = TimeUtils.formatDuration(missingTimeSeconds * 1000) - "in §b$duration" - } else { - "§cno speed data!" - } - itemsWithSpeedCounter++ - list.add(i + itemsWithSpeedCounter, " §7- $formatName($formatSpeed§7)") - } - } - } else { - LorenzUtils.error("§c[SkyHanni] Could not read item '$line'") - } - } - - if (config.visitorCopperPrice) { - val matcher = copperPattern.matcher(line) - if (matcher.matches()) { - val coppers = matcher.group(1).replace(",", "").toInt() - val pricePerCopper = NumberUtil.format((totalPrice / coppers).toInt()) - list[i + itemsWithSpeedCounter] = "$line §7(price per §6$pricePerCopper§7)" - } - } - if (config.visitorExperiencePrice) { - val matcher = gardenExperiencePattern.matcher(line) - if (matcher.matches()) { - val gardenExp = matcher.group(1).replace(",", "").toInt() - val pricePerCopper = NumberUtil.format((totalPrice / gardenExp).toInt()) - list[i + itemsWithSpeedCounter] = "$line §7(price per §6$pricePerCopper§7)" - } - } - } - } - - @SubscribeEvent - fun onTick(event: TickEvent.ClientTickEvent) { - if (!GardenAPI.inGarden()) return - if (!config.visitorNeedsDisplay && config.visitorHighlightStatus == 3) return - if (tick++ % 10 != 0) return - - if (GardenAPI.onBarnPlot && config.visitorHighlightStatus != 3) { - checkVisitorsReady() - } - } - - @SubscribeEvent - fun onTabListUpdate(event: TabListUpdateEvent) { - if (!GardenAPI.inGarden()) return - var found = false - val visitorsInTab = mutableListOf() - for (line in event.tabList) { - if (line.startsWith("§b§lVisitors:")) { - found = true - continue - } - if (found) { - if (line.isEmpty()) { - found = false - continue - } - var name = line.trim().replace("§r", "") - if (!name.contains("§")) { - name = "§f$name" - } - - // Hide hypixel watchdog entries - if (name.contains("§c") && !name.contains("Spaceman") && !name.contains("Grandma Wolf")) continue - - //hide own player name - if (name.contains(LorenzUtils.getPlayerUuid())) continue - - visitorsInTab.add(name) - } - } - if (visitors.keys.removeIf { - val time = System.currentTimeMillis() - SBInfo.getInstance().joinedWorld - it !in visitorsInTab && time > 2_000 - }) { - updateDisplay() - } - for (name in visitorsInTab) { - if (!visitors.containsKey(name)) { - visitors[name] = Visitor(name, status = VisitorStatus.NEW) - LorenzUtils.debug("new visitor '$name'") - if (config.visitorNotificationTitle) { - TitleUtils.sendTitle("§eNew Visitor", 5_000) - } - if (config.visitorNotificationChat) { - val displayName = GardenVisitorColorNames.getColoredName(name) - LorenzUtils.chat("§e[SkyHanni] $displayName §eis visiting your garden!") - } - updateDisplay() - } - } - } - - @SubscribeEvent - fun onChatMessage(event: LorenzChatEvent) { - val matcher = offerAcceptedPattern.matcher(event.message) - if (!matcher.matches()) return - - val visitorName = matcher.group(1) - for (visitor in visitors) { - if (visitor.key == visitorName) { - oldStatus(visitor.value) - visitor.value.status = VisitorStatus.ACCEPTED - statusChange(visitor.value) - update() - } - } - } - - private fun update() { - checkVisitorsReady() - updateDisplay() - } - - private fun checkVisitorsReady() { - for ((visitorName, visitor) in visitors) { - val entity = visitor.getEntity() - if (entity == null) { - findNametag(visitorName.removeColor())?.let { - findEntity(it, visitor) - } - } - - val status = visitor.status - if (status == VisitorStatus.WAITING || status == VisitorStatus.READY) { - oldStatus(visitor) - visitor.status = if (isReady(visitor)) VisitorStatus.READY else VisitorStatus.WAITING - statusChange(visitor) - } - - if (config.visitorHighlightStatus == 0 || config.visitorHighlightStatus == 2) { - if (entity is EntityLivingBase) { - val color = status.color - if (color != -1) { - RenderLivingEntityHelper.setEntityColor( - entity, - color - ) { config.visitorHighlightStatus == 0 || config.visitorHighlightStatus == 2 } - } else { - RenderLivingEntityHelper.removeEntityColor(entity) - } - } - } - } - } - - val oldValue = mutableMapOf() - - private fun oldStatus(visitor: Visitor) { - oldValue[visitor] = visitor.status - } - - private fun statusChange(visitor: Visitor) { - val old = oldValue[visitor] - val new = visitor.status - if (old == new) return - val name = visitor.visitorName.removeColor() - LorenzUtils.debug("Visitor status change for $name: $old -> $new") - } - - private fun Visitor.getEntity() = Minecraft.getMinecraft().theWorld.getEntityByID(entityId) - - private fun findEntity(nameTag: EntityArmorStand, visitor: Visitor) { - for (entity in Minecraft.getMinecraft().theWorld.loadedEntityList) { - if (entity is EntityArmorStand) continue - if (entity.getLorenzVec().distanceIgnoreY(nameTag.getLorenzVec()) != 0.0) continue - - visitor.entityId = entity?.entityId ?: 0 - visitor.nameTagEntityId = nameTag.entityId - } - } - - private fun findNametag(visitorName: String): EntityArmorStand? { - val foundVisitorNameTags = mutableListOf() - for (entity in Minecraft.getMinecraft().theWorld.loadedEntityList) { - if (entity !is EntityArmorStand) continue - - if (entity.name.removeColor() == visitorName) { - foundVisitorNameTags.add(entity) - } - } - - if (visitorName in listOf("Jacob", "Anita")) { - - // Only detect jacob/anita npc if the "wrong" npc got found as well - if (foundVisitorNameTags.size != 2) return null - - for (tag in foundVisitorNameTags.toMutableList()) { - for (entity in Minecraft.getMinecraft().theWorld.loadedEntityList) { - if (entity !is EntityArmorStand) continue - if (entity in foundVisitorNameTags) continue - val distance = entity.getLorenzVec().distance(tag.getLorenzVec()) - if (distance < 1.5 && entity.name == "§bSam") { - foundVisitorNameTags.remove(tag) - } - } - } - } - - if (foundVisitorNameTags.size != 1) return null - return foundVisitorNameTags[0] - } - - private fun isReady(visitor: Visitor): Boolean { - var ready = true - for ((internalName, need) in visitor.items) { - val having = InventoryUtils.countItemsInLowerInventory { it.getInternalName() == internalName } - if (having < need) { - ready = false - } - } - return ready - } - - // TODO make event - @SubscribeEvent - fun onSendEvent(event: PacketEvent.SendEvent) { - val packet = event.packet - if (packet !is C02PacketUseEntity) return - - val theWorld = Minecraft.getMinecraft().theWorld - val entity = packet.getEntityFromWorld(theWorld) ?: return - val entityId = entity.entityId - - lastClickedNpc = entityId - } - - @SubscribeEvent - fun onRenderOverlay(event: GuiRenderEvent) { - if (!GardenAPI.inGarden()) return - if (!config.visitorNeedsDisplay) return - - if (config.visitorNeedsOnlyWhenClose && !GardenAPI.onBarnPlot) return - - config.visitorNeedsPos.renderStringsAndItems(display, posLabel = "Visitor Items Needed") - } - - @SubscribeEvent(priority = EventPriority.HIGH) - fun onRenderLivingB(event: RenderLivingEvent.Specials.Pre) { - val entity = event.entity - val entityId = entity.entityId - for (visitor in visitors.values) { - if (visitor.nameTagEntityId == entityId) { - entity.customNameTag = GardenVisitorColorNames.getColoredName(entity.name) - } - } - } - - class Visitor( - val visitorName: String, - var entityId: Int = -1, - var nameTagEntityId: Int = -1, - var status: VisitorStatus, - val items: MutableMap = mutableMapOf(), - ) - - enum class VisitorStatus(val displayName: String, val color: Int) { - NEW("§e§lNew", LorenzColor.YELLOW.toColor().withAlpha(100)), - WAITING("§lWaiting", -1), - READY("§a§lItems Ready", LorenzColor.GREEN.toColor().withAlpha(80)), - ACCEPTED("§7§lAccepted", LorenzColor.DARK_GRAY.toColor().withAlpha(80)), - REFUSED("§c§lRefused", LorenzColor.RED.toColor().withAlpha(60)), - } -} - diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorTimer.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorTimer.kt deleted file mode 100644 index ea63fb54f..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenVisitorTimer.kt +++ /dev/null @@ -1,69 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.events.TabListUpdateEvent -import at.hannibal2.skyhanni.utils.RenderUtils.renderString -import at.hannibal2.skyhanni.utils.TimeUtils -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import java.util.regex.Pattern - -class GardenVisitorTimer { - private val patternNextVisitor = Pattern.compile(" Next Visitor: §r§b(.*)") - private val patternVisitors = Pattern.compile("§b§lVisitors: §r§f\\((\\d)\\)") - private var render = "" - private var lastMillis = 0L - private var lastVisitors = 0 - - @SubscribeEvent - fun onTabListUpdate(event: TabListUpdateEvent) { - if (!isEnabled()) return - - var visitorsAmount = 0 - var millis = 15 * 60_000L - var queueFull = false - for (line in event.tabList) { - var matcher = patternNextVisitor.matcher(line) - if (matcher.matches()) { - val rawTime = matcher.group(1) - millis = TimeUtils.getMillis(rawTime) - } else if (line == " Next Visitor: §r§c§lQueue Full!") { - queueFull = true - } else if (line == " Next Visitor: §r§cNot Unlocked!") { - render = "" - return - } - - matcher = patternVisitors.matcher(line) - if (matcher.matches()) { - visitorsAmount = matcher.group(1).toInt() - } - } - - val diff = lastMillis - millis - if (diff == 0L && visitorsAmount == lastVisitors) return - lastMillis = millis - lastVisitors = visitorsAmount - - val extraSpeed = if (diff in 1001..10_000) { - val factor = diff / 1000 - "§7/§e" + TimeUtils.formatDuration(millis / factor) - } else "" - - val formatDuration = TimeUtils.formatDuration(millis) - val next = if (queueFull) "§cQueue Full!" else { - "Next in §e$formatDuration$extraSpeed" - } - val visitorLabel = if (visitorsAmount == 1) "visitor" else "visitors" - render = "§b$visitorsAmount $visitorLabel §7($next§7)" - } - - @SubscribeEvent - fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { - if (!isEnabled()) return - - SkyHanniMod.feature.garden.visitorTimerPos.renderString(render, posLabel = "Garden Visitor Timer") - } - - private fun isEnabled() = GardenAPI.inGarden() && SkyHanniMod.feature.garden.visitorTimerEnabled -} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/SkyMartCopperPrice.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/SkyMartCopperPrice.kt deleted file mode 100644 index 7457224e6..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/SkyMartCopperPrice.kt +++ /dev/null @@ -1,86 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.events.InventoryCloseEvent -import at.hannibal2.skyhanni.events.InventoryOpenEvent -import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName -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.LorenzUtils.addAsSingletonList -import at.hannibal2.skyhanni.utils.NEUItems -import at.hannibal2.skyhanni.utils.NumberUtil -import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import java.util.regex.Pattern - -class SkyMartCopperPrice { - private val pattern = Pattern.compile("§c(.*) Copper") - private var display = listOf>() - private val config get() = SkyHanniMod.feature.garden - - companion object { - var inInventory = false - } - - @SubscribeEvent - fun onInventoryOpen(event: InventoryOpenEvent) { - if (!isEnabled()) return - if (event.inventoryName != "SkyMart") return - - inInventory = true - val table = mutableMapOf, Pair>() - for (stack in event.inventoryItems.values) { - for (line in stack.getLore()) { - val matcher = pattern.matcher(line) - if (!matcher.matches()) continue - - val internalName = stack.getInternalName() - val lowestBin = NEUItems.getPrice(internalName) - if (lowestBin == -1.0) continue - - val amount = matcher.group(1).replace(",", "").toInt() - val factor = lowestBin / amount - val perFormat = NumberUtil.format(factor) - val priceFormat = NumberUtil.format(lowestBin) - val amountFormat = NumberUtil.format(amount) - - var name = stack.name!! - if (name == "§fEnchanted Book") { - name = stack.getLore()[0] - } - - val advancedStats = if (config.skyMartCopperPriceAdvancedStats) { - " §7(§6$priceFormat §7/ §c$amountFormat Copper§7)" - } else "" - val pair = Pair("$name§f:", "§6§l$perFormat$advancedStats") - table[pair] = Pair(factor, internalName) - } - } - - val newList = mutableListOf>() - newList.addAsSingletonList("§eCoins per Copper§f:") - LorenzUtils.fillTable(newList, table) - display = newList - } - - @SubscribeEvent - fun onInventoryClose(event: InventoryCloseEvent) { - inInventory = false - } - - @SubscribeEvent - fun onBackgroundDraw(event: GuiRenderEvent.ChestBackgroundRenderEvent) { - if (inInventory) { - config.skyMartCopperPricePos.renderStringsAndItems( - display, - extraSpace = 5, - itemScale = 1.7, - posLabel = "Sky Mart Copper Price" - ) - } - } - - private fun isEnabled() = GardenAPI.inGarden() && config.skyMartCopperPrice -} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/WrongFungiCutterWarning.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/WrongFungiCutterWarning.kt deleted file mode 100644 index b52603590..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/WrongFungiCutterWarning.kt +++ /dev/null @@ -1,82 +0,0 @@ -package at.hannibal2.skyhanni.features.garden - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.data.ClickType -import at.hannibal2.skyhanni.data.TitleUtils -import at.hannibal2.skyhanni.events.BlockClickEvent -import at.hannibal2.skyhanni.events.GardenToolChangeEvent -import at.hannibal2.skyhanni.events.LorenzChatEvent -import at.hannibal2.skyhanni.utils.ItemUtils.getLore -import at.hannibal2.skyhanni.utils.SoundUtils -import net.minecraft.item.ItemStack -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent - -class WrongFungiCutterWarning { - private var mode = FungiMode.UNKNOWN - private var lastPlaySoundTime = 0L - - @SubscribeEvent - fun onChatMessage(event: LorenzChatEvent) { - val message = event.message - if (message == "§eFungi Cutter Mode: §r§cRed Mushrooms") { - mode = FungiMode.RED - } - if (message == "§eFungi Cutter Mode: §r§cBrown Mushrooms") { - mode = FungiMode.BROWN - } - } - - @SubscribeEvent - fun onBlockClick(event: BlockClickEvent) { - if (event.clickType == ClickType.LEFT_CLICK) { - val toString = event.getBlockState.toString() - if (toString == "minecraft:red_mushroom") { - if (mode == FungiMode.BROWN) { - notifyWrong() - } - } - if (toString == "minecraft:brown_mushroom") { - if (mode == FungiMode.RED) { - notifyWrong() - } - } - } - } - - private fun notifyWrong() { - if (!SkyHanniMod.feature.garden.fungiCutterWarn) return - - TitleUtils.sendTitle("§cWrong Fungi Cutter Mode!", 2_000) - if (System.currentTimeMillis() > lastPlaySoundTime + 3_00) { - lastPlaySoundTime = System.currentTimeMillis() - SoundUtils.playBeepSound() - } - } - - @SubscribeEvent - fun onGardenToolChange(event: GardenToolChangeEvent) { - if (event.crop == CropType.MUSHROOM) { - readItem(event.toolItem!!) - } else { - mode = FungiMode.UNKNOWN - } - } - - private fun readItem(item: ItemStack) { - for (line in item.getLore()) { - if (line == "§eMode: §cRed Mushrooms") { - mode = FungiMode.RED - } - - if (line == "§eMode: §cBrown Mushrooms") { - mode = FungiMode.BROWN - } - } - } - - enum class FungiMode { - RED, - BROWN, - UNKNOWN - } -} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropMoneyDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropMoneyDisplay.kt new file mode 100644 index 000000000..b8f123d43 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropMoneyDisplay.kt @@ -0,0 +1,254 @@ +package at.hannibal2.skyhanni.features.garden.farming + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.GardenToolChangeEvent +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.features.bazaar.BazaarApi +import at.hannibal2.skyhanni.features.bazaar.BazaarData +import at.hannibal2.skyhanni.features.garden.CropType +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.features.garden.GardenAPI.getSpeed +import at.hannibal2.skyhanni.features.garden.GardenNextJacobContest +import at.hannibal2.skyhanni.utils.ItemUtils.name +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList +import at.hannibal2.skyhanni.utils.LorenzUtils.sortedDesc +import at.hannibal2.skyhanni.utils.NEUItems +import at.hannibal2.skyhanni.utils.NumberUtil +import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import io.github.moulberry.notenoughupdates.NotEnoughUpdates +import kotlinx.coroutines.launch +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent + +class CropMoneyDisplay { + private var display = mutableListOf>() + private val config get() = SkyHanniMod.feature.garden + private var tick = 0 + private var loaded = false + private var ready = false + private val multipliers = mutableMapOf() + private val cropNames = mutableMapOf() // internalName -> cropName + private var hasCropInHand = false + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { + if (!isEnabled()) return + + config.moneyPerHourPos.renderStringsAndItems(display, posLabel = "Garden Crop Money Per Hour") + } + + @SubscribeEvent + fun onGardenToolChange(event: GardenToolChangeEvent) { + hasCropInHand = event.crop != null + update() + } + + @SubscribeEvent + fun onTick(event: TickEvent.ClientTickEvent) { + if (!isEnabled()) return + if (tick++ % (20 * 5) != 0) return + if (!hasCropInHand && !config.moneyPerHourAlwaysOn) return + + update() + } + + private fun update() { + init() + + display = drawDisplay() + } + + private fun drawDisplay(): MutableList> { + val newDisplay = mutableListOf>() + + val title = if (config.moneyPerHourCompact) { + "§7Money/Hour:" + } else { + "§7Money per Hour when selling:" + } + + if (!ready) { + newDisplay.addAsSingletonList(title) + newDisplay.addAsSingletonList("§eLoading...") + return newDisplay + } + + if (!hasCropInHand && !config.moneyPerHourAlwaysOn) return newDisplay + + newDisplay.addAsSingletonList(fullTitle(title)) + + if (!config.cropMilestoneProgress) { + newDisplay.addAsSingletonList("§cCrop Milestone Progress Display is disabled!") + return newDisplay + } + + val moneyPerHourData = calculateMoneyPerHour() + if (moneyPerHourData.isEmpty()) { + if (!GardenAPI.isSpeedDataEmpty()) { + val message = "money/hr empty but speed data not empty, retry" + LorenzUtils.debug(message) + println(message) + newDisplay.addAsSingletonList("§eStill Loading...") + ready = false + loaded = false + return newDisplay + } + newDisplay.addAsSingletonList("§cFarm crops to add them to this list!") + return newDisplay + } + + var number = 0 + val help = moneyPerHourData.mapValues { (_, value) -> value.max() } + for (internalName in help.sortedDesc().keys) { + number++ + val cropName = cropNames[internalName]!! + val isCurrent = cropName == GardenAPI.cropInHand + if (number > config.moneyPerHourShowOnlyBest && !isCurrent) continue + + val list = mutableListOf() + if (!config.moneyPerHourCompact) { + list.add("§7$number# ") + } + + try { + list.add(NEUItems.getItemStack(internalName)) + } catch (e: NullPointerException) { + e.printStackTrace() + } + + if (!config.moneyPerHourCompact) { + val itemName = NEUItems.getItemStack(internalName).name?.removeColor() ?: continue + val currentColor = if (isCurrent) "§e" else "§7" + val contestFormat = if (GardenNextJacobContest.isNextCrop(cropName)) "§n" else "" + list.add("$currentColor$contestFormat$itemName§7: ") + } + + val coinsColor = if (isCurrent && config.moneyPerHourCompact) "§e" else "§6" + val moneyArray = moneyPerHourData[internalName]!! + + for (price in moneyArray) { + val format = format(price) + list.add("$coinsColor$format") + list.add("§7/") + } + list.removeLast() + + newDisplay.add(list) + } + + return newDisplay + } + + private fun fullTitle(title: String): String { + val titleText: String + val nameList = mutableListOf() + if (config.moneyPerHourUseCustomFormat) { + val map = mapOf( + 0 to "Sell Offer", + 1 to "Instant Sell", + 2 to "NPC Price", + ) + val list = mutableListOf() + for (index in config.moneyPerHourCustomFormat) { + map[index]?.let { + list.add(it) + } + } + for (line in list) { + nameList.add("§e$line") + nameList.add("§7/") + } + nameList.removeLast() + titleText = nameList.joinToString("") + } else { + titleText = if (LorenzUtils.noTradeMode) "§eNPC Price" else "§eSell Offer" + } + return "$title §7($titleText§7)" + } + + private fun format(moneyPerHour: Double) = if (config.moneyPerHourCompactPrice) { + NumberUtil.format(moneyPerHour) + } else { + LorenzUtils.formatInteger(moneyPerHour.toLong()) + } + + private fun calculateMoneyPerHour(): Map> { + val moneyPerHours = mutableMapOf>() + for ((internalName, amount) in multipliers) { + val crop = cropNames[internalName]!! + val speed = crop.getSpeed() + // No speed data for item in hand + if (speed == -1) continue + + val speedPerHr = speed.toDouble() * 60 * 60 + val blocksPerHour = speedPerHr / amount.toDouble() + + val bazaarData = BazaarApi.getBazaarDataForInternalName(internalName) ?: continue + moneyPerHours[internalName] = formatNumbers(bazaarData, blocksPerHour) + } + return moneyPerHours + } + + private fun formatNumbers(bazaarData: BazaarData, blocksPerHour: Double): Array { + val npcPrice = bazaarData.npcPrice * blocksPerHour + val sellOffer = bazaarData.buyPrice * blocksPerHour + val instantSell = bazaarData.sellPrice * blocksPerHour + + return if (config.moneyPerHourUseCustomFormat) { + val map = mapOf( + 0 to sellOffer, + 1 to instantSell, + 2 to npcPrice, + ) + val newList = mutableListOf() + for (index in config.moneyPerHourCustomFormat) { + map[index]?.let { + newList.add(it) + } + } + newList.toTypedArray() + } else { + if (LorenzUtils.noTradeMode) { + arrayOf(npcPrice) + } else { + arrayOf(sellOffer) + } + } + } + + private fun init() { + if (loaded) return + + if (BazaarApi.bazaarMap.isEmpty()) { + LorenzUtils.debug("bz not ready for money/time!") + return + } + + loaded = true + + SkyHanniMod.coroutineScope.launch { + + for ((internalName, _) in NotEnoughUpdates.INSTANCE.manager.itemInformation) { + if (!BazaarApi.isBazaarItem(internalName)) continue + if (internalName == "ENCHANTED_PAPER") continue + + val (newId, amount) = NEUItems.getMultiplier(internalName) + if (amount < 10) continue + val itemName = NEUItems.getItemStack(newId).name?.removeColor() ?: continue + val crop = CropType.getByItemName(itemName) + crop?.let { + multipliers[internalName] = amount + cropNames[internalName] = it + } + } + + + ready = true + update() + } + } + + private fun isEnabled() = GardenAPI.inGarden() && config.moneyPerHourDisplay +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropSpeedMeter.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropSpeedMeter.kt new file mode 100644 index 000000000..a1551fa52 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropSpeedMeter.kt @@ -0,0 +1,143 @@ +package at.hannibal2.skyhanni.features.garden.farming + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.GardenCropMilestones.Companion.getCounter +import at.hannibal2.skyhanni.events.BlockClickEvent +import at.hannibal2.skyhanni.events.CropMilestoneUpdateEvent +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.features.garden.CropType +import at.hannibal2.skyhanni.features.garden.CropType.Companion.getCropType +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.utils.BlockUtils.isBabyCrop +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent + +class CropSpeedMeter { + private var display = listOf() + private var currentCrop: CropType? = null + private var currentBlocks = 0 + private var tick = 0 + private var snapshot = listOf() + + @SubscribeEvent + fun onBlockBreak(event: BlockClickEvent) { + if (!isEnabled()) return + if (startCrops.isEmpty()) return + + val blockState = event.getBlockState + val cropBroken = blockState.getCropType() ?: return + if (cropBroken.multiplier == 1) { + if (blockState.isBabyCrop()) return + } + + if (currentCrop != cropBroken) { + currentCrop = cropBroken + currentBlocks = 0 + snapshot = emptyList() + } + breakBlock() + } + + @SubscribeEvent + fun onTick(event: TickEvent.ClientTickEvent) { + if (!isEnabled()) return + if (tick++ % 30 != 0) return + + updateDisplay() + } + + private fun updateDisplay() { + display = renderDisplay() + } + + private fun renderDisplay(): MutableList { + val list = mutableListOf() + list.add("§7Crop Speed Meter") + if (startCrops.isEmpty()) { + list.add("§cOpen §e/cropmilestones §cto start!") + return list + } + + if (currentCrop == null) { + list.add("§cStart breaking blocks!") + return list + } + currentCrop?.let { + list.add(" §7Current ${it.cropName} counter: §e${currentBlocks.addSeparators()}") + } + + if (snapshot.isNotEmpty()) { + list += snapshot + } else { + list.add("§cOpen §e/cropmilestones §cagain to calculate!") + } + + return list + } + + @SubscribeEvent + fun onCropMilestoneUpdate(event: CropMilestoneUpdateEvent) { + if (!isEnabled()) return + val counters = mutableMapOf() + for (cropType in CropType.values()) { + counters[cropType] = cropType.getCounter() + } + if (startCrops.isEmpty()) { + startCrops = counters + currentCrop = null + snapshot = emptyList() + } else { + currentCrop?.let { + val crops = it.getCounter() - startCrops[it]!! + val blocks = currentBlocks + val cropsPerBlocks = (crops.toDouble() / blocks.toDouble()).round(3) + + val list = mutableListOf() + list.add("") + list.add("§6Calculation results") + list.add(" §7Crops collected: " + crops.addSeparators()) + list.add(" §7Blocks broken: " + blocks.addSeparators()) + list.add(" §7Crops per Block: " + cropsPerBlocks.addSeparators()) + + val baseDrops = it.baseDrops + val farmingFortune = (cropsPerBlocks * 100 / baseDrops).round(3) + + + list.add(" §7Calculated farming Fortune: §e" + farmingFortune.addSeparators()) + list.add("§cOpen /cropmilestones again to recalculate!") + + snapshot = list + updateDisplay() + } + } + } + + private fun breakBlock() { + currentBlocks++ + } + + companion object { + var enabled = false + private var startCrops = mapOf() + + fun toggle() { + enabled = !enabled + LorenzUtils.chat("§e[SkyHanni] Crop Speed Meter " + if (enabled) "§aEnabled" else "§cDisabled") + startCrops = emptyMap() + + } + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { + if (!isEnabled()) return + + SkyHanniMod.feature.garden.cropSpeedMeterPos.renderStrings(display, posLabel = "Crop Speed Meter") + } + + fun isEnabled() = enabled && GardenAPI.inGarden() +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/DicerRngDropCounter.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/DicerRngDropCounter.kt new file mode 100644 index 000000000..c190217bb --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/DicerRngDropCounter.kt @@ -0,0 +1,129 @@ +package at.hannibal2.skyhanni.features.garden.farming + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.ConfigLoadEvent +import at.hannibal2.skyhanni.events.GardenToolChangeEvent +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.features.garden.CropType +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.utils.ItemUtils.name +import at.hannibal2.skyhanni.utils.LorenzUtils.sortedDesc +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +class DicerRngDropCounter { + private var display = listOf() + private val drops = mutableMapOf>() + private val itemDrops = mutableListOf() + private val config get() = SkyHanniMod.feature.garden + + init { + drops[CropType.MELON] = mutableMapOf() + drops[CropType.PUMPKIN] = mutableMapOf() + + itemDrops.add(ItemDrop(CropType.MELON, DropRarity.UNCOMMON, "§a§lUNCOMMON DROP! §r§eDicer dropped §r§a1x §r§aEnchanted Melon§r§e!")) + itemDrops.add(ItemDrop(CropType.MELON, DropRarity.RARE, "§9§lRARE DROP! §r§eDicer dropped §r§a5x §r§aEnchanted Melon§r§e!")) + itemDrops.add(ItemDrop(CropType.MELON, DropRarity.CRAZY_RARE, "§d§lCRAZY RARE DROP! §r§eDicer dropped §r§a50x §r§aEnchanted Melon§r§e!")) + itemDrops.add(ItemDrop(CropType.MELON, DropRarity.PRAY_TO_RNGESUS, "§5§lPRAY TO RNGESUS DROP! §r§eDicer dropped §r§92x §r§9Enchanted Melon Block§r§e!")) + + itemDrops.add(ItemDrop(CropType.PUMPKIN, DropRarity.UNCOMMON, "§a§lUNCOMMON DROP! §r§eDicer dropped §r§f64x §r§fPumpkin§r§e!")) + itemDrops.add(ItemDrop(CropType.PUMPKIN, DropRarity.RARE, "§9§lRARE DROP! §r§eDicer dropped §r§a1x §r§aEnchanted Pumpkin§r§e!")) + itemDrops.add(ItemDrop(CropType.PUMPKIN, DropRarity.CRAZY_RARE, "§d§lCRAZY RARE DROP! §r§eDicer dropped §r§a10x §r§aEnchanted Pumpkin§r§e!")) + itemDrops.add(ItemDrop(CropType.PUMPKIN, DropRarity.PRAY_TO_RNGESUS, "§5§lPRAY TO RNGESUS DROP! §r§eDicer dropped §r§a64x §r§aEnchanted Pumpkin§r§e!")) + } + + enum class DropRarity(val displayName: String) { + UNCOMMON("§a§lUNCOMMON DROP"), + RARE("§9§lRARE DROP"), + CRAZY_RARE("§d§lCRAZY RARE DROP"), + PRAY_TO_RNGESUS("§5§lPRAY TO RNGESUS DROP"), + } + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled()) return + + val message = event.message + for (drop in itemDrops) { + if (message == drop.message) { + addDrop(drop.crop, drop.rarity) + saveConfig() + update() + if (config.dicerCounterHideChat) { + event.blockedReason = "dicer_rng_drop_counter" + } + return + } + } + } + + private fun update() { + display = drawDisplay() + } + + private fun drawDisplay(): List { + val help = mutableListOf() + val items = drops[cropInHand] ?: return help + help.add("§7RNG Drops for $toolName§7:") + for ((rarity, amount) in items.sortedDesc()) { + val displayName = rarity.displayName + help.add(" §7- §e${amount.addSeparators()}x $displayName") + } + + return help + } + + private var cropInHand: CropType? = null + private var toolName = "" + + @SubscribeEvent + fun onGardenToolChange(event: GardenToolChangeEvent) { + val crop = event.crop + cropInHand = if (crop == CropType.MELON || crop == CropType.PUMPKIN) crop else null + if (cropInHand != null) { + toolName = event.toolItem!!.name!! + } + update() + } + + private fun addDrop(crop: CropType, rarity: DropRarity) { + val map = drops[crop]!! + val old = map[rarity] ?: 0 + map[rarity] = old + 1 + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { + if (isEnabled()) { + config.dicerCounterPos.renderStrings(display, posLabel = "Dicer Counter") + } + } + + class ItemDrop(val crop: CropType, val rarity: DropRarity, val message: String) + + private fun saveConfig() { + val map = SkyHanniMod.feature.hidden.gardenDicerRngDrops + map.clear() + for (drop in drops) { + val crop = drop.key + for ((rarity, amount) in drop.value) { + map[crop.cropName + "." + rarity.name] = amount + } + } + } + + @SubscribeEvent + fun onConfigLoad(event: ConfigLoadEvent) { + for ((internalName, amount) in SkyHanniMod.feature.hidden.gardenDicerRngDrops) { + val split = internalName.split(".") + val crop = CropType.getByNameNoNull(split[0]) + val rarityName = split[1] + val rarity = DropRarity.valueOf(rarityName) + drops[crop]!![rarity] = amount + } + } + + fun isEnabled() = GardenAPI.inGarden() && config.dicerCounterDisplay +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/EliteFarmingWeight.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/EliteFarmingWeight.kt new file mode 100644 index 000000000..c0d2b1ee1 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/EliteFarmingWeight.kt @@ -0,0 +1,325 @@ +package at.hannibal2.skyhanni.features.garden.farming + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.HypixelData +import at.hannibal2.skyhanni.events.GardenToolChangeEvent +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.features.garden.CropType +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.features.garden.GardenAPI.getSpeed +import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings +import at.hannibal2.skyhanni.utils.TimeUtils +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import net.minecraftforge.event.world.WorldEvent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent +import java.util.* + +class EliteFarmingWeight { + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { + if (isEnabled()) { + config.eliteFarmingWeightPos.renderStrings(display, posLabel = "Elite Farming Weight") + } + } + + @SubscribeEvent + fun onGardenToolChange(event: GardenToolChangeEvent) { + // Reset speed + weightPerSecond = -1.0 + } + + @SubscribeEvent + fun onWorldChange(event: WorldEvent.Load) { + // We want to try to connect to the api again after a world switch. + apiError = false + // We ask both api endpoints after every world switch + weight = -1.0 + weightPerSecond = -1.0 + + leaderboardPosition = -1 + dirtyCropWeight = true + lastLeaderboardUpdate = 0 + nextPlayerWeight = 0.0 + nextPlayerName = "" + hasPassedNext = false + } + + var tick = 0 + + @SubscribeEvent + fun onTick(event: TickEvent.ClientTickEvent) { + if (!isEnabled()) return + if (tick++ % 5 != 0) return + update() + } + + companion object { + private val config get() = SkyHanniMod.feature.garden + private val localCounter = mutableMapOf() + + private var display = listOf() + private var profileId = "" + private var lastLeaderboardUpdate = 0L + private var apiError = false + private var leaderboardPosition = -1 + private var weight = -2.0 + private var localWeight = 0.0 + private var weightPerSecond = -1.0 + private var dirtyCropWeight = false + private var isLoadingWeight = false + private var isLoadingLeaderboard = false + + private var nextPlayerName = "" + private var nextPlayerWeight = 0.0 + private var hasPassedNext = false + + private fun update() { + if (!GardenAPI.inGarden()) return + if (apiError) { + display = listOf( + "§6Farming Weight§7: §cError!", + "§cCannot load data from Elite Farmers!", + "§eRejoin garden to try again." + ) + return + } + if (weight == -2.0) { + display = Collections.singletonList("§6Farming Weight§7: §eLoading..") + return + } + + if (weight == -1.0) { + if (!isLoadingWeight) { + val localProfile = HypixelData.profileName + if (localProfile == "") return + + isLoadingWeight = true + SkyHanniMod.coroutineScope.launch { + loadWeight(localProfile) + isLoadingWeight = false + } + } + return + } + + val weight = getWeight() + val leaderboard = getLeaderboard() + + val list = mutableListOf() + list.add("§6Farming Weight§7: $weight$leaderboard") + + if (isEtaEnabled() && (weightPerSecond != -1.0 || config.eliteFarmingWeightOvertakeETAAlways)) { + list.add(getETA()) + } + display = list + } + + private fun getLeaderboard(): String { + if (!config.eliteFarmingWeightLeaderboard) return "" + + // Fetching new leaderboard position every 10 minutes + if (System.currentTimeMillis() > lastLeaderboardUpdate + 600_000) { + if (!isLoadingLeaderboard) { + isLoadingLeaderboard = true + SkyHanniMod.coroutineScope.launch { + leaderboardPosition = loadLeaderboardPosition() + lastLeaderboardUpdate = System.currentTimeMillis() + isLoadingLeaderboard = false + } + } + } + + return if (leaderboardPosition != -1) { + val format = LorenzUtils.formatInteger(leaderboardPosition) + " §7[§b#$format§7]" + } else { + if (isLoadingLeaderboard) { + " §7[§b#?§7]" + } else "" + } + } + + private fun getWeight(): String { + if (dirtyCropWeight) { + val values = calculateCollectionWeight().values + if (values.isNotEmpty()) { + localWeight = values.sum() + dirtyCropWeight = false + } + } + + val totalWeight = (localWeight + weight) + return "§e" + LorenzUtils.formatDouble(totalWeight, 2) + } + + private fun getETA(): String { + if (weight < 0) return "" + val nextName = if (leaderboardPosition == -1) "#1000" else nextPlayerName + + val totalWeight = (localWeight + weight) + val weightUntilOvertake = nextPlayerWeight - totalWeight + if (weightUntilOvertake < 0) { + if (!hasPassedNext) { + if (weightPerSecond > 0) { + LorenzUtils.debug("weightPerSecond: '$weightPerSecond'") + LorenzUtils.chat("§e[SkyHanni] You passed §b$nextName §ein the Farming Weight Leaderboard!") + } + if (leaderboardPosition == -1) { + leaderboardPosition = 1000 + } else { + leaderboardPosition-- + } + hasPassedNext = true + } + return "§cWaiting for leaderboard update..." + } + + if (nextPlayerWeight == 0.0) { + return "§cRejoin the garden to show ETA!" + } + val timeFormat = if (weightPerSecond != -1.0) { + val timeTillOvertake = (weightUntilOvertake / weightPerSecond) * 1000 + val format = TimeUtils.formatDuration(timeTillOvertake.toLong()) + " §7(§b$format§7)" + } else "" + + val weightFormat = LorenzUtils.formatDouble(weightUntilOvertake, 2) + return "§e$weightFormat$timeFormat §7behind §b$nextName" + } + + private fun isEnabled() = GardenAPI.inGarden() && config.eliteFarmingWeightDisplay + private fun isEtaEnabled() = config.eliteFarmingWeightOvertakeETA + + fun addCrop(crop: CropType, addedCounter: Int) { + val before = getExactWeight() + localCounter[crop] = crop.getLocalCounter() + addedCounter + val after = getExactWeight() + + updateWeightPerSecond(crop, before, after, addedCounter) + + dirtyCropWeight = true + } + + private fun updateWeightPerSecond(crop: CropType, before: Double, after: Double, diff: Int) { + val speed = crop.getSpeed() + if (speed != -1) { + val weightDiff = (after - before) * 1000 + weightPerSecond = weightDiff / diff * speed / 1000 + } + } + + private fun getExactWeight(): Double { + val values = calculateCollectionWeight(false).values + return if (values.isNotEmpty()) { + values.sum() + } else 0.0 + } + + private suspend fun loadLeaderboardPosition() = try { + val uuid = LorenzUtils.getPlayerUuid() + val showNext = if (isEtaEnabled()) "?showNext=true" else "" + val url = "https://elitebot.dev/api/leaderboard/rank/weight/farming/$uuid/$profileId$showNext" + val result = withContext(Dispatchers.IO) { APIUtil.getJSONResponse(url) }.asJsonObject + + if (isEtaEnabled()) { + result["next"]?.asJsonObject?.let { + nextPlayerName = it["ign"].asString + nextPlayerWeight = it["amount"].asDouble + } + } + + result["rank"].asInt + } catch (e: Exception) { + error() + e.printStackTrace() + -1 + } + + private suspend fun loadWeight(localProfile: String) { + val uuid = LorenzUtils.getPlayerUuid() + val url = "https://elitebot.dev/api/weight/$uuid" + + try { + val result = withContext(Dispatchers.IO) { APIUtil.getJSONResponse(url) }.asJsonObject + for (profileEntry in result["profiles"].asJsonObject.entrySet()) { + val profile = profileEntry.value.asJsonObject + val profileName = profile["cute_name"].asString.lowercase() + if (profileName == localProfile) { + profileId = profileEntry.key + weight = profile["farming"].asJsonObject["total"].asDouble + + localCounter.clear() + dirtyCropWeight = true + + return + } + } + println("localProfile: '$localProfile'") + println("url: '$url'") + println("result: '$result'") + } catch (e: Exception) { + println("url: '$url'") + e.printStackTrace() + } + error() + } + + private fun error() { + apiError = true + LorenzUtils.error("[SkyHanni] Loading the farming weight data from elitebot.dev failed!") + LorenzUtils.chat("§eYou can re-enter the garden to try to fix the problem. If this message repeats itself, please report it on Discord!") + } + + private fun calculateCollectionWeight(round: Boolean = true): MutableMap { + val weightPerCrop = mutableMapOf() + var totalWeight = 0.0 + for (crop in CropType.values()) { + val weight = crop.getLocalCounter() / crop.getFactor() + val roundedWeight = weight.let { if (round) it.round(2) else it } + weightPerCrop[crop] = roundedWeight + totalWeight += roundedWeight + } + if (totalWeight > 0) { + weightPerCrop[CropType.MUSHROOM] = specialMushroomWeight(weightPerCrop, totalWeight) + } + return weightPerCrop + } + + private fun specialMushroomWeight(weightPerCrop: MutableMap, totalWeight: Double): Double { + val cactusWeight = weightPerCrop[CropType.CACTUS]!! + val sugarCaneWeight = weightPerCrop[CropType.SUGAR_CANE]!! + val doubleBreakRatio = (cactusWeight + sugarCaneWeight) / totalWeight; + val normalRatio = (totalWeight - cactusWeight - sugarCaneWeight) / totalWeight; + + val mushroomFactor = CropType.MUSHROOM.getFactor() + val mushroomCollection = CropType.MUSHROOM.getLocalCounter() + return doubleBreakRatio * (mushroomCollection / (2 * mushroomFactor)) + normalRatio * (mushroomCollection / mushroomFactor) + } + + private fun CropType.getLocalCounter() = localCounter[this] ?: 0L + + private fun CropType.getFactor() = factorPerCrop[this]!! + + private val factorPerCrop by lazy { + mapOf( + CropType.WHEAT to 100_000.0, + CropType.CARROT to 300_000.0, + CropType.POTATO to 300_000.0, + CropType.SUGAR_CANE to 200_000.0, + CropType.NETHER_WART to 250_000.0, + CropType.PUMPKIN to 90_066.27, + CropType.MELON to 450_324.6, + CropType.MUSHROOM to 90_178.06, + CropType.COCOA_BEANS to 267_174.04, + CropType.CACTUS to 177_254.45, + ) + } + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingArmorDrops.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingArmorDrops.kt new file mode 100644 index 000000000..80b922af2 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingArmorDrops.kt @@ -0,0 +1,108 @@ +package at.hannibal2.skyhanni.features.garden.farming + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.ConfigLoadEvent +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName +import at.hannibal2.skyhanni.utils.LorenzUtils.sortedDesc +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent +import java.util.regex.Pattern + +class FarmingArmorDrops { + private var display = listOf() + private val drops = mutableMapOf() + private var hasArmor = false + private var tick = 0 + private val armorPattern = Pattern.compile("(FERMENTO|CROPIE|SQUASH|MELON)_(LEGGINGS|CHESTPLATE|BOOTS|HELMET)") + private val config get() = SkyHanniMod.feature.garden + + enum class ArmorDropType(val dropName: String, val chatMessage: String) { + CROPIE("§9Cropie", "§6§lRARE CROP! §r§f§r§9Cropie §r§b(Armor Set Bonus)"), + SQUASH("§5Squash", "§6§lRARE CROP! §r§f§r§5Squash §r§b(Armor Set Bonus)"), + FERMENTO("§6Fermento", "§6§lRARE CROP! §r§f§r§6Fermento §r§b(Armor Set Bonus)"), + } + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + for (dropType in ArmorDropType.values()) { + if (dropType.chatMessage == event.message) { + addDrop(dropType) + if (config.farmingArmorDropsEnabled && config.farmingArmorDropsHideChat) { + event.blockedReason = "farming_armor_drops" + } + } + } + } + + private fun addDrop(drop: ArmorDropType) { + val old = drops[drop] ?: 0 + drops[drop] = old + 1 + saveConfig() + update() + } + + private fun update() { + display = drawDisplay() + } + + private fun drawDisplay(): List { + val help = mutableListOf() + help.add("§7RNG Drops for Farming Armor:") + for ((drop, amount) in drops.sortedDesc()) { + val dropName = drop.dropName + help.add(" §7- §e${amount.addSeparators()}x $dropName") + } + + return help + } + + private fun saveConfig() { + val map = SkyHanniMod.feature.hidden.gardenFarmingArmorDrops + map.clear() + for ((drop, amount) in drops) { + map[drop.toString()] = amount + } + } + + @SubscribeEvent + fun onConfigLoad(event: ConfigLoadEvent) { + for ((rawName, amount) in SkyHanniMod.feature.hidden.gardenFarmingArmorDrops) { + drops[ArmorDropType.valueOf(rawName)] = amount + } + update() + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { + if (!GardenAPI.inGarden()) return + if (!config.farmingArmorDropsEnabled) return + if (!hasArmor) return + + config.farmingArmorDropsPos.renderStrings(display, posLabel = "Farming Armor Drops") + } + + @SubscribeEvent + fun onTick(event: TickEvent.ClientTickEvent) { + if (event.phase != TickEvent.Phase.START) return + if (!GardenAPI.inGarden()) return + if (!config.farmingArmorDropsEnabled) return + + tick++ + if (tick % 30 == 0) { + checkArmor() + } + } + + private fun checkArmor() { + val armorPieces = InventoryUtils.getArmor() + .mapNotNull { it?.getInternalName() } + .count { armorPattern.matcher(it).matches() } + hasArmor = armorPieces > 1 + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenBestCropTime.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenBestCropTime.kt new file mode 100644 index 000000000..b68a89de2 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenBestCropTime.kt @@ -0,0 +1,108 @@ +package at.hannibal2.skyhanni.features.garden.farming + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.GardenCropMilestones +import at.hannibal2.skyhanni.data.GardenCropMilestones.Companion.getCounter +import at.hannibal2.skyhanni.features.garden.CropType +import at.hannibal2.skyhanni.features.garden.GardenAPI.addCropIcon +import at.hannibal2.skyhanni.features.garden.GardenAPI.getSpeed +import at.hannibal2.skyhanni.features.garden.GardenNextJacobContest +import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList +import at.hannibal2.skyhanni.utils.LorenzUtils.sorted +import at.hannibal2.skyhanni.utils.TimeUtils + +class GardenBestCropTime { + var display = listOf>() + val timeTillNextCrop = mutableMapOf() + private val config get() = SkyHanniMod.feature.garden + + fun drawBestDisplay(currentCrop: CropType?): List> { + val newList = mutableListOf>() + if (timeTillNextCrop.size < CropType.values().size) { + updateTimeTillNextCrop() + } + + val gardenExp = config.cropMilestoneBestType == 0 + val sorted = if (gardenExp) { + val helpMap = mutableMapOf() + for ((cropName, time) in timeTillNextCrop) { + val currentTier = GardenCropMilestones.getTierForCrops(cropName.getCounter()) + val gardenExpForTier = getGardenExpForTier(currentTier + 1) + val fakeTime = time / gardenExpForTier + helpMap[cropName] = fakeTime + } + helpMap.sorted() + } else { + timeTillNextCrop.sorted() + } + + val title = if (gardenExp) "§2Garden Experience" else "§bSkyBlock Level" + if (config.cropMilestoneBestCompact) { + newList.addAsSingletonList("§eBest Crop Time") + } else { + newList.addAsSingletonList("§eBest Crop Time §7($title§7)") + } + + if (!config.cropMilestoneProgress) { + newList.addAsSingletonList("§cCrop Milestone Progress Display is disabled!") + return newList + } + + if (sorted.isEmpty()) { + newList.addAsSingletonList("§cFarm crops to add them to this list!") + return newList + } + + var number = 0 + for (crop in sorted.keys) { + val millis = timeTillNextCrop[crop]!! + val duration = TimeUtils.formatDuration(millis, maxUnits = 2) + val isCurrent = crop == currentCrop + number++ + if (number > config.cropMilestoneShowOnlyBest && !isCurrent) continue + + val list = mutableListOf() + list.add("§7$number# ") + list.addCropIcon(crop) + + val color = if (isCurrent) "§e" else "§7" + val contestFormat = if (GardenNextJacobContest.isNextCrop(crop)) "§n" else "" + val nextTier = GardenCropMilestones.getTierForCrops(crop.getCounter()) + 1 + + val cropName = if (!config.cropMilestoneBestCompact) crop.cropName + " " else "" + val cropNameDisplay = "$color$contestFormat$cropName$nextTier§r" + list.add("$cropNameDisplay §b$duration") + + if (gardenExp && !config.cropMilestoneBestCompact) { + val gardenExpForTier = getGardenExpForTier(nextTier) + list.add(" §7(§2$gardenExpForTier §7Exp)") + } + newList.add(list) + } + return newList + } + + private fun getGardenExpForTier(gardenLevel: Int) = if (gardenLevel > 30) 300 else gardenLevel * 10 + + fun updateTimeTillNextCrop() { + for (crop in CropType.values()) { + val speed = crop.getSpeed() + if (speed == -1) continue + + val counter = crop.getCounter() + val currentTier = GardenCropMilestones.getTierForCrops(counter) + + val cropsForCurrentTier = GardenCropMilestones.getCropsForTier(currentTier) + val nextTier = currentTier + 1 + val cropsForNextTier = GardenCropMilestones.getCropsForTier(nextTier) + + val have = counter - cropsForCurrentTier + val need = cropsForNextTier - cropsForCurrentTier + + val missing = need - have + val missingTimeSeconds = missing / speed + val millis = missingTimeSeconds * 1000 + timeTillNextCrop[crop] = millis + } + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt new file mode 100644 index 000000000..92b27e094 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt @@ -0,0 +1,387 @@ +package at.hannibal2.skyhanni.features.garden.farming + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.ClickType +import at.hannibal2.skyhanni.data.GardenCropMilestones +import at.hannibal2.skyhanni.data.GardenCropMilestones.Companion.getCounter +import at.hannibal2.skyhanni.data.GardenCropMilestones.Companion.setCounter +import at.hannibal2.skyhanni.data.MayorElectionData +import at.hannibal2.skyhanni.data.TitleUtils +import at.hannibal2.skyhanni.events.* +import at.hannibal2.skyhanni.features.garden.CropType +import at.hannibal2.skyhanni.features.garden.CropType.Companion.getCropType +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.features.garden.GardenAPI.addCropIcon +import at.hannibal2.skyhanni.features.garden.GardenAPI.getCropType +import at.hannibal2.skyhanni.features.garden.GardenAPI.setSpeed +import at.hannibal2.skyhanni.utils.BlockUtils.isBabyCrop +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList +import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems +import at.hannibal2.skyhanni.utils.SoundUtils +import at.hannibal2.skyhanni.utils.TimeUtils +import net.minecraft.item.ItemStack +import net.minecraftforge.fml.common.eventhandler.EventPriority +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.* +import kotlin.concurrent.fixedRateTimer + +class GardenCropMilestoneDisplay { + private var progressDisplay = listOf>() + private var mushroomCowPerkDisplay = listOf>() + private val cultivatingData = mutableMapOf() + private val config get() = SkyHanniMod.feature.garden + private val bestCropTime = GardenBestCropTime() +// val cropMilestoneLevelUpPattern = Pattern.compile(" §r§b§lGARDEN MILESTONE §3(.*) §8XXIII➜§3(.*)") + + private var lastPlaySoundTime = 0L + + private var needsInventory = false + + private var mushroom_cow_nether_warts = true + + @SubscribeEvent + fun onRepoReload(event: RepositoryReloadEvent) { + try { + val constant = event.getConstant("DisabledFeatures") + mushroom_cow_nether_warts = if (constant != null) { + if (constant.has("mushroom_cow_nether_warts")) { + constant["mushroom_cow_nether_warts"].asBoolean + } else false + } else false + } catch (e: Exception) { + e.printStackTrace() + } + } + + @SubscribeEvent + fun onChatMessage(event: LorenzChatEvent) { + if (!isEnabled()) return + // TODO remove this once hypixel counts 64x pumpkin drops to cultivating + if (event.message == "§a§lUNCOMMON DROP! §r§eDicer dropped §r§f64x §r§fPumpkin§r§e!") { + CropType.PUMPKIN.setCounter(CropType.PUMPKIN.getCounter() + 64) + } +// if (config.cropMilestoneWarnClose) { +// val matcher = cropMilestoneLevelUpPattern.matcher(event.message) +// if (matcher.matches()) { +// val cropType = matcher.group(1) +// val newLevel = matcher.group(2).romanToDecimalIfNeeded() +// LorenzUtils.debug("found milestone messsage!") +// SendTitleHelper.sendTitle("§b$cropType $newLevel", 1_500) +// } +// } + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { + if (!isEnabled()) return + + config.cropMilestoneProgressDisplayPos.renderStringsAndItems( + progressDisplay, + posLabel = "Crop Milestone Progress" + ) + + if (config.cropMilestoneMushroomPetPerkEnabled) { + config.cropMilestoneMushroomPetPerkPos.renderStringsAndItems( + mushroomCowPerkDisplay, + posLabel = "Mushroom Cow Perk" + ) + } + + if (config.cropMilestoneBestDisplay) { + config.cropMilestoneNextDisplayPos.renderStringsAndItems(bestCropTime.display, posLabel = "Best Crop Time") + } + } + + @SubscribeEvent(priority = EventPriority.LOW) + fun onProfileJoin(event: ProfileJoinEvent) { + if (GardenCropMilestones.cropCounter.values.sum() == 0L) { + needsInventory = true + } + } + + @SubscribeEvent + fun onCropMilestoneUpdate(event: CropMilestoneUpdateEvent) { + needsInventory = false + bestCropTime.updateTimeTillNextCrop() + update() + } + + @SubscribeEvent + fun onOwnInventoryItemUpdate(event: OwnInventorItemUpdateEvent) { + if (!GardenAPI.inGarden()) return + + try { + val item = event.itemStack + val counter = GardenAPI.readCounter(item) + if (counter == -1) return + val crop = item.getCropType() ?: return + if (cultivatingData.containsKey(crop)) { + val old = cultivatingData[crop]!! + val addedCounter = counter - old + + if (GardenCropMilestones.cropCounter.isEmpty()) { + for (innerCrop in CropType.values()) { + innerCrop.setCounter(0) + } + } + if (GardenAPI.isSpeedDataEmpty()) { + for (cropType in CropType.values()) { + cropType.setSpeed(-1) + } + } + if (!finneganPerkActive()) { + crop.setCounter(crop.getCounter() + addedCounter) + } + EliteFarmingWeight.addCrop(crop, addedCounter) + if (currentCrop == crop) { + calculateSpeed(addedCounter) + update() + } + } + cultivatingData[crop] = counter + } catch (e: Throwable) { + LorenzUtils.error("[SkyHanni] Error in OwnInventorItemUpdateEvent") + e.printStackTrace() + } + } + + private fun finneganPerkActive(): Boolean { + val forcefullyEnabledAlwaysFinnegan = config.forcefullyEnabledAlwaysFinnegan + val perkActive = MayorElectionData.isPerkActive("Finnegan", "Farming Simulator") + MayorElectionData.currentCandidate?.let { + + } + return forcefullyEnabledAlwaysFinnegan || perkActive + } + + @SubscribeEvent + fun onBlockClick(event: BlockClickEvent) { + if (!isEnabled()) return + if (event.clickType != ClickType.LEFT_CLICK) return + + val blockState = event.getBlockState + + val cropType = blockState.getCropType() ?: return + val multiplier = cropType.multiplier + if (multiplier == 1) { + if (blockState.isBabyCrop()) return + } + blocksBroken += multiplier + } + + private var currentSpeed = 0 + private var averageSpeedPerSecond = 0 + private var countInLastSecond = 0 + private val allCounters = mutableListOf() + private var lastItemInHand: ItemStack? = null + private var currentCrop: CropType? = null + private var blocksBroken = 0 + private var lastBlocksPerSecond = 0 + + private fun resetSpeed() { + currentSpeed = 0 + averageSpeedPerSecond = 0 + countInLastSecond = 0 + allCounters.clear() + } + + init { + fixedRateTimer(name = "skyhanni-crop-milestone-speed", period = 1000L) { + if (GardenAPI.inGarden() && GardenAPI.mushroomCowPet) { + CropType.MUSHROOM.setCounter(CropType.MUSHROOM.getCounter() + blocksBroken) + update() + } + if (isEnabled()) { + checkSpeed() + } + } + } + + private fun checkSpeed() { + if (finneganPerkActive()) { + currentSpeed = (currentSpeed.toDouble() * 0.8).toInt() + } + + if (countInLastSecond > 8) { + allCounters.add(currentSpeed) + while (allCounters.size > 30) { + allCounters.removeFirst() + } + averageSpeedPerSecond = allCounters.average().toInt() + } + countInLastSecond = 0 + + if (finneganPerkActive()) { + currentCrop?.let { + it.setCounter(it.getCounter() + currentSpeed) + } + } + currentSpeed = 0 + + lastBlocksPerSecond = blocksBroken + blocksBroken = 0 + } + + + private fun calculateSpeed(addedCounter: Int) { + currentSpeed += addedCounter + countInLastSecond++ + } + + @SubscribeEvent + fun onGardenToolChange(event: GardenToolChangeEvent) { + lastItemInHand = event.toolItem + currentCrop = event.crop + + if (isEnabled()) { + resetSpeed() + update() + } + } + + private fun update() { + progressDisplay = emptyList() + mushroomCowPerkDisplay = emptyList() + bestCropTime.display = emptyList() + currentCrop?.let { + progressDisplay = drawProgressDisplay(it, it.getCounter()) + if (config.cropMilestoneBestDisplay) { + bestCropTime.display = bestCropTime.drawBestDisplay(it) + } + } + if (config.cropMilestoneBestAlwaysOn) { + if (currentCrop == null) { + bestCropTime.display = bestCropTime.drawBestDisplay(null) + } + } + } + + private fun drawProgressDisplay(crop: CropType, counter: Long): MutableList> { + val lineMap = HashMap>() + lineMap[0] = Collections.singletonList("§6Crop Milestones") + + val currentTier = GardenCropMilestones.getTierForCrops(counter) + val nextTier = currentTier + 1 + + val list = mutableListOf() + list.addCropIcon(crop) + list.add("§7" + crop.cropName + " Tier $nextTier") + lineMap[1] = list + + val cropsForCurrentTier = GardenCropMilestones.getCropsForTier(currentTier) + val cropsForNextTier = GardenCropMilestones.getCropsForTier(nextTier) + + val have = counter - cropsForCurrentTier + val need = cropsForNextTier - cropsForCurrentTier + + val haveFormat = LorenzUtils.formatInteger(have) + val needFormat = LorenzUtils.formatInteger(need) + lineMap[2] = Collections.singletonList("§e$haveFormat§8/§e$needFormat") + + lastItemInHand?.let { + if (GardenAPI.readCounter(it) == -1) { + lineMap[3] = Collections.singletonList("§cWarning: You need Cultivating!") + return formatDisplay(lineMap) + } + } + + if (averageSpeedPerSecond != 0) { + crop.setSpeed(averageSpeedPerSecond) + val missing = need - have + val missingTimeSeconds = missing / averageSpeedPerSecond + val millis = missingTimeSeconds * 1000 + bestCropTime.timeTillNextCrop[crop] = millis + val duration = TimeUtils.formatDuration(millis) + if (config.cropMilestoneWarnClose) { + if (millis < 5_900) { + if (System.currentTimeMillis() > lastPlaySoundTime + 1_000) { + lastPlaySoundTime = System.currentTimeMillis() + SoundUtils.playBeepSound() + } + TitleUtils.sendTitle("§b${crop.cropName} $nextTier in $duration", 1_500) + } + } + lineMap[3] = Collections.singletonList("§7In §b$duration") + + val format = LorenzUtils.formatInteger(averageSpeedPerSecond * 60) + lineMap[4] = Collections.singletonList("§7Crops/Minute§8: §e$format") + lineMap[5] = Collections.singletonList("§7Blocks/Second§8: §e$lastBlocksPerSecond") + } + + if (GardenAPI.mushroomCowPet && crop != CropType.MUSHROOM) { + if (mushroom_cow_nether_warts && crop == CropType.NETHER_WART) { + mushroomCowPerkDisplay = listOf( + listOf("§6Mooshroom Cow Perk"), + listOf("§cNether Warts don't give mushrooms."), + listOf("§7(Hypixel please fix this)") + ) + } else { + addMushroomCowData() + } + } + + return formatDisplay(lineMap) + } + + private fun formatDisplay(lineMap: HashMap>): MutableList> { + val newList = mutableListOf>() + for (index in config.cropMilestoneText) { + lineMap[index]?.let { + newList.add(it) + } + } + + if (needsInventory) { + newList.addAsSingletonList("§cOpen §e/cropmilestones §cto update!") + } + + return newList + } + + private fun addMushroomCowData() { + val lineMap = HashMap>() + val counter = CropType.MUSHROOM.getCounter() + + val currentTier = GardenCropMilestones.getTierForCrops(counter) + val nextTier = currentTier + 1 + + val cropsForCurrentTier = GardenCropMilestones.getCropsForTier(currentTier) + val cropsForNextTier = GardenCropMilestones.getCropsForTier(nextTier) + + val have = counter - cropsForCurrentTier + val need = cropsForNextTier - cropsForCurrentTier + + val haveFormat = LorenzUtils.formatInteger(have) + val needFormat = LorenzUtils.formatInteger(need) + + val missing = need - have + + // We assume perfect 20 blocks per seconds + val blocksPerSecond = 20 * (currentCrop?.multiplier ?: 1) + + val missingTimeSeconds = missing / blocksPerSecond + val millis = missingTimeSeconds * 1000 + val duration = TimeUtils.formatDuration(millis) + + lineMap[0] = Collections.singletonList("§6Mooshroom Cow Perk") + + val list = mutableListOf() + list.addCropIcon(CropType.MUSHROOM) + list.add("§7Mushroom Tier $nextTier") + lineMap[1] = list + + lineMap[2] = Collections.singletonList("§e$haveFormat§8/§e$needFormat") + lineMap[3] = Collections.singletonList("§7In §b$duration") + + val newList = mutableListOf>() + for (index in config.cropMilestoneMushroomPetPerkText) { + lineMap[index]?.let { + newList.add(it) + } + } + mushroomCowPerkDisplay = newList + } + + private fun isEnabled() = GardenAPI.inGarden() && config.cropMilestoneProgress +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCustomKeybinds.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCustomKeybinds.kt new file mode 100644 index 000000000..73a336eaa --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCustomKeybinds.kt @@ -0,0 +1,108 @@ +package at.hannibal2.skyhanni.features.garden.farming + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.features.Garden +import at.hannibal2.skyhanni.events.GardenToolChangeEvent +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.mixins.transformers.AccessorKeyBinding +import io.github.moulberry.moulconfig.internal.KeybindHelper +import net.minecraft.client.Minecraft +import net.minecraft.client.settings.KeyBinding +import net.minecraftforge.event.world.WorldEvent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +class GardenCustomKeybinds { + private val shConfig: Garden get() = SkyHanniMod.feature.garden + private val mcSettings get() = Minecraft.getMinecraft().gameSettings + + private val cache = mutableMapOf() + private val map = mutableMapOf Int>() + + init { + map[mcSettings.keyBindAttack] = { shConfig.keyBindAttack } + map[mcSettings.keyBindLeft] = { shConfig.keyBindLeft } + map[mcSettings.keyBindRight] = { shConfig.keyBindRight } + map[mcSettings.keyBindForward] = { shConfig.keyBindForward } + map[mcSettings.keyBindBack] = { shConfig.keyBindBack } + map[mcSettings.keyBindJump] = { shConfig.keyBindJump } + map[mcSettings.keyBindSneak] = { shConfig.keyBindSneak } + + Runtime.getRuntime().addShutdownHook(Thread { reset() }) + } + + @SubscribeEvent + fun onGardenToolChange(event: GardenToolChangeEvent) { + update() + } + + private fun update() { + if (isEnabled() && GardenAPI.toolInHand != null) { + applyCustomKeybinds() + } else { + reset() + } + } + + @SubscribeEvent + fun onWorldChange(event: WorldEvent.Load) { + reset() + } + + private fun applyCustomKeybinds() { + val alreadyBoundedKeys = mutableListOf() + var counter = 0 + for ((mcBinding, skyHanniBinding) in map) { + val newKeyCode = skyHanniBinding() + if (newKeyCode == mcBinding.keyCode) continue + + disableAlreadyExistingKeybinds(newKeyCode, alreadyBoundedKeys) + + if (!cache.containsKey(mcBinding)) { + cache[mcBinding] = mcBinding.keyCode + mcBinding.unpressKeyIfDown() + } + + mcBinding.keyCode = newKeyCode + alreadyBoundedKeys.add(mcBinding.keyCodeDefault) + counter++ + } + + if (counter > 0) { + KeyBinding.resetKeyBindingArrayAndHash() + } + } + + private fun disableAlreadyExistingKeybinds(newKeyCode: Int, alreadyBoundedKeys: MutableList) { + if (newKeyCode == 0) return + for (keyBinding in mcSettings.keyBindings) { + if (keyBinding.keyCode != newKeyCode) continue + if (alreadyBoundedKeys.contains(keyBinding.keyCodeDefault)) continue + keyBinding.unpressKeyIfDown() + cache[keyBinding] = keyBinding.keyCode + keyBinding.keyCode = 0 + } + } + + private fun reset() { + var counter = 0 + for ((key, keyCode) in cache) { + if (key.keyCode != keyCode) { + key.unpressKeyIfDown() + counter++ + key.keyCode = keyCode + } + } + cache.clear() + if (counter > 0) { + KeyBinding.resetKeyBindingArrayAndHash() + } + } + + private fun KeyBinding.unpressKeyIfDown() { + if (KeybindHelper.isKeyDown(keyCode)) { + (this as AccessorKeyBinding).skyhanni_unpressKey() + } + } + + private fun isEnabled() = GardenAPI.inGarden() && shConfig.keyBindEnabled +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/WrongFungiCutterWarning.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/WrongFungiCutterWarning.kt new file mode 100644 index 000000000..3aa4da422 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/WrongFungiCutterWarning.kt @@ -0,0 +1,83 @@ +package at.hannibal2.skyhanni.features.garden.farming + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.ClickType +import at.hannibal2.skyhanni.data.TitleUtils +import at.hannibal2.skyhanni.events.BlockClickEvent +import at.hannibal2.skyhanni.events.GardenToolChangeEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.features.garden.CropType +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.SoundUtils +import net.minecraft.item.ItemStack +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +class WrongFungiCutterWarning { + private var mode = FungiMode.UNKNOWN + private var lastPlaySoundTime = 0L + + @SubscribeEvent + fun onChatMessage(event: LorenzChatEvent) { + val message = event.message + if (message == "§eFungi Cutter Mode: §r§cRed Mushrooms") { + mode = FungiMode.RED + } + if (message == "§eFungi Cutter Mode: §r§cBrown Mushrooms") { + mode = FungiMode.BROWN + } + } + + @SubscribeEvent + fun onBlockClick(event: BlockClickEvent) { + if (event.clickType == ClickType.LEFT_CLICK) { + val toString = event.getBlockState.toString() + if (toString == "minecraft:red_mushroom") { + if (mode == FungiMode.BROWN) { + notifyWrong() + } + } + if (toString == "minecraft:brown_mushroom") { + if (mode == FungiMode.RED) { + notifyWrong() + } + } + } + } + + private fun notifyWrong() { + if (!SkyHanniMod.feature.garden.fungiCutterWarn) return + + TitleUtils.sendTitle("§cWrong Fungi Cutter Mode!", 2_000) + if (System.currentTimeMillis() > lastPlaySoundTime + 3_00) { + lastPlaySoundTime = System.currentTimeMillis() + SoundUtils.playBeepSound() + } + } + + @SubscribeEvent + fun onGardenToolChange(event: GardenToolChangeEvent) { + if (event.crop == CropType.MUSHROOM) { + readItem(event.toolItem!!) + } else { + mode = FungiMode.UNKNOWN + } + } + + private fun readItem(item: ItemStack) { + for (line in item.getLore()) { + if (line == "§eMode: §cRed Mushrooms") { + mode = FungiMode.RED + } + + if (line == "§eMode: §cBrown Mushrooms") { + mode = FungiMode.BROWN + } + } + } + + enum class FungiMode { + RED, + BROWN, + UNKNOWN + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenDeskInSBMenu.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenDeskInSBMenu.kt new file mode 100644 index 000000000..2ef7e5378 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenDeskInSBMenu.kt @@ -0,0 +1,52 @@ +package at.hannibal2.skyhanni.features.garden.inventory + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.events.InventoryOpenEvent +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.utils.NEUItems +import io.github.moulberry.notenoughupdates.events.ReplaceItemEvent +import io.github.moulberry.notenoughupdates.events.SlotClickEvent +import io.github.moulberry.notenoughupdates.util.Utils +import net.minecraft.client.Minecraft +import net.minecraft.client.player.inventory.ContainerLocalMenu +import net.minecraftforge.fml.common.eventhandler.EventPriority +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +class GardenDeskInSBMenu { + + private val config get() = SkyHanniMod.feature.garden + private var showItem = false + + private val item by lazy { + val neuItem = NEUItems.getItemStack("DOUBLE_PLANT") + Utils.createItemStack(neuItem.item, "§bDesk", "§7Click here to", "§7run §e/desk") + } + + + @SubscribeEvent + fun onInventoryOpen(event: InventoryOpenEvent) { + showItem = GardenAPI.inGarden() && config.deskInSkyBlockMenu && event.inventoryName == "SkyBlock Menu" + } + + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + showItem = false + } + + @SubscribeEvent + fun replaceItem(event: ReplaceItemEvent) { + if (event.inventory is ContainerLocalMenu && showItem && event.slotNumber == 10) { + event.replaceWith(item) + } + } + + @SubscribeEvent(priority = EventPriority.HIGH) + fun onStackClick(event: SlotClickEvent) { + if (showItem && event.slotId == 10) { + event.isCanceled = true + val thePlayer = Minecraft.getMinecraft().thePlayer + thePlayer.sendChatMessage("/desk") + } + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryNumbers.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryNumbers.kt new file mode 100644 index 000000000..a68838876 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenInventoryNumbers.kt @@ -0,0 +1,54 @@ +package at.hannibal2.skyhanni.features.garden.inventory + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.model.ComposterUpgrade +import at.hannibal2.skyhanni.events.RenderItemTipEvent +import at.hannibal2.skyhanni.features.garden.GardenAPI +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.NumberUtil.romanToDecimalIfNeeded +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.regex.Pattern + +class GardenInventoryNumbers { + private var patternTierProgress = Pattern.compile("§7Progress to Tier (.*): §e(?:.*)") + private var patternUpgradeTier = Pattern.compile("§7Current Tier: §[ea](.*)§7/§a.*") + + @SubscribeEvent + fun onRenderItemTip(event: RenderItemTipEvent) { + if (!GardenAPI.inGarden()) return + + if (InventoryUtils.openInventoryName() == "Crop Milestones") { + if (!SkyHanniMod.feature.garden.numberCropMilestone) return + + event.stack.getLore() + .map { patternTierProgress.matcher(it) } + .filter { it.matches() } + .map { it.group(1).romanToDecimalIfNeeded() - 1 } + .forEach { event.stackTip = "" + it } + } + + if (InventoryUtils.openInventoryName() == "Crop Upgrades") { + if (!SkyHanniMod.feature.garden.numberCropUpgrades) return + + event.stack.getLore() + .map { patternUpgradeTier.matcher(it) } + .filter { it.matches() } + .map { it.group(1) } + .forEach { event.stackTip = "" + it } + } + + if (InventoryUtils.openInventoryName() == "Composter Upgrades") { + if (!SkyHanniMod.feature.garden.numberComposterUpgrades) return + + event.stack.name?.let { + val matcher = ComposterUpgrade.regex.matcher(it) + if (matcher.matches()) { + val level = matcher.group("level")?.romanToDecimalIfNeeded() ?: 0 + event.stackTip = "$level" + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenNextPlotPrice.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenNextPlotPrice.kt new file mode 100644 index 000000000..e97da2f38 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenNextPlotPrice.kt @@ -0,0 +1,47 @@ +package at.hannibal2.skyhanni.features.garden.inventory + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.utils.* +import at.hannibal2.skyhanni.utils.ItemUtils.name +import net.minecraftforge.event.entity.player.ItemTooltipEvent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +class GardenNextPlotPrice { + + @SubscribeEvent + fun onTooltip(event: ItemTooltipEvent) { + if (!GardenAPI.inGarden()) return + if (!SkyHanniMod.feature.garden.plotPrice) return + + if (InventoryUtils.openInventoryName() != "Configure Plots") return + + val name = event.itemStack.name ?: return + if (!name.startsWith("§ePlot")) return + + var next = false + val list = event.toolTip + var i = -1 + for (l in list) { + i++ + val line = l.substring(4) + if (line.contains("Cost")) { + next = true + continue + } + + if (next) { + val (itemName, amount) = ItemUtils.readItemAmount(line) + if (itemName != null) { + val lowestBin = NEUItems.getPrice(NEUItems.getInternalName(itemName)) + val price = lowestBin * amount + val format = NumberUtil.format(price) + list[i] = list[i] + " §7(§6$format§7)" + } else { + LorenzUtils.error("§c[SkyHanni] Could not read item '$line'") + } + break + } + } + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/SkyMartCopperPrice.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/SkyMartCopperPrice.kt new file mode 100644 index 000000000..946d40884 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/SkyMartCopperPrice.kt @@ -0,0 +1,87 @@ +package at.hannibal2.skyhanni.features.garden.inventory + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.events.InventoryOpenEvent +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName +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.LorenzUtils.addAsSingletonList +import at.hannibal2.skyhanni.utils.NEUItems +import at.hannibal2.skyhanni.utils.NumberUtil +import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.regex.Pattern + +class SkyMartCopperPrice { + private val pattern = Pattern.compile("§c(.*) Copper") + private var display = listOf>() + private val config get() = SkyHanniMod.feature.garden + + companion object { + var inInventory = false + } + + @SubscribeEvent + fun onInventoryOpen(event: InventoryOpenEvent) { + if (!isEnabled()) return + if (event.inventoryName != "SkyMart") return + + inInventory = true + val table = mutableMapOf, Pair>() + for (stack in event.inventoryItems.values) { + for (line in stack.getLore()) { + val matcher = pattern.matcher(line) + if (!matcher.matches()) continue + + val internalName = stack.getInternalName() + val lowestBin = NEUItems.getPrice(internalName) + if (lowestBin == -1.0) continue + + val amount = matcher.group(1).replace(",", "").toInt() + val factor = lowestBin / amount + val perFormat = NumberUtil.format(factor) + val priceFormat = NumberUtil.format(lowestBin) + val amountFormat = NumberUtil.format(amount) + + var name = stack.name!! + if (name == "§fEnchanted Book") { + name = stack.getLore()[0] + } + + val advancedStats = if (config.skyMartCopperPriceAdvancedStats) { + " §7(§6$priceFormat §7/ §c$amountFormat Copper§7)" + } else "" + val pair = Pair("$name§f:", "§6§l$perFormat$advancedStats") + table[pair] = Pair(factor, internalName) + } + } + + val newList = mutableListOf>() + newList.addAsSingletonList("§eCoins per Copper§f:") + LorenzUtils.fillTable(newList, table) + display = newList + } + + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + inInventory = false + } + + @SubscribeEvent + fun onBackgroundDraw(event: GuiRenderEvent.ChestBackgroundRenderEvent) { + if (inInventory) { + config.skyMartCopperPricePos.renderStringsAndItems( + display, + extraSpace = 5, + itemScale = 1.7, + posLabel = "Sky Mart Copper Price" + ) + } + } + + private fun isEnabled() = GardenAPI.inGarden() && config.skyMartCopperPrice +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorColorNames.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorColorNames.kt new file mode 100644 index 000000000..789e8e241 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorColorNames.kt @@ -0,0 +1,55 @@ +package at.hannibal2.skyhanni.features.garden.visitor + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +class GardenVisitorColorNames { + + @SubscribeEvent + fun onRepoReload(event: RepositoryReloadEvent) { + try { + val mapColor = mutableMapOf() + val mapItems = mutableMapOf>() + val garden = event.getConstant("Garden")!! + for ((name, element) in garden["visitors"].asJsonObject.entrySet()) { + val jsonObject = element.asJsonObject + val rarity = jsonObject["rarity"].asString + mapColor[name] = getColor(rarity) + mapItems[name] = jsonObject["need_items"].asJsonArray.map { it.asString } + + } + visitorColor = mapColor + visitorItems = mapItems + + } catch (e: Exception) { + e.printStackTrace() + LorenzUtils.error("error in RepositoryReloadEvent") + } + } + + companion object { + private var visitorColor = mapOf() // name -> color code + var visitorItems = mapOf>() + + fun getColoredName(name: String): String { + if (!SkyHanniMod.feature.garden.visitorColoredName) return name + + val cleanName = name.removeColor() + val color = visitorColor[cleanName] ?: return name + return color + cleanName + } + } + + + private fun getColor(rarity: String) = when (rarity) { + "uncommon" -> "§a" + "rare" -> "§9" + "legendary" -> "§6" + "special" -> "§c" + + else -> throw RuntimeException("Unknown rarity for '$rarity'") + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt new file mode 100644 index 000000000..f25d84d71 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt @@ -0,0 +1,551 @@ +package at.hannibal2.skyhanni.features.garden.visitor + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.TitleUtils +import at.hannibal2.skyhanni.events.* +import at.hannibal2.skyhanni.features.garden.CropType +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.features.garden.GardenAPI.getSpeed +import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper +import at.hannibal2.skyhanni.utils.* +import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.ItemUtils.name +import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.RenderUtils.drawString +import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import io.github.moulberry.notenoughupdates.events.SlotClickEvent +import io.github.moulberry.notenoughupdates.util.SBInfo +import net.minecraft.client.Minecraft +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.item.EntityArmorStand +import net.minecraft.network.play.client.C02PacketUseEntity +import net.minecraftforge.client.event.RenderLivingEvent +import net.minecraftforge.client.event.RenderWorldLastEvent +import net.minecraftforge.event.entity.player.ItemTooltipEvent +import net.minecraftforge.fml.common.eventhandler.EventPriority +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent +import java.util.regex.Pattern + +class GardenVisitorFeatures { + private val visitors = mutableMapOf() + private var display = listOf>() + private var lastClickedNpc = 0 + private var tick = 0 + private val copperPattern = Pattern.compile(" §8\\+§c(.*) Copper") + private val gardenExperiencePattern = Pattern.compile(" §8\\+§2(.*) §7Garden Experience") + private val offerAcceptedPattern = Pattern.compile("§6§lOFFER ACCEPTED §r§8with §r(.*) §r.*") + private val config get() = SkyHanniMod.feature.garden + + companion object { + var inVisitorInventory = false + } + + @SubscribeEvent + fun onInventoryOpen(event: InventoryOpenEvent) { + inVisitorInventory = false + + if (!GardenAPI.inGarden()) return + val npcItem = event.inventoryItems[13] ?: return + val lore = npcItem.getLore() + var isVisitor = false + if (lore.size == 4) { + val line = lore[3] + if (line.startsWith("§7Offers Accepted: §a")) { + isVisitor = true + } + } + if (!isVisitor) return + + val offerItem = event.inventoryItems[29] ?: return + if (offerItem.name != "§aAccept Offer") return + inVisitorInventory = true + + if (!config.visitorNeedsDisplay && config.visitorHighlightStatus == 3) return + + var name = npcItem.name ?: return + if (name.length == name.removeColor().length + 4) { + name = name.substring(2) + } + val visitor = visitors[name]!! + visitor.entityId = lastClickedNpc + for (line in offerItem.getLore()) { + if (line == "§7Items Required:") continue + if (line.isEmpty()) break + + val (itemName, amount) = ItemUtils.readItemAmount(line) + if (itemName == null) { + LorenzUtils.error("§c[SkyHanni] Could not read item '$line'") + continue + } + val internalName = NEUItems.getInternalName(itemName) + visitor.items[internalName] = amount + } + if (visitor.status == VisitorStatus.NEW) { + oldStatus(visitor) + visitor.status = VisitorStatus.WAITING + statusChange(visitor) + } + + update() + } + + private fun updateDisplay() { + display = drawDisplay() + } + + private fun drawDisplay(): List> { + val newDisplay = mutableListOf>() + if (!config.visitorNeedsDisplay) return newDisplay + + val requiredItems = mutableMapOf() + val newVisitors = mutableListOf() + for ((visitorName, visitor) in visitors) { + if (visitor.status != VisitorStatus.WAITING && visitor.status != VisitorStatus.NEW) continue + + val items = visitor.items + if (items.isEmpty()) { + newVisitors.add(visitorName) + } + for ((internalName, amount) in items) { + val old = requiredItems.getOrDefault(internalName, 0) + requiredItems[internalName] = old + amount + } + } + if (requiredItems.isNotEmpty()) { + newDisplay.addAsSingletonList("§7Visitor items needed:") + for ((internalName, amount) in requiredItems) { + val name = NEUItems.getItemStack(internalName).name!! + val itemStack = NEUItems.getItemStack(internalName) + + val list = mutableListOf() + list.add(" §7- ") + list.add(itemStack) + list.add("$name §8x${amount.addSeparators()}") + + if (config.visitorNeedsShowPrice) { + val price = NEUItems.getPrice(internalName) * amount + val format = NumberUtil.format(price) + list.add(" §7(§6$format§7)") + } + + newDisplay.add(list) + } + } + if (newVisitors.isNotEmpty()) { + if (requiredItems.isNotEmpty()) { + newDisplay.addAsSingletonList("") + } + val amount = newVisitors.size + val visitorLabel = if (amount == 1) "visitor" else "visitors" + newDisplay.addAsSingletonList("§e$amount §7new $visitorLabel:") + for (visitor in newVisitors) { + val displayName = GardenVisitorColorNames.getColoredName(visitor) + + val list = mutableListOf() + list.add(" §7- $displayName") + + if (config.visitorItemPreview) { + val items = GardenVisitorColorNames.visitorItems[visitor.removeColor()] + if (items == null) { + LorenzUtils.debug("Visitor '$visitor' has no items in repo!") + list.add(" §7(§c?§7)") + continue + } + list.add(" ") + if (items.isEmpty()) { + list.add("§7(§fAny§7)") + } else { + for (item in items) { + try { + val internalName = NEUItems.getInternalName(item) + list.add(NEUItems.getItemStack(internalName)) + } catch (e: Exception) { + list.add(" '$item' ") + } + } + } + } + + newDisplay.add(list) + } + } + + return newDisplay + } + + @SubscribeEvent(priority = EventPriority.HIGH) + fun onStackClick(event: SlotClickEvent) { + if (!inVisitorInventory) return + if (event.slot.stack?.name != "§cRefuse Offer") return + if (event.slotId != 33) return + + getVisitor(lastClickedNpc)?.let { + oldStatus(it) + it.status = VisitorStatus.REFUSED + statusChange(it) + update() + } + } + + private fun getVisitor(id: Int) = visitors.map { it.value }.find { it.entityId == id } + + @SubscribeEvent + fun onCheckRender(event: CheckRenderEntityEvent<*>) { + if (!GardenAPI.inGarden()) return + if (!GardenAPI.onBarnPlot) return + if (config.visitorHighlightStatus != 1 && config.visitorHighlightStatus != 2) return + + val entity = event.entity + if (entity is EntityArmorStand) { + if (entity.name == "§e§lCLICK") { + event.isCanceled = true + } + } + } + + @SubscribeEvent + fun onRenderWorld(event: RenderWorldLastEvent) { + if (!GardenAPI.inGarden()) return + if (!GardenAPI.onBarnPlot) return + if (config.visitorHighlightStatus != 1 && config.visitorHighlightStatus != 2) return + + for (visitor in visitors.values) { + visitor.getEntity()?.let { + val location = it.getLorenzVec().add(0.0, 2.2, 0.0) + val text = visitor.status.displayName + event.drawString(location, text) + } + } + } + + @SubscribeEvent(priority = EventPriority.HIGH) + fun onTooltip(event: ItemTooltipEvent) { + if (!GardenAPI.inGarden()) return + if (!inVisitorInventory) return + val name = event.itemStack.name ?: return + if (name != "§aAccept Offer") return + + val list = event.toolTip + var totalPrice = 0.0 + var itemsCounter = 0 + var itemsWithSpeedCounter = 0 + var endReached = false + for ((i, l) in list.toMutableList().withIndex()) { + if (l.length < 4) continue + + val line = l.substring(4) + if (line == "") { + if (!endReached) { + if (config.visitorShowPrice) { + if (itemsCounter > 1) { + val format = NumberUtil.format(totalPrice) + list[1] = list[1] + "$line §7(§6Total §6$format§7)" + } + } + endReached = true + } + } + + // Items Required + if (i > 1 && !endReached) { + val (itemName, amount) = ItemUtils.readItemAmount(line) + if (itemName != null) { + var internalName: String + try { + internalName = NEUItems.getInternalName(itemName) + } catch (e: NullPointerException) { + val message = "internal name is null: '$itemName'" + println(message) + LorenzUtils.error(message) + e.printStackTrace() + return + } + val price = NEUItems.getPrice(internalName) * amount + totalPrice += price + if (config.visitorShowPrice) { + val format = NumberUtil.format(price) + list[i + itemsWithSpeedCounter] = "$line §7(§6$format§7)" + } + itemsCounter++ + + if (config.visitorExactAmountAndTime) { + val multiplier = NEUItems.getMultiplier(internalName) + val rawName = NEUItems.getItemStack(multiplier.first).name?.removeColor() ?: continue + CropType.getByItemName(rawName)?.let { + val speed = it.getSpeed() + val cropAmount = multiplier.second.toLong() * amount + val formatAmount = LorenzUtils.formatInteger(cropAmount) + val formatName = "§e$formatAmount§7x ${it.cropName} " + val formatSpeed = if (speed != -1) { + val missingTimeSeconds = cropAmount / speed + val duration = TimeUtils.formatDuration(missingTimeSeconds * 1000) + "in §b$duration" + } else { + "§cno speed data!" + } + itemsWithSpeedCounter++ + list.add(i + itemsWithSpeedCounter, " §7- $formatName($formatSpeed§7)") + } + } + } else { + LorenzUtils.error("§c[SkyHanni] Could not read item '$line'") + } + } + + if (config.visitorCopperPrice) { + val matcher = copperPattern.matcher(line) + if (matcher.matches()) { + val coppers = matcher.group(1).replace(",", "").toInt() + val pricePerCopper = NumberUtil.format((totalPrice / coppers).toInt()) + list[i + itemsWithSpeedCounter] = "$line §7(price per §6$pricePerCopper§7)" + } + } + if (config.visitorExperiencePrice) { + val matcher = gardenExperiencePattern.matcher(line) + if (matcher.matches()) { + val gardenExp = matcher.group(1).replace(",", "").toInt() + val pricePerCopper = NumberUtil.format((totalPrice / gardenExp).toInt()) + list[i + itemsWithSpeedCounter] = "$line §7(price per §6$pricePerCopper§7)" + } + } + } + } + + @SubscribeEvent + fun onTick(event: TickEvent.ClientTickEvent) { + if (!GardenAPI.inGarden()) return + if (!config.visitorNeedsDisplay && config.visitorHighlightStatus == 3) return + if (tick++ % 10 != 0) return + + if (GardenAPI.onBarnPlot && config.visitorHighlightStatus != 3) { + checkVisitorsReady() + } + } + + @SubscribeEvent + fun onTabListUpdate(event: TabListUpdateEvent) { + if (!GardenAPI.inGarden()) return + var found = false + val visitorsInTab = mutableListOf() + for (line in event.tabList) { + if (line.startsWith("§b§lVisitors:")) { + found = true + continue + } + if (found) { + if (line.isEmpty()) { + found = false + continue + } + var name = line.trim().replace("§r", "") + if (!name.contains("§")) { + name = "§f$name" + } + + // Hide hypixel watchdog entries + if (name.contains("§c") && !name.contains("Spaceman") && !name.contains("Grandma Wolf")) continue + + //hide own player name + if (name.contains(LorenzUtils.getPlayerUuid())) continue + + visitorsInTab.add(name) + } + } + if (visitors.keys.removeIf { + val time = System.currentTimeMillis() - SBInfo.getInstance().joinedWorld + it !in visitorsInTab && time > 2_000 + }) { + updateDisplay() + } + for (name in visitorsInTab) { + if (!visitors.containsKey(name)) { + visitors[name] = Visitor(name, status = VisitorStatus.NEW) + LorenzUtils.debug("new visitor '$name'") + if (config.visitorNotificationTitle) { + TitleUtils.sendTitle("§eNew Visitor", 5_000) + } + if (config.visitorNotificationChat) { + val displayName = GardenVisitorColorNames.getColoredName(name) + LorenzUtils.chat("§e[SkyHanni] $displayName §eis visiting your garden!") + } + updateDisplay() + } + } + } + + @SubscribeEvent + fun onChatMessage(event: LorenzChatEvent) { + val matcher = offerAcceptedPattern.matcher(event.message) + if (!matcher.matches()) return + + val visitorName = matcher.group(1) + for (visitor in visitors) { + if (visitor.key == visitorName) { + oldStatus(visitor.value) + visitor.value.status = VisitorStatus.ACCEPTED + statusChange(visitor.value) + update() + } + } + } + + private fun update() { + checkVisitorsReady() + updateDisplay() + } + + private fun checkVisitorsReady() { + for ((visitorName, visitor) in visitors) { + val entity = visitor.getEntity() + if (entity == null) { + findNametag(visitorName.removeColor())?.let { + findEntity(it, visitor) + } + } + + val status = visitor.status + if (status == VisitorStatus.WAITING || status == VisitorStatus.READY) { + oldStatus(visitor) + visitor.status = if (isReady(visitor)) VisitorStatus.READY else VisitorStatus.WAITING + statusChange(visitor) + } + + if (config.visitorHighlightStatus == 0 || config.visitorHighlightStatus == 2) { + if (entity is EntityLivingBase) { + val color = status.color + if (color != -1) { + RenderLivingEntityHelper.setEntityColor( + entity, + color + ) { config.visitorHighlightStatus == 0 || config.visitorHighlightStatus == 2 } + } else { + RenderLivingEntityHelper.removeEntityColor(entity) + } + } + } + } + } + + val oldValue = mutableMapOf() + + private fun oldStatus(visitor: Visitor) { + oldValue[visitor] = visitor.status + } + + private fun statusChange(visitor: Visitor) { + val old = oldValue[visitor] + val new = visitor.status + if (old == new) return + val name = visitor.visitorName.removeColor() + LorenzUtils.debug("Visitor status change for $name: $old -> $new") + } + + private fun Visitor.getEntity() = Minecraft.getMinecraft().theWorld.getEntityByID(entityId) + + private fun findEntity(nameTag: EntityArmorStand, visitor: Visitor) { + for (entity in Minecraft.getMinecraft().theWorld.loadedEntityList) { + if (entity is EntityArmorStand) continue + if (entity.getLorenzVec().distanceIgnoreY(nameTag.getLorenzVec()) != 0.0) continue + + visitor.entityId = entity?.entityId ?: 0 + visitor.nameTagEntityId = nameTag.entityId + } + } + + private fun findNametag(visitorName: String): EntityArmorStand? { + val foundVisitorNameTags = mutableListOf() + for (entity in Minecraft.getMinecraft().theWorld.loadedEntityList) { + if (entity !is EntityArmorStand) continue + + if (entity.name.removeColor() == visitorName) { + foundVisitorNameTags.add(entity) + } + } + + if (visitorName in listOf("Jacob", "Anita")) { + + // Only detect jacob/anita npc if the "wrong" npc got found as well + if (foundVisitorNameTags.size != 2) return null + + for (tag in foundVisitorNameTags.toMutableList()) { + for (entity in Minecraft.getMinecraft().theWorld.loadedEntityList) { + if (entity !is EntityArmorStand) continue + if (entity in foundVisitorNameTags) continue + val distance = entity.getLorenzVec().distance(tag.getLorenzVec()) + if (distance < 1.5 && entity.name == "§bSam") { + foundVisitorNameTags.remove(tag) + } + } + } + } + + if (foundVisitorNameTags.size != 1) return null + return foundVisitorNameTags[0] + } + + private fun isReady(visitor: Visitor): Boolean { + var ready = true + for ((internalName, need) in visitor.items) { + val having = InventoryUtils.countItemsInLowerInventory { it.getInternalName() == internalName } + if (having < need) { + ready = false + } + } + return ready + } + + // TODO make event + @SubscribeEvent + fun onSendEvent(event: PacketEvent.SendEvent) { + val packet = event.packet + if (packet !is C02PacketUseEntity) return + + val theWorld = Minecraft.getMinecraft().theWorld + val entity = packet.getEntityFromWorld(theWorld) ?: return + val entityId = entity.entityId + + lastClickedNpc = entityId + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent) { + if (!GardenAPI.inGarden()) return + if (!config.visitorNeedsDisplay) return + + if (config.visitorNeedsOnlyWhenClose && !GardenAPI.onBarnPlot) return + + config.visitorNeedsPos.renderStringsAndItems(display, posLabel = "Visitor Items Needed") + } + + @SubscribeEvent(priority = EventPriority.HIGH) + fun onRenderLivingB(event: RenderLivingEvent.Specials.Pre) { + val entity = event.entity + val entityId = entity.entityId + for (visitor in visitors.values) { + if (visitor.nameTagEntityId == entityId) { + entity.customNameTag = GardenVisitorColorNames.getColoredName(entity.name) + } + } + } + + class Visitor( + val visitorName: String, + var entityId: Int = -1, + var nameTagEntityId: Int = -1, + var status: VisitorStatus, + val items: MutableMap = mutableMapOf(), + ) + + enum class VisitorStatus(val displayName: String, val color: Int) { + NEW("§e§lNew", LorenzColor.YELLOW.toColor().withAlpha(100)), + WAITING("§lWaiting", -1), + READY("§a§lItems Ready", LorenzColor.GREEN.toColor().withAlpha(80)), + ACCEPTED("§7§lAccepted", LorenzColor.DARK_GRAY.toColor().withAlpha(80)), + REFUSED("§c§lRefused", LorenzColor.RED.toColor().withAlpha(60)), + } +} + diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorTimer.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorTimer.kt new file mode 100644 index 000000000..923437960 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorTimer.kt @@ -0,0 +1,70 @@ +package at.hannibal2.skyhanni.features.garden.visitor + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.TabListUpdateEvent +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.utils.RenderUtils.renderString +import at.hannibal2.skyhanni.utils.TimeUtils +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.regex.Pattern + +class GardenVisitorTimer { + private val patternNextVisitor = Pattern.compile(" Next Visitor: §r§b(.*)") + private val patternVisitors = Pattern.compile("§b§lVisitors: §r§f\\((\\d)\\)") + private var render = "" + private var lastMillis = 0L + private var lastVisitors = 0 + + @SubscribeEvent + fun onTabListUpdate(event: TabListUpdateEvent) { + if (!isEnabled()) return + + var visitorsAmount = 0 + var millis = 15 * 60_000L + var queueFull = false + for (line in event.tabList) { + var matcher = patternNextVisitor.matcher(line) + if (matcher.matches()) { + val rawTime = matcher.group(1) + millis = TimeUtils.getMillis(rawTime) + } else if (line == " Next Visitor: §r§c§lQueue Full!") { + queueFull = true + } else if (line == " Next Visitor: §r§cNot Unlocked!") { + render = "" + return + } + + matcher = patternVisitors.matcher(line) + if (matcher.matches()) { + visitorsAmount = matcher.group(1).toInt() + } + } + + val diff = lastMillis - millis + if (diff == 0L && visitorsAmount == lastVisitors) return + lastMillis = millis + lastVisitors = visitorsAmount + + val extraSpeed = if (diff in 1001..10_000) { + val factor = diff / 1000 + "§7/§e" + TimeUtils.formatDuration(millis / factor) + } else "" + + val formatDuration = TimeUtils.formatDuration(millis) + val next = if (queueFull) "§cQueue Full!" else { + "Next in §e$formatDuration$extraSpeed" + } + val visitorLabel = if (visitorsAmount == 1) "visitor" else "visitors" + render = "§b$visitorsAmount $visitorLabel §7($next§7)" + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { + if (!isEnabled()) return + + SkyHanniMod.feature.garden.visitorTimerPos.renderString(render, posLabel = "Garden Visitor Timer") + } + + private fun isEnabled() = GardenAPI.inGarden() && SkyHanniMod.feature.garden.visitorTimerEnabled +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/HideNotClickableItems.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/HideNotClickableItems.kt index e9e570faf..84cb782ae 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/HideNotClickableItems.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/HideNotClickableItems.kt @@ -6,7 +6,7 @@ import at.hannibal2.skyhanni.data.ItemRenderBackground.Companion.borderLine import at.hannibal2.skyhanni.events.GuiContainerEvent import at.hannibal2.skyhanni.events.RepositoryReloadEvent import at.hannibal2.skyhanni.features.bazaar.BazaarApi -import at.hannibal2.skyhanni.features.garden.GardenVisitorFeatures +import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorFeatures import at.hannibal2.skyhanni.utils.* import at.hannibal2.skyhanni.utils.InventoryUtils.getInventoryName import at.hannibal2.skyhanni.utils.ItemUtils.cleanName diff --git a/src/main/java/at/hannibal2/skyhanni/test/LorenzTest.kt b/src/main/java/at/hannibal2/skyhanni/test/LorenzTest.kt index 45748339c..55b01dd9f 100644 --- a/src/main/java/at/hannibal2/skyhanni/test/LorenzTest.kt +++ b/src/main/java/at/hannibal2/skyhanni/test/LorenzTest.kt @@ -5,7 +5,7 @@ import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.PlaySoundEvent import at.hannibal2.skyhanni.events.ReceiveParticleEvent -import at.hannibal2.skyhanni.features.garden.GardenVisitorColorNames +import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorColorNames import at.hannibal2.skyhanni.utils.* import at.hannibal2.skyhanni.utils.RenderUtils.renderString import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems -- cgit