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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
package com.ambientaddons.features.display
import AmbientAddons.Companion.config
import AmbientAddons.Companion.mc
import com.ambientaddons.events.ReceivePacketEvent
import com.ambientaddons.gui.GuiElement
import com.ambientaddons.utils.Alignment
import com.ambientaddons.utils.Extensions.renderWidth
import com.ambientaddons.utils.Extensions.withModPrefix
import com.ambientaddons.utils.SBLocation
import com.ambientaddons.utils.dungeon.TextStyle
import com.ambientaddons.utils.render.OverlayUtils
import gg.essential.universal.UChat
import net.minecraft.client.renderer.GlStateManager
import net.minecraft.network.play.client.C16PacketClientStatus
import net.minecraft.network.play.server.S01PacketJoinGame
import net.minecraft.network.play.server.S03PacketTimeUpdate
import net.minecraft.network.play.server.S37PacketStatistics
import net.minecraftforge.client.event.RenderGameOverlayEvent
import net.minecraftforge.event.world.WorldEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.TickEvent
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent
import kotlin.math.max
// Modified from SkytilsMod/Skytils, under AGPL 3.0
object PingOverlay {
val element = GuiElement("ping", 55, 20)
private val alpha = 1 / 3.0
private var averageTps: Double? = null
private var tpsCount = 0
private var lastTpsSample: Long? = null
private var averagePing: Double? = null
private var pingCount = 0
private var pingStartTime: Long? = null
private var ticks = 0
private var isPinging = false
private var chatNextPing = false
@SubscribeEvent
fun onPacketReceived(event: ReceivePacketEvent) {
if (event.packet is S03PacketTimeUpdate) {
val currentTime = System.currentTimeMillis()
lastTpsSample?.let { lastTime ->
val time = currentTime - lastTime
val instantTps = (20000.0 / time).coerceIn(0.0, 20.0)
tpsCount++
averageTps = instantTps * alpha + (averageTps ?: instantTps) * (1 - alpha)
}
lastTpsSample = currentTime
} else if (config.shouldPing != 0 && event.packet is S37PacketStatistics) {
isPinging = false
pingStartTime?.let { startTime ->
val instantPing = (System.nanoTime() - startTime) / 1e6
pingCount++
averagePing = instantPing * alpha + (averagePing ?: instantPing) * (1 - alpha)
}
if (chatNextPing) {
printPing()
chatNextPing = false
}
} else if (event.packet is S01PacketJoinGame) reset()
}
@SubscribeEvent
fun onWorldLoad(event: WorldEvent.Load) {
reset()
}
private fun reset() {
isPinging = false
tpsCount = 0
averageTps = null
pingCount = 0
averagePing = null
}
private fun printPing() {
val pingValue = averagePing?.let { "${colorizePing(it) }%.1f".format(it) } ?: "§e?"
val tpsValue = averageTps?.let { "${colorizeTps(it) }%.1f".format(it) } ?: "§e?"
if (shouldPing()) {
UChat.chat("$pingValue §7ms ($tpsValue §7tps)".withModPrefix())
} else {
UChat.chat("$tpsValue §7tps".withModPrefix())
}
}
fun sendPing(isFromCommand: Boolean) {
if (isFromCommand) chatNextPing = true
if (!isPinging) {
isPinging = true
mc.thePlayer.sendQueue.networkManager.sendPacket(C16PacketClientStatus(C16PacketClientStatus.EnumState.REQUEST_STATS),
{
pingStartTime = System.nanoTime()
}
)
} else if (isFromCommand && !shouldPing()) {
UChat.chat("§cAlready pinging!".withModPrefix())
}
}
@SubscribeEvent
fun onTick(event: ClientTickEvent) {
if (!shouldPing() || event.phase != TickEvent.Phase.START) return
if (ticks % 40 == 0) {
sendPing(false)
}
ticks++
}
private fun colorizeTps(tps: Double) = when {
(tps > 19) -> "§a"
(tps > 18) -> "§2"
(tps > 17) -> "§e"
(tps > 15) -> "§6"
else -> "§c"
}
private fun colorizePing(ping: Double) = when {
(ping < 50) -> "§a"
(ping < 100) -> "§2"
(ping < 150) -> "§e"
(ping < 250) -> "§6"
else -> "§c"
}
private fun shouldPing(): Boolean =
mc.theWorld != null && (config.shouldPing == 3 || (config.shouldPing == 2 && SBLocation.onHypixel) || (config.shouldPing == 1 && SBLocation.inSkyblock))
@SubscribeEvent
fun onRenderOverlay(event: RenderGameOverlayEvent) {
if (config.pingDisplay == 0 || event.type != RenderGameOverlayEvent.ElementType.TEXT) return
val textStyle = TextStyle.fromInt(config.pingDisplay - 1) ?: return
GlStateManager.pushMatrix()
GlStateManager.translate(element.position.x, element.position.y, 500.0)
GlStateManager.scale(element.position.scale, element.position.scale, 1.0)
val tpsValue = averageTps?.let { "${colorizeTps(it) }%.1f".format(it) } ?: "§e?"
if (shouldPing()) {
val pingValue = averagePing?.let { "${colorizePing(it)}%.1f".format(it) } ?: "§e?"
val valueWidth = max(pingValue.renderWidth(), tpsValue.renderWidth())
OverlayUtils.drawString(0, 0, "§bPing:", textStyle, Alignment.Left)
OverlayUtils.drawString(0, 10, "§bTPS:", textStyle, Alignment.Left)
OverlayUtils.drawString(30 + valueWidth, 0, pingValue, textStyle, Alignment.Right)
OverlayUtils.drawString(30 + valueWidth, 10, tpsValue, textStyle, Alignment.Right)
} else {
OverlayUtils.drawString(0, 0, "§bTPS:", textStyle, Alignment.Left)
OverlayUtils.drawString(30 + tpsValue.renderWidth(), 0, tpsValue, textStyle, Alignment.Right)
}
GlStateManager.popMatrix()
}
}
|