diff --git a/common/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt b/common/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt index 729e8a718..c11a3769b 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt @@ -18,14 +18,23 @@ package com.lambda.module.modules.network import com.lambda.event.events.PacketEvent +import com.lambda.event.events.PlayerEvent +import com.lambda.event.events.RenderEvent import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.graphics.renderer.gui.FontRenderer import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.Communication.info import com.lambda.util.collections.LimitedDecayQueue +import com.lambda.util.math.Vec2d +import net.minecraft.client.gui.screen.ingame.GenericContainerScreen import net.minecraft.network.packet.c2s.common.CommonPongC2SPacket -import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.* +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.Full +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.LookAndOnGround +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.OnGroundOnly +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.PositionAndOnGround import net.minecraft.network.packet.c2s.play.TeleportConfirmC2SPacket +import java.awt.Color // ToDo: HUD info object PacketLimiter : Module( @@ -33,11 +42,12 @@ object PacketLimiter : Module( description = "Limits the amount of packets sent to the server", defaultTags = setOf(ModuleTag.NETWORK) ) { - private var packetQueue = LimitedDecayQueue(99, 1000) - private val limit by setting("Limit", 99, 1..100, 1, "The maximum amount of packets to send per given time interval", unit = " packets") + private val page by setting("Page", Page.General) + + private val limit by setting("Limit", 99, 1..1000, 1, "The maximum amount of packets to send per given time interval", unit = " packets") { page == Page.General } .onValueChange { _, to -> packetQueue.setSizeLimit(to) } - private val interval by setting("Duration", 4000L, 1L..10000L, 50L, "The interval / duration in milliseconds to limit packets for", unit = " ms") + private val interval by setting("Duration", 4000L, 1L..10000L, 50L, "The interval / duration in milliseconds to limit packets for", unit = " ms") { page == Page.General } .onValueChange { _, to -> packetQueue.setDecayTime(to) } private val defaultIgnorePackets = setOf( @@ -48,21 +58,63 @@ object PacketLimiter : Module( OnGroundOnly::class, TeleportConfirmC2SPacket::class ) - private val ignorePackets by setting("Ignore Packets", defaultIgnorePackets.mapNotNull { it.simpleName }, "Packets to ignore when limiting") - init { - onEnable { - packetQueue = LimitedDecayQueue(limit, interval) - } + private val limitAllPackets by setting("Limit All", false, "Limit all send packets") { page == Page.General } + private val ignorePackets by setting("Ignore Packets", defaultIgnorePackets.mapNotNull { it.simpleName }, "Packets to ignore when limiting") { page == Page.General && limitAllPackets } + + private val limitClicks by setting("Clicks Limit", true, "Limits the amount of click packets you can send to prevent kicks on certain servers.") { page == Page.Clicks } + private val limitClickWindowSize by setting("Click Limit Window Size", 4.0, 0.1..10.0, 0.1, "Click limit window size", unit = " s") { page == Page.Clicks && limitClicks } + .onValueChange { _, to -> clickPacketQueue.setDecayTime((to * 1000).toLong()) } + private val limitClickRate by setting("Click Limit Rate", 19, 1..40, 1, "Click limit rate", unit = " packets/sec") { page == Page.Clicks && limitClicks } + .onValueChange { _, to -> clickPacketQueue.setSizeLimit((limitClickWindowSize * to).toInt()) } + private val limitClickRender by setting("Render Limit in Container", true, "Render the amount of clicks remaining in the container screen") { page == Page.Clicks && limitClicks } + + private var packetQueue = LimitedDecayQueue(999, 1000) + private var clickPacketQueue = LimitedDecayQueue(500, 30000) + private val clickPacketsWindowAmount: Double + get() = limitClickWindowSize * limitClickRate + + private val clickPacketsRemaining: Int + get() = clickPacketsWindowAmount.toInt() - clickPacketQueue.size + + private val canSendClickPackets: Boolean + get() = clickPacketQueue.size + 1 <= clickPacketsWindowAmount + + init { listen(Int.MAX_VALUE) { if (it.packet::class.simpleName in ignorePackets) return@listen - -// this@PacketLimiter.info("Packet sent: ${it.packet::class.simpleName} (${packetQueue.size} / $limit) ${Instant.now()}") if (packetQueue.add(it)) return@listen it.cancel() this@PacketLimiter.info("Packet limit reached, dropping packet: ${it.packet::class.simpleName} (${packetQueue.size} / $limit)") } + + listen { + if (limitClicks && !canSendClickPackets) it.cancel() + else if (clickPacketQueue.add(Unit)) return@listen + + this@PacketLimiter.info("Slot click limit reached, dropping ${it.action} at ${it.slot} in ${it.screenHandler::class.simpleName} (${clickPacketQueue.size} / $limitClickRate)") + } + + listen { + if (!limitClickRender) return@listen + + val screen = mc.currentScreen as? GenericContainerScreen ?: return@listen + val mcScale = mc.window.scaleFactor + val fontHeight = FontRenderer.getHeight(mcScale * 1.5) + val position = Vec2d(screen.x * mcScale, screen.y * mcScale - fontHeight) + + FontRenderer.drawString("Clicks Remaining: $clickPacketsRemaining", position, Color(0x9DFFFF)) + } + + onEnable { + packetQueue = LimitedDecayQueue(limit, interval) + } + } + + enum class Page { + General, + Clicks } } diff --git a/common/src/main/resources/lambda.accesswidener b/common/src/main/resources/lambda.accesswidener index 9e33b952c..5dbe47b66 100644 --- a/common/src/main/resources/lambda.accesswidener +++ b/common/src/main/resources/lambda.accesswidener @@ -40,6 +40,10 @@ accessible field com/mojang/blaze3d/systems/RenderSystem$ShapeIndexBuffer id I accessible field net/minecraft/client/render/BufferRenderer currentVertexBuffer Lnet/minecraft/client/gl/VertexBuffer; accessible field net/minecraft/client/texture/NativeImage pointer J accessible class net/minecraft/client/gui/screen/SplashOverlay$LogoTexture +accessible field net/minecraft/client/gui/screen/ingame/HandledScreen x I +accessible field net/minecraft/client/gui/screen/ingame/HandledScreen y I +accessible field net/minecraft/client/gui/screen/ingame/HandledScreen backgroundWidth I +accessible field net/minecraft/client/gui/screen/Screen textRenderer Lnet/minecraft/client/font/TextRenderer; # Text accessible field net/minecraft/text/Style color Lnet/minecraft/text/TextColor;