1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
package at.hannibal2.skyhanni.features.garden.contest
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.events.InventoryCloseEvent
import at.hannibal2.skyhanni.events.RenderItemTooltipEvent
import at.hannibal2.skyhanni.features.garden.CropType
import at.hannibal2.skyhanni.features.garden.FarmingFortuneDisplay.getLatestTrueFarmingFortune
import at.hannibal2.skyhanni.features.garden.GardenAPI
import at.hannibal2.skyhanni.features.garden.farming.GardenCropSpeed.getLatestBlocksPerSecond
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.utils.CollectionUtils.addAsSingletonList
import at.hannibal2.skyhanni.utils.InventoryUtils
import at.hannibal2.skyhanni.utils.ItemUtils.name
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.renderStringsAndItems
import at.hannibal2.skyhanni.utils.SimpleTimeMark
import net.minecraft.item.ItemStack
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import kotlin.math.ceil
import kotlin.time.Duration.Companion.milliseconds
@SkyHanniModule
object JacobContestFFNeededDisplay {
private val config get() = GardenAPI.config
private var display = emptyList<List<Any>>()
private var lastToolTipTime = SimpleTimeMark.farPast()
private val cache = mutableMapOf<ItemStack, List<List<Any>>>()
@SubscribeEvent
fun onRenderItemTooltip(event: RenderItemTooltipEvent) {
if (!isEnabled()) return
if (!InventoryUtils.openInventoryName().contains("Your Contests")) return
val stack = event.stack
val oldData = cache[stack]
if (oldData != null) {
display = oldData
lastToolTipTime = SimpleTimeMark.now()
return
}
val time = FarmingContestAPI.getSbTimeFor(stack.name) ?: return
val contest = FarmingContestAPI.getContestAtTime(time) ?: return
val newDisplay = drawDisplay(contest)
display = newDisplay
cache[stack] = newDisplay
lastToolTipTime = SimpleTimeMark.now()
}
@SubscribeEvent
fun onInventoryClose(event: InventoryCloseEvent) {
cache.clear()
}
private fun drawDisplay(contest: FarmingContest) = buildList<List<Any>> {
addAsSingletonList("§6Minimum Farming Fortune needed")
addAsSingletonList("")
val crop = contest.crop
add(listOf("§7For this ", crop.icon, "§7${crop.cropName} contest:"))
for (bracket in ContestBracket.entries) {
addAsSingletonList(getLine(bracket, contest.brackets, crop))
}
addAsSingletonList("")
val (size, averages) = FarmingContestAPI.calculateAverages(crop)
add(listOf("§7For the last §e$size ", crop.icon, "§7${crop.cropName} contests:"))
for (bracket in ContestBracket.entries) {
addAsSingletonList(getLine(bracket, averages, crop))
}
addAsSingletonList("")
var blocksPerSecond = crop.getLatestBlocksPerSecond()
if (blocksPerSecond == null) {
add(listOf("§cNo ", crop.icon, "§cblocks/second data,"))
addAsSingletonList("§cassuming 19.9 instead.")
} else {
if (blocksPerSecond < 15.0) {
add(listOf("§7Your latest ", crop.icon, "§7blocks/second: §e${blocksPerSecond.round(2)}"))
add(listOf("§cThis is too low, showing 19.9 Blocks/second instead!"))
blocksPerSecond = 19.9
}
}
addAsSingletonList("")
val trueFF = crop.getLatestTrueFarmingFortune()
if (trueFF == null) {
addAsSingletonList("§cNo latest true FF saved!")
} else {
val farmingFortune = formatFarmingFortune(trueFF)
add(listOf("§6Your ", crop.icon, "§6FF: $farmingFortune"))
}
addAsSingletonList("")
if (blocksPerSecond == null || trueFF == null) {
add(listOf("§cMissing data from above!"))
} else {
val predictedScore =
((100.0 + trueFF) * blocksPerSecond * crop.baseDrops * 20 * 60 / 100).toInt().addSeparators()
add(listOf("§6Predicted ", crop.icon, "§6crops: $predictedScore"))
}
}
private fun formatFarmingFortune(farmingFortune: Double) = ceil(farmingFortune).addSeparators()
private fun getLine(bracket: ContestBracket, map: Map<ContestBracket, Int>, crop: CropType): String {
val counter = map[bracket] ?: return " ${bracket.displayName}§f: §8Not found!"
val blocksPerSecond = crop.getRealBlocksPerSecond()
val cropsPerSecond = counter.toDouble() / blocksPerSecond / 60
val farmingFortune = (cropsPerSecond * 100 / 20 / crop.baseDrops) - 100
val format = formatFarmingFortune(farmingFortune.coerceAtLeast(0.0))
return " ${bracket.displayName}§f: §6$format FF §7(${counter.addSeparators()} crops)"
}
@SubscribeEvent
fun onBackgroundDraw(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) {
if (!isEnabled()) return
if (!FarmingContestAPI.inInventory) return
if (lastToolTipTime.passedSince() > 200.milliseconds) return
config.farmingFortuneForContestPos.renderStringsAndItems(display, posLabel = "Jacob Contest Crop Data")
}
fun isEnabled() = LorenzUtils.inSkyBlock && config.farmingFortuneForContest
}
private fun CropType.getRealBlocksPerSecond(): Double {
val bps = getLatestBlocksPerSecond() ?: 20.0
return if (bps < 15.0) {
return 19.9
} else bps
}
|