Compare commits
65
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55c084216d | ||
|
|
ea85282f52 | ||
|
|
d723dec820 | ||
|
|
de03945f42 | ||
|
|
03ea36ad28 | ||
|
|
b27678c753 | ||
|
|
6eb99263a2 | ||
|
|
bde44f5136 | ||
|
|
d5927578a9 | ||
|
|
cc9273d05d | ||
|
|
c354b4481d | ||
|
|
ba8c411ed4 | ||
|
|
da1468e858 | ||
|
|
9708ebc821 | ||
|
|
fad39af575 | ||
|
|
4e4492e417 | ||
|
|
5374ee3c0d | ||
|
|
936662db2d | ||
|
|
7ac2319c07 | ||
|
|
89a795a7e6 | ||
|
|
510247f3b4 | ||
|
|
a61b710e81 | ||
|
|
049c30f8b1 | ||
|
|
21a7bdd395 | ||
|
|
598caa9259 | ||
|
|
0d28fa3a9d | ||
|
|
87c5c1d6c7 | ||
|
|
dde9cea757 | ||
|
|
1fe77a1dd6 | ||
|
|
72a2dfdde4 | ||
|
|
4c039e612b | ||
|
|
b0cd32622e | ||
|
|
3445a0220f | ||
|
|
f1a1e46edc | ||
|
|
343e9ef16d | ||
|
|
c4c063418a | ||
|
|
95955b81f6 | ||
|
|
f4cb19c113 | ||
|
|
f313d0897d | ||
|
|
0293606dc9 | ||
|
|
705f223a70 | ||
|
|
409b1ae646 | ||
|
|
13bd66de7b | ||
|
|
b3d59788b3 | ||
|
|
c58ae74a41 | ||
|
|
aa6d07f893 | ||
|
|
cef044c4fe | ||
|
|
e8c7b9066f | ||
|
|
7f0dbdbc28 | ||
|
|
3890d12105 | ||
|
|
d62755bc01 | ||
|
|
dfc8c988d1 | ||
|
|
508daaa472 | ||
|
|
a765065f98 | ||
|
|
7add2b6658 | ||
|
|
b3d780b52b | ||
|
|
1e46837fec | ||
|
|
ac516060c0 | ||
|
|
a5c34a0829 | ||
|
|
06fa4bab17 | ||
|
|
aabead19ec | ||
|
|
af60e07327 | ||
|
|
b72fafaa47 | ||
|
|
e35845cf7d | ||
|
|
0c78830524 |
No files matched your search
+26
-20
@@ -9,11 +9,15 @@ plugins {
|
||||
}
|
||||
|
||||
group = "ac.grim.grimac"
|
||||
version = "2.3.67"
|
||||
version = "2.3.68"
|
||||
description = "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0."
|
||||
java.sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
java.targetCompatibility = JavaVersion.VERSION_1_8
|
||||
|
||||
// Set to false for debug builds
|
||||
// You cannot live reload classes if the jar relocates dependencies
|
||||
var relocate = true;
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot
|
||||
@@ -34,7 +38,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.github.retrooper:packetevents-spigot:2.5.0-SNAPSHOT")
|
||||
implementation("com.github.retrooper:packetevents-spigot:2.5.1-SNAPSHOT")
|
||||
implementation("co.aikar:acf-paper:0.5.1-SNAPSHOT")
|
||||
implementation("club.minnced:discord-webhooks:0.8.0") // Newer versions include kotlin-stdlib, which leads to incompatibility with plugins that use Kotlin
|
||||
implementation("it.unimi.dsi:fastutil:8.5.13")
|
||||
@@ -133,21 +137,23 @@ publishing.publications.create<MavenPublication>("maven") {
|
||||
tasks.shadowJar {
|
||||
minimize()
|
||||
archiveFileName.set("${project.name}-${project.version}.jar")
|
||||
relocate("io.github.retrooper.packetevents", "ac.grim.grimac.shaded.io.github.retrooper.packetevents")
|
||||
relocate("com.github.retrooper.packetevents", "ac.grim.grimac.shaded.com.github.retrooper.packetevents")
|
||||
relocate("co.aikar.commands", "ac.grim.grimac.shaded.acf")
|
||||
relocate("co.aikar.locale", "ac.grim.grimac.shaded.locale")
|
||||
relocate("club.minnced", "ac.grim.grimac.shaded.discord-webhooks")
|
||||
relocate("github.scarsz.configuralize", "ac.grim.grimac.shaded.configuralize")
|
||||
relocate("com.github.puregero", "ac.grim.grimac.shaded.com.github.puregero")
|
||||
relocate("com.google.code.gson", "ac.grim.grimac.shaded.gson")
|
||||
relocate("alexh", "ac.grim.grimac.shaded.maps")
|
||||
relocate("it.unimi.dsi.fastutil", "ac.grim.grimac.shaded.fastutil")
|
||||
relocate("net.kyori", "ac.grim.grimac.shaded.kyori")
|
||||
relocate("okhttp3", "ac.grim.grimac.shaded.okhttp3")
|
||||
relocate("okio", "ac.grim.grimac.shaded.okio")
|
||||
relocate("org.yaml.snakeyaml", "ac.grim.grimac.shaded.snakeyaml")
|
||||
relocate("org.json", "ac.grim.grimac.shaded.json")
|
||||
relocate("org.intellij", "ac.grim.grimac.shaded.intellij")
|
||||
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
|
||||
}
|
||||
if (relocate) {
|
||||
relocate("io.github.retrooper.packetevents", "ac.grim.grimac.shaded.io.github.retrooper.packetevents")
|
||||
relocate("com.github.retrooper.packetevents", "ac.grim.grimac.shaded.com.github.retrooper.packetevents")
|
||||
relocate("co.aikar.commands", "ac.grim.grimac.shaded.acf")
|
||||
relocate("co.aikar.locale", "ac.grim.grimac.shaded.locale")
|
||||
relocate("club.minnced", "ac.grim.grimac.shaded.discord-webhooks")
|
||||
relocate("github.scarsz.configuralize", "ac.grim.grimac.shaded.configuralize")
|
||||
relocate("com.github.puregero", "ac.grim.grimac.shaded.com.github.puregero")
|
||||
relocate("com.google.code.gson", "ac.grim.grimac.shaded.gson")
|
||||
relocate("alexh", "ac.grim.grimac.shaded.maps")
|
||||
relocate("it.unimi.dsi.fastutil", "ac.grim.grimac.shaded.fastutil")
|
||||
relocate("net.kyori", "ac.grim.grimac.shaded.kyori")
|
||||
relocate("okhttp3", "ac.grim.grimac.shaded.okhttp3")
|
||||
relocate("okio", "ac.grim.grimac.shaded.okio")
|
||||
relocate("org.yaml.snakeyaml", "ac.grim.grimac.shaded.snakeyaml")
|
||||
relocate("org.json", "ac.grim.grimac.shaded.json")
|
||||
relocate("org.intellij", "ac.grim.grimac.shaded.intellij")
|
||||
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
|
||||
import github.scarsz.configuralize.DynamicConfig;
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -28,6 +29,7 @@ public class Check implements AbstractCheck {
|
||||
private boolean experimental;
|
||||
@Setter
|
||||
private boolean isEnabled;
|
||||
private boolean exempted;
|
||||
|
||||
@Override
|
||||
public boolean isExperimental() {
|
||||
@@ -56,7 +58,14 @@ public class Check implements AbstractCheck {
|
||||
}
|
||||
|
||||
public boolean shouldModifyPackets() {
|
||||
return isEnabled && !player.disableGrim && !player.noModifyPacketPermission;
|
||||
return isEnabled && !player.disableGrim && !player.noModifyPacketPermission && !exempted;
|
||||
}
|
||||
|
||||
public void updateExempted() {
|
||||
if (player.bukkitPlayer == null || checkName == null) return;
|
||||
FoliaScheduler.getEntityScheduler().run(player.bukkitPlayer, GrimAPI.INSTANCE.getPlugin(),
|
||||
t -> exempted = player.bukkitPlayer.hasPermission("grim.exempt." + checkName.toLowerCase()),
|
||||
() -> {});
|
||||
}
|
||||
|
||||
public final boolean flagAndAlert(String verbose) {
|
||||
@@ -72,7 +81,7 @@ public class Check implements AbstractCheck {
|
||||
}
|
||||
|
||||
public final boolean flag() {
|
||||
if (player.disableGrim || (experimental && !GrimAPI.INSTANCE.getConfigManager().isExperimentalChecks()))
|
||||
if (player.disableGrim || (experimental && !GrimAPI.INSTANCE.getConfigManager().isExperimentalChecks()) || exempted)
|
||||
return false; // Avoid calling event if disabled
|
||||
|
||||
FlagEvent event = new FlagEvent(player, this);
|
||||
@@ -103,6 +112,8 @@ public class Check implements AbstractCheck {
|
||||
setbackVL = getConfig().getDoubleElse(configName + ".setbackvl", setbackVL);
|
||||
|
||||
if (setbackVL == -1) setbackVL = Double.MAX_VALUE;
|
||||
|
||||
updateExempted();
|
||||
}
|
||||
|
||||
public boolean alert(String verbose) {
|
||||
|
||||
@@ -25,17 +25,16 @@ public class BadPacketsX extends Check implements PacketCheck {
|
||||
if (dig.getAction() != DiggingAction.START_DIGGING && dig.getAction() != DiggingAction.FINISHED_DIGGING)
|
||||
return;
|
||||
|
||||
final boolean invalid;
|
||||
|
||||
if (dig.getAction() == DiggingAction.FINISHED_DIGGING) {
|
||||
invalid = BlockBreakSpeed.getBlockDamage(player, dig.getBlockPosition()) >= 1 || block.getHardness() == -1.0f;
|
||||
} else invalid = (block == StateTypes.LIGHT && !(player.getInventory().getHeldItem().is(ItemTypes.LIGHT) || player.getInventory().getOffHand().is(ItemTypes.LIGHT)))
|
||||
// the block does not have a hitbox
|
||||
boolean invalid = (block == StateTypes.LIGHT && !(player.getInventory().getHeldItem().is(ItemTypes.LIGHT) || player.getInventory().getOffHand().is(ItemTypes.LIGHT)))
|
||||
|| block.isAir()
|
||||
|| block == StateTypes.WATER
|
||||
|| block == StateTypes.LAVA
|
||||
|| block == StateTypes.BUBBLE_COLUMN
|
||||
|| block == StateTypes.MOVING_PISTON
|
||||
|| (block == StateTypes.FIRE && noFireHitbox);
|
||||
|| (block == StateTypes.FIRE && noFireHitbox)
|
||||
// or the client claims to have broken an unbreakable block
|
||||
|| block.getHardness() == -1.0f && dig.getAction() == DiggingAction.FINISHED_DIGGING;
|
||||
|
||||
if (invalid && flagAndAlert("block=" + block.getName() + ", type=" + dig.getAction()) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
|
||||
@@ -4,7 +4,9 @@ import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
@@ -21,7 +23,7 @@ public class BadPacketsZ extends Check implements PacketCheck {
|
||||
|
||||
private boolean lastBlockWasInstantBreak = false;
|
||||
private Vector3i lastBlock, lastCancelledBlock, lastLastBlock = null;
|
||||
private final int exemptedY = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) ? 4095 : 255;
|
||||
private final int exemptedY = player.getClientVersion().isOlderThan(ClientVersion.V_1_8) ? 255 : (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_14) ? -1 : 4095);
|
||||
|
||||
// The client sometimes sends a wierd cancel packet
|
||||
private boolean shouldExempt(final Vector3i pos) {
|
||||
@@ -33,10 +35,6 @@ public class BadPacketsZ extends Check implements PacketCheck {
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) && pos.y != exemptedY)
|
||||
return false;
|
||||
|
||||
// the client only sends this packet if the last block was an instant break
|
||||
if (getBlockDamage(player, lastBlock) < 1)
|
||||
return false;
|
||||
|
||||
// and if this block is not an instant break
|
||||
return player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || getBlockDamage(player, pos) < 1;
|
||||
}
|
||||
|
||||
@@ -15,16 +15,12 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package ac.grim.grimac.checks.impl.combat;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.HitData;
|
||||
import ac.grim.grimac.utils.data.Pair;
|
||||
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
|
||||
import ac.grim.grimac.utils.nmsutil.BlockRayTrace;
|
||||
import ac.grim.grimac.utils.data.packetentity.dragon.PacketEntityEnderDragonPart;
|
||||
import ac.grim.grimac.utils.nmsutil.ReachUtils;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
@@ -34,22 +30,12 @@ import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
// You may not copy the check unless you are licensed under GPL
|
||||
@CheckData(name = "Reach", configName = "Reach", setback = 10)
|
||||
@@ -57,9 +43,6 @@ public class Reach extends Check implements PacketCheck {
|
||||
// Only one flag per reach attack, per entity, per tick.
|
||||
// We store position because lastX isn't reliable on teleports.
|
||||
private final Map<Integer, Vector3d> playerAttackQueue = new HashMap<>();
|
||||
// Used to prevent falses in the wall hit check
|
||||
private final Set<Vector3i> blocksChangedThisTick = new HashSet<>();
|
||||
|
||||
private static final List<EntityType> blacklisted = Arrays.asList(
|
||||
EntityTypes.BOAT,
|
||||
EntityTypes.CHEST_BOAT,
|
||||
@@ -122,11 +105,10 @@ public class Reach extends Check implements PacketCheck {
|
||||
}
|
||||
|
||||
// If the player set their look, or we know they have a new tick
|
||||
final boolean isFlying = WrapperPlayClientPlayerFlying.isFlying(event.getPacketType());
|
||||
if (isFlying ||
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) ||
|
||||
event.getPacketType() == PacketType.Play.Client.PONG ||
|
||||
event.getPacketType() == PacketType.Play.Client.WINDOW_CONFIRMATION) {
|
||||
tickBetterReachCheckWithAngle(isFlying);
|
||||
tickBetterReachCheckWithAngle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +140,7 @@ public class Reach extends Check implements PacketCheck {
|
||||
}
|
||||
}
|
||||
|
||||
private void tickBetterReachCheckWithAngle(boolean isFlying) {
|
||||
private void tickBetterReachCheckWithAngle() {
|
||||
for (Map.Entry<Integer, Vector3d> attack : playerAttackQueue.entrySet()) {
|
||||
PacketEntity reachEntity = player.compensatedEntities.entityMap.get(attack.getKey().intValue());
|
||||
if (reachEntity != null) {
|
||||
@@ -173,9 +155,6 @@ public class Reach extends Check implements PacketCheck {
|
||||
}
|
||||
}
|
||||
playerAttackQueue.clear();
|
||||
// We can't use transactions for this because of this problem:
|
||||
// transaction -> block changed applied -> 2nd transaction -> list cleared -> attack packet -> flying -> reach block hit checked, falses
|
||||
if (isFlying) blocksChangedThisTick.clear();
|
||||
}
|
||||
|
||||
private String checkReach(PacketEntity reachEntity, Vector3d from, boolean isPrediction) {
|
||||
@@ -240,26 +219,9 @@ public class Reach extends Check implements PacketCheck {
|
||||
}
|
||||
}
|
||||
|
||||
final boolean experimentalChecks = true; //GrimAPI.INSTANCE.getConfigManager().isExperimentalChecks(); // TODO fix for undraft
|
||||
HitData foundHitData = null;
|
||||
// If the entity is within range of the player (we'll flag anyway if not, so no point checking blocks in this case)
|
||||
// Ignore when could be hitting through a moving shulker, piston blocks. They are just too glitchy/uncertain to check.
|
||||
if (experimentalChecks && minDistance <= 3 && !player.compensatedWorld.isNearHardEntity(player.boundingBox.copy().expand(4))) {
|
||||
final @Nullable Pair<Double, HitData> targetBlock = getTargetBlock(player, possibleLookDirs, from, minDistance);
|
||||
// And if the target block is closer to the player than the entity box, they should hit the block instead
|
||||
// So, this hit is invalid.
|
||||
if (targetBlock != null && targetBlock.getFirst() < (minDistance * minDistance)) { // targetBlock is squared
|
||||
minDistance = Double.MIN_VALUE;
|
||||
foundHitData = targetBlock.getSecond();
|
||||
}
|
||||
}
|
||||
|
||||
// if the entity is not exempt and the entity is alive
|
||||
if ((!blacklisted.contains(reachEntity.getType()) && reachEntity.isLivingEntity()) || reachEntity.getType() == EntityTypes.END_CRYSTAL) {
|
||||
if (minDistance == Double.MIN_VALUE && foundHitData != null) {
|
||||
cancelBuffer = 1;
|
||||
return "Hit block block=" + foundHitData.getState().getType().getName();
|
||||
} else if (minDistance == Double.MAX_VALUE) {
|
||||
if (minDistance == Double.MAX_VALUE) {
|
||||
cancelBuffer = 1;
|
||||
return "Missed hitbox";
|
||||
} else if (minDistance > player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE)) {
|
||||
@@ -273,45 +235,6 @@ public class Reach extends Check implements PacketCheck {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void handleBlockChange(Vector3i vector3i, WrappedBlockState state) {
|
||||
if (blocksChangedThisTick.size() >= 40) return; // Don't let players freeze movement packets to grow this
|
||||
// Only do this for nearby blocks
|
||||
if (new Vector(vector3i.x, vector3i.y, vector3i.z).distanceSquared(new Vector(player.x, player.y, player.z)) > 6) return;
|
||||
// Only do this if the state really had any world impact
|
||||
if (state.equals(player.compensatedWorld.getWrappedBlockStateAt(vector3i))) return;
|
||||
blocksChangedThisTick.add(vector3i);
|
||||
}
|
||||
|
||||
// Returns a pair so we can check the block type in the flag
|
||||
@Nullable
|
||||
private Pair<Double, HitData> getTargetBlock(GrimPlayer player, List<Vector> possibleLookDirs, Vector3d from, double minDistance) {
|
||||
// Check every possible look direction and every possible eye height
|
||||
// IF *NONE* of them allow the player to hit the entity, this is an invalid hit
|
||||
HitData bestHitData = null;
|
||||
double min = Double.MAX_VALUE;
|
||||
for (Vector lookVec : possibleLookDirs) {
|
||||
for (double eye : player.getPossibleEyeHeights()) {
|
||||
Vector eyes = new Vector(from.getX(), from.getY() + eye, from.getZ());
|
||||
final double reach = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
|
||||
final HitData hitResult = BlockRayTrace.getNearestReachHitResult(player, eyes, lookVec, minDistance, reach);
|
||||
if (hitResult == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final double distance = eyes.distanceSquared(hitResult.getBlockHitLocation());
|
||||
// Block changes are uncertain, can't check this tick
|
||||
if (distance < (minDistance * minDistance) && blocksChangedThisTick.contains(hitResult.getPosition())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
bestHitData = hitResult;
|
||||
min = Math.min(min, distance);
|
||||
}
|
||||
}
|
||||
|
||||
return bestHitData == null ? null : Pair.of(min, bestHitData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
|
||||
@@ -19,7 +19,6 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPl
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -87,6 +86,7 @@ public class PostCheck extends Check implements PacketCheck, PostPredictionCheck
|
||||
post.clear();
|
||||
sentFlying = false;
|
||||
} else if (PLAYER_ABILITIES.equals(packetType)
|
||||
|| (HELD_ITEM_CHANGE.equals(packetType) && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8))
|
||||
|| INTERACT_ENTITY.equals(packetType) || PLAYER_BLOCK_PLACEMENT.equals(packetType)
|
||||
|| USE_ITEM.equals(packetType) || PLAYER_DIGGING.equals(packetType)) {
|
||||
if (sentFlying) post.add(event.getPacketType());
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package ac.grim.grimac.checks.impl.scaffolding;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.BlockPlaceCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.MessageUtil;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
|
||||
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.util.Vector3f;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@CheckData(name = "MultiPlace", experimental = true)
|
||||
public class MultiPlace extends BlockPlaceCheck {
|
||||
public MultiPlace(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private final List<String> flags = new ArrayList<>();
|
||||
|
||||
private boolean hasPlaced;
|
||||
private BlockFace lastFace;
|
||||
private Vector3f lastCursor;
|
||||
private Vector3i lastPos;
|
||||
|
||||
@Override
|
||||
public void onBlockPlace(final BlockPlace place) {
|
||||
final BlockFace face = place.getDirection();
|
||||
final Vector3f cursor = place.getCursor();
|
||||
final Vector3i pos = place.getPlacedAgainstBlockLocation();
|
||||
|
||||
if (hasPlaced && (face != lastFace || !cursor.equals(lastCursor) || !pos.equals(lastPos))) {
|
||||
final String verbose = "face=" + face + ", lastFace=" + lastFace
|
||||
+ ", cursor=" + MessageUtil.toUnlabledString(cursor) + ", lastCursor=" + MessageUtil.toUnlabledString(lastCursor)
|
||||
+ ", pos=" + MessageUtil.toUnlabledString(pos) + ", lastPos=" + MessageUtil.toUnlabledString(lastPos);
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets() && shouldCancel()) {
|
||||
place.resync();
|
||||
}
|
||||
} else {
|
||||
flags.add(verbose);
|
||||
}
|
||||
}
|
||||
|
||||
lastFace = face;
|
||||
lastCursor = cursor;
|
||||
lastPos = pos;
|
||||
hasPlaced = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
|
||||
hasPlaced = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8) && !player.skippedTickInActualMovement) {
|
||||
for (String verbose : flags) {
|
||||
flagAndAlert(verbose);
|
||||
}
|
||||
}
|
||||
|
||||
flags.clear();
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import ac.grim.grimac.utils.nmsutil.Ray;
|
||||
import ac.grim.grimac.utils.nmsutil.ReachUtils;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
@@ -33,6 +34,7 @@ public class RotationPlace extends BlockPlaceCheck {
|
||||
@Override
|
||||
public void onBlockPlace(final BlockPlace place) {
|
||||
if (place.getMaterial() == StateTypes.SCAFFOLDING) return;
|
||||
if (player.gamemode == GameMode.SPECTATOR) return; // you don't send flying packets when spectating entities
|
||||
if (flagBuffer > 0 && !didRayTraceHit(place)) {
|
||||
ignorePost = true;
|
||||
// If the player hit and has flagged this check recently
|
||||
@@ -46,6 +48,7 @@ public class RotationPlace extends BlockPlaceCheck {
|
||||
@Override
|
||||
public void onPostFlyingBlockPlace(BlockPlace place) {
|
||||
if (place.getMaterial() == StateTypes.SCAFFOLDING) return;
|
||||
if (player.gamemode == GameMode.SPECTATOR) return; // you don't send flying packets when spectating entities
|
||||
|
||||
// Don't flag twice
|
||||
if (ignorePost) {
|
||||
@@ -68,8 +71,8 @@ public class RotationPlace extends BlockPlaceCheck {
|
||||
SimpleCollisionBox box = new SimpleCollisionBox(place.getPlacedAgainstBlockLocation());
|
||||
|
||||
List<Vector3f> possibleLookDirs = new ArrayList<>(Arrays.asList(
|
||||
new Vector3f(player.lastXRot, player.yRot, 0),
|
||||
new Vector3f(player.xRot, player.yRot, 0)
|
||||
new Vector3f(player.xRot, player.yRot, 0),
|
||||
new Vector3f(player.lastXRot, player.yRot, 0)
|
||||
));
|
||||
|
||||
// Start checking if player is in the block
|
||||
|
||||
@@ -14,7 +14,7 @@ import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BlockPlaceCheck extends Check implements RotationCheck {
|
||||
public class BlockPlaceCheck extends Check implements RotationCheck, PostPredictionCheck {
|
||||
private static final List<StateType> weirdBoxes = new ArrayList<>();
|
||||
private static final List<StateType> buggyBoxes = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.*;
|
||||
import ac.grim.grimac.utils.inventory.Inventory;
|
||||
import ac.grim.grimac.utils.latency.CompensatedWorld;
|
||||
import ac.grim.grimac.utils.math.GrimMath;
|
||||
import ac.grim.grimac.utils.math.VectorUtils;
|
||||
import ac.grim.grimac.utils.nmsutil.*;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
@@ -46,9 +47,11 @@ import com.github.retrooper.packetevents.wrapper.play.client.*;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerAcknowledgeBlockChanges;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetSlot;
|
||||
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.bukkit.util.Vector;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class CheckManagerListener extends PacketListenerAbstract {
|
||||
|
||||
@@ -56,8 +59,79 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
super(PacketListenerPriority.LOW);
|
||||
}
|
||||
|
||||
// Copied from MCP...
|
||||
// Returns null if there isn't anything.
|
||||
//
|
||||
// I do have to admit that I'm starting to like bifunctions/new java 8 things more than I originally did.
|
||||
// although I still don't understand Mojang's obsession with streams in some of the hottest methods... that kills performance
|
||||
public static HitData traverseBlocks(GrimPlayer player, Vector3d start, Vector3d end, BiFunction<WrappedBlockState, Vector3i, HitData> predicate) {
|
||||
// I guess go back by the collision epsilon?
|
||||
double endX = GrimMath.lerp(-1.0E-7D, end.x, start.x);
|
||||
double endY = GrimMath.lerp(-1.0E-7D, end.y, start.y);
|
||||
double endZ = GrimMath.lerp(-1.0E-7D, end.z, start.z);
|
||||
double startX = GrimMath.lerp(-1.0E-7D, start.x, end.x);
|
||||
double startY = GrimMath.lerp(-1.0E-7D, start.y, end.y);
|
||||
double startZ = GrimMath.lerp(-1.0E-7D, start.z, end.z);
|
||||
int floorStartX = GrimMath.floor(startX);
|
||||
int floorStartY = GrimMath.floor(startY);
|
||||
int floorStartZ = GrimMath.floor(startZ);
|
||||
|
||||
|
||||
if (start.equals(end)) return null;
|
||||
|
||||
WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(floorStartX, floorStartY, floorStartZ);
|
||||
HitData apply = predicate.apply(state, new Vector3i(floorStartX, floorStartY, floorStartZ));
|
||||
|
||||
if (apply != null) {
|
||||
return apply;
|
||||
}
|
||||
|
||||
double xDiff = endX - startX;
|
||||
double yDiff = endY - startY;
|
||||
double zDiff = endZ - startZ;
|
||||
double xSign = Math.signum(xDiff);
|
||||
double ySign = Math.signum(yDiff);
|
||||
double zSign = Math.signum(zDiff);
|
||||
|
||||
double posXInverse = xSign == 0 ? Double.MAX_VALUE : xSign / xDiff;
|
||||
double posYInverse = ySign == 0 ? Double.MAX_VALUE : ySign / yDiff;
|
||||
double posZInverse = zSign == 0 ? Double.MAX_VALUE : zSign / zDiff;
|
||||
|
||||
double d12 = posXInverse * (xSign > 0 ? 1.0D - GrimMath.frac(startX) : GrimMath.frac(startX));
|
||||
double d13 = posYInverse * (ySign > 0 ? 1.0D - GrimMath.frac(startY) : GrimMath.frac(startY));
|
||||
double d14 = posZInverse * (zSign > 0 ? 1.0D - GrimMath.frac(startZ) : GrimMath.frac(startZ));
|
||||
|
||||
// Can't figure out what this code does currently
|
||||
while (d12 <= 1.0D || d13 <= 1.0D || d14 <= 1.0D) {
|
||||
if (d12 < d13) {
|
||||
if (d12 < d14) {
|
||||
floorStartX += xSign;
|
||||
d12 += posXInverse;
|
||||
} else {
|
||||
floorStartZ += zSign;
|
||||
d14 += posZInverse;
|
||||
}
|
||||
} else if (d13 < d14) {
|
||||
floorStartY += ySign;
|
||||
d13 += posYInverse;
|
||||
} else {
|
||||
floorStartZ += zSign;
|
||||
d14 += posZInverse;
|
||||
}
|
||||
|
||||
state = player.compensatedWorld.getWrappedBlockStateAt(floorStartX, floorStartY, floorStartZ);
|
||||
apply = predicate.apply(state, new Vector3i(floorStartX, floorStartY, floorStartZ));
|
||||
|
||||
if (apply != null) {
|
||||
return apply;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void placeWaterLavaSnowBucket(GrimPlayer player, ItemStack held, StateType toPlace, InteractionHand hand) {
|
||||
HitData data = BlockRayTrace.getNearestHitResult(player, StateTypes.AIR, false);
|
||||
HitData data = getNearestHitResult(player, StateTypes.AIR, false);
|
||||
if (data != null) {
|
||||
BlockPlace blockPlace = new BlockPlace(player, hand, data.getPosition(), data.getClosestDirection().getFaceValue(), data.getClosestDirection(), held, data);
|
||||
|
||||
@@ -194,7 +268,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
// The offhand is unable to interact with blocks like this... try to stop some desync points before they happen
|
||||
if ((!player.isSneaking || onlyAir) && place.getHand() == InteractionHand.MAIN_HAND) {
|
||||
Vector3i blockPosition = place.getBlockPosition();
|
||||
BlockPlace blockPlace = new BlockPlace(player, place.getHand(), blockPosition, place.getFaceId(), place.getFace(), placedWith, BlockRayTrace.getNearestHitResult(player, null, true));
|
||||
BlockPlace blockPlace = new BlockPlace(player, place.getHand(), blockPosition, place.getFaceId(), place.getFace(), placedWith, getNearestHitResult(player, null, true));
|
||||
|
||||
// Right-clicking a trapdoor/door/etc.
|
||||
StateType placedAgainst = blockPlace.getPlacedAgainstMaterial();
|
||||
@@ -234,7 +308,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
placedWith = player.getInventory().getOffHand();
|
||||
}
|
||||
|
||||
BlockPlace blockPlace = new BlockPlace(player, place.getHand(), blockPosition, place.getFaceId(), face, placedWith, BlockRayTrace.getNearestHitResult(player, null, true));
|
||||
BlockPlace blockPlace = new BlockPlace(player, place.getHand(), blockPosition, place.getFaceId(), face, placedWith, getNearestHitResult(player, null, true));
|
||||
// At this point, it is too late to cancel, so we can only flag, and cancel subsequent block places more aggressively
|
||||
if (!player.compensatedEntities.getSelf().inVehicle()) {
|
||||
player.checkManager.onPostFlyingBlockPlace(blockPlace);
|
||||
@@ -434,7 +508,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
player.placeUseItemPackets.add(new BlockPlaceSnapshot(packet, player.isSneaking));
|
||||
} else {
|
||||
// Anti-air place
|
||||
BlockPlace blockPlace = new BlockPlace(player, packet.getHand(), packet.getBlockPosition(), packet.getFaceId(), packet.getFace(), placedWith, BlockRayTrace.getNearestHitResult(player, null, true));
|
||||
BlockPlace blockPlace = new BlockPlace(player, packet.getHand(), packet.getBlockPosition(), packet.getFaceId(), packet.getFace(), placedWith, getNearestHitResult(player, null, true));
|
||||
blockPlace.setCursor(packet.getCursorPosition());
|
||||
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_11) && player.getClientVersion().isOlderThan(ClientVersion.V_1_11)) {
|
||||
@@ -508,7 +582,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
}
|
||||
|
||||
private static void placeBucket(GrimPlayer player, InteractionHand hand) {
|
||||
HitData data = BlockRayTrace.getNearestHitResult(player, null, true);
|
||||
HitData data = getNearestHitResult(player, null, true);
|
||||
|
||||
if (data != null) {
|
||||
BlockPlace blockPlace = new BlockPlace(player, hand, data.getPosition(), data.getClosestDirection().getFaceValue(), data.getClosestDirection(), ItemStack.EMPTY, data);
|
||||
@@ -674,7 +748,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
}
|
||||
|
||||
private static void placeLilypad(GrimPlayer player, InteractionHand hand) {
|
||||
HitData data = BlockRayTrace.getNearestHitResult(player, null, true);
|
||||
HitData data = getNearestHitResult(player, null, true);
|
||||
|
||||
if (data != null) {
|
||||
// A lilypad cannot replace a fluid
|
||||
@@ -704,6 +778,56 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
private static HitData getNearestHitResult(GrimPlayer player, StateType heldItem, boolean sourcesHaveHitbox) {
|
||||
Vector3d startingPos = new Vector3d(player.x, player.y + player.getEyeHeight(), player.z);
|
||||
Vector startingVec = new Vector(startingPos.getX(), startingPos.getY(), startingPos.getZ());
|
||||
Ray trace = new Ray(player, startingPos.getX(), startingPos.getY(), startingPos.getZ(), player.xRot, player.yRot);
|
||||
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
|
||||
Vector endVec = trace.getPointAtDistance(distance);
|
||||
Vector3d endPos = new Vector3d(endVec.getX(), endVec.getY(), endVec.getZ());
|
||||
|
||||
return traverseBlocks(player, startingPos, endPos, (block, vector3i) -> {
|
||||
CollisionBox data = HitboxData.getBlockHitbox(player, heldItem, player.getClientVersion(), block, vector3i.getX(), vector3i.getY(), vector3i.getZ());
|
||||
List<SimpleCollisionBox> boxes = new ArrayList<>();
|
||||
data.downCast(boxes);
|
||||
|
||||
double bestHitResult = Double.MAX_VALUE;
|
||||
Vector bestHitLoc = null;
|
||||
BlockFace bestFace = null;
|
||||
|
||||
for (SimpleCollisionBox box : boxes) {
|
||||
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
|
||||
if (intercept.getFirst() == null) continue; // No intercept
|
||||
|
||||
Vector hitLoc = intercept.getFirst();
|
||||
|
||||
if (hitLoc.distanceSquared(startingVec) < bestHitResult) {
|
||||
bestHitResult = hitLoc.distanceSquared(startingVec);
|
||||
bestHitLoc = hitLoc;
|
||||
bestFace = intercept.getSecond();
|
||||
}
|
||||
}
|
||||
if (bestHitLoc != null) {
|
||||
return new HitData(vector3i, bestHitLoc, bestFace, block);
|
||||
}
|
||||
|
||||
if (sourcesHaveHitbox &&
|
||||
(player.compensatedWorld.isWaterSourceBlock(vector3i.getX(), vector3i.getY(), vector3i.getZ())
|
||||
|| player.compensatedWorld.getLavaFluidLevelAt(vector3i.getX(), vector3i.getY(), vector3i.getZ()) == (8 / 9f))) {
|
||||
double waterHeight = player.compensatedWorld.getFluidLevelAt(vector3i.getX(), vector3i.getY(), vector3i.getZ());
|
||||
SimpleCollisionBox box = new SimpleCollisionBox(vector3i.getX(), vector3i.getY(), vector3i.getZ(), vector3i.getX() + 1, vector3i.getY() + waterHeight, vector3i.getZ() + 1);
|
||||
|
||||
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
|
||||
|
||||
if (intercept.getFirst() != null) {
|
||||
return new HitData(vector3i, intercept.getFirst(), intercept.getSecond(), block);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(PacketSendEvent event) {
|
||||
if (event.getConnectionState() != ConnectionState.PLAY) return;
|
||||
|
||||
@@ -175,7 +175,7 @@ public class PacketPlayerDigging extends PacketListenerAbstract {
|
||||
if (player == null) return;
|
||||
|
||||
if (!player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
|
||||
if (player.packetStateData.isSlowedByUsingItem() && player.packetStateData.getSlowedByUsingItemSlot() != player.packetStateData.lastSlotSelected) {
|
||||
if (player.packetStateData.isSlowedByUsingItem() && player.packetStateData.eatingHand != InteractionHand.OFF_HAND && player.packetStateData.getSlowedByUsingItemSlot() != player.packetStateData.lastSlotSelected) {
|
||||
player.packetStateData.setSlowedByUsingItem(false);
|
||||
player.checkManager.getPostPredictionCheck(NoSlowA.class).didSlotChangeLastTick = true;
|
||||
}
|
||||
@@ -196,7 +196,7 @@ public class PacketPlayerDigging extends PacketListenerAbstract {
|
||||
|
||||
if (player.packetStateData.lastSlotSelected != slot) {
|
||||
// just assume they tick after this
|
||||
if (!player.isTickingReliablyFor(3) && player.skippedTickInActualMovement) {
|
||||
if (!player.isTickingReliablyFor(3) && player.skippedTickInActualMovement && player.packetStateData.eatingHand != InteractionHand.OFF_HAND) {
|
||||
player.packetStateData.setSlowedByUsingItem(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,6 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
|
||||
player.compensatedEntities.serverPositionsMap.clear();
|
||||
}
|
||||
|
||||
// TODO: What does keep all metadata do?
|
||||
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get() + 1, () -> {
|
||||
player.isSneaking = false;
|
||||
player.lastOnGround = false;
|
||||
@@ -141,8 +140,16 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
|
||||
player.packetStateData.lastClaimedPosition = new Vector3d();
|
||||
player.filterMojangStupidityOnMojangStupidity = new Vector3d();
|
||||
|
||||
final boolean keepTrackedData = this.hasFlag(respawn, KEEP_TRACKED_DATA);
|
||||
|
||||
if (!keepTrackedData) {
|
||||
player.powderSnowFrozenTicks = 0;
|
||||
player.compensatedEntities.getSelf().hasGravity = true;
|
||||
player.playerEntityHasGravity = true;
|
||||
}
|
||||
|
||||
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_19_4)) {
|
||||
if (!this.hasFlag(respawn, KEEP_TRACKED_DATA)) {
|
||||
if (!keepTrackedData) {
|
||||
player.isSprinting = false;
|
||||
}
|
||||
} else {
|
||||
@@ -184,7 +191,6 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
|
||||
player.compensatedWorld.setDimension(respawn.getDimensionType(), event.getUser());
|
||||
}
|
||||
|
||||
// TODO And there should probably be some attribute holder that we can just call reset() on.
|
||||
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_16) && !this.hasFlag(respawn, KEEP_ATTRIBUTES)) {
|
||||
// Reset attributes if not kept
|
||||
player.compensatedEntities.getSelf().resetAttributes();
|
||||
|
||||
@@ -139,6 +139,7 @@ public class CheckManager {
|
||||
.put(InvalidPlaceA.class, new InvalidPlaceA(player))
|
||||
.put(InvalidPlaceB.class, new InvalidPlaceB(player))
|
||||
.put(AirLiquidPlace.class, new AirLiquidPlace(player))
|
||||
.put(MultiPlace.class, new MultiPlace(player))
|
||||
.put(FarPlace.class, new FarPlace(player))
|
||||
.put(FabricatedPlace.class, new FabricatedPlace(player))
|
||||
.put(PositionPlace.class, new PositionPlace(player))
|
||||
@@ -201,6 +202,9 @@ public class CheckManager {
|
||||
for (PostPredictionCheck check : postPredictionCheck.values()) {
|
||||
check.onPacketReceive(packet);
|
||||
}
|
||||
for (BlockPlaceCheck check : blockPlaceCheck.values()) {
|
||||
check.onPacketReceive(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public void onPacketSend(final PacketSendEvent packet) {
|
||||
@@ -213,6 +217,9 @@ public class CheckManager {
|
||||
for (PostPredictionCheck check : postPredictionCheck.values()) {
|
||||
check.onPacketSend(packet);
|
||||
}
|
||||
for (BlockPlaceCheck check : blockPlaceCheck.values()) {
|
||||
check.onPacketSend(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public void onPositionUpdate(final PositionUpdate position) {
|
||||
@@ -240,6 +247,9 @@ public class CheckManager {
|
||||
for (PostPredictionCheck check : postPredictionCheck.values()) {
|
||||
check.onPredictionComplete(complete);
|
||||
}
|
||||
for (BlockPlaceCheck check : blockPlaceCheck.values()) {
|
||||
check.onPredictionComplete(complete);
|
||||
}
|
||||
}
|
||||
|
||||
public void onBlockPlace(final BlockPlace place) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package ac.grim.grimac.manager;
|
||||
import ac.grim.grimac.GrimAC;
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import ac.grim.grimac.utils.math.GrimMath;
|
||||
import github.scarsz.configuralize.DynamicConfig;
|
||||
import github.scarsz.configuralize.Language;
|
||||
import lombok.Getter;
|
||||
@@ -77,7 +78,15 @@ public class ConfigManager {
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to load config", e);
|
||||
}
|
||||
maxPingTransaction = config.getIntElse("max-transaction-time", 60);
|
||||
|
||||
final int configuredMaxTransactionTime = config.getIntElse("max-transaction-time", 60);
|
||||
maxPingTransaction = (int) GrimMath.clamp(configuredMaxTransactionTime, 1, 180);
|
||||
if (maxPingTransaction != configuredMaxTransactionTime) {
|
||||
LogUtil.warn("Detected invalid max-transaction-time! This setting is clamped between 1 and 180 to prevent issues. " +
|
||||
"Changed: " + configuredMaxTransactionTime + " -> " + maxPingTransaction);
|
||||
LogUtil.warn("Attempting to disable or set this too high can result in memory usage issues.");
|
||||
}
|
||||
|
||||
ignoredClientPatterns.clear();
|
||||
for (String string : config.getStringList("client-brand.ignored-clients")) {
|
||||
try {
|
||||
|
||||
@@ -19,6 +19,7 @@ public class DiscordManager implements Initable {
|
||||
private static WebhookClient client;
|
||||
private int embedColor;
|
||||
private String staticContent = "";
|
||||
private String embedTitle = "";
|
||||
|
||||
public static final Pattern WEBHOOK_PATTERN = Pattern.compile("(?:https?://)?(?:\\w+\\.)?\\w+\\.\\w+/api(?:/v\\d+)?/webhooks/(\\d+)/([\\w-]+)(?:/(?:\\w+)?)?");
|
||||
|
||||
@@ -40,6 +41,8 @@ public class DiscordManager implements Initable {
|
||||
client = WebhookClient.withId(Long.parseUnsignedLong(matcher.group(1)), matcher.group(2));
|
||||
client.setTimeout(15000); // Requests expire after 15 seconds
|
||||
|
||||
embedTitle = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("embed-title", "**Grim Alert**");
|
||||
|
||||
try {
|
||||
embedColor = Color.decode(GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("embed-color", "#00FFFF")).getRGB();
|
||||
} catch (NumberFormatException e) {
|
||||
@@ -70,7 +73,7 @@ public class DiscordManager implements Initable {
|
||||
public void sendAlert(GrimPlayer player, String verbose, String checkName, String violations) {
|
||||
if (client != null) {
|
||||
|
||||
String content = staticContent + "";
|
||||
String content = staticContent;
|
||||
content = content.replace("%check%", checkName);
|
||||
content = content.replace("%violations%", violations);
|
||||
content = GrimAPI.INSTANCE.getExternalAPI().replaceVariables(player, content, false);
|
||||
@@ -80,7 +83,7 @@ public class DiscordManager implements Initable {
|
||||
.setImageUrl("https://i.stack.imgur.com/Fzh0w.png") // Constant width
|
||||
.setThumbnailUrl("https://crafthead.net/helm/" + player.user.getProfile().getUUID())
|
||||
.setColor(embedColor)
|
||||
.setTitle(new WebhookEmbed.EmbedTitle("**Grim Alert**", null))
|
||||
.setTitle(new WebhookEmbed.EmbedTitle(embedTitle, null))
|
||||
.setDescription(content)
|
||||
.setTimestamp(Instant.now())
|
||||
.setFooter(new WebhookEmbed.EmbedFooter("", "https://grim.ac/images/grim.png"));
|
||||
|
||||
@@ -3,6 +3,7 @@ package ac.grim.grimac.player;
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.AbstractCheck;
|
||||
import ac.grim.grimac.api.GrimUser;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.impl.aim.processor.AimProcessor;
|
||||
import ac.grim.grimac.checks.impl.misc.ClientBrand;
|
||||
import ac.grim.grimac.checks.impl.misc.TransactionOrder;
|
||||
@@ -35,7 +36,6 @@ import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.protocol.world.Dimension;
|
||||
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
@@ -504,6 +504,13 @@ public class GrimPlayer implements GrimUser {
|
||||
if (bukkitPlayer == null) return;
|
||||
this.noModifyPacketPermission = bukkitPlayer.hasPermission("grim.nomodifypacket");
|
||||
this.noSetbackPermission = bukkitPlayer.hasPermission("grim.nosetback");
|
||||
FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(), t -> {
|
||||
for (AbstractCheck check : checkManager.allChecks.values()) {
|
||||
if (check instanceof Check) {
|
||||
((Check) check).updateExempted();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int spamThreshold = 100;
|
||||
|
||||
@@ -364,7 +364,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
|
||||
}
|
||||
player.uncertaintyHandler.isSteppingOnHoney = true;
|
||||
}
|
||||
if (BlockTags.BEDS.contains(data.getType()) && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (BlockTags.BEDS.contains(data.getType()) && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_12)) {
|
||||
player.uncertaintyHandler.isSteppingOnBouncyBlock = true;
|
||||
}
|
||||
if (BlockTags.ICE.contains(data.getType())) {
|
||||
|
||||
@@ -16,9 +16,10 @@ import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class PlayerBaseTick {
|
||||
GrimPlayer player;
|
||||
|
||||
@@ -149,9 +150,14 @@ public class PlayerBaseTick {
|
||||
// Pre-1.17 clients don't have powder snow and therefore don't desync
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_16_4)) return;
|
||||
|
||||
// The client first desync's this attribute
|
||||
final ValuedAttribute playerSpeed = player.compensatedEntities.getSelf().getAttribute(Attributes.GENERIC_MOVEMENT_SPEED).get();
|
||||
playerSpeed.property().get().getModifiers().removeIf(modifier -> modifier.getUUID().equals(CompensatedEntities.SNOW_MODIFIER_UUID) || modifier.getName().getKey().equals("powder_snow"));
|
||||
|
||||
// Might be null after respawn?
|
||||
final Optional<WrapperPlayServerUpdateAttributes.Property> property = playerSpeed.property();
|
||||
if (!property.isPresent()) return;
|
||||
|
||||
// The client first desync's this attribute
|
||||
property.get().getModifiers().removeIf(modifier -> modifier.getUUID().equals(CompensatedEntities.SNOW_MODIFIER_UUID) || modifier.getName().getKey().equals("powder_snow"));
|
||||
playerSpeed.recalculate();
|
||||
|
||||
// And then re-adds it using purely what the server has sent it
|
||||
@@ -165,7 +171,7 @@ public class PlayerBaseTick {
|
||||
float percentFrozen = (float) Math.min(i, ticksToFreeze) / (float) ticksToFreeze;
|
||||
float percentFrozenReducedToSpeed = -0.05F * percentFrozen;
|
||||
|
||||
playerSpeed.property().get().getModifiers().add(new WrapperPlayServerUpdateAttributes.PropertyModifier(CompensatedEntities.SNOW_MODIFIER_UUID, percentFrozenReducedToSpeed, WrapperPlayServerUpdateAttributes.PropertyModifier.Operation.ADDITION));
|
||||
property.get().getModifiers().add(new WrapperPlayServerUpdateAttributes.PropertyModifier(CompensatedEntities.SNOW_MODIFIER_UUID, percentFrozenReducedToSpeed, WrapperPlayServerUpdateAttributes.PropertyModifier.Operation.ADDITION));
|
||||
playerSpeed.recalculate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package ac.grim.grimac.predictionengine;
|
||||
|
||||
import ac.grim.grimac.checks.impl.combat.Reach;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.predictionengine.predictions.PredictionEngine;
|
||||
import ac.grim.grimac.utils.collisions.CollisionData;
|
||||
@@ -17,7 +16,6 @@ import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState
|
||||
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.util.Vector;
|
||||
@@ -153,8 +151,6 @@ public class PointThreeEstimator {
|
||||
isNearFluid = true;
|
||||
}
|
||||
|
||||
player.checkManager.getPacketCheck(Reach.class).handleBlockChange(new Vector3i(x, y, z), state);
|
||||
|
||||
if (pointThreeBox.isIntersected(new SimpleCollisionBox(x, y, z))) {
|
||||
// https://github.com/MWHunter/Grim/issues/613
|
||||
int controllingEntityId = player.compensatedEntities.getSelf().inVehicle() ? player.getRidingVehicleId() : player.entityID;
|
||||
|
||||
+35
-5
@@ -1,14 +1,20 @@
|
||||
package ac.grim.grimac.predictionengine.movementtick;
|
||||
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.data.attribute.ValuedAttribute;
|
||||
import ac.grim.grimac.utils.data.packetentity.PacketEntityStrider;
|
||||
import ac.grim.grimac.utils.nmsutil.BlockProperties;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MovementTickerStrider extends MovementTickerRideable {
|
||||
|
||||
public MovementTickerStrider(GrimPlayer player) {
|
||||
@@ -34,21 +40,45 @@ public class MovementTickerStrider extends MovementTickerRideable {
|
||||
public void livingEntityAIStep() {
|
||||
super.livingEntityAIStep();
|
||||
|
||||
((PacketEntityStrider) player.compensatedEntities.getSelf().getRiding()).isShaking = true;
|
||||
|
||||
StateType posMaterial = player.compensatedWorld.getStateTypeAt(player.x, player.y, player.z);
|
||||
StateType belowMaterial = BlockProperties.getOnPos(player, player.mainSupportingBlockData, new Vector3d(player.x, player.y, player.z));
|
||||
|
||||
((PacketEntityStrider) player.compensatedEntities.getSelf().getRiding()).isShaking =
|
||||
!BlockTags.STRIDER_WARM_BLOCKS.contains(posMaterial) &&
|
||||
final PacketEntityStrider strider = (PacketEntityStrider) player.compensatedEntities.getSelf().getRiding();
|
||||
strider.isShaking = !BlockTags.STRIDER_WARM_BLOCKS.contains(posMaterial) &&
|
||||
!BlockTags.STRIDER_WARM_BLOCKS.contains(belowMaterial) &&
|
||||
!player.wasTouchingLava;
|
||||
}
|
||||
|
||||
private static final WrapperPlayServerUpdateAttributes.PropertyModifier SUFFOCATING_MODIFIER = new WrapperPlayServerUpdateAttributes.PropertyModifier(
|
||||
ResourceLocation.minecraft("suffocating"), -0.34F, WrapperPlayServerUpdateAttributes.PropertyModifier.Operation.MULTIPLY_BASE);
|
||||
|
||||
@Override
|
||||
public float getSteeringSpeed() {
|
||||
PacketEntityStrider strider = (PacketEntityStrider) player.compensatedEntities.getSelf().getRiding();
|
||||
return (float) strider.getAttributeValue(Attributes.GENERIC_MOVEMENT_SPEED) * (strider.isShaking ? 0.23F : 0.55F);
|
||||
// Unsure which version the speed changed in
|
||||
final boolean newSpeed = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20);
|
||||
final float coldSpeed = newSpeed ? 0.35F : 0.23F;
|
||||
|
||||
// Client desyncs the attribute
|
||||
// Again I don't know when this was changed, or whether it always existed, so I will just put it behind 1.20+
|
||||
final ValuedAttribute movementSpeedAttr = strider.getAttribute(Attributes.GENERIC_MOVEMENT_SPEED).get();
|
||||
float updatedMovementSpeed = (float) movementSpeedAttr.get();
|
||||
if (newSpeed) {
|
||||
final WrapperPlayServerUpdateAttributes.Property lastProperty = movementSpeedAttr.property().orElse(null);
|
||||
if (lastProperty != null && (!strider.isShaking || lastProperty.getModifiers().stream().noneMatch(mod -> mod.getName().getKey().equals("suffocating")))) {
|
||||
WrapperPlayServerUpdateAttributes.Property newProperty = new WrapperPlayServerUpdateAttributes.Property(lastProperty.getAttribute(), lastProperty.getValue(), new ArrayList<>(lastProperty.getModifiers()));
|
||||
if (!strider.isShaking) {
|
||||
newProperty.getModifiers().removeIf(modifier -> modifier.getName().getKey().equals("suffocating"));
|
||||
} else {
|
||||
newProperty.getModifiers().add(SUFFOCATING_MODIFIER);
|
||||
}
|
||||
movementSpeedAttr.with(newProperty);
|
||||
updatedMovementSpeed = (float) movementSpeedAttr.get();
|
||||
movementSpeedAttr.with(lastProperty);
|
||||
}
|
||||
}
|
||||
|
||||
return updatedMovementSpeed * (strider.isShaking ? coldSpeed : 0.55F);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,8 @@ package ac.grim.grimac.utils.anticheat;
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.util.Vector3f;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
@@ -11,6 +13,13 @@ import java.util.regex.Pattern;
|
||||
|
||||
@UtilityClass
|
||||
public class MessageUtil {
|
||||
public String toUnlabledString(Vector3i vec) {
|
||||
return vec == null ? "null" : vec.x + ", " + vec.y + ", " + vec.z;
|
||||
}
|
||||
|
||||
public String toUnlabledString(Vector3f vec) {
|
||||
return vec == null ? "null" : vec.x + ", " + vec.y + ", " + vec.z;
|
||||
}
|
||||
|
||||
public String format(String string) {
|
||||
string = formatWithNoColor(string);
|
||||
|
||||
@@ -567,7 +567,14 @@ public enum CollisionData {
|
||||
|
||||
}, StateTypes.GRINDSTONE),
|
||||
|
||||
PANE(new DynamicPane(), Materials.getPanes().toArray(new StateType[0])),
|
||||
|
||||
CHAIN_BLOCK((player, version, data, x, y, z) -> {
|
||||
if (version.isOlderThan(ClientVersion.V_1_16)) {
|
||||
// viaversion replacement - iron bars
|
||||
return CollisionData.PANE.dynamic.fetch(player, version, data, x, y, z);
|
||||
}
|
||||
|
||||
if (data.getAxis() == Axis.X) {
|
||||
return new HexCollisionBox(0.0D, 6.5D, 6.5D, 16.0D, 9.5D, 9.5D);
|
||||
} else if (data.getAxis() == Axis.Y) {
|
||||
@@ -599,8 +606,6 @@ public enum CollisionData {
|
||||
|
||||
FENCE(new DynamicFence(), BlockTags.FENCES.getStates().toArray(new StateType[0])),
|
||||
|
||||
PANE(new DynamicPane(), Materials.getPanes().toArray(new StateType[0])),
|
||||
|
||||
SNOW((player, version, data, x, y, z) -> {
|
||||
if (data.getLayers() == 1 && version.isNewerThanOrEquals(ClientVersion.V_1_13)) {
|
||||
// Via doesn't touch this
|
||||
|
||||
@@ -112,7 +112,7 @@ public enum HitboxData {
|
||||
}
|
||||
|
||||
List<SimpleCollisionBox> boxes = new ArrayList<>();
|
||||
CollisionData.getData(state.getType()).getMovementCollisionBox(player, version, state, x, y, z).downCast(boxes);
|
||||
CollisionData.getData(state.getType()).getMovementCollisionBox(player, version, state).downCast(boxes);
|
||||
|
||||
for (SimpleCollisionBox box : boxes) {
|
||||
box.maxY = 1;
|
||||
|
||||
@@ -84,7 +84,7 @@ public class DynamicPane extends DynamicConnecting implements CollisionFactory {
|
||||
|
||||
@Override
|
||||
public boolean checkCanConnect(GrimPlayer player, WrappedBlockState state, StateType one, StateType two, BlockFace direction) {
|
||||
if (BlockTags.GLASS_PANES.contains(one) || one == StateTypes.IRON_BARS)
|
||||
if (BlockTags.GLASS_PANES.contains(one) || one == StateTypes.IRON_BARS || one == StateTypes.CHAIN && player.getClientVersion().isOlderThan(ClientVersion.V_1_16))
|
||||
return true;
|
||||
else
|
||||
return CollisionData.getData(one).getMovementCollisionBox(player, player.getClientVersion(), state, 0, 0, 0).isSideFullBlock(direction);
|
||||
|
||||
@@ -80,6 +80,7 @@ public final class ValuedAttribute {
|
||||
|
||||
public void reset() {
|
||||
this.value = defaultValue;
|
||||
this.lastProperty = null; // Remove the old property with its modifiers so we don't accidentally use it again, messing up the calculation.
|
||||
}
|
||||
|
||||
public double get() {
|
||||
@@ -122,7 +123,7 @@ public final class ValuedAttribute {
|
||||
d1 *= 1.0D + attributemodifier.getAmount();
|
||||
}
|
||||
|
||||
double newValue = GrimMath.clampFloat((float) d1, (float) min, (float) max);
|
||||
double newValue = GrimMath.clamp(d1, min, max);
|
||||
if (setRewriter != null) {
|
||||
newValue = setRewriter.apply(this.value, newValue);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package ac.grim.grimac.utils.data.packetentity;
|
||||
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.data.attribute.ValuedAttribute;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
@@ -20,7 +22,16 @@ public class PacketEntityHorse extends PacketEntityTrackXRot {
|
||||
setAttribute(Attributes.GENERIC_STEP_HEIGHT, 1.0f);
|
||||
|
||||
final boolean preAttribute = player.getClientVersion().isOlderThan(ClientVersion.V_1_20_5);
|
||||
trackAttribute(ValuedAttribute.ranged(Attributes.GENERIC_JUMP_STRENGTH, 0.7, 0, preAttribute ? 2 : 32));
|
||||
// This was horse.jump_strength pre-attribute
|
||||
trackAttribute(ValuedAttribute.ranged(Attributes.GENERIC_JUMP_STRENGTH, 0.7, 0, preAttribute ? 2 : 32)
|
||||
.withSetRewriter((oldValue, newValue) -> {
|
||||
// Seems viabackwards doesn't rewrite this (?)
|
||||
if (preAttribute && PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_20_5)) {
|
||||
return oldValue;
|
||||
}
|
||||
// Modern player OR an old server setting legacy horse.jump_strength attribute
|
||||
return newValue;
|
||||
}));
|
||||
trackAttribute(ValuedAttribute.ranged(Attributes.GENERIC_MOVEMENT_SPEED, 0.225f, 0, 1024));
|
||||
|
||||
if (EntityTypes.isTypeInstanceOf(type, EntityTypes.CHESTED_HORSE)) {
|
||||
|
||||
@@ -110,10 +110,11 @@ public class BlockBreakSpeed {
|
||||
if (tool.getType().hasAttribute(ItemTypes.ItemAttribute.SWORD)) {
|
||||
if (block.getType() == StateTypes.COBWEB) {
|
||||
speedMultiplier = 15.0f;
|
||||
} else if (block.getType().getMaterialType() == MaterialType.PLANT ||
|
||||
BlockTags.LEAVES.contains(block.getType()) ||
|
||||
block.getType() == StateTypes.PUMPKIN ||
|
||||
block.getType() == StateTypes.MELON) {
|
||||
} else if (block.getType().getMaterialType() == MaterialType.PLANT
|
||||
|| BlockTags.LEAVES.contains(block.getType())
|
||||
|| block.getType() == StateTypes.VINE
|
||||
|| block.getType() == StateTypes.PUMPKIN
|
||||
|| block.getType() == StateTypes.MELON) {
|
||||
speedMultiplier = 1.5f;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@ public class BlockProperties {
|
||||
}
|
||||
|
||||
if (player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityStrider) {
|
||||
// Unsure which version the speed changed in
|
||||
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20)) {
|
||||
return (float) player.speed * 0.1f;
|
||||
}
|
||||
|
||||
PacketEntityStrider strider = (PacketEntityStrider) player.compensatedEntities.getSelf().getRiding();
|
||||
// Vanilla multiplies by 0.1 to calculate speed
|
||||
return (float) strider.getAttributeValue(Attributes.GENERIC_MOVEMENT_SPEED) * (strider.isShaking ? 0.66F : 1.0F) * 0.1f;
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
package ac.grim.grimac.utils.nmsutil;
|
||||
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.HitboxData;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.HitData;
|
||||
import ac.grim.grimac.utils.data.Pair;
|
||||
import ac.grim.grimac.utils.math.GrimMath;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class BlockRayTrace {
|
||||
|
||||
// Copied from MCP...
|
||||
// Returns null if there isn't anything.
|
||||
//
|
||||
// I do have to admit that I'm starting to like bifunctions/new java 8 things more than I originally did.
|
||||
// although I still don't understand Mojang's obsession with streams in some of the hottest methods... that kills performance
|
||||
public static HitData traverseBlocks(GrimPlayer player, Vector3d start, Vector3d end, BiFunction<WrappedBlockState, Vector3i, HitData> predicate) {
|
||||
// I guess go back by the collision epsilon?
|
||||
double endX = GrimMath.lerp(-1.0E-7D, end.x, start.x);
|
||||
double endY = GrimMath.lerp(-1.0E-7D, end.y, start.y);
|
||||
double endZ = GrimMath.lerp(-1.0E-7D, end.z, start.z);
|
||||
double startX = GrimMath.lerp(-1.0E-7D, start.x, end.x);
|
||||
double startY = GrimMath.lerp(-1.0E-7D, start.y, end.y);
|
||||
double startZ = GrimMath.lerp(-1.0E-7D, start.z, end.z);
|
||||
int floorStartX = GrimMath.floor(startX);
|
||||
int floorStartY = GrimMath.floor(startY);
|
||||
int floorStartZ = GrimMath.floor(startZ);
|
||||
|
||||
|
||||
if (start.equals(end)) return null;
|
||||
|
||||
WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(floorStartX, floorStartY, floorStartZ);
|
||||
HitData apply = predicate.apply(state, new Vector3i(floorStartX, floorStartY, floorStartZ));
|
||||
|
||||
if (apply != null) {
|
||||
return apply;
|
||||
}
|
||||
|
||||
double xDiff = endX - startX;
|
||||
double yDiff = endY - startY;
|
||||
double zDiff = endZ - startZ;
|
||||
double xSign = Math.signum(xDiff);
|
||||
double ySign = Math.signum(yDiff);
|
||||
double zSign = Math.signum(zDiff);
|
||||
|
||||
double posXInverse = xSign == 0 ? Double.MAX_VALUE : xSign / xDiff;
|
||||
double posYInverse = ySign == 0 ? Double.MAX_VALUE : ySign / yDiff;
|
||||
double posZInverse = zSign == 0 ? Double.MAX_VALUE : zSign / zDiff;
|
||||
|
||||
double d12 = posXInverse * (xSign > 0 ? 1.0D - GrimMath.frac(startX) : GrimMath.frac(startX));
|
||||
double d13 = posYInverse * (ySign > 0 ? 1.0D - GrimMath.frac(startY) : GrimMath.frac(startY));
|
||||
double d14 = posZInverse * (zSign > 0 ? 1.0D - GrimMath.frac(startZ) : GrimMath.frac(startZ));
|
||||
|
||||
// Can't figure out what this code does currently
|
||||
while (d12 <= 1.0D || d13 <= 1.0D || d14 <= 1.0D) {
|
||||
if (d12 < d13) {
|
||||
if (d12 < d14) {
|
||||
floorStartX += xSign;
|
||||
d12 += posXInverse;
|
||||
} else {
|
||||
floorStartZ += zSign;
|
||||
d14 += posZInverse;
|
||||
}
|
||||
} else if (d13 < d14) {
|
||||
floorStartY += ySign;
|
||||
d13 += posYInverse;
|
||||
} else {
|
||||
floorStartZ += zSign;
|
||||
d14 += posZInverse;
|
||||
}
|
||||
|
||||
state = player.compensatedWorld.getWrappedBlockStateAt(floorStartX, floorStartY, floorStartZ);
|
||||
apply = predicate.apply(state, new Vector3i(floorStartX, floorStartY, floorStartZ));
|
||||
|
||||
if (apply != null) {
|
||||
return apply;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HitData getNearestHitResult(GrimPlayer player, StateType heldItem, boolean sourcesHaveHitbox) {
|
||||
Vector3d startingPos = new Vector3d(player.x, player.y + player.getEyeHeight(), player.z);
|
||||
Vector startingVec = new Vector(startingPos.getX(), startingPos.getY(), startingPos.getZ());
|
||||
Ray trace = new Ray(player, startingPos.getX(), startingPos.getY(), startingPos.getZ(), player.xRot, player.yRot);
|
||||
final double distance = player.compensatedEntities.getSelf().getAttributeValue(
|
||||
Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
|
||||
Vector endVec = trace.getPointAtDistance(distance);
|
||||
Vector3d endPos = new Vector3d(endVec.getX(), endVec.getY(), endVec.getZ());
|
||||
return getTraverseResult(player, heldItem, startingPos, startingVec, trace, endPos, sourcesHaveHitbox, false, distance + 3);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static HitData getNearestReachHitResult(GrimPlayer player, Vector eyePos, Vector lookVec, double currentDistance, double maxDistance) {
|
||||
Vector3d startingPos = new Vector3d(eyePos.getX(), eyePos.getY(), eyePos.getZ());
|
||||
Vector startingVec = new Vector(startingPos.getX(), startingPos.getY(), startingPos.getZ());
|
||||
Ray trace = new Ray(eyePos, lookVec);
|
||||
Vector endVec = trace.getPointAtDistance(maxDistance);
|
||||
Vector3d endPos = new Vector3d(endVec.getX(), endVec.getY(), endVec.getZ());
|
||||
return getTraverseResult(player, null, startingPos, startingVec, trace, endPos, false, true, currentDistance);
|
||||
}
|
||||
|
||||
private static HitData getTraverseResult(GrimPlayer player, @Nullable StateType heldItem, Vector3d startingPos, Vector startingVec, Ray trace, Vector3d endPos, boolean sourcesHaveHitbox, boolean checkInside, double knownDistance) {
|
||||
return traverseBlocks(player, startingPos, endPos, (block, vector3i) -> {
|
||||
CollisionBox data = HitboxData.getBlockHitbox(player, heldItem, player.getClientVersion(), block, vector3i.getX(), vector3i.getY(), vector3i.getZ());
|
||||
List<SimpleCollisionBox> boxes = new ArrayList<>();
|
||||
data.downCast(boxes);
|
||||
|
||||
double bestHitResult = Double.MAX_VALUE;
|
||||
Vector bestHitLoc = null;
|
||||
BlockFace bestFace = null;
|
||||
|
||||
for (SimpleCollisionBox box : boxes) {
|
||||
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(knownDistance));
|
||||
if (intercept.getFirst() == null) continue; // No intercept
|
||||
|
||||
Vector hitLoc = intercept.getFirst();
|
||||
|
||||
// If inside a block, return empty result for reach check (don't bother checking this?)
|
||||
if (checkInside && ReachUtils.isVecInside(box, trace.getOrigin())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (hitLoc.distanceSquared(startingVec) < bestHitResult) {
|
||||
bestHitResult = hitLoc.distanceSquared(startingVec);
|
||||
bestHitLoc = hitLoc;
|
||||
bestFace = intercept.getSecond();
|
||||
}
|
||||
}
|
||||
|
||||
if (bestHitLoc != null) {
|
||||
return new HitData(vector3i, bestHitLoc, bestFace, block);
|
||||
}
|
||||
|
||||
if (sourcesHaveHitbox &&
|
||||
(player.compensatedWorld.isWaterSourceBlock(vector3i.getX(), vector3i.getY(), vector3i.getZ())
|
||||
|| player.compensatedWorld.getLavaFluidLevelAt(vector3i.getX(), vector3i.getY(), vector3i.getZ()) == (8 / 9f))) {
|
||||
double waterHeight = player.compensatedWorld.getFluidLevelAt(vector3i.getX(), vector3i.getY(), vector3i.getZ());
|
||||
SimpleCollisionBox box = new SimpleCollisionBox(vector3i.getX(), vector3i.getY(), vector3i.getZ(), vector3i.getX() + 1, vector3i.getY() + waterHeight, vector3i.getZ() + 1);
|
||||
|
||||
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(knownDistance));
|
||||
|
||||
if (intercept.getFirst() != null) {
|
||||
return new HitData(vector3i, intercept.getFirst(), intercept.getSecond(), block);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import org.bukkit.util.Vector;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class Collisions {
|
||||
@@ -699,7 +700,7 @@ public class Collisions {
|
||||
int x = currX | chunkXGlobalPos;
|
||||
int z = currZ | chunkZGlobalPos;
|
||||
|
||||
WrappedBlockState data = section.get(CompensatedWorld.blockVersion, x & 0xF, y & 0xF, z & 0xF);
|
||||
WrappedBlockState data = section.get(CompensatedWorld.blockVersion, x & 0xF, y & 0xF, z & 0xF, false);
|
||||
|
||||
if (searchingFor.test(new Pair<>(data, new Vector3d(x, y, z)))) return true;
|
||||
}
|
||||
@@ -710,6 +711,85 @@ public class Collisions {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Thanks Tuinity
|
||||
public static void forEachCollisionBox(GrimPlayer player, SimpleCollisionBox checkBox, Consumer<Vector3d> searchingFor) {
|
||||
int minBlockX = (int) Math.floor(checkBox.minX - COLLISION_EPSILON) - 1;
|
||||
int maxBlockX = (int) Math.floor(checkBox.maxX + COLLISION_EPSILON) + 1;
|
||||
int minBlockY = (int) Math.floor(checkBox.minY - COLLISION_EPSILON) - 1;
|
||||
int maxBlockY = (int) Math.floor(checkBox.maxY + COLLISION_EPSILON) + 1;
|
||||
int minBlockZ = (int) Math.floor(checkBox.minZ - COLLISION_EPSILON) - 1;
|
||||
int maxBlockZ = (int) Math.floor(checkBox.maxZ + COLLISION_EPSILON) + 1;
|
||||
|
||||
final int minSection = player.compensatedWorld.getMinHeight() >> 4;
|
||||
final int minBlock = minSection << 4;
|
||||
final int maxBlock = player.compensatedWorld.getMaxHeight() - 1;
|
||||
|
||||
int minChunkX = minBlockX >> 4;
|
||||
int maxChunkX = maxBlockX >> 4;
|
||||
|
||||
int minChunkZ = minBlockZ >> 4;
|
||||
int maxChunkZ = maxBlockZ >> 4;
|
||||
|
||||
int minYIterate = Math.max(minBlock, minBlockY);
|
||||
int maxYIterate = Math.min(maxBlock, maxBlockY);
|
||||
|
||||
for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
|
||||
int minZ = currChunkZ == minChunkZ ? minBlockZ & 15 : 0; // coordinate in chunk
|
||||
int maxZ = currChunkZ == maxChunkZ ? maxBlockZ & 15 : 15; // coordinate in chunk
|
||||
|
||||
for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) {
|
||||
int minX = currChunkX == minChunkX ? minBlockX & 15 : 0; // coordinate in chunk
|
||||
int maxX = currChunkX == maxChunkX ? maxBlockX & 15 : 15; // coordinate in chunk
|
||||
|
||||
int chunkXGlobalPos = currChunkX << 4;
|
||||
int chunkZGlobalPos = currChunkZ << 4;
|
||||
|
||||
Column chunk = player.compensatedWorld.getChunk(currChunkX, currChunkZ);
|
||||
|
||||
if (chunk == null) continue;
|
||||
BaseChunk[] sections = chunk.getChunks();
|
||||
|
||||
for (int y = minYIterate; y <= maxYIterate; ++y) {
|
||||
BaseChunk section = sections[(y >> 4) - minSection];
|
||||
|
||||
if (section == null || (IS_FOURTEEN && section.isEmpty())) { // Check for empty on 1.13+ servers
|
||||
// empty
|
||||
// skip to next section
|
||||
y = (y & ~(15)) + 15; // increment by 15: iterator loop increments by the extra one
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int currZ = minZ; currZ <= maxZ; ++currZ) {
|
||||
for (int currX = minX; currX <= maxX; ++currX) {
|
||||
int x = currX | chunkXGlobalPos;
|
||||
int z = currZ | chunkZGlobalPos;
|
||||
|
||||
WrappedBlockState data = section.get(CompensatedWorld.blockVersion, x & 0xF, y & 0xF, z & 0xF, false);
|
||||
|
||||
// Works on both legacy and modern! Faster than checking for material types, most common case
|
||||
if (data.getGlobalId() == 0) continue;
|
||||
|
||||
// Thanks SpottedLeaf for this optimization, I took edgeCount from Tuinity
|
||||
int edgeCount = ((x == minBlockX || x == maxBlockX) ? 1 : 0) +
|
||||
((y == minBlockY || y == maxBlockY) ? 1 : 0) +
|
||||
((z == minBlockZ || z == maxBlockZ) ? 1 : 0);
|
||||
|
||||
final StateType type = data.getType();
|
||||
if (edgeCount != 3 && (edgeCount != 1 || Materials.isShapeExceedsCube(type))
|
||||
&& (edgeCount != 2 || type == StateTypes.PISTON_HEAD)) {
|
||||
final CollisionBox collisionBox = CollisionData.getData(type).getMovementCollisionBox(player, player.getClientVersion(), data, x, y, z);
|
||||
|
||||
if (collisionBox.isIntersected(checkBox)) {
|
||||
searchingFor.accept(new Vector3d(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean onClimbable(GrimPlayer player, double x, double y, double z) {
|
||||
WrappedBlockState blockState = player.compensatedWorld.getWrappedBlockStateAt(x, y, z);
|
||||
StateType blockMaterial = blockState.getType();
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package ac.grim.grimac.utils.nmsutil;
|
||||
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.CollisionData;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.MainSupportingBlockData;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
@@ -42,12 +40,8 @@ public class MainSupportingBlockPosFinder {
|
||||
AtomicReference<Vector3i> bestBlockPos = new AtomicReference<>();
|
||||
AtomicDouble blockPosDistance = new AtomicDouble(Double.MAX_VALUE);
|
||||
|
||||
Collisions.hasMaterial(player, searchBox, (thing) -> {
|
||||
Vector3i blockPos = thing.getSecond().toVector3i();
|
||||
|
||||
CollisionBox collision = CollisionData.getData(thing.getFirst().getType()).getMovementCollisionBox(player, player.getClientVersion(), thing.getFirst(), blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
||||
if (!collision.isIntersected(searchBox)) return false;
|
||||
|
||||
Collisions.forEachCollisionBox(player, searchBox, (pos) -> {
|
||||
Vector3i blockPos = pos.toVector3i();
|
||||
Vector3d blockPosAsVector3d = new Vector3d(blockPos.getX() + 0.5, blockPos.getY() + 0.5, blockPos.getZ() + 0.5);
|
||||
double distance = playerPos.distanceSquared(blockPosAsVector3d);
|
||||
|
||||
@@ -55,8 +49,6 @@ public class MainSupportingBlockPosFinder {
|
||||
bestBlockPos.set(blockPos);
|
||||
blockPosDistance.set(distance);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -10,16 +10,17 @@ alerts:
|
||||
# Isso controla se/como os alertas são compartilhados entre os servidores conectados ao proxy.
|
||||
# Deve-se ter 'bungee-plugin-message-channel' habilitado na configuração do Velocity se estiver usando.
|
||||
proxy:
|
||||
# Os alertas deveriam ser enviados para outros servidores conectados no mesmo proxy?
|
||||
# Deviam os alertas ser enviados para outros servidores conectados no mesmo proxy?
|
||||
send: false
|
||||
# Os alertas deveriam ser recebidos de outros servidores conectados no mesmo proxy?
|
||||
# Deviam os alertas ser recebidos de outros servidores conectados no mesmo proxy?
|
||||
receive: false
|
||||
|
||||
verbose:
|
||||
print-to-console: false
|
||||
|
||||
client-brand:
|
||||
# Isso signifia que, caso o nome do cliente seja igual aos listados abaixo, não será notificados aos operadores.
|
||||
# Isso signifia que, caso a marca do cliente seja igual às listadas abaixo, não será notificado aos
|
||||
# administradores.
|
||||
ignored-clients:
|
||||
- "^vanilla$"
|
||||
- "^fabric$"
|
||||
@@ -27,7 +28,7 @@ client-brand:
|
||||
- "^Feather Fabric$"
|
||||
|
||||
spectators:
|
||||
# Esconde todos espectadores com a permissão 'grim.spectator' mesmo se não estiverem espectando ativamente.
|
||||
# Esconde todos espectadores com a permissão 'grim.spectator' mesmo se não estiverem ativamente espectando.
|
||||
hide-regardless: false
|
||||
# Fará os espectadores serem escondidos apenas nos mundos listados abaixo, deixe em branco para habilitar em todos os mundos.
|
||||
allowed-worlds:
|
||||
@@ -36,35 +37,35 @@ spectators:
|
||||
# Quanto tempo os jogadores tem até expulsarmos eles por inatividade? Padrão = 60 segundos.
|
||||
max-transaction-time: 60
|
||||
|
||||
# Should the duplicate movement packet be cancelled?
|
||||
# Mojang has fixed this issue in 1.21. This was their attempt to fix the "bucket desync". https://bugs.mojang.com/browse/MC-12363
|
||||
# This setting only applies to 1.17-1.20.5 clients on 1.8 servers.
|
||||
# Deve-se cancelar o pacote de movimento duplicado?
|
||||
# A Mojang arrumou esse erro na 1.21, sendo sua tentativa de concertar a dessincronização do balde. https://bugs.mojang.com/browse/MC-12363
|
||||
# Isso só se aplica à clientes da 1.17-1.20.5 em servidores da 1.8.
|
||||
cancel-duplicate-packet: true
|
||||
|
||||
# Whether or not to ignore the rotation in duplicate packets
|
||||
# Deve-se ignorar rotação em pacotes duplicados?
|
||||
ignore-duplicate-packet-rotation: false
|
||||
|
||||
Simulation:
|
||||
# Por quanto deveríamos multiplicar a vantagem caso o jogador não tenha falhado em nem uma verificação?
|
||||
# Por quanto deve-se multiplicar a vantagem desde a última vez que falhou uma verificação?
|
||||
# Isso é como a configuração padrão se parece (eixo X = segundos, eixo Y = 1/1000 blocos): https://www.desmos.com/calculator/d4ufgxrxer
|
||||
setback-decay-multiplier: 0.999
|
||||
# O quão longe o jogador deve estar da área simulada para adicionarmos violações?
|
||||
# O quão longe o jogador deve estar da área simulada para registrar violações?
|
||||
# Medido em blocos do último movimento legítmo.
|
||||
# Aceitamos o Optifine trocando as tabelas trigonométricas, mas abaixar para 0.001 reduzirá o 'FastMath'
|
||||
# de falhar, caso esta compensação não funcionar...
|
||||
# Incluímos o Optifine trocando as tabelas trigonométricas; entretanto, abaixar para 0.001 reduzirá o 'FastMath'
|
||||
# de falhar, caso essa compensação não funcionar.
|
||||
threshold: 0.001
|
||||
# O quão longe o jogador deve estar da área simulada para imediatamente recuá-lo?
|
||||
# -1 desabilitará
|
||||
immediate-setback-threshold: 0.1
|
||||
# O quão longe da área simulada sobre todos os ticks para começarmos a recuar?
|
||||
# Qual é a soma do desalinhamento da simulação em todos os ticks até começarmos a recuar?
|
||||
# -1 desabilitará
|
||||
max-advantage: 1
|
||||
# Depois de 50 segundos, com a configuração padrão, o jogador irá de 4 blocos -> 1 bloco de vantagem.
|
||||
# Depois de 50 segundos, com a configuração padrão, o jogador irá de 4 blocos a 1 bloco de vantagem.
|
||||
# Isso serve para previnir o jogador de alcançar violações demais e nunca conseguir se livrar delas.
|
||||
# Cela de vantagens padrão (eixo X = segundos, eixo Y = 1/1000 blocos): https://www.desmos.com/calculator/4lovswdarj
|
||||
max-ceiling: 4
|
||||
|
||||
# Verifica se um jogador entrou em um bloco durante o movimento.
|
||||
# Verifica se um jogador entrou em um bloco ao se mover.
|
||||
Phase:
|
||||
setbackvl: 1 # Entrar em blocos possibilita escalar paredes, além disso, essa verificação é relativamente estável.
|
||||
decay: 0.005
|
||||
@@ -85,29 +86,29 @@ RotationPlace:
|
||||
cancelvl: 5
|
||||
|
||||
# Verificação de NoSlow por simulação.
|
||||
# Grim considera erros no netcode... difícil de gerar falsos positivos, até mesmo spamando o blotão direito e a offhand.
|
||||
# Muito mais estável que outros anticheats, mas por favor, reporte quaisquer falsos positivos... eu já arrumei diversos
|
||||
# Grim considera erros no netcode. Difícil de gerar falsos positivos, até mesmo spamando o blotão direito e a offhand.
|
||||
# Muito mais estável que outros anticheats, mas por favor, reporte quaisquer falsos positivos. Eu já arrumei diversos
|
||||
# erros de netcode.
|
||||
NoSlowA:
|
||||
# Quanto de desvio da simulação é considerado trapaça?
|
||||
# Por padrão isso é menor que outros desvios.
|
||||
# Acusa com 0.03-0.2 com consistência com o NoSlow ativo.
|
||||
# Quanto de desalinhamento é considerado trapaça?
|
||||
# Por padrão é menor que os outros.
|
||||
# Em 0.03-0.2 detecta com consistência.
|
||||
threshold: 0.001
|
||||
# Recua rapidamente no primeiro item para remover quaisquer vantagens que o NoSlow dá.
|
||||
# Recuo imediato para inibir as vantagens rapidamente.
|
||||
setbackvl: 5
|
||||
# Decai quando o jogador usa um item E é desasceletado por isso.
|
||||
# Decai quando o jogador usa um item e é efetivamente desacelerado.
|
||||
decay: 0.05
|
||||
|
||||
Knockback:
|
||||
# Por quanto deveriamos multiplicar a vantagem caso o jogador não tenha falhado nessa verificação?
|
||||
# Por quanto deve-se multiplicar a vantagem desde a última vez que falhou na verificação?
|
||||
setback-decay-multiplier: 0.999
|
||||
# O quão longe da área do recuo recebido o jogador deve estar para adicionarmos uma violação?
|
||||
# O quão longe da área do recuo recebido o jogador deve estar para registrar violações?
|
||||
# Medido em blocos do recuo recebido.
|
||||
threshold: 0.001
|
||||
# O quão longe o jogador deve estar da área simulada para imediatamente recuá-lo?
|
||||
# -1 desabilitará.
|
||||
immediate-setback-threshold: 0.1
|
||||
# O quão longe da área simulada sobre todos os ticks deverá ser para começarmos a recuar?
|
||||
# Qual é a soma do desalinhamento da simulação em todos os ticks até começarmos a recuar?
|
||||
# -1 desabilitará.
|
||||
max-advantage: 1
|
||||
# Isso serve para previnir o jogador de alcançar violações demais e nunca conseguir se livrar delas.
|
||||
@@ -120,16 +121,16 @@ Explosion:
|
||||
TimerA:
|
||||
setbackvl: 10
|
||||
# Milissegundos que o jogador pode acumular para depois usar quando eles têm um atraso no ping.
|
||||
# Pode permitir o uso de fast use / fast heal / fast bow na 1.8 caso o valor seja definido muito alto. 120ms parece
|
||||
# um bom balanceamento.
|
||||
# Pode ignorar o uso de fast use / fast heal / fast bow na 1.8 caso o valor seja definido muito alto.
|
||||
# 120ms parece um bom balanceamento.
|
||||
drift: 120
|
||||
# Ping no qual a verificação vai começar a limitar o balançeamento do timer para previnir abuso.
|
||||
# Pode causar recuos a jogadores legítmos, mas somente se estiverem acima deste ping.
|
||||
# Pode causar recuos a jogadores legítmos, mas somente se estiverem acima desse ping.
|
||||
# -1 desabilitará.
|
||||
ping-abuse-limit-threshold: 1000
|
||||
|
||||
NegativeTimer:
|
||||
# Número de milissegundos perdidos ao se mover antes de começarmos a adicionar violações.
|
||||
# Número de milissegundos perdidos ao se mover antes de começarmos a registrar violações.
|
||||
drift: 1200
|
||||
|
||||
# Mesmo método usado no TimerA, mas para veículos.
|
||||
@@ -141,56 +142,54 @@ EntityControl:
|
||||
setbackvl: 25
|
||||
|
||||
Reach:
|
||||
# Por quanto devíamos expandir as caixas de colisão? 0.0005 deve detectar 3.0005+ de alcance.
|
||||
# Por quanto deve-se expandir as caixas de colisão? 0.0005 deve detectar 3.0005+ de alcance.
|
||||
#
|
||||
# Há 0.03 de expansão forçada nas versões 1.9-1.18.1 (não a 1.18.2), ou algumas combinações de cliente/servidor por
|
||||
# conta de mudanças no protocolo e limitações. Essa verificação é mais poderosa com clientes da 1.7/1.8 em servidores
|
||||
# da 1.8.
|
||||
threshold: 0.0005
|
||||
# Deveríamos cancelar hits que sabemos que são impossíveis?
|
||||
# O alcance de 3.00-3.03 pode acabar passando, mas continuarão adicionando violações, por conta de limitações na
|
||||
# ordem de pacotes.
|
||||
# Deve-se cancelar hits que sabemos que são impossíveis?
|
||||
# O alcance de 3.00-3.03 pode acabar passando, por conta da ordem de pacotes, mas continuará registrando violações.
|
||||
block-impossible-hits: true
|
||||
# Isso enviará um pacote adicional no final de todos os ticks para aumentar a probabilidade de detectarmos trapaceiros.
|
||||
# Isso injeta na lista de conecção do servidor para envar um pacote final logo antes do servidor recarregar.
|
||||
# Habilitando isso, irá aumentar o uso de banda para todos os jogadores.
|
||||
# Isso não irá interferir na performance do servidor.
|
||||
# Habilitando isso, aumentará a probabilidade de detectarmos trapaceiros.
|
||||
# Deixando-o desabilitado, continuará detectando cheaters e não irá causar falsos positivos.
|
||||
# A menos que estiver em um servidor focado em PvP esse pacote adicional não é recomendado.
|
||||
# Deixando-o desabilitado, continuará detectando trapaceiros e não irá causar falsos positivos.
|
||||
# A menos que estiver em um servidor focado em PvP, esse pacote adicional não é recomendado.
|
||||
enable-post-packet: false
|
||||
|
||||
exploit:
|
||||
# Você pode ganhar altas velocidades enquanto pular correndo com uma elytra, isso previne o exploitação de ocorrer quando
|
||||
# definido falso.
|
||||
# Você pode ganhar altas velocidades se pular correndo com uma elytra, previne isso de ocorrer quando definido falso.
|
||||
# A Mojang vacilou com o netcode por fazer a Elytra iniciar pelo lado do cliente.
|
||||
# As Elytras levam 0.99 de fricção horizontal, então constantemente adicionando 0.2 de velocidade horizontal resulta
|
||||
# em velocidades altíssimas.
|
||||
allow-sprint-jumping-when-using-elytra: true
|
||||
# Essa opção mitiga o posicionamento de blocos em blocos fantasmas, ressincronizando o jogador quando isso ocorrer.
|
||||
# Essa opção mitiga posicionar blocos em blocos fantasma, ressincronizando o jogador quando isso ocorrer.
|
||||
allow-building-on-ghostblocks: true
|
||||
# Este ajuste, influenciado pelo booleano acima, define a distância para verificar blocos fantasmas.
|
||||
# Seu intervalo válido é limitado de 2 a 4.
|
||||
# Esse ajuste, influído pela opção acima, define a distância para verificar blocos fantasmas.
|
||||
# O valor válido é limitado de 2 a 4.
|
||||
distance-to-check-if-ghostblocks: 2
|
||||
|
||||
# Habilita registrar plugins que são injetados na netty ao entrar para depurar erros de compatibilidade.
|
||||
# Registra plugins que são injetados na netty ao entrar para depurar erros de compatibilidade.
|
||||
debug-pipeline-on-join: false
|
||||
|
||||
# Habilita verificações experimentais.
|
||||
experimental-checks: false
|
||||
|
||||
# Grim às vezes cancela pacotes ilegais como com o timer, depois de X pacotes em um segundo que foram cancelados, quando
|
||||
# devemos simplesmente expulsar o jogador? Isso é requirido já que alguns limitadores de pacotes não contam pacotes
|
||||
# deve-se simplesmente expulsar o jogador? Isso é requirido já que alguns limitadores de pacotes não contam pacotes
|
||||
# cancelados pelo Grim.
|
||||
packet-spam-threshold: 100
|
||||
|
||||
# Grim é capaz de garantir que um jogador fora do estado de voo não possa ter mais de X milissegundos de ping.
|
||||
# Grim pode impor que o jogador fora do estado de voo não possa ter mais de X milissegundos de ping.
|
||||
# Isso ocorre porque o Grim atualmente não verifica os jogadores que estão voando.
|
||||
# To disable, use -1
|
||||
# -1 desabilitará.
|
||||
max-ping-out-of-flying: 1000
|
||||
|
||||
# Maximum ping when a firework boost is removed from the player.
|
||||
# This prevents high latency players from being able to use 1 firework boost with an elytra forever.
|
||||
# Ping máximo quando o impulso do foguete acaba.
|
||||
# Previne jogadores com ping alto de usarem um foguete ara voar indefinidamente.
|
||||
max-ping-firework-boost: 1000
|
||||
|
||||
config-version: 9
|
||||
@@ -0,0 +1,192 @@
|
||||
# GrimAC ana konfigrasyon dosyası
|
||||
# Kaynak kodu: https://github.com/MWHunter/Grim
|
||||
# Telif Hakkı 2024 DefineOutside ve katkıda bulunanlar, GPLv3 altında lisanslanmıştır.
|
||||
# Değiştirilmiş ikili dosyalar veya kopyalanmış grim kodlu eklentiler özel olmalıdır,
|
||||
# veya ek ücret ödemeden alıcılara sunulan tam kaynak kodu ile.
|
||||
|
||||
alerts:
|
||||
# Oyunculara uyarı yayınlamanın yanı sıra, uyarılar konsola da gönderilmeli mi?
|
||||
print-to-console: true
|
||||
# Bu, uyarıların proxy'nize bağlı sunucular arasında paylaşılıp paylaşılmayacağını/nasıl paylaşılacağını kontrol eder.
|
||||
# Velocity kullanılıyorsa, Velocity yapılandırmanızda 'bungee-plugin-message-channel' etkinleştirilmiş olmalıdır.
|
||||
proxy:
|
||||
# Proxy'nize bağlı diğer sunuculara uyarılar gönderilmeli mi?
|
||||
send: false
|
||||
# Diğer sunuculardan alınan uyarılar bu sunucuya duyurulmalı mı?
|
||||
receive: false
|
||||
|
||||
verbose:
|
||||
print-to-console: false
|
||||
|
||||
client-brand:
|
||||
# Bu, giriş yapılan clientin aşağıdaki regex'lerle eşleşmesi durumunda markalarını operatörlere yayınlamayacağı anlamına gelir
|
||||
ignored-clients:
|
||||
- "^vanilla$"
|
||||
- "^fabric$"
|
||||
- "^lunarclient:v\\d+\\.\\d+\\.\\d+-\\d{4}$"
|
||||
- "^Feather Fabric$"
|
||||
|
||||
spectators:
|
||||
# Seyirciler aktif olarak izliyor olsalar bile, grim.spectator iznine sahip tüm seyircileri gizle
|
||||
hide-regardless: false
|
||||
# Sadece bu dünyalarda seyircileri gizleyecek, tüm dünyalara izin vermek için boş bırakın
|
||||
allowed-worlds:
|
||||
- ""
|
||||
|
||||
# Oyuncuların zaman aşımından dolayı sunucudan atılmadan önce ne kadar süreleri olmalı? Varsayılan = 60 saniye
|
||||
max-transaction-time: 60
|
||||
|
||||
# Kopya hareket paketinin iptal edilip edilmemesi gerektiği
|
||||
# Mojang bu sorunu 1.21'de çözdü. Bu, "kova senkronizasyonu" sorununu düzeltme girişimiydi. https://bugs.mojang.com/browse/MC-12363
|
||||
# Bu ayar yalnızca 1.17-1.20.5 istemcileri için 1.8 sunucularında geçerlidir.
|
||||
cancel-duplicate-packet: true
|
||||
|
||||
# Eşya çoğaltma paketlerindeki rotayı göz ardı edip etmeyeceğimiz
|
||||
ignore-duplicate-packet-rotation: false
|
||||
|
||||
Simulation:
|
||||
# Oyuncu meşru olduğunda toplam avantajı ne kadar çarpmalıyız?
|
||||
# Varsayılan yapılandırma bu şekilde görünür (x ekseni = saniye, y ekseni = 1/1000 blok): https://www.desmos.com/calculator/d4ufgxrxer
|
||||
setback-decay-multiplier: 0.999
|
||||
# Oyuncunun hareketinden ne kadar büyük bir sapma ihlal oluşturmalıyız?
|
||||
# Mümkün olan hareketten blok cinsinden ölçülür
|
||||
# Optifine için trig tablolarını değiştirerek hesaba katıyoruz, ancak bunu 0.001'e düşürmek FastMath'ı azaltır
|
||||
# Bu telafi işe yaramazsa anticheat'i işaretle...
|
||||
threshold: 0.001
|
||||
# Bir tik içinde ne kadar büyük bir ihlal olmalı ki oyuncu hemen geri dönsün?
|
||||
# Devre dışı bırakmak için -1 yazın
|
||||
immediate-setback-threshold: 0.1
|
||||
# Tüm tikler boyunca ne kadar büyük bir avantaja sahip olmalıyız ki geri dönüş yapmaya başlayalım?
|
||||
# Devre dışı bırakmak için -1 yazın
|
||||
max-advantage: 1
|
||||
# Varsayılan config ile 50 saniye sonra, oyuncu 4 bloktan -> 1 bloğa kadar avantaj kazanır
|
||||
# Bu, oyuncunun çok fazla ihlal biriktirmesini ve bunların hepsini temizleyememesini önlemek içindir
|
||||
# Varsayılan avantaj tavanı (x ekseni = saniye, y ekseni = 1/1000 blok): https://www.desmos.com/calculator/4lovswdarj
|
||||
max-ceiling: 4
|
||||
|
||||
# Bir oyuncunun bir hareket sırasında bir bloğa girip girmediğini kontrol eder
|
||||
Phase:
|
||||
setbackvl: 1 # Blokların içinde glitch yapmak duvara tırmanmaya izin verebilir, ayrıca bu kontrol nispeten stabildir
|
||||
decay: 0.005
|
||||
|
||||
AirLiquidPlace:
|
||||
cancelvl: 0
|
||||
|
||||
FabricatedPlace:
|
||||
cancelvl: 5
|
||||
|
||||
FarPlace:
|
||||
cancelvl: 5
|
||||
|
||||
PositionPlace:
|
||||
cancelvl: 5
|
||||
|
||||
RotationPlace:
|
||||
cancelvl: 5
|
||||
|
||||
# Tahmin tabanlı yavaşlama kontrolü
|
||||
# Grim burada hatalı ağ kodunu dikkate alır... sağ tıklama ve el yan tuşunu spam yapsanız bile yanlış pozitiflik oluşturması zordur
|
||||
# Diğer anti-hilelerden çok daha stabil, ancak herhangi bir yanlış pozitif rapor edin... burada birçok ağ kodu sorununu çözdüm.
|
||||
NoSlowA:
|
||||
# Ne kadar bir sapma "hile" olarak kabul edilir?
|
||||
# Varsayılan olarak bu, diğer sapmalardan daha düşüktür
|
||||
# NoSlow açıkken 0.03-0.2 aralığında sürekli olarak uyarı verir
|
||||
threshold: 0.001
|
||||
# NoSlow'un sağladığı avantajı ortadan kaldırmak için ilk itemi hızlı bir şekilde geri alın
|
||||
setbackvl: 5
|
||||
# Oyuncu bir eşya kullandığında VE onun tarafından yavaşlatıldığında beklenilen zaman
|
||||
decay: 0.05
|
||||
|
||||
Knockback:
|
||||
# Oyuncu legit olduğunda toplam avantajı ne kadarla çarpmalıyız
|
||||
setback-decay-multiplier: 0.999
|
||||
# Oyuncunun hızından ne kadar büyük bir sapma ihlal oluşturmalıyız?
|
||||
# Mümkün olan hızdan blok cinsinden ölçülür
|
||||
threshold: 0.001
|
||||
# Bir tik içinde ne kadar büyük bir ihlal olmalı ki oyuncu hemen geri dönsün?
|
||||
# Devre dışı bırakmak için -1 yazın
|
||||
immediate-setback-threshold: 0.1
|
||||
# Tüm tikler boyunca ne kadar büyük bir avantaja sahip olmalıyız ki geri dönüş yapmaya başlayalım?
|
||||
# Devre dışı bırakmak için -1 yazın
|
||||
max-advantage: 1
|
||||
# Bu, oyuncunun çok fazla ihlal toplamasını ve asla hepsini temizleyememesini engellemek içindir
|
||||
max-ceiling: 4
|
||||
|
||||
Explosion:
|
||||
threshold: 0.001
|
||||
setbackvl: 3
|
||||
|
||||
TimerA:
|
||||
setbackvl: 10
|
||||
# Oyuncunun geri kaldığında biriktirebileceği milisaniye miktarı
|
||||
# Çok yüksek ayarlandığında 1.8 hızlı kullanma/hızlı iyileşme/hızlı yay atlama durumlarına izin verebilir, 120 ms iyi bir denge gibi görünüyor
|
||||
drift: 120
|
||||
# Kontrolün zamanlayıcı dengesini sınırlamaya başlayacağı ping değeri, kötüye kullanımı önlemek için.
|
||||
# Bu, yalnızca bu ping eşiğini aşan meşru oyuncular için bazı geri dönüşlere neden olabilir.
|
||||
# Devre dışı bırakmak için -1 yazın
|
||||
ping-abuse-limit-threshold: 1000
|
||||
|
||||
NegativeTimer:
|
||||
# Uyarı vermeye başlamadan önce hareket halindeyken kaybedilen milisaniye sayısı
|
||||
drift: 1200
|
||||
|
||||
# TimerA ile aynı kontrol yöntemi, ancak araçlar için
|
||||
TimerVehicle:
|
||||
# Hedef 1.005 timer
|
||||
setbackvl: 10
|
||||
|
||||
EntityControl:
|
||||
setbackvl: 25
|
||||
|
||||
Reach:
|
||||
# Hitbox'ları ne kadar genişletmeliyiz? 0.0005, 3.0005+ menzili tespit etmelidir
|
||||
#
|
||||
# 1.9-1.18.1 (1.18.2 değil) ile zorunlu olarak 0.03 genişletme vardır veya bazı istemci/sunucu kombinasyonları nedeniyle
|
||||
# protokol değişiklikleri ve sınırlamaları nedeniyle. Bu kontrol, 1.7/1.8 istemcilerle 1.8 sunucularda en güçlüdür.
|
||||
threshold: 0.0005
|
||||
# İmkansız olduğunu bildiğimiz vuruşları iptal etmeli miyiz?
|
||||
# Paket sırası sınırlamaları nedeniyle 3.00-3.03 arası vuruşlar gerçekleşebilir, ancak yine de işaretlenebilir
|
||||
block-impossible-hits: true
|
||||
# Bu, hileleri yakalama olasılığını artırmak için her tikin sonunda ek bir paket gönderecektir
|
||||
# Bu, sunucunun bağlantı listesine enjekte edilerek sunucu boşaltmadan hemen önce son bir paket göndermek için yapılır
|
||||
# Bunu etkinleştirmek, tüm oyuncular için bant genişliği kullanımını artıracaktır
|
||||
# Bu, genel sunucu performansını düşürmez
|
||||
# Bunu etkinleştirmek, daha fazla hilecinin yakalanmasını sağlar
|
||||
# Bu özellik devre dışı bırakılsa bile hileciler yakalanır ve yanlış pozitifler oluşmaz
|
||||
# 1.8 PvP odaklı bir sunucu değilseniz, bu ek paket önerilmez
|
||||
enable-post-packet: false
|
||||
|
||||
exploit:
|
||||
# Elytra ile sprint zıplarken yüksek hızlar kazanabilirsiniz, bu ayar false olarak ayarlandığında bu istismarı önler
|
||||
# Mojang, elytra'nın istemci tarafında başlamasını ve sunucu tarafında bitmesini sağlayarak netcode'u bozdu
|
||||
# Elytra'lar 0.99 yatay sürtünme alır, bu yüzden sürekli olarak 0.2 yatay hız eklemek çok yüksek hızlara yol açar
|
||||
allow-sprint-jumping-when-using-elytra: true
|
||||
# Bu seçenek, oyuncunun hayalet bloklar üzerindeki yerleşimini, gerçekleştiğinde oyuncuyu yeniden senkronize ederek hafifletir
|
||||
allow-building-on-ghostblocks: true
|
||||
# Bu ayar, yukarıdaki boolean ile etkilenen hayalet blokları kontrol etmek için mesafeyi tanımlar
|
||||
# Geçerli aralığı 2 ile 4 arasında sınırlıdır
|
||||
distance-to-check-if-ghostblocks: 2
|
||||
|
||||
# Netty'ye enjekte olan eklentileri giriş sırasında günlüklemeyi etkinleştirerek uyumluluk sorunlarını gider
|
||||
debug-pipeline-on-join: false
|
||||
|
||||
# Deneysel kontrolleri etkinleştir
|
||||
experimental-checks: false
|
||||
|
||||
# Grim bazen timer gibi yasa dışı paketleri iptal eder; bir saniyede X paket iptal edildikten sonra, ne zaman
|
||||
# oyuncuyu basitçe atmalıyız? Bu, bazı paket sınırlayıcılarının Grim tarafından iptal edilen paketleri saymaması gerektiğindendir.
|
||||
packet-spam-threshold: 100
|
||||
|
||||
# Grim, uçma durumundan çıkmış bir oyuncunun X milisaniyeden fazla ping'e sahip olamayacağını uygulayabilir
|
||||
# Bu, Grim'in şu anda uçan oyuncuları kontrol etmemesindendir
|
||||
# Devre dışı bırakmak için -1 yazın
|
||||
max-ping-out-of-flying: 1000
|
||||
|
||||
# Bir havai fişek ivmesi oyuncudan çıkarıldığında maksimum ping.
|
||||
# Bu, yüksek gecikmeli oyuncuların bir havai fişek ivmesini elytra ile sonsuza kadar kullanmalarını engeller.
|
||||
max-ping-firework-boost: 1000
|
||||
|
||||
config-version: 9
|
||||
|
||||
# Translated by Kayera
|
||||
# Have a nice day :)
|
||||
@@ -2,7 +2,7 @@
|
||||
# 源代码链接: https://github.com/MWHunter/Grim
|
||||
# 版权归 DefineOutside 和 贡献者所有,基于GPLv3开源协议。
|
||||
# 修改过的二进制文件,或带有复制的Grim代码的插件,必须是私有仓库,不得公开售卖此插件。
|
||||
# 中文翻译提供 nuym ,如有错误请提交 Issues 并@我
|
||||
# 中文翻译提供 nuym/Dg32z_ ,如有错误请提交 Issues 并@我
|
||||
|
||||
alerts:
|
||||
# 是否在控制台显示作弊消息?
|
||||
@@ -27,21 +27,22 @@ client-brand:
|
||||
- "^Feather Fabric$"
|
||||
|
||||
spectators:
|
||||
# 把所有拥有 grim.spectartor 权限的人都隐藏起来,不管他是否观察玩家。
|
||||
# 将拥有 grim.spectator 权限的人进行隐藏,不管他是否在观察玩家
|
||||
hide-regardless: false
|
||||
# 观察者这些世界不会隐藏
|
||||
allowed-worlds:
|
||||
- ""
|
||||
|
||||
# 在我们让他们超时之前,玩家应该有多长时间? 此处的60 指60s
|
||||
# 在玩家无法接收 GrimAC的 transaction 数据包后,多少秒对玩家进行踢出
|
||||
# 踢出原因为: disconnect.timeout
|
||||
max-transaction-time: 60
|
||||
|
||||
# Should the duplicate movement packet be cancelled?
|
||||
# Mojang has fixed this issue in 1.21. This was their attempt to fix the "bucket desync". https://bugs.mojang.com/browse/MC-12363
|
||||
# This setting only applies to 1.17-1.20.5 clients on 1.8 servers.
|
||||
# 是否对重复的移动数据包进行撤销?
|
||||
# 这可以修复 "bucket desync". https://bugs.mojang.com/browse/MC-12363,不过Mojang已经在1.21修复了这个问题
|
||||
# 这仅仅适用于1.8服务器中使用1.17-1.20.5版本的玩家
|
||||
cancel-duplicate-packet: true
|
||||
|
||||
# Whether or not to ignore the rotation in duplicate packets
|
||||
# 是否忽视重复的数据包中的玩家转头
|
||||
ignore-duplicate-packet-rotation: false
|
||||
|
||||
Simulation:
|
||||
@@ -84,7 +85,7 @@ PositionPlace:
|
||||
RotationPlace:
|
||||
cancelvl: 5
|
||||
|
||||
# Prediction-based NoSlow 检查
|
||||
# 使用模拟移动进行的NoSlow(使用物品时不会减速)检查
|
||||
# 在这里解释错误的服务器代码......即使在发送垃圾数据包时右键单击和副手按钮也很分辨
|
||||
# 比其他反作弊更稳定,但请报告任何错误......我在这里修复了大量的代码问题。
|
||||
NoSlowA:
|
||||
@@ -121,13 +122,13 @@ TimerA:
|
||||
# 玩家卡顿时可以累积以供以后使用的毫秒数
|
||||
# 如果设置得太高,可能会允许 1.8 快速使用/快速治疗/快速弓箭绕过,120 毫秒似乎是一个很好的平衡
|
||||
drift: 120
|
||||
# Ping at which the check will start to limit timer balance, to prevent abuse.
|
||||
# Can cause some setbacks for legitimate players but only if they are over this ping threshold.
|
||||
# -1 to disable
|
||||
# 在检查玩家的延迟时对timer balance进行限制, 防止滥用
|
||||
# 在合法玩家的延迟超过这个延迟阈值时可能会造成误拉回
|
||||
# 填写-1则关闭
|
||||
ping-abuse-limit-threshold: 1000
|
||||
|
||||
NegativeTimer:
|
||||
# Number of milliseconds lost while moving before we should start flagging
|
||||
# 在开始检查玩家时,玩家的移动丢失了多少毫秒数
|
||||
drift: 1200
|
||||
|
||||
# 与 TimerA 相同的检查方法,但适用于坐骑
|
||||
@@ -157,8 +158,10 @@ Reach:
|
||||
enable-post-packet: false
|
||||
|
||||
exploit:
|
||||
#是否允许玩家在使用鞘翅时候进行的疾跑跳跃
|
||||
allow-sprint-jumping-when-using-elytra: true
|
||||
# 该选项可在发生鬼块时重新同步玩家,从而减轻玩家在鬼块上的位置。
|
||||
# 这可以在玩家遇到幽灵方块时进行同步,这可以减少玩家所碰到幽灵方块
|
||||
allow-building-on-ghostblocks: true
|
||||
distance-to-check-if-ghostblocks: 2
|
||||
|
||||
@@ -173,11 +176,12 @@ experimental-checks: false
|
||||
packet-spam-threshold: 100
|
||||
|
||||
# Grim 能够强制执行一个规则:被设置为非飞行状态的玩家的 ping 值不能超过 X 毫秒。这是因为 Grim 目前不检查处于飞行状态的玩家。
|
||||
# To disable, use -1
|
||||
# 填写-1则关闭
|
||||
max-ping-out-of-flying: 1000
|
||||
|
||||
# Maximum ping when a firework boost is removed from the player.
|
||||
# This prevents high latency players from being able to use 1 firework boost with an elytra forever.
|
||||
# 限制玩家在使用鞘翅飞行时使用烟花加速的延迟
|
||||
# 这可以解决高延迟的玩家可以使用鞘翅时一直使用 1 个烟花就可以加速
|
||||
# 填写-1则关闭
|
||||
max-ping-firework-boost: 1000
|
||||
|
||||
config-version: 9
|
||||
@@ -1,6 +1,7 @@
|
||||
# Ob Discord Webhook aktiviert werden soll
|
||||
enabled: false
|
||||
webhook: ""
|
||||
embed-title: "**Grim Alert**"
|
||||
embed-color: "#00FFFF"
|
||||
violation-content:
|
||||
- "**Spieler**: %player%"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
enabled: false
|
||||
webhook: ""
|
||||
embed-title: "**Grim Alert**"
|
||||
embed-color: "#00FFFF"
|
||||
violation-content:
|
||||
- "**Player**: %player%"
|
||||
|
||||
@@ -7,6 +7,8 @@ enabled: false
|
||||
# La URL del webhook.
|
||||
webhook: ""
|
||||
|
||||
embed-title: "**Grim Alert**"
|
||||
|
||||
# El color del embed que se mandara por este webhook.
|
||||
embed-color: "#00FFFF"
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
enabled: false
|
||||
webhook: ""
|
||||
embed-title: "**Grim Alert**"
|
||||
embed-color: "#00FFFF"
|
||||
violation-content:
|
||||
- "**Joueur**: %player%"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
enabled: false
|
||||
webhook: ""
|
||||
embed-title: "**Grim Alert**"
|
||||
embed-color: "#00FFFF"
|
||||
violation-content:
|
||||
- "**Giocatore**: %player%"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
enabled: false
|
||||
webhook: ""
|
||||
embed-title: "**Grim Alert**"
|
||||
embed-color: "#00FFFF"
|
||||
violation-content:
|
||||
- "**Speler**: %player%"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
enabled: false
|
||||
webhook: ""
|
||||
embed-title: "**Grim Alert**"
|
||||
embed-color: "#00FFFF"
|
||||
violation-content:
|
||||
- "**Jogador**: %player%"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Включать ли веб-крючок discord
|
||||
enabled: false
|
||||
webhook: ""
|
||||
embed-title: "**Grim Alert**"
|
||||
embed-color: "#00FFFF"
|
||||
violation-content:
|
||||
- "**Игрок**: %player%"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
enabled: false
|
||||
webhook: ""
|
||||
embed-color: "#00FFFF"
|
||||
violation-content:
|
||||
- "**Oyuncu**: %player%"
|
||||
- "**Kontrol**: %check%"
|
||||
- "**İhlaller**: %violations%"
|
||||
- "**Client Versiyonu**: %version%"
|
||||
- "**Kullanılan Client**: %brand%"
|
||||
- "**Gecikme**: %ping%"
|
||||
- "**TPS**: %tps%"
|
||||
@@ -1,12 +1,13 @@
|
||||
# 是否启用discord webhook
|
||||
enabled: false
|
||||
webhook: ""
|
||||
embed-title: "**Grim Alert**"
|
||||
embed-color: "#00FFFF"
|
||||
violation-content:
|
||||
- "**Player**: %player%"
|
||||
- "**Check**: %check%"
|
||||
- "**Violations**: %violations%"
|
||||
- "**Client Version**: %version%"
|
||||
- "**Brand**: %brand%"
|
||||
- "**Ping**: %ping%"
|
||||
- "**TPS**: %tps%"
|
||||
- "**玩家名**: %player%"
|
||||
- "**检查**: %check%"
|
||||
- "**违规率**: %violations%"
|
||||
- "**游戏版本**: %version%"
|
||||
- "**客户端品牌**: %brand%"
|
||||
- "**延迟**: %ping%"
|
||||
- "**服务器卡顿程度**: %tps%"
|
||||
@@ -1,34 +1,31 @@
|
||||
# Você pode usar códigos hexadecimais também, no formato #FFFFFF ou #ffffff.
|
||||
|
||||
# \u00BB é » (>> duplo), ANSI e UTF-8 interpretam isso diferentemente... você pode acabar vendo '?' por conta disso.
|
||||
prefix: "&bGrim &8\u00BB"
|
||||
|
||||
alerts-enabled: "%prefix% &fAlertas do AntiCheat foram habilitados para você."
|
||||
alerts-disabled: "%prefix% &fAlertas do AntiCheat foram desabilitados para você."
|
||||
client-brand-format: "%prefix% &f%player% entrou usando: &c%brand%"
|
||||
console-specify-target: "%prefix% &cVocê deve especificar o nome do alvo como o terminal!"
|
||||
alerts-enabled: "%prefix% &fAlertas habilitados."
|
||||
alerts-disabled: "%prefix% &fAlertas desabilitados."
|
||||
client-brand-format: "%prefix% &f%player% entrou usando %brand%."
|
||||
console-specify-target: "%prefix% &cVocê deve especificar o nome do alvo!"
|
||||
player-not-found: "%prefix% &cJogador não encontrado!"
|
||||
player-not-this-server: "%prefix% &cO jogador não está nesse servidor!"
|
||||
player-not-this-server: "%prefix% &cO jogador não está no servidor!"
|
||||
spectate-return: "\n%prefix% &fClique aqui para retornar a localização anterior\n"
|
||||
cannot-spectate-return: "%prefix% &cVocê só pode fazer isso enquanto estiver espectando alguém."
|
||||
cannot-run-on-self: "%prefix% &cVocê não pode usar esse comando em você mesmo!"
|
||||
upload-log: "%prefix% &fLogs enviadas para: %url%"
|
||||
upload-log-start: "%prefix% &fEnviando a log... Por favor, aguarde..."
|
||||
upload-log-not-found: "%prefix% &cNão foi possível encontrar essa log."
|
||||
upload-log-upload-failure: "%prefix% &cAlgo deu errado ao enviar essa log, veja o terminal para mais informações."
|
||||
cannot-spectate-return: "%prefix% &cVocê só pode fazer isso após espectar um jogador."
|
||||
cannot-run-on-self: "%prefix% &cVocê não pode usar esse comando em sí mesmo!"
|
||||
upload-log: "%prefix% &fRegistro enviado para: %url%"
|
||||
upload-log-start: "%prefix% &fEnviando o registro. Aguarde."
|
||||
upload-log-not-found: "%prefix% &cNúmero do registro não encontrado."
|
||||
upload-log-upload-failure: "%prefix% &cAlgo deu errado ao enviar o registro, veja o terminal para mais informações."
|
||||
|
||||
# Placeholders válidos:
|
||||
# %prefix%
|
||||
# %player%
|
||||
# %check_name%
|
||||
# %description%
|
||||
# %experimental%
|
||||
# %vl% - violações
|
||||
# %verbose% - Informação extra da verificação, como os desvios, nem todas as verifiações terão essa informação.
|
||||
# %verbose% - Informação extra da verificação, como os desalinhamentos, nem todas as verifiações terão essa informação.
|
||||
alerts-format: "%prefix% &f%player% &bfalhou em &f%check_name%%experimental% &f(x&c%vl%&f) &7%verbose%"
|
||||
alerts-format-proxy: "%prefix% &f[&cproxy&f] &f%player% &bfalhou em &f%check_name%%experimental% &f(x&c%vl%&f) &7%verbose%"
|
||||
experimental-symbol: "*"
|
||||
|
||||
profile:
|
||||
- "&7======================"
|
||||
- "%prefix% &bPerfil de &f%player%"
|
||||
@@ -41,13 +38,13 @@ profile:
|
||||
- "&7======================"
|
||||
help:
|
||||
- "&7======================"
|
||||
- "/grim alerts &f- &7Alterna entre &aon&f/&coff &7as notificações."
|
||||
- "/grim alerts &f- &7Alterna noificações."
|
||||
- "/grim profile <player> &f- &7Mosta as informações do jogador."
|
||||
- "/grim help &f- &7Mostra essa mensagem de ajuda."
|
||||
- "/grim debug <player> &f- &7Modo de depuração do plugin."
|
||||
- "/grim perf &f- &7Informações de performance do plugin."
|
||||
- "/grim reload &f- &7Recarregar configurações do AntiCheat."
|
||||
- "/grim spectate <player> &f- &7Espectar um jogador."
|
||||
- "/grim verbose &f- &7Mostra todos os flags para você sem os buffers."
|
||||
- "/grim log [0-255] &f- &7Envie um log para visualização externa."
|
||||
- "/grim debug <player> &f- &7Depura a simulação."
|
||||
- "/grim perf &f- &7Depura a performance."
|
||||
- "/grim reload &f- &7Recarrega as configurações."
|
||||
- "/grim spectate <player> &f- &7Especta um jogador."
|
||||
- "/grim verbose &f- &7Esconde as informações extra."
|
||||
- "/grim log [0-255] &f- &7Envia o registro da simulação."
|
||||
- "&7======================"
|
||||
@@ -0,0 +1,56 @@
|
||||
# Hex kodlarını #FFFFFF veya #ffffff formatında kullanabilirsiniz :)
|
||||
|
||||
# \u00BB eşittir » (çift >>), ANSI ve UTF-8 bunu farklı yorumlar. bu nedenle ? bile görebilirsiniz
|
||||
prefix: "&bGrim &8\u00BB"
|
||||
|
||||
alerts-enabled: "%prefix% &fUyarılar aktif edildi."
|
||||
alerts-disabled: "%prefix% &fUyarılar deaktif edildi."
|
||||
client-brand-format: "%prefix% &f%player% adlı oyuncu %brand% kullanarak giriş yaptı."
|
||||
console-specify-target: "%prefix% &cKonsol olarak bir hedef belirtmelisiniz!"
|
||||
player-not-found: "%prefix% &cOyuncu bulunamadı veya aktif değil!"
|
||||
player-not-this-server: "%prefix% &cBu oyuncu sunucuda değil!"
|
||||
spectate-return: "\n%prefix% &fBir önceki konuma dönmek için buraya tıklayın.\n"
|
||||
cannot-spectate-return: "%prefix% &cBunu yalnızca bir oyuncuyu izledikten sonra yapabilirsiniz."
|
||||
cannot-run-on-self: "%prefix% &cBu komutu kendi üzerinizde kullanamazsınız!"
|
||||
upload-log: "%prefix% &fDebug şu adrese yüklendi: %url%"
|
||||
upload-log-start: "%prefix% &fLog yükleniyor... lütfen bekleyin."
|
||||
upload-log-not-found: "%prefix% &cLog bulunamadı."
|
||||
upload-log-upload-failure: "%prefix% &cLog yüklenirken bir problem oluştu, lütfen konsolu kontrol edin."
|
||||
|
||||
# Geçerli placeholderlar:
|
||||
# %prefix%
|
||||
# %player%
|
||||
# %check_name%
|
||||
# %description%
|
||||
# %experimental%
|
||||
# %vl% - ihlal uyarıları
|
||||
# %verbose% - detaylı olarak verilen tüm uyarılar, checkler tüm bilgileri vermez
|
||||
alerts-format: "%prefix% &b%player% &fadlı oyuncuda &f(x&c%vl%&f) &fadet &b%check_name%%experimental% &ftespit edildi: &7%verbose%"
|
||||
alerts-format-proxy: "%prefix% &f[&cproxy&f] &b%player% &fadlı oyuncuda &f(x&c%vl%&f) &fadet &b%check_name%%experimental% &ftespit edildi: &7%verbose%"
|
||||
experimental-symbol: "*"
|
||||
|
||||
profile:
|
||||
- "&7======================"
|
||||
- "%prefix% &f%player% &badlı oyuncunun profili:"
|
||||
- "&bGecikme: &f%ping%"
|
||||
- "&bVersiyon: &f%version%"
|
||||
- "&bKullanılan Client: &f%brand%"
|
||||
- "&bDikey Hassasiyet: &f%h_sensitivity%%"
|
||||
- "&bYatay Hassasiyet: &f%v_sensitivity%%"
|
||||
- "&bFastMath Ayarı: &f%fast_math%"
|
||||
- "&7======================"
|
||||
help:
|
||||
- "&7======================"
|
||||
- "/grim alerts &f- &7Uyarıları aktif/deaktif eder"
|
||||
- "/grim profile (oyuncu) &f- &7Oyuncu profilini gösterir"
|
||||
- "/grim help &f- &7Bu yardım mesajını gösterir"
|
||||
- "/grim debug <player> &f- &7Geliştirici Debug'ını verir"
|
||||
- "/grim perf &f- &7Geliştirici Performansını verir"
|
||||
- "/grim reload &f- &7Configi yeniden yükler"
|
||||
- "/grim spectate (oyuncu) &f- &7Bir oyuncuyu izlemenizi sağlar"
|
||||
- "/grim verbose &f- &7Arabelleğe almadan tüm uyarıları görmenizi sağlar"
|
||||
- "/grim log (0-255) &f- &7Uyarılar için bir debug logu çıktısı verir"
|
||||
- "&7======================"
|
||||
|
||||
# Translated by Kayera
|
||||
# Have a nice day ;)
|
||||
@@ -17,12 +17,12 @@ upload-log-start: "%prefix% &f上传中...请等待"
|
||||
upload-log-not-found: "%prefix% &c找不到该日志."
|
||||
upload-log-upload-failure: "%prefix% &c上载此日志时出错, 有关详细信息, 请参阅控制台"
|
||||
|
||||
# Valid placeholders:
|
||||
# 变量:
|
||||
# %prefix% - 前缀
|
||||
# %player% - 玩家
|
||||
# %check_name% - 检查名字
|
||||
# %description%
|
||||
# %experimental%
|
||||
# %description% - 检查的介绍
|
||||
# %experimental% - 检查是否是实验性
|
||||
# %vl% - VL值
|
||||
# %verbose% - 检查中的额外信息,例如偏移量,并非所有检查都会添加信息
|
||||
alerts-format: "%prefix% &f%player% &b触发了 &f%check_name%%experimental% &f(x&c%vl%&f) &7%verbose%"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# %check_name% - nome da verificação
|
||||
# %description% - description of the check
|
||||
# %description% - descrição da verificação
|
||||
# %vl% - violações
|
||||
# %verbose% - informação extra
|
||||
# %player% - nome do jogador
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# %check_name% - Kontrolün ismi
|
||||
# %description% - Kontrolün açıklaması
|
||||
# %vl% - Yapılan ihlaller
|
||||
# %verbose% - Ekstra bilgilendirme
|
||||
# %player% - Oyuncu ismi
|
||||
# [alert] - Uyarılar için bunu kullanın
|
||||
# [webhook] - Discord webhook için bunu kullanın
|
||||
# [proxy] - Proxy'nize bağlı diğer sunuculara uyarı göndermek için bunu kullanın (BungeeCord/Velocity)
|
||||
Punishments:
|
||||
Simulation:
|
||||
# Kaç saniye sonra ihlaller kaldırılsın?
|
||||
remove-violations-after: 300
|
||||
# Bu bölüm, aşağıdaki adlara sahip tüm kontrollerle eşleşecektir,
|
||||
# Aksi takdirde eşleşecek bir denetimi hariç tutmak için, isminin önüne ünlem işareti koyun
|
||||
# Örnek olarak, !BadPacketsN
|
||||
checks:
|
||||
- "Simulation"
|
||||
- "GroundSpoof"
|
||||
- "Timer"
|
||||
- "NoFall"
|
||||
# Eşik:Aralık Komutu
|
||||
#
|
||||
# Örnek: 100 ihlalde "yanlış hareket!" mesajıyla oyuncuyu atmak için, aralık komutu olmadan:
|
||||
# - "100:0 kick %player% Yanlış hareket!"
|
||||
# 0, tam olarak bir kez çalıştırılmasını ifade eder
|
||||
# - "100:50 say %player% Hile yapıyor!"
|
||||
# Kullanıcı 100 işaretine ulaştığında çalışır ve bundan sonra, 100'ün üzerindeki her 50. işarette çalışır
|
||||
commands:
|
||||
- "100:40 [alert]"
|
||||
- "100:100 [webhook]"
|
||||
- "100:100 [proxy]"
|
||||
Knockback:
|
||||
remove-violations-after: 300
|
||||
checks:
|
||||
- "Knockback"
|
||||
- "Explosion"
|
||||
commands:
|
||||
- "5:5 [alert]"
|
||||
- "20:20 [webhook]"
|
||||
- "20:20 [proxy]"
|
||||
Post:
|
||||
remove-violations-after: 300
|
||||
checks:
|
||||
- "Post"
|
||||
commands:
|
||||
- "20:20 [alert]"
|
||||
- "40:40 [webhook]"
|
||||
- "40:40 [proxy]"
|
||||
BadPackets:
|
||||
remove-violations-after: 300
|
||||
checks:
|
||||
- "BadPackets"
|
||||
- "Crash"
|
||||
commands:
|
||||
- "20:20 [alert]"
|
||||
- "40:40 [webhook]"
|
||||
- "40:40 [proxy]"
|
||||
Reach:
|
||||
remove-violations-after: 300
|
||||
checks:
|
||||
- "Reach"
|
||||
commands:
|
||||
- "5:5 [alert]"
|
||||
- "5:5 [webhook]"
|
||||
- "5:5 [proxy]"
|
||||
Misc:
|
||||
remove-violations-after: 300
|
||||
checks:
|
||||
- "EntityControl"
|
||||
- "NoSlow"
|
||||
- "Place"
|
||||
- "Baritone"
|
||||
- "FastBreak"
|
||||
- "TransactionOrder"
|
||||
commands:
|
||||
- "10:5 [alert]"
|
||||
- "20:10 [webhook]"
|
||||
- "20:10 [proxy]"
|
||||
Combat:
|
||||
remove-violations-after: 300
|
||||
checks:
|
||||
- "Killaura"
|
||||
- "Aim"
|
||||
commands:
|
||||
- "20:40 [alert]"
|
||||
# 2.2.10 itibarıyla, AutoClicker denetimleri yoktur ve bu bir yer tutucudur. Grim, gelecekte AutoClicker denetimlerini dahil edecektir.
|
||||
Autoclicker:
|
||||
remove-violations-after: 300
|
||||
checks:
|
||||
- "Autoclicker"
|
||||
commands:
|
||||
- "20:40 [alert]"
|
||||
@@ -1,31 +1,31 @@
|
||||
# %check_name% - 检查名称
|
||||
# %description% - description of the check
|
||||
# %description% - 检查的介绍
|
||||
# %vl% - 违规
|
||||
# %verbose% - 额外信息
|
||||
# %player% - 玩家名字
|
||||
# [alert] - 警告的特殊命令
|
||||
# [webhook] - 警告discord webhook 的特殊命令
|
||||
# [proxy] - special command to alert to other servers connected to your proxy (BungeeCord/Velocity)
|
||||
# [proxy] - 用于使用(BungeeCord/Velocity)服务器时的警报
|
||||
Punishments:
|
||||
Simulation:
|
||||
# 多少秒后重置VL
|
||||
remove-violations-after: 300
|
||||
# This section will match all checks with the name,
|
||||
# To exclude a check that would otherwise be matched, put an exclamation mark in front of the name
|
||||
# For example, !BadPacketsN
|
||||
# 这个部分将会匹配检查的名字
|
||||
# 要关闭掉一个检查就在检查前面加感叹号
|
||||
# 例如, !BadPacketsN
|
||||
checks:
|
||||
- "Simulation"
|
||||
- "GroundSpoof"
|
||||
- "Timer"
|
||||
- "NoFall"
|
||||
# Threshold:Interval Command
|
||||
# 最大vl:下一次执行需要的vl
|
||||
#
|
||||
# 这是个例子, 当到达100VL时为了以 "incorrect movement!" 为理由踢出玩家
|
||||
# commands:
|
||||
# - "100:0 kick %player% incorrect movement!"
|
||||
# 0 means execute exactly once
|
||||
# 后面的数如果使用0就代表只执行一次
|
||||
# - "100:50 say %player% is cheating"
|
||||
# Execute when the user hits flag 100, and after that, every 50th flag after 100
|
||||
# 在100vl后执行say %player% is cheating,之后的每50vl都执行一次say %player% is cheating
|
||||
#
|
||||
commands:
|
||||
- "100:40 [alert]"
|
||||
|
||||
Reference in new issue
Block a user