Skip to content

Commit ca60470

Browse files
committed
Version 1.3: add an option to force disable slowdown on clients
1 parent 049fe17 commit ca60470

File tree

10 files changed

+113
-17
lines changed

10 files changed

+113
-17
lines changed

.idea/checkstyle-idea.xml

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,16 @@ Due to the sprint state being stored in a bitmask the plugin can't always cancel
2424

2525
Doing this fix should make hit slowdown **less latency** dependant.
2626

27-
**Warning:** This plugin will make hit slowdown happen completely different to most servers (To compare: minemen.club has fixed this issue partly by not doing setSprinting(false) internally, it still has the other issue, of when the client sends START_SPRINTING / STOP_SPRINTING)
27+
**Warning:** This plugin will make hit slowdown happen completely different to most servers
2828

2929
## Attribute
30-
Since version 1.1 BetterSlowdown also cancels "useless" attribute packets which apply / remove the sprint modifier, this is handled client side and the server should not try to override this.
30+
BetterSlowdown also cancels "useless" attribute packets which apply / remove the sprint modifier, this is handled client side and the server should not try to override this.
31+
32+
## No slowdown
33+
You can also use the plugin to disable hit slowdown by spamming metadata sprinting packets to the client. (Note if a client lag spikes its possible they miss the packet and still have slowdown hits)
34+
35+
**Warning:** this breaks dynamic fov when you toggle your sprint
3136

3237
## Dependencies
3338

34-
This plugin uses, and depends on [PacketEvents](https://github.com/retrooper/packetevents)
39+
This plugin uses, and depends on [PacketEvents](https://github.com/retrooper/packetevents)

build.gradle.kts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins {
33
}
44

55
group = "me.beanes"
6-
version = "1.2"
6+
version = "1.3"
77

88

99
repositories {
@@ -20,13 +20,17 @@ repositories {
2020
name = "sonatype"
2121
url = uri("https://oss.sonatype.org/content/groups/public/")
2222
}
23+
maven {
24+
url = uri("https://maven.elmakers.com/repository")
25+
}
2326
}
2427

2528
dependencies {
2629
compileOnly("org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT")
27-
compileOnly("com.github.retrooper:packetevents-spigot:2.7.0")
30+
compileOnly("com.github.retrooper:packetevents-spigot:2.11.2")
31+
compileOnly("io.netty:netty-all:4.1.72.Final")
2832
}
2933

3034
tasks.test {
3135
useJUnitPlatform()
32-
}
36+
}

src/main/java/me/beanes/betterslowdown/BetterSlowdown.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
import com.github.retrooper.packetevents.PacketEvents;
44
import com.github.retrooper.packetevents.event.PacketListenerCommon;
55
import com.github.retrooper.packetevents.event.PacketListenerPriority;
6-
import me.beanes.betterslowdown.listener.FilterListener;
6+
import me.beanes.betterslowdown.listener.PacketListener;
77
import org.bukkit.plugin.java.JavaPlugin;
88

99
public class BetterSlowdown extends JavaPlugin {
1010
private FallbackMode mode = FallbackMode.SPRINT;
1111
private boolean alwaysAddSprint = false;
12+
private int forceSlowdown = -1;
1213
private PacketListenerCommon listener;
1314

1415
public FallbackMode getMode() {
@@ -19,9 +20,13 @@ public boolean isAlwaysAddSprint() {
1920
return alwaysAddSprint;
2021
}
2122

23+
public int getForceSlowdown() {
24+
return forceSlowdown;
25+
}
26+
2227
@Override
2328
public void onLoad() {
24-
listener = PacketEvents.getAPI().getEventManager().registerListener(new FilterListener(this), PacketListenerPriority.LOWEST);
29+
listener = PacketEvents.getAPI().getEventManager().registerListener(new PacketListener(this), PacketListenerPriority.LOWEST);
2530
}
2631

2732
@Override
@@ -31,6 +36,7 @@ public void onEnable() {
3136
try {
3237
mode = FallbackMode.valueOf(getConfig().getString("mode").toUpperCase());
3338
alwaysAddSprint = getConfig().getBoolean("always-add-sprint");
39+
forceSlowdown = getConfig().getInt("force-slowdown", -1);
3440
} catch (Exception ex) {
3541
mode = FallbackMode.SERVER;
3642
getLogger().info("Failed to load config due to error");

src/main/java/me/beanes/betterslowdown/data/PlayerData.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package me.beanes.betterslowdown.data;
22

3+
import com.github.retrooper.packetevents.protocol.player.User;
4+
35
public class PlayerData {
6+
private final User user;
47
private byte lastUsefulBitmask;
58
private double lastSpeed;
69
private boolean clientSprintingState;
710

8-
public PlayerData() {
11+
public PlayerData(User user) {
12+
this.user = user;
913
this.reset();
1014
}
1115

@@ -15,6 +19,10 @@ public void reset() {
1519
this.clientSprintingState = false;
1620
}
1721

22+
public User getUser() {
23+
return user;
24+
}
25+
1826
public double getLastSpeed() {
1927
return lastSpeed;
2028
}

src/main/java/me/beanes/betterslowdown/data/PlayerDataManager.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ public PlayerData get(User user) {
2626
PlayerData data = cache.get(user);
2727

2828
if (data == null) {
29-
data = new PlayerData();
29+
data = new PlayerData(user);
3030
cache.put(user, data);
3131
}
3232

3333
return data;
3434
}
35+
36+
public Collection<PlayerData> getAll() {
37+
return cacheThreadLocal.get().values();
38+
}
3539
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package me.beanes.betterslowdown.listener;
2+
3+
import com.github.retrooper.packetevents.protocol.ConnectionState;
4+
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
5+
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
6+
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
7+
import io.netty.channel.EventLoop;
8+
import me.beanes.betterslowdown.data.PlayerData;
9+
import me.beanes.betterslowdown.data.PlayerDataManager;
10+
11+
import java.util.Collections;
12+
import java.util.HashSet;
13+
import java.util.List;
14+
import java.util.Set;
15+
import java.util.concurrent.TimeUnit;
16+
17+
public class ForceSlowdownUtil {
18+
private static Set<EventLoop> EVENTLOOP_DONE = new HashSet<>();
19+
20+
public static void repeatInEventLoop(PlayerDataManager manager, EventLoop eventLoop, int repeatTime) {
21+
if (EVENTLOOP_DONE.add(eventLoop)) {
22+
eventLoop.scheduleAtFixedRate(() -> {
23+
for (PlayerData data : manager.getAll()) {
24+
sendSlowdown(data);
25+
}
26+
}, 0, repeatTime, TimeUnit.MILLISECONDS);
27+
}
28+
}
29+
30+
private static void sendSlowdown(PlayerData data) {
31+
if (data.getUser().getName() != null && data.getUser().getConnectionState() == ConnectionState.PLAY) { // Bit of a hack :/
32+
List<EntityData<?>> forcedNoSprint = Collections.singletonList(new EntityData<>(0, EntityDataTypes.BYTE, (byte) data.getLastUsefulBitmask()));
33+
WrapperPlayServerEntityMetadata wrapper = new WrapperPlayServerEntityMetadata(data.getUser().getEntityId(), forcedNoSprint);
34+
data.getUser().sendPacketSilently(wrapper);
35+
}
36+
}
37+
}

src/main/java/me/beanes/betterslowdown/listener/FilterListener.java renamed to src/main/java/me/beanes/betterslowdown/listener/PacketListener.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
99
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
1010
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
11+
import io.netty.channel.Channel;
1112
import me.beanes.betterslowdown.BetterSlowdown;
1213
import me.beanes.betterslowdown.FallbackMode;
1314
import me.beanes.betterslowdown.data.PlayerData;
@@ -16,7 +17,7 @@
1617
import java.util.Iterator;
1718
import java.util.UUID;
1819

19-
public class FilterListener implements PacketListener {
20+
public class PacketListener implements com.github.retrooper.packetevents.event.PacketListener {
2021
private static final UUID SPRINT_MODIFIER_UUID = UUID.fromString("662A6B8D-DA3E-4C1C-8813-96EA6097278D");
2122
private static final WrapperPlayServerUpdateAttributes.PropertyModifier SPRINT_MODIFIER = new WrapperPlayServerUpdateAttributes.PropertyModifier(
2223
SPRINT_MODIFIER_UUID,
@@ -26,7 +27,7 @@ public class FilterListener implements PacketListener {
2627
private final BetterSlowdown plugin;
2728
private final PlayerDataManager manager;
2829

29-
public FilterListener(BetterSlowdown plugin) {
30+
public PacketListener(BetterSlowdown plugin) {
3031
this.plugin = plugin;
3132
this.manager = new PlayerDataManager();
3233
}
@@ -53,11 +54,10 @@ public void onPacketSend(PacketSendEvent event) {
5354
// Listen for metadata packets
5455
if (event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) {
5556
WrapperPlayServerEntityMetadata wrapper = new WrapperPlayServerEntityMetadata(event);
56-
User user = event.getUser();
5757

5858
// Only check metadata packets about the player itself
5959
if (wrapper.getEntityId() == event.getUser().getEntityId()) {
60-
Iterator<EntityData> iterator = wrapper.getEntityMetadata().iterator();
60+
Iterator<EntityData<?>> iterator = wrapper.getEntityMetadata().iterator();
6161

6262
while (iterator.hasNext()) {
6363
EntityData entityData = iterator.next();
@@ -155,11 +155,19 @@ public void onPacketSend(PacketSendEvent event) {
155155

156156
@Override
157157
public void onUserConnect(UserConnectEvent event) {
158-
manager.cache(event.getUser(), new PlayerData());
158+
User user = event.getUser();
159+
manager.cache(user, new PlayerData(user));
160+
161+
int repeatTimeNoSlowdown = plugin.getForceSlowdown();
162+
163+
if (repeatTimeNoSlowdown >= 1) {
164+
Channel channel = (Channel) user.getChannel();
165+
ForceSlowdownUtil.repeatInEventLoop(manager, channel.eventLoop(), repeatTimeNoSlowdown);
166+
}
159167
}
160168

161169
@Override
162170
public void onUserDisconnect(UserDisconnectEvent event) {
163171
manager.remove(event.getUser());
164172
}
165-
}
173+
}

src/main/resources/config.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,11 @@ mode: CLIENT
2121
# This is useful for HCF servers when you get speed 3 / speed 2, and your sprint suddenly disappears
2222
# Worst case scenario, this can cause OmniSprint due to using client state
2323
always-add-sprint: false
24+
25+
# Force no slowdown
26+
# This features allows you to completely disable hit slowdown by spamming packets to the client
27+
# The setting allows you to configure how often this "force no slowdown" packet should be sent
28+
# You want this packet to arrive each client so in ideal circumstances with no lag spikes a 50 ms delay between packet send is perfect (put 50 in the option below)
29+
# WARNING: this option breaks dynamic fov for sprinting, players their fov will not update properly anymore while this is enabled
30+
# Use -1 to disable this feature
31+
force-slowdown: -1

src/main/resources/plugin.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: BetterSlowdown
2-
version: 1.1
2+
version: 1.3
33
main: me.beanes.betterslowdown.BetterSlowdown
44
author: Beanes
55
description: Fixes server/network issues related to hit slowdown

0 commit comments

Comments
 (0)