Skip to content

Commit

Permalink
Improvement + Backend: ServerTimeMark (#2823)
Browse files Browse the repository at this point in the history
Co-authored-by: Empa <itsempa@users.noreply.github.com>
Co-authored-by: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com>
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
  • Loading branch information
4 people authored Dec 8, 2024
1 parent 0e70168 commit 9fb3897
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 57 deletions.
69 changes: 38 additions & 31 deletions src/main/java/at/hannibal2/skyhanni/data/MinecraftData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import at.hannibal2.skyhanni.events.LorenzTickEvent
import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent
import at.hannibal2.skyhanni.events.PlaySoundEvent
import at.hannibal2.skyhanni.events.ReceiveParticleEvent
import at.hannibal2.skyhanni.events.minecraft.ServerTickEvent
import at.hannibal2.skyhanni.events.minecraft.packet.PacketReceivedEvent
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.utils.DelayedRun
Expand All @@ -17,26 +18,47 @@ import at.hannibal2.skyhanni.utils.NEUInternalName
import net.minecraft.client.Minecraft
import net.minecraft.network.play.server.S29PacketSoundEffect
import net.minecraft.network.play.server.S2APacketParticles
import net.minecraft.network.play.server.S32PacketConfirmTransaction
import net.minecraftforge.event.world.WorldEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.TickEvent

@SkyHanniModule
object MinecraftData {

@HandleEvent(receiveCancelled = true, onlyOnSkyblock = true)
fun onSoundPacket(event: PacketReceivedEvent) {
@HandleEvent(receiveCancelled = true)
fun onPacket(event: PacketReceivedEvent) {
val packet = event.packet
if (packet !is S29PacketSoundEffect) return

if (PlaySoundEvent(
packet.soundName,
LorenzVec(packet.x, packet.y, packet.z),
packet.pitch,
packet.volume
).postAndCatch()
) {
event.cancel()
when (packet) {
is S29PacketSoundEffect -> {
if (PlaySoundEvent(
packet.soundName,
LorenzVec(packet.x, packet.y, packet.z),
packet.pitch,
packet.volume
).postAndCatch()
) {
event.cancel()
}
}
is S2APacketParticles -> {
if (ReceiveParticleEvent(
packet.particleType!!,
LorenzVec(packet.xCoordinate, packet.yCoordinate, packet.zCoordinate),
packet.particleCount,
packet.particleSpeed,
LorenzVec(packet.xOffset, packet.yOffset, packet.zOffset),
packet.isLongDistance,
packet.particleArgs,
).postAndCatch()
) {
event.cancel()
}
}
is S32PacketConfirmTransaction -> {
totalServerTicks++
ServerTickEvent.post()
}
}
}

Expand All @@ -45,26 +67,11 @@ object MinecraftData {
LorenzWorldChangeEvent().postAndCatch()
}

@HandleEvent(receiveCancelled = true, onlyOnSkyblock = true)
fun onParticlePacketReceive(event: PacketReceivedEvent) {
val packet = event.packet
if (packet !is S2APacketParticles) return

if (ReceiveParticleEvent(
packet.particleType!!,
LorenzVec(packet.xCoordinate, packet.yCoordinate, packet.zCoordinate),
packet.particleCount,
packet.particleSpeed,
LorenzVec(packet.xOffset, packet.yOffset, packet.zOffset),
packet.isLongDistance,
packet.particleArgs,
).postAndCatch()
) {
event.cancel()
}
}

var totalTicks = 0
private set

var totalServerTicks: Long = 0L
private set

@SubscribeEvent
fun onTick(event: TickEvent.ClientTickEvent) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package at.hannibal2.skyhanni.events.minecraft

import at.hannibal2.skyhanni.api.event.SkyHanniEvent

object ServerTickEvent : SkyHanniEvent()
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ import at.hannibal2.skyhanni.utils.RegexUtils.matches
import at.hannibal2.skyhanni.utils.RenderUtils
import at.hannibal2.skyhanni.utils.RenderUtils.drawString
import at.hannibal2.skyhanni.utils.RenderUtils.exactLocation
import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables
import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderable
import at.hannibal2.skyhanni.utils.ServerTimeMark
import at.hannibal2.skyhanni.utils.SimpleTimeMark
import at.hannibal2.skyhanni.utils.SkullTextureHolder
import at.hannibal2.skyhanni.utils.SoundUtils
Expand Down Expand Up @@ -96,11 +97,11 @@ object GoldenFishTimer {
private var lastFishEntity = SimpleTimeMark.farPast()
private var lastChatMessage = SimpleTimeMark.farPast()

private var lastGoldenFishTime = SimpleTimeMark.farPast()
private var lastGoldenFishTime = ServerTimeMark.FAR_PAST

private var lastRodThrowTime = SimpleTimeMark.farPast()
private var goldenFishDespawnTimer = SimpleTimeMark.farFuture()
private var timePossibleSpawn = SimpleTimeMark.farFuture()
private var lastRodThrowTime = ServerTimeMark.FAR_PAST
private var goldenFishDespawnTimer = ServerTimeMark.FAR_FUTURE
private var timePossibleSpawn = ServerTimeMark.FAR_FUTURE

private val isFishing get() = FishingAPI.isFishing() || lastRodThrowTime.passedSince() < maxRodTime
private var hasLavaRodInInventory = false
Expand Down Expand Up @@ -128,7 +129,7 @@ object GoldenFishTimer {
private var possibleGoldenFishEntity: EntityLivingBase? = null
private var confirmedGoldenFishEntity: EntityLivingBase? = null

private var display = listOf<Renderable>()
private var display: Renderable? = null

@SubscribeEvent
fun onChat(event: LorenzChatEvent) {
Expand All @@ -139,12 +140,12 @@ object GoldenFishTimer {
return
}
if (interactPattern.matches(event.message)) {
goldenFishDespawnTimer = SimpleTimeMark.now() + despawnTime
goldenFishDespawnTimer = ServerTimeMark.now() + despawnTime
interactions++
return
}
if (weakPattern.matches(event.message)) {
goldenFishDespawnTimer = SimpleTimeMark.now() + despawnTime
goldenFishDespawnTimer = ServerTimeMark.now() + despawnTime
val entity = confirmedGoldenFishEntity ?: return
if (config.highlight) RenderLivingEntityHelper.setEntityColorWithNoHurtTime(
entity,
Expand All @@ -153,14 +154,14 @@ object GoldenFishTimer {
return
}
if (despawnPattern.matches(event.message)) {
timePossibleSpawn = SimpleTimeMark.now() + minimumSpawnTime
timePossibleSpawn = ServerTimeMark.now() + minimumSpawnTime
removeGoldenFish()
return
}
TrophyFishMessages.trophyFishPattern.matchMatcher(event.message) {
val internalName = TrophyFishMessages.getInternalName(group("displayName"))
if (internalName != "goldenfish") return@matchMatcher
timePossibleSpawn = SimpleTimeMark.now() + minimumSpawnTime
timePossibleSpawn = ServerTimeMark.now() + minimumSpawnTime
removeGoldenFish()
return
}
Expand All @@ -182,13 +183,11 @@ object GoldenFishTimer {
@SubscribeEvent
fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) {
if (!isActive()) return
val list = display.takeIf { it.isNotEmpty() } ?: return
val renderable = Renderable.horizontalContainer(list, verticalAlign = RenderUtils.VerticalAlignment.CENTER)
config.position.renderRenderables(listOf(renderable), posLabel = "Golden Fish Timer")
config.position.renderRenderable(display, posLabel = "Golden Fish Timer")
}

private fun updateDisplay() {
display = drawDisplay()
display = Renderable.horizontalContainer(drawDisplay())
}

private fun drawDisplay() = buildList {
Expand Down Expand Up @@ -244,8 +243,8 @@ object GoldenFishTimer {
if (!isActive()) return

if (lastRodThrowTime.passedSince() > maxRodTime) {
timePossibleSpawn = SimpleTimeMark.farFuture()
lastRodThrowTime = SimpleTimeMark.farPast()
timePossibleSpawn = ServerTimeMark.FAR_FUTURE
lastRodThrowTime = ServerTimeMark.FAR_PAST
}
if (!lastRodThrowTime.isFarPast() && (lastRodThrowTime + maxRodTime).timeUntil() < config.throwRodWarningTime.seconds) {
rodWarning()
Expand All @@ -272,8 +271,8 @@ object GoldenFishTimer {
else if (bobber.motionY < 0 && !goingDownInit && !goingDownPost) {
hasWarnedRod = false
goingDownPost = true
lastRodThrowTime = SimpleTimeMark.now()
if (timePossibleSpawn.isFarFuture()) timePossibleSpawn = SimpleTimeMark.now() + minimumSpawnTime
lastRodThrowTime = ServerTimeMark.now()
if (timePossibleSpawn.isFarFuture()) timePossibleSpawn = ServerTimeMark.now() + minimumSpawnTime
}
}

Expand All @@ -297,12 +296,12 @@ object GoldenFishTimer {
fun onWorldChange(event: LorenzWorldChangeEvent) {
lastChatMessage = SimpleTimeMark.farPast()
lastFishEntity = SimpleTimeMark.farPast()
lastGoldenFishTime = SimpleTimeMark.farPast()
lastGoldenFishTime = ServerTimeMark.FAR_PAST
possibleGoldenFishEntity = null
lastRodThrowTime = SimpleTimeMark.farPast()
timePossibleSpawn = SimpleTimeMark.farFuture()
lastRodThrowTime = ServerTimeMark.FAR_PAST
timePossibleSpawn = ServerTimeMark.FAR_FUTURE
interactions = 0
display = listOf()
display = null
removeGoldenFish()
}

Expand Down Expand Up @@ -330,7 +329,7 @@ object GoldenFishTimer {
}

private fun removeGoldenFish() {
goldenFishDespawnTimer = SimpleTimeMark.farFuture()
goldenFishDespawnTimer = ServerTimeMark.FAR_FUTURE
confirmedGoldenFishEntity?.let {
confirmedGoldenFishEntity = null
RenderLivingEntityHelper.removeEntityColor(it)
Expand All @@ -341,15 +340,18 @@ object GoldenFishTimer {
if (lastChatMessage.passedSince() > timeOut || lastFishEntity.passedSince() > timeOut) return
lastFishEntity = SimpleTimeMark.farPast()
lastChatMessage = SimpleTimeMark.farPast()
lastGoldenFishTime = SimpleTimeMark.now()
lastGoldenFishTime = ServerTimeMark.now()
interactions = 0
ChatUtils.debug("Found Golden Fish!")
confirmedGoldenFishEntity = possibleGoldenFishEntity
possibleGoldenFishEntity = null
goldenFishDespawnTimer = SimpleTimeMark.now() + despawnTime
goldenFishDespawnTimer = ServerTimeMark.now() + despawnTime
}

private fun Duration.formatTime() = format(showMilliSeconds = false, showSmallerUnits = true)
private fun Duration.formatTime(): String {
val duration = this.inWholeSeconds.seconds // workaround to not show milliseconds under 1s
return duration.format(showMilliSeconds = false, showSmallerUnits = true)
}

private fun isGoldenFishActive() = confirmedGoldenFishEntity != null

Expand Down
57 changes: 57 additions & 0 deletions src/main/java/at/hannibal2/skyhanni/utils/ServerTimeMark.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package at.hannibal2.skyhanni.utils

import at.hannibal2.skyhanni.data.MinecraftData
import at.hannibal2.skyhanni.utils.TimeUtils.inWholeTicks
import at.hannibal2.skyhanni.utils.TimeUtils.ticks
import kotlin.time.Duration

/**
* This is a Helper Class similar to [SimpleTimeMark], but for a rough estimate of Server Ticks instead of real time.
*
* This can provide a more accurate estimate of certain timers for ingame events, because some are based off of
* the server's tps instead of real time, and therefore are affected by server lag.
*/
@JvmInline
value class ServerTimeMark private constructor(val ticks: Long) : Comparable<ServerTimeMark> {

operator fun minus(other: ServerTimeMark): Duration =
(ticks - other.ticks).ticks

operator fun plus(other: Duration) =
ServerTimeMark(ticks + other.inWholeTicks)

operator fun minus(other: Duration): ServerTimeMark = plus(-other)

fun passedSince(): Duration = now() - this

fun timeUntil(): Duration = -passedSince()

fun isInPast(): Boolean = timeUntil().isNegative()

fun isInFuture(): Boolean = timeUntil().isPositive()

fun isFarPast(): Boolean = this == FAR_PAST

fun isFarFuture(): Boolean = ticks == FAR_FUTURE_TICKS

override fun compareTo(other: ServerTimeMark): Int = ticks.compareTo(other.ticks)

override fun toString(): String = when (ticks) {
FAR_PAST_TICKS -> "The Far Past"
FAR_FUTURE_TICKS -> "The Far Future"
else -> "ServerTimeMark(ticks=$ticks, now=${MinecraftData.totalServerTicks})"
}

companion object {

fun now() = ServerTimeMark(MinecraftData.totalServerTicks)

private const val FAR_PAST_TICKS = Long.MIN_VALUE
private const val FAR_FUTURE_TICKS = Long.MAX_VALUE

val FAR_PAST = ServerTimeMark(FAR_PAST_TICKS)
val FAR_FUTURE = ServerTimeMark(FAR_FUTURE_TICKS)

}

}

0 comments on commit 9fb3897

Please sign in to comment.