aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/features/misc/TpsCounter.kt
blob: 1905e43af32420d7558110ceac463570466ebdc3 (plain)
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
136
137
138
package at.hannibal2.skyhanni.features.misc

import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.api.event.HandleEvent
import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator
import at.hannibal2.skyhanni.config.commands.CommandCategory
import at.hannibal2.skyhanni.config.commands.CommandRegistrationEvent
import at.hannibal2.skyhanni.config.enums.OutsideSbFeature
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.events.LorenzTickEvent
import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent
import at.hannibal2.skyhanni.events.SecondPassedEvent
import at.hannibal2.skyhanni.events.minecraft.packet.PacketReceivedEvent
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.utils.ChatUtils
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.NumberUtil.roundTo
import at.hannibal2.skyhanni.utils.RenderUtils.renderString
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import kotlin.time.Duration.Companion.seconds

@SkyHanniModule
object TpsCounter {

    private val config get() = SkyHanniMod.feature.gui

    private val ignorePacketDelay = 5.seconds
    private val minimumSecondsDisplayDelay = 10.seconds

    private var packetsFromLastSecond = 0
    private val tpsList = mutableListOf<Int>()
    private var hasRemovedFirstSecond = false

    private var hasReceivedPacket = false

    var tps: Double? = null
        private set

    private var display: String? = null

    private val timeSinceWorldSwitch get() = LorenzUtils.lastWorldSwitch.passedSince()

    @SubscribeEvent
    fun onSecondPassed(event: SecondPassedEvent) {
        if (shouldIgnore()) {
            updateDisplay()
            return
        }

        if (packetsFromLastSecond != 0) {
            if (hasRemovedFirstSecond) tpsList.add(packetsFromLastSecond)
            hasRemovedFirstSecond = true
        }
        packetsFromLastSecond = 0

        if (tpsList.size > 10) tpsList.removeAt(0)

        updateDisplay()
    }

    private fun updateDisplay() {
        val timeUntil = minimumSecondsDisplayDelay - timeSinceWorldSwitch
        val text = if (timeUntil.isPositive()) {
            "§f(${timeUntil.inWholeSeconds}s)"
        } else {
            val sum = tpsList.sum().toDouble()
            val newTps = (sum / tpsList.size).roundTo(1).coerceIn(0.0..20.0)
            tps = newTps
            val legacyColor = getColor(newTps)
            "$legacyColor$newTps"
        }
        display = "§eTPS: $text"
    }

    private fun tpsCommand() {
        val tps = tps ?: return ChatUtils.chat("§eTPS: §fCalculating...")
        ChatUtils.chat("§eTPS: ${getColor(tps)}$tps")
    }

    @SubscribeEvent
    fun onTick(event: LorenzTickEvent) {
        if (hasReceivedPacket) {
            packetsFromLastSecond++
            hasReceivedPacket = false
        }
    }

    @SubscribeEvent
    fun onWorldChange(event: LorenzWorldChangeEvent) {
        tpsList.clear()
        tps = null
        packetsFromLastSecond = 0
        display = null
        hasRemovedFirstSecond = false
    }

    @HandleEvent(priority = HandleEvent.HIGHEST, receiveCancelled = true)
    fun onPacketReceive(event: PacketReceivedEvent) {
        hasReceivedPacket = true
    }

    @SubscribeEvent
    fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) {
        if (!isEnabled()) return

        config.tpsDisplayPosition.renderString(display, posLabel = "Tps Display")
    }

    @HandleEvent
    fun onCommandRegistration(event: CommandRegistrationEvent) {
        event.register("shtps") {
            description = "Informs in chat about the server ticks per second (TPS)."
            category = CommandCategory.USERS_ACTIVE
            callback { tpsCommand() }
        }
    }

    private fun shouldIgnore() = timeSinceWorldSwitch < ignorePacketDelay

    private fun isEnabled() = LorenzUtils.onHypixel &&
        config.tpsDisplay &&
        (LorenzUtils.inSkyBlock || OutsideSbFeature.TPS_DISPLAY.isSelected())

    @SubscribeEvent
    fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) {
        event.move(2, "misc.tpsDisplayEnabled", "gui.tpsDisplay")
        event.move(2, "misc.tpsDisplayPosition", "gui.tpsDisplayPosition")
    }

    private fun getColor(tps: Double) = when {
        tps > 19.8 -> "§2"
        tps > 19 -> "§a"
        tps > 17.5 -> "§6"
        tps > 12 -> "§c"

        else -> "§4"
    }
}