From 36aecf8d01eab58513a3ba804e119fa729b22fad Mon Sep 17 00:00:00 2001 From: 1zuna <1zuna@ccbluex.net> Date: Mon, 2 Dec 2024 04:07:17 +0100 Subject: [PATCH] fix(PacketQueueManager): schedule order and packet tracking (#4783) --- .../minecraft/client/MixinMinecraftClient.java | 8 ++++++++ .../net/ccbluex/liquidbounce/event/EventManager.kt | 1 + .../liquidbounce/event/events/GameEvents.kt | 8 ++++++++ .../module/modules/combat/ModuleBacktrack.kt | 2 +- .../modules/combat/velocity/ModuleVelocity.kt | 8 ++++---- .../liquidbounce/utils/aiming/RotationsUtil.kt | 10 +++++----- .../liquidbounce/utils/client/NetworkUtils.kt | 10 +++++++++- .../utils/client/PacketQueueManager.kt | 14 ++++++-------- .../ccbluex/liquidbounce/utils/kotlin/Priority.kt | 5 +++++ 9 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/client/MixinMinecraftClient.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/client/MixinMinecraftClient.java index 5489588cde2..bdd0652b459 100644 --- a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/client/MixinMinecraftClient.java +++ b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/minecraft/client/MixinMinecraftClient.java @@ -238,6 +238,14 @@ private void hookTickEvent(CallbackInfo callbackInfo) { EventManager.INSTANCE.callEvent(new GameTickEvent()); } + /** + * Hook game render task queue event + */ + @Inject(method = "render", at = @At("HEAD")) + private void hookRenderTaskQueue(CallbackInfo callbackInfo) { + EventManager.INSTANCE.callEvent(new GameRenderTaskQueueEvent()); + } + /** * Hook input handling */ diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/event/EventManager.kt b/src/main/kotlin/net/ccbluex/liquidbounce/event/EventManager.kt index bcd0f437a7b..c2c3df8bf39 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/event/EventManager.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/event/EventManager.kt @@ -30,6 +30,7 @@ import kotlin.reflect.KClass */ val ALL_EVENT_CLASSES: Array> = arrayOf( GameTickEvent::class, + GameRenderTaskQueueEvent::class, BlockChangeEvent::class, ChunkLoadEvent::class, ChunkDeltaUpdateEvent::class, diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/event/events/GameEvents.kt b/src/main/kotlin/net/ccbluex/liquidbounce/event/events/GameEvents.kt index e90712afcc3..6f19bcf721f 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/event/events/GameEvents.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/event/events/GameEvents.kt @@ -35,6 +35,14 @@ import net.minecraft.text.Text @Nameable("gameTick") class GameTickEvent : Event() +/** + * We can use this event to populate the render task queue with tasks that should be + * executed in the same frame. This is useful for more responsive task execution + * and allows to also schedule tasks off-schedule. + */ +@Nameable("gameRenderTaskQueue") +class GameRenderTaskQueueEvent : Event() + @Nameable("key") @WebSocketEvent class KeyEvent(val key: InputUtil.Key, val action: Int) : Event() diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/ModuleBacktrack.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/ModuleBacktrack.kt index 0912d113085..9120134cb43 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/ModuleBacktrack.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/ModuleBacktrack.kt @@ -242,7 +242,7 @@ object ModuleBacktrack : ClientModule("Backtrack", Category.COMBAT) { * That gets called first, then the client's packets. */ @Suppress("unused") - private val tickHandler = handler(priority = 1002) { + private val handleRenderTaskQueue = handler { if (shouldCancelPackets()) { processPackets() } else { diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/velocity/ModuleVelocity.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/velocity/ModuleVelocity.kt index 91187b6be7b..a5a2090bb80 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/velocity/ModuleVelocity.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/combat/velocity/ModuleVelocity.kt @@ -73,17 +73,17 @@ object ModuleVelocity : ClientModule("Velocity", Category.COMBAT) { } @Suppress("unused") - private val packetHandler = sequenceHandler(priority = 1) { - val packet = it.packet + private val packetHandler = sequenceHandler(priority = 1) { event -> + val packet = event.packet - if (!it.original) { + if (!event.original) { return@sequenceHandler } if (packet is EntityVelocityUpdateS2CPacket && packet.entityId == player.id || packet is ExplosionS2CPacket) { // When delay is above 0, we will delay the velocity update if (delay.last > 0) { - it.cancelEvent() + event.cancelEvent() delay.random().let { ticks -> if (ticks > 0) { diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/RotationsUtil.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/RotationsUtil.kt index 39ff3461f5e..63c02cab281 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/RotationsUtil.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/aiming/RotationsUtil.kt @@ -378,10 +378,11 @@ object RotationManager : EventListener { * sometimes we update the rotation off chain (e.g. on interactItem) * and the player.lastYaw and player.lastPitch are not updated. */ - val packetHandler = handler(priority = -1000) { event -> - val packet = event.packet - - val rotation = when (packet) { + @Suppress("unused") + val packetHandler = handler( + priority = EventPriorityConvention.READ_FINAL_STATE + ) { event -> + val rotation = when (val packet = event.packet) { is PlayerMoveC2SPacket -> { // If we are not changing the look, we don't need to update the rotation // but, we want to handle slow start triggers @@ -402,7 +403,6 @@ object RotationManager : EventListener { if (!event.isCancelled) { actualServerRotation = rotation } - theoreticalServerRotation = rotation } diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/client/NetworkUtils.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/client/NetworkUtils.kt index 775f25d7422..dc408a44ffa 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/utils/client/NetworkUtils.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/client/NetworkUtils.kt @@ -19,7 +19,10 @@ package net.ccbluex.liquidbounce.utils.client import net.ccbluex.liquidbounce.config.types.NamedChoice +import net.ccbluex.liquidbounce.event.events.PacketEvent +import net.ccbluex.liquidbounce.event.events.TransferOrigin import net.ccbluex.liquidbounce.features.module.modules.combat.crystalaura.SwitchMode +import net.ccbluex.liquidbounce.utils.aiming.RotationManager import net.ccbluex.liquidbounce.utils.block.SwingMode import net.ccbluex.liquidbounce.utils.inventory.OFFHAND_SLOT import net.minecraft.client.network.ClientPlayerEntity @@ -134,7 +137,12 @@ fun ClientPlayerInteractionManager.interactItem( fun handlePacket(packet: Packet<*>) = runCatching { (packet as Packet).apply(mc.networkHandler) } -fun sendPacketSilently(packet: Packet<*>) = mc.networkHandler?.connection?.send(packet, null) +fun sendPacketSilently(packet: Packet<*>) { + // hack fix for the packet handler not being called on Rotation Manager for tracking + val packetEvent = PacketEvent(TransferOrigin.SEND, packet, false) + RotationManager.packetHandler.handler(packetEvent) + mc.networkHandler?.connection?.send(packetEvent.packet, null) +} enum class MovePacketType(override val choiceName: String, val generatePacket: () -> PlayerMoveC2SPacket) : NamedChoice { diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/client/PacketQueueManager.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/client/PacketQueueManager.kt index a8b7f60e909..8cb44384eb8 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/utils/client/PacketQueueManager.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/client/PacketQueueManager.kt @@ -68,9 +68,7 @@ object PacketQueueManager : EventListener { get() = packetQueue.isNotEmpty() @Suppress("unused") - private val flushHandler = handler( - priority = EventPriorityConvention.FIRST_PRIORITY - ) { + private val flushHandler = handler { if (!inGame) { packetQueue.clear() return@handler @@ -87,7 +85,7 @@ object PacketQueueManager : EventListener { @Suppress("unused") private val packetHandler = handler( - priority = EventPriorityConvention.READ_FINAL_STATE + priority = EventPriorityConvention.FINAL_DECISION ) { event -> // Ignore packets that are already cancelled, as they are already handled if (event.isCancelled) { @@ -186,7 +184,7 @@ object PacketQueueManager : EventListener { } } - fun flush(flushWhen: (PacketSnapshot) -> Boolean) { + fun flush(flushWhen: (PacketSnapshot) -> Boolean) = mc.renderTaskQueue.add(Runnable { packetQueue.removeIf { snapshot -> if (flushWhen(snapshot)) { flushSnapshot(snapshot) @@ -195,9 +193,9 @@ object PacketQueueManager : EventListener { false } } - } + }) - fun flush(count: Int) { + fun flush(count: Int) = mc.renderTaskQueue.add(Runnable { // Take all packets until the counter of move packets reaches count and send them var counter = 0 @@ -215,7 +213,7 @@ object PacketQueueManager : EventListener { break } } - } + }) fun cancel() { positions.firstOrNull().let { pos -> diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/kotlin/Priority.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/kotlin/Priority.kt index 1fc328072f8..b308bd241f4 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/utils/kotlin/Priority.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/kotlin/Priority.kt @@ -59,6 +59,11 @@ object EventPriorityConvention { */ const val OBJECTION_AGAINST_EVERYTHING: Int = -100 + /** + * Used when the event handler should be able to object anything that happened previously + */ + const val FINAL_DECISION: Int = -500 + /** * The event should be called last. It should not only be used for events that want to read the final state of the * event