Skip to content

Commit

Permalink
反作弊功能更新
Browse files Browse the repository at this point in the history
添加BlinkA检查。
添加AirJumpA检查。
添加AirPlaceA检查。
添加SpeedA检查。
修复一些误判。
更改架构,改善性能。

已知误判:
- **FlightA** 鞘翅、三叉戟。
- **BlinkA** 状态效果。
- **SpeedA** 状态效果、道具。
- **AirJumpA** blink时意外触发。
  • Loading branch information
xia-mc committed Mar 30, 2024
1 parent 47363d0 commit 627bb50
Show file tree
Hide file tree
Showing 13 changed files with 374 additions and 135 deletions.
73 changes: 34 additions & 39 deletions src/main/java/top/infsky/timerecorder/anticheat/Check.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,63 @@
import lombok.Getter;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ServerGamePacketListener;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import top.infsky.timerecorder.config.AntiCheatConfig;
import top.infsky.timerecorder.config.ModConfig;
import top.infsky.timerecorder.data.PlayerData;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import top.infsky.timerecorder.log.LogUtils;

import static top.infsky.timerecorder.anticheat.TRPlayer.CONFIG;

@Getter
public abstract class Check {
protected final TRPlayer player;
public String checkName;
public PlayerData playerData;
public final ServerPlayer player;
public static AntiCheatConfig CONFIG() { return ModConfig.INSTANCE.getAntiCheat(); }
public double violations;

@Nullable public Integer setbackFoodLevel;

public Vec3 currentPos;
public Vec3 lastPos;
public Vec3 lastPos2;
public Vec3 lastOnGroundPos;
public Vec3 lastInWaterPos;

public Check(String checkName, @NotNull PlayerData playerData) {
assert playerData.player != null;
public Check(String checkName, @NotNull TRPlayer player) {
this.checkName = checkName;
this.playerData = playerData;
this.player = (ServerPlayer) playerData.player;
currentPos = player.position();
this.player = player;
}

public final void flag() {
playerData.antiCheat.violations++;
LogUtils.alert(playerData.getName(), checkName, String.format("VL: %s", playerData.antiCheat.violations));
violations++;
LogUtils.alert(player.playerData.getName(), checkName, String.format("VL: %s", violations));
}

public final void flag(String extraMsg) {
playerData.antiCheat.violations++;
LogUtils.alert(playerData.getName(), checkName, extraMsg);
violations++;
LogUtils.alert(player.playerData.getName(), checkName, extraMsg);
}

public final void setback(@NotNull Vec3 position) {
if (!CONFIG().isAllowSetback()) return;
player.teleportTo(position.x(), position.y(), position.z());
player.connection.resetPosition();
player.hasSetback = true;
player.needToDoNextTick.add(() -> player.needToDoNextTick.add(() -> player.hasSetback = false));
player.fabricPlayer.moveTo(position);
player.fabricPlayer.teleportTo(position.x(), position.y(), position.z());
player.fabricPlayer.connection.resetPosition();
}

public void _onTick() {}
public final void setback(@NotNull CallbackInfo ci) {
if (!CONFIG().isAllowSetback()) return;
ci.cancel();
player.fabricPlayer.connection.resetPosition();
if (setbackFoodLevel == null)
setbackFoodLevel = player.fabricPlayer.getFoodData().getFoodLevel();
player.fabricPlayer.getFoodData().setFoodLevel(0);
player.needToDoNextTick.add(() -> {
player.fabricPlayer.getFoodData().setFoodLevel(setbackFoodLevel);
setbackFoodLevel = null;
});
}

public void _onTick() {}
public void _onTeleport() {}
public void _onJump() {}
public void _onPacketReceive(Packet<ServerGamePacketListener> packet, CallbackInfo ci) {}

public void _onPacketReceive(Packet<ServerGamePacketListener> packet) {}

public void update() {
if (player == null) return;
currentPos = player.position();
if (player.onGround()) {
lastOnGroundPos = currentPos;
}
if (player.isInWater()) {
lastInWaterPos = currentPos;
}
_onTick();
lastPos2 = lastPos;
lastPos = currentPos;
}
}
38 changes: 22 additions & 16 deletions src/main/java/top/infsky/timerecorder/anticheat/CheckManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,43 @@
import net.minecraft.network.protocol.game.ServerGamePacketListener;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.infsky.timerecorder.anticheat.checks.BlinkA;
import top.infsky.timerecorder.anticheat.checks.FlightA;
import top.infsky.timerecorder.data.PlayerData;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import top.infsky.timerecorder.anticheat.checks.*;

import java.util.ArrayList;
import java.util.List;

public class CheckManager {
public final PlayerData playerData;
public final TRPlayer player;
public List<Check> checks = new ArrayList<>();
public double violations = 0;
public CheckManager(List<Check> checks, PlayerData playerData) {
this.playerData = playerData;
public CheckManager(List<Check> checks, TRPlayer player) {
this.player = player;
this.checks.addAll(checks);
}

@Contract("_ -> new")
public static @NotNull CheckManager create(PlayerData playerData) {
public static @NotNull CheckManager create(TRPlayer player) {
final CheckManager checkManager = new CheckManager(List.of(
new FlightA(playerData),
new BlinkA(playerData)
), playerData);
new FlightA(player),
new BlinkA(player),
new AirJumpA(player),
new AirPlaceA(player),
new SpeedA(player)
), player);
checkManager.onTeleport();
return checkManager;
}

public void update() {
assert playerData.player != null;
if (playerData.player.isSpectator()) return;
if (player.fabricPlayer.isSpectator() || player.fabricPlayer.isCreative()) return;
for (Check check : checks) {
check.update();
check._onTick();
}
}

public void onPacketReceive(Packet<ServerGamePacketListener> packet, CallbackInfo ci) {
for (Check check : checks) {
check._onPacketReceive(packet, ci);
}
}

Expand All @@ -44,9 +50,9 @@ public void onTeleport() {
}
}

public void onPacketReceive(Packet<ServerGamePacketListener> packet) {
public void onJump() {
for (Check check : checks) {
check._onPacketReceive(packet);
check._onJump();
}
}
}
83 changes: 83 additions & 0 deletions src/main/java/top/infsky/timerecorder/anticheat/TRPlayer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package top.infsky.timerecorder.anticheat;

import lombok.Getter;
import lombok.val;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Range;
import top.infsky.timerecorder.Utils;
import top.infsky.timerecorder.config.AntiCheatConfig;
import top.infsky.timerecorder.config.ModConfig;
import top.infsky.timerecorder.data.PlayerData;

import java.util.LinkedList;
import java.util.List;

/**
* 管理玩家信息的类。每个玩家都应有一个TRPlayer实例。
*/
@Getter
public class TRPlayer {
public ServerPlayer fabricPlayer;
public CheckManager manager;
public PlayerData playerData;
public static MinecraftServer SERVER = Utils.getSERVER();

public static AntiCheatConfig CONFIG() { return ModConfig.INSTANCE.getAntiCheat(); }
public Vec3 currentPos;
public Vec3 lastPos;
@Range(from = 0, to = 19) public List<Vec3> posHistory;
public Vec3 lastOnGroundPos;
public Vec3 lastInLiquidPos;
public boolean lastOnGround;
public boolean hasSetback = false;

public List<Runnable> needToDoNextTick = new LinkedList<>();

public TRPlayer(@NotNull PlayerData playerData) {
this.fabricPlayer = (ServerPlayer) playerData.player;
this.manager = CheckManager.create(this);
this.playerData = playerData;
currentPos = fabricPlayer.position();
lastOnGround = fabricPlayer.onGround();
posHistory = new LinkedList<>();
for (int i = 0; i < 20; i++) {
posHistory.add(currentPos);
}
}

public void update() {
fabricPlayer = (ServerPlayer) playerData.player;
if (fabricPlayer == null) return;

currentPos = fabricPlayer.position();
updatePoses();
if (fabricPlayer.onGround()) {
lastOnGroundPos = currentPos;
}
if (fabricPlayer.isInWater() || fabricPlayer.isInLava()) {
lastInLiquidPos = currentPos;
}

val preTask = needToDoNextTick;
for (Runnable task : preTask) {
task.run();
needToDoNextTick.remove(task);
}
manager.update();


lastPos = currentPos;
lastOnGround = fabricPlayer.onGround();
}

private void updatePoses() {
if (posHistory.size() >= 20) {
posHistory.remove(posHistory.size() - 1);
updatePoses();
}
posHistory.add(0, currentPos);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package top.infsky.timerecorder.anticheat.checks;

import org.jetbrains.annotations.NotNull;
import top.infsky.timerecorder.anticheat.Check;
import top.infsky.timerecorder.anticheat.TRPlayer;

public class AirJumpA extends Check {
public AirJumpA(@NotNull TRPlayer player) {
super("AirJumpA", player);
}

@Override
public void _onJump() {
if (!player.fabricPlayer.onGround()) {
flag();
setback(player.currentPos);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package top.infsky.timerecorder.anticheat.checks;

import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ServerGamePacketListener;
import net.minecraft.network.protocol.game.ServerboundUseItemOnPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.AirBlock;
import net.minecraft.world.phys.BlockHitResult;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import top.infsky.timerecorder.anticheat.Check;
import top.infsky.timerecorder.anticheat.TRPlayer;

import java.util.List;

public class AirPlaceA extends Check {
public AirPlaceA(@NotNull TRPlayer player) {
super("AirPlaceA", player);
}

@Contract("_ -> new")
private static @Unmodifiable List<BlockPos> getBlocksNeedToCheck(@NotNull BlockPos pos) {
return List.of(pos.east(), pos.west(), pos.north(), pos.south(), pos.above(), pos.below());
}

@Override
public void _onPacketReceive(Packet<ServerGamePacketListener> basePacket, CallbackInfo ci) {
if (basePacket instanceof ServerboundUseItemOnPacket packet) {
final BlockHitResult hitResult = packet.getHitResult();
final ServerLevel level = player.fabricPlayer.serverLevel();

short airCount = 0;
for (BlockPos pos : getBlocksNeedToCheck(hitResult.getBlockPos())) {
if (level.getBlockState(pos).getBlock() instanceof AirBlock) {
airCount++;
}
}

if (airCount >= 6) {
flag();
setback(ci);
}
}
}
}
34 changes: 12 additions & 22 deletions src/main/java/top/infsky/timerecorder/anticheat/checks/BlinkA.java
Original file line number Diff line number Diff line change
@@ -1,36 +1,26 @@
package top.infsky.timerecorder.anticheat.checks;

import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ServerGamePacketListener;
import net.minecraft.network.protocol.game.ServerboundKeepAlivePacket;
import org.jetbrains.annotations.NotNull;
import top.infsky.timerecorder.anticheat.Check;
import top.infsky.timerecorder.data.PlayerData;
import top.infsky.timerecorder.anticheat.TRPlayer;

import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import static top.infsky.timerecorder.anticheat.TRPlayer.CONFIG;

public class BlinkA extends Check {
public Queue<ServerboundKeepAlivePacket> keepAlivePackets = new LinkedBlockingQueue<>(10);

public BlinkA(@NotNull PlayerData playerData) {
super("BlinkA", playerData);
}

@Override
public void _onPacketReceive(Packet<ServerGamePacketListener> packet) {
if (packet instanceof ServerboundKeepAlivePacket) {
try {
keepAlivePackets.add((ServerboundKeepAlivePacket) packet);
} catch (IllegalStateException ignored) {
keepAlivePackets.poll();
keepAlivePackets.add((ServerboundKeepAlivePacket) packet);
}
}
public class BlinkA extends Check {

public BlinkA(@NotNull TRPlayer player) {
super("BlinkA", player);
}

@Override
public void _onTick() {
if (player.lastPos == null || player.hasSetback) return;

if (player.lastPos.distanceTo(player.currentPos) > (player.fabricPlayer.getSpeed() * 10 + player.fabricPlayer.fallDistance + CONFIG().getThreshold())) {
flag();

setback(player.lastPos);
}
}
}
Loading

0 comments on commit 627bb50

Please sign in to comment.