2525
2626package org .geysermc .geyser .translator .protocol .java .entity ;
2727
28+ import org .cloudburstmc .protocol .bedrock .data .AttributeData ;
2829import org .cloudburstmc .protocol .bedrock .packet .MobEffectPacket ;
2930import org .cloudburstmc .protocol .bedrock .packet .UpdateAttributesPacket ;
3031import org .geysermc .geyser .entity .attribute .GeyserAttributeType ;
3132import org .geysermc .geyser .entity .type .Entity ;
3233import org .geysermc .geyser .entity .vehicle .ClientVehicle ;
3334import org .geysermc .geyser .session .GeyserSession ;
35+ import org .geysermc .geyser .session .cache .EntityEffectCache ;
3436import org .geysermc .geyser .translator .protocol .PacketTranslator ;
3537import org .geysermc .geyser .translator .protocol .Translator ;
3638import org .geysermc .geyser .util .EntityUtils ;
37- import org .geysermc .mcprotocollib .protocol .data .game .entity .Effect ;
3839import org .geysermc .mcprotocollib .protocol .packet .ingame .clientbound .entity .ClientboundUpdateMobEffectPacket ;
3940
4041import java .util .Collections ;
@@ -49,33 +50,45 @@ public void translate(GeyserSession session, ClientboundUpdateMobEffectPacket pa
4950 return ;
5051 }
5152
53+ var event = MobEffectPacket .Event .ADD ;
54+
5255 if (entity == session .getPlayerEntity ()) {
53- session .getEffectCache ().setEffect (packet .getEffect (), packet .getAmplifier ());
56+ EntityEffectCache cache = session .getEffectCache ();
57+ cache .setEffect (packet .getEffect (), packet .getAmplifier ());
58+ // Matches BDS
59+ if (cache .getEntityEffects ().contains (packet .getEffect ())) {
60+ event = MobEffectPacket .Event .MODIFY ;
61+ }
5462 } else if (entity instanceof ClientVehicle clientVehicle ) {
5563 clientVehicle .getVehicleComponent ().setEffect (packet .getEffect (), packet .getAmplifier ());
5664 }
5765
5866 MobEffectPacket mobEffectPacket = new MobEffectPacket ();
5967 mobEffectPacket .setAmplifier (packet .getAmplifier ());
6068 mobEffectPacket .setDuration (packet .getDuration ());
61- mobEffectPacket .setEvent (MobEffectPacket . Event . ADD );
69+ mobEffectPacket .setEvent (event );
6270 mobEffectPacket .setRuntimeEntityId (entity .getGeyserId ());
6371 mobEffectPacket .setParticles (packet .isShowParticles ());
6472 mobEffectPacket .setEffectId (EntityUtils .toBedrockEffectId (packet .getEffect ()));
6573 session .sendUpstreamPacket (mobEffectPacket );
6674
67- // Fixes https://github.com/GeyserMC/Geyser/issues/5347 by re-sending the correct absorption hearts
68- if (entity == session .getPlayerEntity () && packet .getEffect () == Effect .ABSORPTION ) {
69- var absorptionAttribute = session .getPlayerEntity ().getAttributes ().get (GeyserAttributeType .ABSORPTION );
70- if (absorptionAttribute == null ) {
75+ // Bedrock expects some attributes to be updated in the same tick as the effect causing them
76+ if (entity == session .getPlayerEntity ()) {
77+ AttributeData attribute = switch (packet .getEffect ()) {
78+ // Fixes https://github.com/GeyserMC/Geyser/issues/5347
79+ case ABSORPTION -> session .getPlayerEntity ().getAttributes ().get (GeyserAttributeType .ABSORPTION );
80+ // Fixes https://github.com/GeyserMC/Geyser/issues/5388
81+ case SPEED -> session .getPlayerEntity ().getAttributes ().get (GeyserAttributeType .MOVEMENT_SPEED );
82+ default -> null ;
83+ };
84+
85+ if (attribute == null ) {
7186 return ;
7287 }
7388
7489 UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket ();
7590 attributesPacket .setRuntimeEntityId (entity .getGeyserId ());
76- // Setting to a higher maximum since plugins/datapacks can probably extend the Bedrock soft limit
77- attributesPacket .setAttributes (Collections .singletonList (
78- GeyserAttributeType .ABSORPTION .getAttribute (absorptionAttribute .getValue ())));
91+ attributesPacket .setAttributes (Collections .singletonList (attribute ));
7992 session .sendUpstreamPacket (attributesPacket );
8093 }
8194 }
0 commit comments