Skip to content

Commit e954124

Browse files
authored
check for keepsprint on 1.9 servers (#2070)
* check for keepsprint on 1.9 servers * update held item in AttackCooldownHandler every time the slot is changed * fix #2389 * change AttackCooldownHandler package
1 parent 598aae0 commit e954124

File tree

10 files changed

+101
-52
lines changed

10 files changed

+101
-52
lines changed

common/src/main/java/ac/grim/grimac/events/packets/PacketPlayerAttack.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.github.retrooper.packetevents.protocol.item.enchantment.type.EnchantmentTypes;
1717
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
1818
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
19+
import com.github.retrooper.packetevents.protocol.player.GameMode;
1920
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
2021

2122
public class PacketPlayerAttack extends PacketListenerAbstract {
@@ -65,7 +66,7 @@ public void onPacketReceive(PacketReceiveEvent event) {
6566

6667
final boolean isLegacyPlayer = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8);
6768
// assume cooldown is full on 1.8 servers
68-
final boolean noCooldown = isLegacyPlayer || PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9);
69+
final boolean sufficientCooldownProgress = isLegacyPlayer || player.attackCooldown.getMinimumProgress() > 0.9F;
6970

7071
if (!isLegacyPlayer) {
7172
knockbackLevel = Math.max(knockbackLevel, 0);
@@ -75,7 +76,7 @@ public void onPacketReceive(PacketReceiveEvent event) {
7576
// 1.9+ players who are packet sprinting might not, based on attack cooldown
7677
// Players with knockback enchantments always get slowed
7778

78-
if ((player.lastSprinting && !hasNegativeKB && noCooldown) || knockbackLevel > 0) {
79+
if (player.lastSprinting && !hasNegativeKB && sufficientCooldownProgress || knockbackLevel > 0) {
7980
player.minAttackSlow++;
8081
player.maxAttackSlow++;
8182

@@ -95,6 +96,10 @@ public void onPacketReceive(PacketReceiveEvent event) {
9596
player.maxAttackSlow++;
9697
}
9798
}
99+
100+
if (player.gamemode != GameMode.SPECTATOR) {
101+
player.attackCooldown.reset();
102+
}
98103
} else if (interact.getAction() == WrapperPlayClientInteractEntity.InteractAction.INTERACT) {
99104
// Interacting with a horse in versions 1.13- will cause the client to
100105
// set the player's rotation to the horse's rotation

common/src/main/java/ac/grim/grimac/manager/ActionManager.java

Lines changed: 0 additions & 38 deletions
This file was deleted.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package ac.grim.grimac.manager;
2+
3+
import ac.grim.grimac.checks.Check;
4+
import ac.grim.grimac.checks.type.PacketCheck;
5+
import ac.grim.grimac.player.GrimPlayer;
6+
import ac.grim.grimac.utils.math.GrimMath;
7+
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
8+
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
9+
import com.github.retrooper.packetevents.protocol.item.ItemStack;
10+
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
11+
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
12+
import com.github.retrooper.packetevents.protocol.world.BlockFace;
13+
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
14+
15+
public class AttackCooldownHandler extends Check implements PacketCheck {
16+
private int ticksSinceLastSwing;
17+
private ItemStack stack = ItemStack.EMPTY;
18+
// Since we don't know when the client ticks, we call updateHeldItem() when the held item changes,
19+
// but that means ticksSinceLastSwing is incremented after it gets reset. This is wrong, so we
20+
// compensate for that by not incrementing ticksSinceLastSwing if updateHeldItem() was called
21+
// (and the held item changed) before the tick packet.
22+
private boolean stackChanged;
23+
24+
public AttackCooldownHandler(GrimPlayer player) {
25+
super(player);
26+
}
27+
28+
@Override
29+
public void onPacketReceive(final PacketReceiveEvent event) {
30+
if (event.getPacketType() == PacketType.Play.Client.ANIMATION) {
31+
// FIXME: should only run when the click misses
32+
reset();
33+
}
34+
35+
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
36+
WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
37+
if (packet.getAction() == DiggingAction.CANCELLED_DIGGING && packet.getBlockFace() == BlockFace.DOWN) {
38+
// FIXME: this could also be triggered by switching targets while looking at the bottom face of a block
39+
reset();
40+
}
41+
}
42+
43+
if (isTickPacket(event.getPacketType())) {
44+
if (!stackChanged) {
45+
++ticksSinceLastSwing;
46+
}
47+
updateHeldItem();
48+
stackChanged = false;
49+
}
50+
}
51+
52+
public void reset() {
53+
ticksSinceLastSwing = 0;
54+
}
55+
56+
// called on client tick and whenever the slot gets updated
57+
public void updateHeldItem() {
58+
ItemStack held = player.inventory.getHeldItem().copy();
59+
60+
if (!(stack.isEmpty() && held.isEmpty() || stack.getType() == held.getType() && (stack.isDamageableItem() || stack.getLegacyData() == held.getLegacyData()))) {
61+
reset();
62+
stackChanged = true;
63+
}
64+
65+
stack = held;
66+
}
67+
68+
public float getMinimumProgress() {
69+
return GrimMath.clamp(((float) ticksSinceLastSwing + 0.5F) / (float) (1d / player.compensatedEntities.self.getAttributeValue(Attributes.ATTACK_SPEED) * 20.0D), 0, 1);
70+
}
71+
}

common/src/main/java/ac/grim/grimac/manager/CheckManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public CheckManager(GrimPlayer player) {
9999
.put(CompensatedInventory.class, player.inventory)
100100
.put(PacketPlayerAbilities.class, new PacketPlayerAbilities(player))
101101
.put(PacketWorldBorder.class, new PacketWorldBorder(player))
102-
.put(ActionManager.class, player.actionManager)
102+
.put(AttackCooldownHandler.class, player.attackCooldown)
103103
.put(TeamHandler.class, new TeamHandler(player))
104104
.put(ClientBrand.class, new ClientBrand(player))
105105
.put(NoFall.class, new NoFall(player))

common/src/main/java/ac/grim/grimac/player/GrimPlayer.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import ac.grim.grimac.predictionengine.MovementCheckRunner;
2121
import ac.grim.grimac.predictionengine.PointThreeEstimator;
2222
import ac.grim.grimac.predictionengine.UncertaintyHandler;
23+
import ac.grim.grimac.manager.AttackCooldownHandler;
2324
import ac.grim.grimac.utils.anticheat.LogUtil;
2425
import ac.grim.grimac.utils.anticheat.MessageUtil;
2526
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
@@ -113,7 +114,7 @@ public class GrimPlayer implements GrimUser {
113114
// End transaction handling stuff
114115
// Manager like classes
115116
public final CheckManager checkManager;
116-
public final ActionManager actionManager;
117+
public final AttackCooldownHandler attackCooldown;
117118
public final PunishmentManager punishmentManager;
118119
public final MovementCheckRunner movementCheckRunner;
119120
public final SyncedTags tagManager;
@@ -242,7 +243,6 @@ public class GrimPlayer implements GrimUser {
242243
public final Object2DoubleMap<FluidTag> fluidHeight = new Object2DoubleArrayMap<>(2);
243244
// possibleEyeHeights[0] = Standing eye heights, [1] = Sneaking. [2] = Elytra, Swimming, and Riptide Trident which only exists in 1.9+
244245
public final double[][] possibleEyeHeights = new double[3][];
245-
public int totalFlyingPacketsSent;
246246
public final Queue<BlockPlaceSnapshot> placeUseItemPackets = new LinkedBlockingQueue<>();
247247
public final Queue<BlockBreak> queuedBreaks = new LinkedBlockingQueue<>();
248248
public final PlayerBlockHistory blockHistory = new PlayerBlockHistory();
@@ -291,7 +291,7 @@ public GrimPlayer(@NotNull User user) {
291291
cameraEntity = new CompensatedCameraEntity(this);
292292

293293
lastInstanceManager = new LastInstanceManager(this);
294-
actionManager = new ActionManager(this);
294+
attackCooldown = new AttackCooldownHandler(this);
295295
checkManager = new CheckManager(this);
296296
punishmentManager = new PunishmentManager(this);
297297
this.tagManager = new SyncedTags(this); // must be after this.user = user

common/src/main/java/ac/grim/grimac/utils/data/packetentity/PacketEntitySelf.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ protected void initAttributes(GrimPlayer player) {
7070
trackAttribute(movementSpeed);
7171
trackAttribute(ValuedAttribute.ranged(Attributes.ATTACK_DAMAGE, 2, 0, 2048)); // NOTE: Not synced to client currently.
7272
trackAttribute(ValuedAttribute.ranged(Attributes.ATTACK_SPEED, 4, 0, 1024)
73-
.requiredVersion(player, ClientVersion.V_1_9));
73+
.requiredVersion(player, ClientVersion.V_1_9)
74+
.withGetRewriter(value -> PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9) ? 20 : value));
7475
trackAttribute(ValuedAttribute.ranged(Attributes.JUMP_STRENGTH, 0.42f, 0, 32)
7576
.requiredVersion(player, ClientVersion.V_1_20_5));
7677
trackAttribute(ValuedAttribute.ranged(Attributes.BLOCK_BREAK_SPEED, 1.0, 0, 1024)

common/src/main/java/ac/grim/grimac/utils/inventory/Inventory.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ public class Inventory extends AbstractContainerMenu {
2121
public static final int SLOT_LEGGINGS = 6;
2222
public static final int SLOT_BOOTS = 7;
2323
private static final int TOTAL_SIZE = 46;
24-
public int selected = 0;
24+
@Getter
25+
private int selected;
2526
@Getter
2627
private final CorrectingPlayerInventoryStorage inventoryStorage;
2728

@@ -68,7 +69,7 @@ public ItemStack getOffhand() {
6869
}
6970

7071
public boolean hasItemType(ItemType item) {
71-
for (int i = 0; i < inventoryStorage.items.length; ++i) {
72+
for (int i = 0; i < inventoryStorage.getSize(); ++i) {
7273
if (inventoryStorage.getItem(i).getType() == item) {
7374
return true;
7475
}
@@ -93,7 +94,7 @@ public boolean add(ItemStack p_36055_) {
9394
}
9495

9596
public int getFreeSlot() {
96-
for (int i = 0; i < inventoryStorage.items.length; ++i) {
97+
for (int i = 0; i < inventoryStorage.getSize(); ++i) {
9798
if (inventoryStorage.getItem(i).isEmpty()) {
9899
return i;
99100
}
@@ -252,4 +253,9 @@ public ItemStack quickMoveStack(int slotID) {
252253
public boolean canTakeItemForPickAll(ItemStack p_38908_, Slot p_38909_) {
253254
return p_38909_.inventoryStorageSlot != 0; // Result slot
254255
}
256+
257+
public void setSelected(int selected) {
258+
this.selected = selected;
259+
this.player.attackCooldown.updateHeldItem();
260+
}
255261
}

common/src/main/java/ac/grim/grimac/utils/inventory/InventoryStorage.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import lombok.Getter;
55

66
public class InventoryStorage {
7-
protected final ItemStack[] items;
7+
private final ItemStack[] items;
88
@Getter
99
private final int size;
1010

@@ -26,7 +26,7 @@ public ItemStack getItem(int index) {
2626
}
2727

2828
public ItemStack removeItem(int slot, int amount) {
29-
return slot >= 0 && slot < items.length && !items[slot].isEmpty() && amount > 0 ? items[slot].split(amount) : ItemStack.EMPTY;
29+
return slot >= 0 && slot < size && !items[slot].isEmpty() && amount > 0 ? items[slot].split(amount) : ItemStack.EMPTY;
3030
}
3131

3232
public int getMaxStackSize() {

common/src/main/java/ac/grim/grimac/utils/latency/CompensatedInventory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ public void onPacketReceive(final PacketReceiveEvent event) {
231231
return;
232232

233233
// 1.19.4+ clients support swapping with non-empty items
234-
int swapItemSlot = item.getHand() == InteractionHand.MAIN_HAND ? inventory.selected + Inventory.HOTBAR_OFFSET : Inventory.SLOT_OFFHAND;
234+
int swapItemSlot = item.getHand() == InteractionHand.MAIN_HAND ? inventory.getSelected() + Inventory.HOTBAR_OFFSET : Inventory.SLOT_OFFHAND;
235235

236236
// Mojang implemented this stupidly, I rewrote their item swap code to make it somewhat cleaner.
237237
// Slot in hotbar
@@ -270,7 +270,7 @@ public void onPacketReceive(final PacketReceiveEvent event) {
270270
// Stop people from spamming the server with an out-of-bounds exception
271271
if (slot > 8 || slot < 0) return;
272272

273-
inventory.selected = slot;
273+
inventory.setSelected(slot);
274274
} else if (event.getPacketType() == PacketType.Play.Client.CREATIVE_INVENTORY_ACTION) {
275275
WrapperPlayClientCreativeInventoryAction action = new WrapperPlayClientCreativeInventoryAction(event);
276276
if (player.gamemode != GameMode.CREATIVE) return;

common/src/main/java/ac/grim/grimac/utils/lists/CorrectingPlayerInventoryStorage.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ public void setItem(int item, ItemStack stack) {
8989
}
9090

9191
super.setItem(item, stack);
92+
93+
if (item == player.inventory.inventory.getSelected() + Inventory.HOTBAR_OFFSET) {
94+
player.attackCooldown.updateHeldItem();
95+
}
9296
}
9397

9498
/**

0 commit comments

Comments
 (0)