1818package com.lambda.module.modules.network
1919
2020import com.lambda.event.events.PacketEvent
21+ import com.lambda.event.events.PlayerEvent
22+ import com.lambda.event.events.RenderEvent
2123import com.lambda.event.listener.SafeListener.Companion.listen
2224import com.lambda.module.Module
2325import com.lambda.module.tag.ModuleTag
2426import com.lambda.util.Communication.info
2527import com.lambda.util.collections.LimitedDecayQueue
28+ import com.mojang.blaze3d.systems.RenderSystem
29+ import net.minecraft.client.gui.DrawContext
30+ import net.minecraft.client.gui.screen.ingame.HandledScreen
2631import net.minecraft.network.packet.c2s.common.CommonPongC2SPacket
32+ import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket
2733import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket.*
2834import net.minecraft.network.packet.c2s.play.TeleportConfirmC2SPacket
35+ import net.minecraft.text.Text
2936
3037// ToDo: HUD info
3138object PacketLimiter : Module(
3239 name = " PacketLimiter" ,
3340 description = " Limits the amount of packets sent to the server" ,
3441 defaultTags = setOf(ModuleTag .NETWORK )
3542) {
36- private var packetQueue = LimitedDecayQueue <PacketEvent .Send .Pre >(99 , 1000 )
37- private val limit by setting(" Limit" , 99 , 1 .. 100 , 1 , " The maximum amount of packets to send per given time interval" , unit = " packets" )
43+ private var packetQueue = LimitedDecayQueue <PacketEvent .Send .Pre >(999 , 1000 )
44+ private var clickPacketQueue = LimitedDecayQueue <Long >(500 , 30000 )
45+ private val limit by setting(" Limit" , 99 , 1 .. 1000 , 1 , " The maximum amount of packets to send per given time interval" , unit = " packets" )
3846 .onValueChange { _, to -> packetQueue.setSizeLimit(to) }
3947
4048 private val interval by setting(" Duration" , 4000L , 1L .. 10000L , 50L , " The interval / duration in milliseconds to limit packets for" , unit = " ms" )
@@ -48,7 +56,18 @@ object PacketLimiter : Module(
4856 OnGroundOnly ::class ,
4957 TeleportConfirmC2SPacket ::class
5058 )
51- private val ignorePackets by setting(" Ignore Packets" , defaultIgnorePackets.mapNotNull { it.simpleName }, " Packets to ignore when limiting" )
59+ private val limitAllPackets by setting(" Limit All" , false , " Limit all send packets" )
60+ private val ignorePackets by setting(" Ignore Packets" , defaultIgnorePackets.mapNotNull { it.simpleName }, " Packets to ignore when limiting" ) { limitAllPackets }
61+ private val limitClickPackets by setting(" Clicks limit" , true , " Limits the amount of click packets you can send to prevent kicks." )
62+ private val limitClickWindowSize by setting(" Click limit window size" , 4f , 0.1f .. 10.0f , 0.1f , " Click limit window size" , unit = " s" ) {
63+ limitClickPackets
64+ }.onValueChange { _, to -> clickPacketQueue.setDecayTime((to * 1000 ).toLong()) }
65+ private val limitClickRate by setting(" Click limit rate" , 19.3f , 0.1f .. 40f , 0.1f , " Click limit rate" , unit = " packets/sec" ) {
66+ limitClickPackets
67+ }.onValueChange { _, to -> clickPacketQueue.setSizeLimit((limitClickWindowSize * to).toInt()) }
68+ private val limitClickRender by setting(" Render Limit in Container" , true , " Render the amount of clicks remaining in the container screen" ) {
69+ limitClickPackets
70+ }
5271
5372 init {
5473 onEnable {
@@ -58,11 +77,46 @@ object PacketLimiter : Module(
5877 listen<PacketEvent .Send .Pre >(Int .MAX_VALUE ) {
5978 if (it.packet::class .simpleName in ignorePackets) return @listen
6079
80+ if (limitClickPackets && it.packet is ClickSlotC2SPacket ) {
81+ if (! canSendClickPackets(1 )) {
82+ it.cancel()
83+ return @listen
84+ } else {
85+ clickPacketQueue.add(System .currentTimeMillis())
86+ }
87+ }
88+
6189// [email protected] ("Packet sent: ${it.packet::class.simpleName} (${packetQueue.size} / $limit) ${Instant.now()}")6290 if (packetQueue.add(it)) return @listen
6391
6492 it.cancel()
6593 this @PacketLimiter.info(" Packet limit reached, dropping packet: ${it.packet::class .simpleName} (${packetQueue.size} / $limit )" )
6694 }
95+
96+ listen<PlayerEvent .SlotClick >{
97+ if (! limitClickPackets) return @listen
98+ if (! canSendClickPackets(1 )) {
99+ it.cancel()
100+ return @listen
101+ }
102+ }
103+
104+ listen<RenderEvent .GUI .Container > {
105+ if (! limitClickRender) return @listen
106+ val renderScreen: HandledScreen <* > = it.genericContainerScreen
107+ val context: DrawContext = it.drawContext
108+ val x = renderScreen.x
109+ val y = renderScreen.y
110+
111+ RenderSystem .disableDepthTest()
112+ val remainingText = " Clicks Remaining: " + clickPacketsRemaining().toInt().toString()
113+ context.drawText(renderScreen.textRenderer, Text .literal(remainingText), x + renderScreen.backgroundWidth, y, 4210752 , false )
114+ RenderSystem .enableDepthTest()
115+ }
67116 }
117+
118+ fun canSendClickPackets (packets : Int ) = clickPacketQueue.size + packets < clickPacketsWindowAmount()
119+ fun clickPacketsRemaining () = clickPacketsWindowAmount() - clickPacketQueue.size
120+
121+ private fun clickPacketsWindowAmount () = limitClickWindowSize * limitClickRate
68122}
0 commit comments