Send mining efficiency attribute on item switch

For some reason, mining efficiency is not calculated by the client anymore, but by the server, then sending the current value to the client every time the item changes. This roughly emulates that behavior (without tracking any inventory state beyond events).
This commit is contained in:
Nassim Jahnke 2024-06-13 18:21:55 +02:00
parent 67a349d74b
commit 877053c471
No known key found for this signature in database
GPG Key ID: EF6771C01F6EF02F
2 changed files with 96 additions and 0 deletions

View File

@ -0,0 +1,92 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21;
import com.viaversion.viaversion.ViaVersionPlugin;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
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 io.papermc.paper.event.player.PlayerInventorySlotChangeEvent;
import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.inventory.ItemStack;
/**
* For some reason, mining efficiency is not calculated by the client anymore, but by the server,
* then sending the current value to the client every time the item changes. This roughly emulates that behavior.
*/
public final class PlayerChangeItemListener extends ViaBukkitListener {
private static final int MINING_EFFICIENCY_ID = 19;
private final Enchantment efficiency = Enchantment.getByKey(NamespacedKey.minecraft("efficiency"));
public PlayerChangeItemListener(final ViaVersionPlugin plugin) {
super(plugin, Protocol1_20_5To1_21.class);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerInventorySlotChangedEvent(final PlayerInventorySlotChangeEvent event) {
final Player player = event.getPlayer();
final ItemStack item = event.getNewItemStack();
if (event.getSlot() == player.getInventory().getHeldItemSlot()) {
sendAttributeUpdate(player, item);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerItemHeld(final PlayerItemHeldEvent event) {
final Player player = event.getPlayer();
final ItemStack item = player.getInventory().getItem(event.getNewSlot());
sendAttributeUpdate(player, item != null ? item : ItemStack.empty());
}
private void sendAttributeUpdate(final Player player, final ItemStack item) {
final UserConnection connection = Via.getAPI().getConnection(player.getUniqueId());
if (connection == null || !isOnPipe(player)) {
return;
}
final int efficiencyLevel = item.getEnchantmentLevel(efficiency);
final PacketWrapper attributesPacket = PacketWrapper.create(ClientboundPackets1_21.UPDATE_ATTRIBUTES, connection);
attributesPacket.write(Types.VAR_INT, player.getEntityId());
attributesPacket.write(Types.VAR_INT, 1); // Size
attributesPacket.write(Types.VAR_INT, MINING_EFFICIENCY_ID); // Attribute ID
attributesPacket.write(Types.DOUBLE, 0D); // Base
if (efficiencyLevel > 0) {
final double modifierAmount = (efficiencyLevel * efficiencyLevel) + 1D;
attributesPacket.write(Types.VAR_INT, 1); // Modifiers
attributesPacket.write(Types.STRING, "minecraft:enchantment.efficiency/mainhand"); // Id
attributesPacket.write(Types.DOUBLE, modifierAmount);
attributesPacket.write(Types.BYTE, (byte) 0); // 'Add' operation
} else {
attributesPacket.write(Types.VAR_INT, 0); // Modifiers
}
attributesPacket.scheduleSend(Protocol1_20_5To1_21.class);
}
}

View File

@ -33,6 +33,7 @@ import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.BlockListener
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.DeathListener; import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.DeathListener;
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.HandItemCache; import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.HandItemCache;
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.PaperPatch; import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.PaperPatch;
import com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21.PlayerChangeItemListener;
import com.viaversion.viaversion.bukkit.providers.BukkitAckSequenceProvider; import com.viaversion.viaversion.bukkit.providers.BukkitAckSequenceProvider;
import com.viaversion.viaversion.bukkit.providers.BukkitBlockConnectionProvider; import com.viaversion.viaversion.bukkit.providers.BukkitBlockConnectionProvider;
import com.viaversion.viaversion.bukkit.providers.BukkitInventoryQuickMoveProvider; import com.viaversion.viaversion.bukkit.providers.BukkitInventoryQuickMoveProvider;
@ -176,6 +177,9 @@ public class BukkitViaLoader implements ViaPlatformLoader {
Via.getManager().getProviders().use(AckSequenceProvider.class, new BukkitAckSequenceProvider(plugin)); Via.getManager().getProviders().use(AckSequenceProvider.class, new BukkitAckSequenceProvider(plugin));
new BlockBreakListener(plugin).register(); new BlockBreakListener(plugin).register();
} }
if (serverProtocolVersion.olderThan(ProtocolVersion.v1_21) && PaperViaInjector.hasClass("io.papermc.paper.event.player.PlayerInventorySlotChangeEvent")) {
new PlayerChangeItemListener(plugin).register();
}
} }
private boolean hasGetHandMethod() { private boolean hasGetHandMethod() {