package wtf.dettex.modules.impl.movement;
import antidaunleak.api.annotation.Native;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket;
import wtf.dettex.event.EventHandler;
import wtf.dettex.modules.api.Module;
import wtf.dettex.modules.api.ModuleCategory;
import wtf.dettex.modules.setting.implement.BooleanSetting;
import wtf.dettex.modules.setting.implement.ValueSetting;
import wtf.dettex.common.util.entity.PlayerIntersectionUtil;
import wtf.dettex.common.util.other.StopWatch;
import wtf.dettex.event.impl.packet.PacketEvent;
import wtf.dettex.event.impl.player.TickEvent;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
@FieldDefaults(level = AccessLevel.PRIVATE)
public class BlockFly extends Module {
private final ValueSetting intervalSetting = new ValueSetting("Interval", "Интервал в мс")
.range(50f, 5000f).setValue(500f);
private final ValueSetting maxQueueSetting = new ValueSetting("MaxQueue", "Размер очереди")
.range(100f, 5000f).setValue(1000f);
private final BooleanSetting debugSetting = new BooleanSetting("Debug", "Логирование").setValue(false);
private final Queue<Packet<?>> storedPackets = new LinkedList<>();
private final Random random = new Random();
private boolean sending = false;
private final StopWatch pulseTimer = new StopWatch();
private int currentDelayMs = 0;
public BlockFly() {
super("BlockFly", "BlockFly", ModuleCategory.MOVEMENT);
setup(intervalSetting, maxQueueSetting, debugSetting);
}
@Override
@Native(type = Native.Type.VMProtectBeginUltra)
public void activate() {
if (PlayerIntersectionUtil.nullCheck()) {
setState(false);
return;
}
storedPackets.clear();
sending = false;
pulseTimer.reset();
currentDelayMs = getDelay();
}
@Override
@Native(type = Native.Type.VMProtectBeginUltra)
public void deactivate() {
if (!PlayerIntersectionUtil.nullCheck()) {
flushPackets();
}
}
@EventHandler
@Native(type = Native.Type.VMProtectBeginUltra)
public void onTick(TickEvent e) {
if (PlayerIntersectionUtil.nullCheck()) return;
if (pulseTimer.finished(currentDelayMs) && !storedPackets.isEmpty()) {
flushPackets();
pulseTimer.reset();
currentDelayMs = getDelay();
}
}
@EventHandler
@Native(type = Native.Type.VMProtectBeginUltra)
public void onPacket(PacketEvent e) {
if (PlayerIntersectionUtil.nullCheck() || !e.isSend() || sending) return;
Packet<?> packet = e.getPacket();
// Не блокируем важные пакеты
if (packet instanceof PlayerMoveC2SPacket || packet instanceof ClientCommandC2SPacket) {
return;
}
if (storedPackets.size() >= (int) maxQueueSetting.getValue()) {
return;
}
e.cancel();
storedPackets.add(packet);
}
private int flushPackets() {
if (PlayerIntersectionUtil.nullCheck()) return 0;
sending = true;
int count = 0;
while (!storedPackets.isEmpty()) {
Packet<?> packet = storedPackets.poll();
if (packet != null) {
mc.getNetworkHandler().sendPacket(packet);
count++;
}
}
sending = false;
return count;
}
private int getDelay() {
return rand(150, 250);
}
private int rand(int min, int max) {
return min + random.nextInt(max - min + 1);
}
public String getDisplayInfo() {
return String.valueOf(storedPackets.size());
}
}