Skip to content

Commit

Permalink
反作弊功能更新
Browse files Browse the repository at this point in the history
添加拉回功能,允许反作弊阻止作弊行为。
修复FlightA的游泳误判。
修复FlightA的出水误判。
修复TP误判。

已知误判:跳跃提升、激流、鞘翅。
  • Loading branch information
xia-mc committed Mar 27, 2024
1 parent aaacc29 commit f4113d0
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 40 deletions.
3 changes: 3 additions & 0 deletions src/main/java/top/infsky/timerecorder/TimeRecorder.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package top.infsky.timerecorder;

import cn.evole.mods.mcbot.api.McBotEvents;
import cn.evole.mods.mcbot.init.callbacks.IEvents;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.loader.api.FabricLoader;
Expand All @@ -14,6 +16,7 @@

import java.io.IOException;
import java.nio.file.Files;
import java.util.Objects;

public class TimeRecorder implements ModInitializer {
@Override
Expand Down
9 changes: 2 additions & 7 deletions src/main/java/top/infsky/timerecorder/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,8 @@ public class Utils {
@Getter
public static StatsData statsData;

public static @Nullable PlayerData getPlayer(UUID uuid){
try {
return Objects.requireNonNull(Utils.getStatsData().getPlayerDataMap().get(uuid));
} catch (NullPointerException e) {
LogUtils.LOGGER.error("获取PlayerData时失败", e);
return null;
}
public static @Nullable PlayerData getPlayer(UUID uuid) throws NullPointerException {
return Utils.getStatsData().getPlayerDataMap().get(uuid);
}

public static void sendChatAs(ServerPlayer player, String message) {
Expand Down
48 changes: 39 additions & 9 deletions src/main/java/top/infsky/timerecorder/anticheat/Check.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,65 @@
package top.infsky.timerecorder.anticheat;

import lombok.Getter;
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 top.infsky.timerecorder.log.LogUtils;

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

public Check(String checkName, PlayerData player) {
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;
this.checkName = checkName;
this.player = player;
this.playerData = playerData;
this.player = (ServerPlayer) playerData.player;
currentPos = player.position();
}

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

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

public final void setback(@NotNull Vec3 position) {
if (!CONFIG().isAllowSetback()) return;
player.teleportTo(position.x(), position.y(), position.z());
}

public abstract void _onTick();

public abstract void _onTeleport();

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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,22 @@ public CheckManager(List<Check> checks) {

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

public void update() {
for (Check check : checks) {
check.update();
}
}

public void onTeleport() {
for (Check check : checks) {
check._onTeleport();
}
}
}
59 changes: 39 additions & 20 deletions src/main/java/top/infsky/timerecorder/anticheat/checks/FlightA.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,61 @@

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 jumpTick = 0;
public short waterTick = 0;
public short disableTick = 0;

public Vec3 setbackPos;

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

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

if (disableTick > 0) {
disableTick--;
return;
}

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

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()));
// fix water
if (player.isInWater()) {
waterTick = 8;
setbackPos = lastInWaterPos;
}


if (!player.onGround() && jumpTick > 0
&& currentPos.y() - lastOnGroundPos.y() < 1.25219 + CONFIG().getThreshold()) {
jumpTick--;
} else if (!player.isInWater() && waterTick > 0
// && (lastPos.y() - lastPos2.y() + CONFIG().getThreshold()) > (player.position().y() - lastPos.y()) // 警惕出水弱检测
) {
waterTick--;
} else if (lastPos2 != null && !player.onGround() && !player.isInWater()) {
jumpTick = 0;
waterTick = 0;
if (lastPos.y() - player.position().y() < CONFIG().getThreshold() &&
lastPos2.y() - lastPos.y() <= CONFIG().getThreshold()) {
flag();
setback(setbackPos);
}
}
lastPos2 = lastPos;
lastPos = player.player.position();
}

@Override
public void _onTeleport() {
disableTick = 6;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class RecallCommand {
public static int execute(@NotNull CommandContext<CommandSourceStack> context) {
MessageObject messageObject;
try {
messageObject = Objects.requireNonNull(Utils.getPlayer(Objects.requireNonNull(context.getSource().getPlayer()).getUUID())).getMessageSent().removeLast();
messageObject = Utils.getPlayer(Objects.requireNonNull(context.getSource().getPlayer()).getUUID()).getMessageSent().removeLast();
} catch (NullPointerException | NoSuchElementException ignored) {
LogUtils.LOGGER.error("尝试撤回消息时失败");
context.getSource().sendSystemMessage(Component.literal("无法撤回消息").withStyle(ChatFormatting.DARK_RED));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
public class AntiCheatConfig extends AutoLoadTomlConfig {
@TableField(rightComment = "启用反作弊")
private boolean enable = false;
@TableField(rightComment = "允许拉回")
private boolean allowSetback = true;
@TableField(rightComment = "允许展示警报的玩家")
private List<String> allowAlertPlayers = new ArrayList<>();
@TableField(rightComment = "最大偏移量")
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/top/infsky/timerecorder/data/PlayerData.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ public class PlayerData {
public Player player; // 玩家
@Nullable
public ServerStatsCounter vanillaStats; // 原版统计信息
@Nullable
public CheckManager antiCheat; // 反作弊模块

public String name; // 名字
Expand Down Expand Up @@ -92,6 +91,16 @@ public void playerBuilder() {
}
}

public void playerBuilder(ServerPlayer player) {
try {
this.player = player;
if (player != null)
vanillaStats = player.getStats();
} catch (Exception e) {
LogUtils.LOGGER.error(String.format("恢复玩家 %s 失败。", uuid), e);
}
}

/**
* 更新该玩家的数据(每tick)
*/
Expand Down
1 change: 1 addition & 0 deletions src/main/java/top/infsky/timerecorder/data/StatsData.java
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ private void update(Player player, UUID uuid) {
onlineMap.replace(uuid, true);
try {
playerDataMap.get(uuid).update();
playerDataMap.get(uuid).playerBuilder((ServerPlayer) player);
} catch (NullPointerException e) {
LogUtils.LOGGER.error(String.format("玩家 %s 的数据不存在!丢弃玩家。", player.getName()), e);
onlineMap.remove(uuid);
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/top/infsky/timerecorder/mixins/MixinTeleport.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package top.infsky.timerecorder.mixins;


import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.world.entity.RelativeMovement;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import top.infsky.timerecorder.Utils;

import java.util.Objects;
import java.util.Set;

@Mixin(ServerGamePacketListenerImpl.class)
public abstract class MixinTeleport {
@Shadow public abstract ServerPlayer getPlayer();

@Inject(method = "teleport(DDDFFLjava/util/Set;)V", at = @At(value = "HEAD"))
public void teleport(double d, double e, double f, float g, float h, Set<RelativeMovement> set, CallbackInfo ci) {
try {
Objects.requireNonNull(Utils.getPlayer(this.getPlayer().getUUID())).antiCheat.onTeleport();
} catch (NullPointerException ignored) {}
}
}
3 changes: 2 additions & 1 deletion src/main/resources/timerecorder.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"package": "top.infsky.timerecorder.mixins",
"compatibilityLevel": "JAVA_17",
"mixins": [
"MixinCommand"
"MixinCommand",
"MixinTeleport"
],
"injectors": {
"defaultRequire": 1
Expand Down

0 comments on commit f4113d0

Please sign in to comment.