11package me .beanes .betterslowdown .listener ;
22
3- import com .github .retrooper .packetevents .event .PacketListener ;
4- import com .github .retrooper .packetevents .event .PacketSendEvent ;
5- import com .github .retrooper .packetevents .event .UserDisconnectEvent ;
3+ import com .github .retrooper .packetevents .event .*;
4+ import com .github .retrooper .packetevents .protocol .attribute .Attributes ;
65import com .github .retrooper .packetevents .protocol .entity .data .EntityData ;
76import com .github .retrooper .packetevents .protocol .packettype .PacketType ;
87import com .github .retrooper .packetevents .protocol .player .User ;
8+ import com .github .retrooper .packetevents .wrapper .play .client .WrapperPlayClientEntityAction ;
99import com .github .retrooper .packetevents .wrapper .play .server .WrapperPlayServerEntityMetadata ;
1010import com .github .retrooper .packetevents .wrapper .play .server .WrapperPlayServerUpdateAttributes ;
1111import me .beanes .betterslowdown .BetterSlowdown ;
1212import me .beanes .betterslowdown .FallbackMode ;
13+ import me .beanes .betterslowdown .data .PlayerData ;
14+ import me .beanes .betterslowdown .data .PlayerDataManager ;
1315
14- import java .util .HashMap ;
1516import java .util .Iterator ;
16- import java .util .Map ;
1717import java .util .UUID ;
1818
1919public class FilterListener implements PacketListener {
2020 private static final UUID SPRINT_MODIFIER_UUID = UUID .fromString ("662A6B8D-DA3E-4C1C-8813-96EA6097278D" );
21- private static final WrapperPlayServerUpdateAttributes .PropertyModifier SPRINT_MODIFIER = new WrapperPlayServerUpdateAttributes .PropertyModifier (SPRINT_MODIFIER_UUID , 0.30000001192092896D , WrapperPlayServerUpdateAttributes .PropertyModifier .Operation .MULTIPLY_TOTAL );
21+ private static final WrapperPlayServerUpdateAttributes .PropertyModifier SPRINT_MODIFIER = new WrapperPlayServerUpdateAttributes .PropertyModifier (
22+ SPRINT_MODIFIER_UUID ,
23+ 0.30000001192092896D ,
24+ WrapperPlayServerUpdateAttributes .PropertyModifier .Operation .MULTIPLY_TOTAL
25+ );
2226 private final BetterSlowdown plugin ;
23- private final ThreadLocal <Map <User , Byte >> lastUsefulBitmaskThreadLocal ;
24- private final ThreadLocal <Map <User , Double >> lastSpeedThreadLocal ;
27+ private final PlayerDataManager manager ;
2528
2629 public FilterListener (BetterSlowdown plugin ) {
2730 this .plugin = plugin ;
28- this .lastUsefulBitmaskThreadLocal = ThreadLocal .withInitial (HashMap ::new );
29- this .lastSpeedThreadLocal = ThreadLocal .withInitial (HashMap ::new );
31+ this .manager = new PlayerDataManager ();
3032 }
3133
3234
35+ @ Override
36+ public void onPacketReceive (PacketReceiveEvent event ) {
37+ // We keep track of the current client sprinting metadata
38+ if (event .getPacketType () == PacketType .Play .Client .ENTITY_ACTION ) {
39+ WrapperPlayClientEntityAction wrapper = new WrapperPlayClientEntityAction (event );
40+
41+ PlayerData data = manager .get (event .getUser ());
42+
43+ if (wrapper .getAction () == WrapperPlayClientEntityAction .Action .START_SPRINTING ) {
44+ data .setClientSprintingState (true );
45+ } else if (wrapper .getAction () == WrapperPlayClientEntityAction .Action .STOP_SPRINTING ) {
46+ data .setClientSprintingState (false );
47+ }
48+ }
49+ }
50+
3351 @ Override
3452 public void onPacketSend (PacketSendEvent event ) {
3553 // Listen for metadata packets
@@ -42,26 +60,35 @@ public void onPacketSend(PacketSendEvent event) {
4260 Iterator <EntityData > iterator = wrapper .getEntityMetadata ().iterator ();
4361
4462 while (iterator .hasNext ()) {
45- EntityData data = iterator .next ();
63+ EntityData entityData = iterator .next ();
4664
4765 // Check if the entity metadata bitmask is in this packet
48- if (data .getIndex () == 0 ) {
49- byte bitmask = (byte ) data .getValue ();
66+ if (entityData .getIndex () == MetadataValues . BITMASK_INDEX ) {
67+ byte bitmask = (byte ) entityData .getValue ();
5068 // Calculate the useful bitmask
51- bitmask &= ~0x02 ; // Remove crouching
52- bitmask &= ~0x08 ; // Remove sprinting
53- bitmask &= ~0x10 ; // Remove using
69+ bitmask &= ~MetadataValues . FLAG_CROUCHING ; // Remove crouching
70+ bitmask &= ~MetadataValues . FLAG_SPRINTING ; // Remove sprinting
71+ bitmask &= ~MetadataValues . FLAG_USING ; // Remove using
5472
5573 // Check if the "useful" bitmask has changed, which means either the client is on fire or invisible
56- Map <User , Byte > lastUsefulBitmask = lastUsefulBitmaskThreadLocal .get ();
57- if (lastUsefulBitmask .getOrDefault (user , (byte ) 0 ) != bitmask ) {
58- lastUsefulBitmask .put (user , bitmask );
59-
60- if (plugin .getMode () != FallbackMode .SERVER ) {
61- if (plugin .getMode () == FallbackMode .SPRINT ) {
62- data .setValue ((byte ) ((byte ) data .getValue () | 0x08 )); // Rewrite with sprinting = true
63- } else if (plugin .getMode () == FallbackMode .NO_SPRINT ) {
64- data .setValue ((byte ) ((byte ) data .getValue () & ~0x08 )); // Rewrite with sprinting = false
74+ PlayerData data = manager .get (event .getUser ());
75+ byte lastUsefulBitmask = data .getLastUsefulBitmask ();
76+
77+ if (lastUsefulBitmask != bitmask ) {
78+ data .setLastUsefulBitmask (bitmask );
79+
80+ // Get the fallback mode as we are 100% sending the bitmask
81+ FallbackMode mode = plugin .getMode ();
82+
83+ if (mode != FallbackMode .SERVER ) {
84+ if (mode == FallbackMode .SPRINT
85+ || (mode == FallbackMode .CLIENT && data .isClientSprintingState ())) {
86+ // Rewrite with sprinting = true
87+ entityData .setValue ((byte ) ((byte ) entityData .getValue () | MetadataValues .FLAG_SPRINTING ));
88+ } else if (mode == FallbackMode .NO_SPRINT
89+ || (mode == FallbackMode .CLIENT && !data .isClientSprintingState ())) {
90+ // Rewrite with sprinting = false
91+ entityData .setValue ((byte ) ((byte ) entityData .getValue () & ~MetadataValues .FLAG_SPRINTING ));
6592 }
6693
6794 // Needs re-encode
@@ -87,7 +114,7 @@ public void onPacketSend(PacketSendEvent event) {
87114
88115 if (wrapper .getEntityId () == user .getEntityId ()) {
89116 for (WrapperPlayServerUpdateAttributes .Property snapshot : wrapper .getProperties ()) {
90- if (snapshot .getAttribute ().getName (). getKey (). equals ("movement_speed" )) {
117+ if (snapshot .getAttribute ().equals (Attributes . MOVEMENT_SPEED )) {
91118 // Calculate the movement speed without sprint
92119 boolean exists = snapshot .getModifiers ().removeIf (modifier -> modifier .getUUID ().equals (SPRINT_MODIFIER_UUID ));
93120 if (exists ) {
@@ -96,19 +123,21 @@ public void onPacketSend(PacketSendEvent event) {
96123
97124 double speed = snapshot .calcValue ();
98125
99- Map <User , Double > lastSpeed = lastSpeedThreadLocal .get ();
126+ PlayerData data = manager .get (user );
127+ double lastSpeed = data .getLastSpeed ();
100128
101- if (lastSpeed . getOrDefault ( user , - 1.0D ) == speed ) {
129+ if (lastSpeed == speed ) {
102130 // Cancel this attribute packet as it only changes the sprint attribute
103131 event .setCancelled (true );
104132 } else {
105133 // Update the speed
106- lastSpeed . put ( user , speed );
134+ data . setLastSpeed ( speed );
107135
108136 if (exists ) {
109- snapshot .addModifier (SPRINT_MODIFIER ); // Re-add the modifier if packetevents is on default re-encode
110- } else if (plugin .isAlwaysAddSprint ()) {
111- // TODO: check if the player is "allowed" to sprint, keep food value, and check START_SPRINTING and STOP_SPRINTING to prevent omnisprint?
137+ // Re-add the modifier if packetevents is on default re-encode
138+ snapshot .addModifier (SPRINT_MODIFIER );
139+ } else if (plugin .isAlwaysAddSprint () && data .isClientSprintingState ()) {
140+ // Add sprint modifier is the client claimed he was sprinting and always add sprint is enabled
112141 snapshot .addModifier (SPRINT_MODIFIER );
113142 event .markForReEncode (true );
114143 }
@@ -120,14 +149,17 @@ public void onPacketSend(PacketSendEvent event) {
120149 User user = event .getUser ();
121150
122151 // Reset last as the entity is recreated
123- this .lastUsefulBitmaskThreadLocal .get ().remove (user );
124- this .lastSpeedThreadLocal .get ().remove (user );
152+ manager .get (user ).reset ();
125153 }
126154 }
127155
156+ @ Override
157+ public void onUserConnect (UserConnectEvent event ) {
158+ manager .cache (event .getUser (), new PlayerData ());
159+ }
160+
128161 @ Override
129162 public void onUserDisconnect (UserDisconnectEvent event ) {
130- this .lastUsefulBitmaskThreadLocal .get ().remove (event .getUser ());
131- this .lastSpeedThreadLocal .get ().remove (event .getUser ());
163+ manager .remove (event .getUser ());
132164 }
133165}
0 commit comments