Skip to content

Commit

Permalink
反作弊更新
Browse files Browse the repository at this point in the history
添加一个实验性的默认关闭的反作弊。目前仅包含飞行检查。
已知误判:游泳、跳跃提升。
  • Loading branch information
xia-mc committed Mar 26, 2024
1 parent 4575945 commit aaacc29
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 31 deletions.
35 changes: 35 additions & 0 deletions src/main/java/top/infsky/timerecorder/anticheat/Check.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package top.infsky.timerecorder.anticheat;

import lombok.Getter;
import top.infsky.timerecorder.data.PlayerData;
import top.infsky.timerecorder.log.LogUtils;

@Getter
public abstract class Check {
public String checkName;
public PlayerData player;

public Check(String checkName, PlayerData player) {
this.checkName = checkName;
this.player = player;
}

public final void flag() {
assert player.antiCheat != null;
player.antiCheat.violations++;
LogUtils.alert(player.getName(), checkName);
}

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

public abstract void _onTick();

public void update() {
if (player == null) return;
_onTick();
}
}
30 changes: 30 additions & 0 deletions src/main/java/top/infsky/timerecorder/anticheat/CheckManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package top.infsky.timerecorder.anticheat;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.infsky.timerecorder.anticheat.checks.FlightA;
import top.infsky.timerecorder.data.PlayerData;

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

public class CheckManager {
public List<Check> checks = new ArrayList<>();
public double violations = 0;
public CheckManager(List<Check> checks) {
this.checks.addAll(checks);
}

@Contract("_ -> new")
public static @NotNull CheckManager create(PlayerData playerData) {
return new CheckManager(List.of(
new FlightA(playerData)
));
}

public void update() {
for (Check check : checks) {
check.update();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package top.infsky.timerecorder.anticheat.checks;

import net.minecraft.world.phys.Vec3;
import top.infsky.timerecorder.anticheat.Check;
import top.infsky.timerecorder.config.ModConfig;
import top.infsky.timerecorder.data.PlayerData;

public class FlightA extends Check {
public Vec3 lastPos;
public Vec3 lastPos2;
public Vec3 lastOnGroundPos;
public short disableTick = 0;

public FlightA(PlayerData player) {
super("FlightA", player);
assert player.player != null;
lastPos = player.player.position();
}

@Override
public void _onTick() {
assert player.player != null;

// fix jump
if (player.player.onGround()) {
lastOnGroundPos = player.player.position();
disableTick = 8;
}

if (!player.player.onGround() && disableTick > 0
&& player.player.position().y() - lastOnGroundPos.y() < 1.25219 + ModConfig.INSTANCE.getAntiCheat().getThreshold()) {
disableTick--;
} else if (lastPos2 != null && !player.player.onGround()) {
disableTick = 0;
if (lastPos.y() - player.player.position().y() < ModConfig.INSTANCE.getAntiCheat().getThreshold() &&
lastPos2.y() - lastPos.y() <= ModConfig.INSTANCE.getAntiCheat().getThreshold()) {
flag(String.format("Pos:%s OnGround:%s", player.player.position(), player.player.onGround()));
}
}
lastPos2 = lastPos;
lastPos = player.player.position();
}
}
21 changes: 21 additions & 0 deletions src/main/java/top/infsky/timerecorder/command/AlertCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package top.infsky.timerecorder.command;

import com.mojang.brigadier.context.CommandContext;
import net.minecraft.ChatFormatting;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.NotNull;
import top.infsky.timerecorder.config.ModConfig;

import java.util.Objects;

public class AlertCommand {
public static int execute(@NotNull CommandContext<CommandSourceStack> context) {
if (context.getSource().isPlayer()) {
ModConfig.INSTANCE.getAntiCheat().getAllowAlertPlayers().add(Objects.requireNonNull(context.getSource().getPlayer()).getStringUUID());
ModConfig.INSTANCE.save();
context.getSource().sendSystemMessage(Component.literal("警报已开启").withStyle(ChatFormatting.AQUA).withStyle(ChatFormatting.BOLD));
}
return 1;
}
}
55 changes: 29 additions & 26 deletions src/main/java/top/infsky/timerecorder/command/ICmdEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,35 @@ public class ICmdEvent {
public static void register(@NotNull CommandDispatcher<CommandSourceStack> dispatcher) {
dispatcher.register(literal("tr") // 没参数默认显示帮助信息
.executes(HelpCommand::execute)
.then(literal("help") // 显示帮助信息
.executes(HelpCommand::execute))
.then(literal("reload") // 热重载
.requires(source -> source.hasPermission(2))
.executes(ReloadCommand::execute))
.then(literal("dump")
.requires(source -> source.hasPermission(2))
.then(literal("save") // 保存迄今的统计数据
.executes(DumpCommand.Save::execute))
.then(literal("load") // 从文件还原统计数据
.executes(DumpCommand.Load::execute)
.then(argument("filename", StringArgumentType.string())
.executes(DumpCommand.Load.Custom::execute))))
.then(literal("report") // 对自己显示当日截止目前的统计信息
.executes(ReportCommand::execute))
.then(literal("reportall") // 对自己显示当日截止目前的所有玩家的统计信息
.requires(source -> source.hasPermission(2))
.executes(ReportAllCommand::execute))
.then(literal("reportqq") // 对所有人显示和发送当日截止目前的统计信息到QQ
.requires(source -> source.hasPermission(2))
.executes(ReportQQCommand::execute))
.then(literal("recall") // 撤回上一条消息
.executes(RecallCommand::execute)
.then(literal("confirm") // 确认撤回(由/tr recall触发)
.then(argument("message_id", IntegerArgumentType.integer())
.executes(RecallCommand.Confirm::execute))))
.then(literal("help") // 显示帮助信息
.executes(HelpCommand::execute))
.then(literal("reload") // 热重载
.requires(source -> source.hasPermission(2))
.executes(ReloadCommand::execute))
.then(literal("dump")
.requires(source -> source.hasPermission(2))
.then(literal("save") // 保存迄今的统计数据
.executes(DumpCommand.Save::execute))
.then(literal("load") // 从文件还原统计数据
.executes(DumpCommand.Load::execute)
.then(argument("filename", StringArgumentType.string())
.executes(DumpCommand.Load.Custom::execute))))
.then(literal("report") // 对自己显示当日截止目前的统计信息
.executes(ReportCommand::execute))
.then(literal("reportall") // 对自己显示当日截止目前的所有玩家的统计信息
.requires(source -> source.hasPermission(2))
.executes(ReportAllCommand::execute))
.then(literal("reportqq") // 对所有人显示和发送当日截止目前的统计信息到QQ
.requires(source -> source.hasPermission(2))
.executes(ReportQQCommand::execute))
.then(literal("recall") // 撤回上一条消息
.executes(RecallCommand::execute)
.then(literal("confirm") // 确认撤回(由/tr recall触发)
.then(argument("message_id", IntegerArgumentType.integer())
.executes(RecallCommand.Confirm::execute))))
.then(literal("alert") // 启用警报
.requires(source -> source.hasPermission(2))
.executes(AlertCommand::execute))
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@
import lombok.Setter;
import org.tomlj.TomlTable;

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

@Getter
@Setter
public class AntiCheatConfig extends AutoLoadTomlConfig {
@TableField(rightComment = "启用反作弊")
private boolean enable = false;
@TableField(rightComment = "允许展示警报的玩家")
private List<String> allowAlertPlayers = new ArrayList<>();
@TableField(rightComment = "最大偏移量")
private double threshold = 0.001;

public AntiCheatConfig() {
super(null);
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/top/infsky/timerecorder/config/ModConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ public class ModConfig extends AutoReloadToml {
private CommonConfig common = new CommonConfig();
@TableField(value = "addon", topComment = "扩展")
private AddonConfig addon = new AddonConfig();
// @TableField(value = "anticheat", topComment = "反作弊(实验性)")
// private AntiCheatConfig antiCheatConfig = new AntiCheatConfig();
@TableField(value = "anticheat", topComment = "反作弊(实验性)")
private AntiCheatConfig antiCheat = new AntiCheatConfig();


public ModConfig() {
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/top/infsky/timerecorder/data/PlayerData.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.infsky.timerecorder.Utils;
import top.infsky.timerecorder.anticheat.CheckManager;
import top.infsky.timerecorder.compat.CarpetCompat;
import top.infsky.timerecorder.config.ModConfig;
import top.infsky.timerecorder.data.mcstats.StatsObject;
Expand All @@ -23,7 +24,9 @@ public class PlayerData {
@Nullable
public Player player; // 玩家
@Nullable
public ServerStatsCounter vanillaStats; // 原版统计信息
public ServerStatsCounter vanillaStats; // 原版统计信息
@Nullable
public CheckManager antiCheat; // 反作弊模块

public String name; // 名字

Expand Down Expand Up @@ -53,6 +56,7 @@ public PlayerData(@NotNull Player gamePlayer, boolean isFakePlayer) {
messageSent = new LinkedBlockingDeque<>();
vanillaStats = ((ServerPlayer) player).getStats();
statsObject = new StatsObject((ServerPlayer) player, vanillaStats);
antiCheat = CheckManager.create(this);
}

/**
Expand Down Expand Up @@ -98,6 +102,7 @@ public void update() {
OP = player.hasPermissions(2);
if (fakePlayer) fakePlayer = CarpetCompat.isFakePlayer(player);
playTime += 1;
if (ModConfig.INSTANCE.getAntiCheat().isEnable() && antiCheat != null) antiCheat.update();
}

/**
Expand Down
24 changes: 22 additions & 2 deletions src/main/java/top/infsky/timerecorder/log/LogUtils.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,40 @@
package top.infsky.timerecorder.log;

import lombok.Getter;
import net.minecraft.network.chat.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.infsky.timerecorder.Utils;
import top.infsky.timerecorder.config.ModConfig;

import java.util.Objects;
import java.util.UUID;

@Getter
public class LogUtils {
public static final Logger LOGGER = LoggerFactory.getLogger("TimeRecorder"); // 抄代码抄的

public static void alert(String player, String module, String extraMsg) {
// LOGGER.info(String.format("§b§lTR§r§l> §r%s 触发了 %s | %s", player, module, extraMsg));
LOGGER.info(String.format("TR> %s 触发了 %s | %s", player, module, extraMsg));
ModConfig.INSTANCE.getAntiCheat().getAllowAlertPlayers().forEach(string -> {
assert Utils.getSERVER() != null;
try {
Objects.requireNonNull(Utils.getSERVER().getPlayerList().getPlayer(UUID.fromString(string))).sendSystemMessage(Component.literal(
String.format("§b§lTR§r§l> §r%s 触发了 %s | %s", player, module, extraMsg)
));
} catch (NullPointerException ignored) {}
});
}

public static void alert(String player, String module) {
// LOGGER.info(String.format("§b§lTR§r§l> §r%s 触发了 %s", player, module));
LOGGER.info(String.format("TR> %s 触发了 %s", player, module));
ModConfig.INSTANCE.getAntiCheat().getAllowAlertPlayers().forEach(string -> {
assert Utils.getSERVER() != null;
try {
Objects.requireNonNull(Utils.getSERVER().getPlayerList().getPlayer(UUID.fromString(string))).sendSystemMessage(Component.literal(
String.format("§b§lTR§r§l> §r%s 触发了 %s", player, module)
));
} catch (NullPointerException ignored) {}
});
}
}

0 comments on commit aaacc29

Please sign in to comment.