Only resend attribute modifiers when necessary

Fixes #3973
This commit is contained in:
Nassim Jahnke 2024-08-07 11:59:13 +02:00
parent 5349de91c5
commit 02442a9775
No known key found for this signature in database
GPG Key ID: EF6771C01F6EF02F
2 changed files with 32 additions and 18 deletions

View File

@ -124,6 +124,9 @@ public final class EntityPacketRewriter1_21 extends EntityRewriter<ClientboundPa
final int dimensionId = wrapper.passthrough(Types.VAR_INT); final int dimensionId = wrapper.passthrough(Types.VAR_INT);
final String world = wrapper.passthrough(Types.STRING); final String world = wrapper.passthrough(Types.STRING);
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); // Tracks world height and name for chunk data and entity (un)tracking trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); // Tracks world height and name for chunk data and entity (un)tracking
// Resend attribute modifiers from items
wrapper.user().get(EfficiencyAttributeStorage.class).onRespawn(wrapper.user());
}); });
} }

View File

@ -24,6 +24,7 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21; import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21; import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
public final class EfficiencyAttributeStorage implements StorableObject { public final class EfficiencyAttributeStorage implements StorableObject {
@ -33,11 +34,11 @@ public final class EfficiencyAttributeStorage implements StorableObject {
private static final EnchantAttributeModifier AQUA_AFFINITY = new EnchantAttributeModifier("minecraft:enchantment.aqua_affinity", 28, 0.2, level -> level * 4, (byte) 2); private static final EnchantAttributeModifier AQUA_AFFINITY = new EnchantAttributeModifier("minecraft:enchantment.aqua_affinity", 28, 0.2, level -> level * 4, (byte) 2);
private static final EnchantAttributeModifier DEPTH_STRIDER = new EnchantAttributeModifier("minecraft:enchantment.depth_strider", 30, 0, level -> level / 3D); private static final EnchantAttributeModifier DEPTH_STRIDER = new EnchantAttributeModifier("minecraft:enchantment.depth_strider", 30, 0, level -> level / 3D);
private static final ActiveEnchants DEFAULT = new ActiveEnchants(-1, private static final ActiveEnchants DEFAULT = new ActiveEnchants(-1,
new ActiveEnchant(EFFICIENCY, 0), new ActiveEnchant(EFFICIENCY, 0, 0),
new ActiveEnchant(SOUL_SPEED, 0), new ActiveEnchant(SOUL_SPEED, 0, 0),
new ActiveEnchant(SWIFT_SNEAK, 0), new ActiveEnchant(SWIFT_SNEAK, 0, 0),
new ActiveEnchant(AQUA_AFFINITY, 0), new ActiveEnchant(AQUA_AFFINITY, 0, 0),
new ActiveEnchant(DEPTH_STRIDER, 0) new ActiveEnchant(DEPTH_STRIDER, 0, 0)
); );
private final Object lock = new Object(); private final Object lock = new Object();
private volatile boolean attributesSent = true; private volatile boolean attributesSent = true;
@ -57,15 +58,15 @@ public final class EfficiencyAttributeStorage implements StorableObject {
synchronized (lock) { synchronized (lock) {
this.activeEnchants = new ActiveEnchants(entityId, this.activeEnchants = new ActiveEnchants(entityId,
new ActiveEnchant(EFFICIENCY, efficiency), new ActiveEnchant(activeEnchants.efficiency, efficiency),
new ActiveEnchant(SOUL_SPEED, soulSpeed), new ActiveEnchant(activeEnchants.soulSpeed, soulSpeed),
new ActiveEnchant(SWIFT_SNEAK, swiftSneak), new ActiveEnchant(activeEnchants.swiftSneak, swiftSneak),
new ActiveEnchant(AQUA_AFFINITY, aquaAffinity), new ActiveEnchant(activeEnchants.aquaAffinity, aquaAffinity),
new ActiveEnchant(DEPTH_STRIDER, depthStrider) new ActiveEnchant(activeEnchants.depthStrider, depthStrider)
); );
this.attributesSent = false; this.attributesSent = false;
} }
sendAttributesPacket(connection); sendAttributesPacket(connection, false);
} }
public ActiveEnchants activeEnchants() { public ActiveEnchants activeEnchants() {
@ -75,14 +76,18 @@ public final class EfficiencyAttributeStorage implements StorableObject {
public void onLoginSent(final UserConnection connection) { public void onLoginSent(final UserConnection connection) {
// Always called from the netty thread // Always called from the netty thread
this.loginSent = true; this.loginSent = true;
sendAttributesPacket(connection); sendAttributesPacket(connection, false);
} }
private void sendAttributesPacket(final UserConnection connection) { public void onRespawn(final UserConnection connection) {
sendAttributesPacket(connection, true);
}
private void sendAttributesPacket(final UserConnection connection, final boolean forceSendAll) {
final ActiveEnchants enchants; final ActiveEnchants enchants;
synchronized (lock) { synchronized (lock) {
// Older servers (and often Bungee) will send world state packets before sending the login packet // Older servers (and often Bungee) will send world state packets before sending the login packet
if (!loginSent || attributesSent) { if (!forceSendAll && (!loginSent || attributesSent)) {
return; return;
} }
@ -93,13 +98,15 @@ public final class EfficiencyAttributeStorage implements StorableObject {
final PacketWrapper attributesPacket = PacketWrapper.create(ClientboundPackets1_21.UPDATE_ATTRIBUTES, connection); final PacketWrapper attributesPacket = PacketWrapper.create(ClientboundPackets1_21.UPDATE_ATTRIBUTES, connection);
attributesPacket.write(Types.VAR_INT, enchants.entityId()); attributesPacket.write(Types.VAR_INT, enchants.entityId());
final List<ActiveEnchant> list = List.of( // Make sure to update this list with new enchantments
// Only send the attribute if it actually changed
final List<ActiveEnchant> list = Stream.of(
enchants.efficiency(), enchants.efficiency(),
enchants.soulSpeed(), enchants.soulSpeed(),
enchants.swiftSneak(), enchants.swiftSneak(),
enchants.aquaAffinity(), enchants.aquaAffinity(),
enchants.depthStrider() enchants.depthStrider()
); ).filter(enchant -> forceSendAll || enchant.previousLevel != enchant.level).toList();
attributesPacket.write(Types.VAR_INT, list.size()); attributesPacket.write(Types.VAR_INT, list.size());
for (final ActiveEnchant enchant : list) { for (final ActiveEnchant enchant : list) {
final EnchantAttributeModifier modifier = enchant.modifier; final EnchantAttributeModifier modifier = enchant.modifier;
@ -123,7 +130,11 @@ public final class EfficiencyAttributeStorage implements StorableObject {
ActiveEnchant swiftSneak, ActiveEnchant aquaAffinity, ActiveEnchant depthStrider) { ActiveEnchant swiftSneak, ActiveEnchant aquaAffinity, ActiveEnchant depthStrider) {
} }
public record ActiveEnchant(EnchantAttributeModifier modifier, int level) { public record ActiveEnchant(EnchantAttributeModifier modifier, int previousLevel, int level) {
public ActiveEnchant(final ActiveEnchant from, final int level) {
this(from.modifier, from.level, level);
}
} }
public record EnchantAttributeModifier(String key, int attributeId, double baseValue, LevelToModifier modifierFunction, byte operation) { public record EnchantAttributeModifier(String key, int attributeId, double baseValue, LevelToModifier modifierFunction, byte operation) {