Mirror von
https://github.com/ViaVersion/ViaVersion.git
synchronisiert 2024-12-25 15:50:10 +01:00
Ursprung
c098e24c4f
Commit
77d702bc9b
@ -31,6 +31,7 @@ import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
@ -40,6 +41,9 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
public final class PlayerChangeItemListener extends ViaBukkitListener {
|
||||
|
||||
private final Enchantment efficiency = Enchantment.getByKey(NamespacedKey.minecraft("efficiency"));
|
||||
private final Enchantment depthStrider = Enchantment.getByKey(NamespacedKey.minecraft("depth_strider"));
|
||||
private final Enchantment soulSpeed = Enchantment.getByKey(NamespacedKey.minecraft("soul_speed"));
|
||||
private final Enchantment swiftSneak = Enchantment.getByKey(NamespacedKey.minecraft("swift_sneak"));
|
||||
|
||||
public PlayerChangeItemListener(final ViaVersionPlugin plugin) {
|
||||
super(plugin, Protocol1_20_5To1_21.class);
|
||||
@ -49,8 +53,14 @@ public final class PlayerChangeItemListener extends ViaBukkitListener {
|
||||
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);
|
||||
final PlayerInventory inventory = player.getInventory();
|
||||
final int slot = event.getSlot();
|
||||
if (slot == inventory.getHeldItemSlot()) {
|
||||
sendAttributeUpdate(player, item, Slot.HAND);
|
||||
} else if (slot == 36) {
|
||||
sendAttributeUpdate(player, item, Slot.BOOTS);
|
||||
} else if (slot == 37) {
|
||||
sendAttributeUpdate(player, item, Slot.LEGGINGS);
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,10 +68,10 @@ public final class PlayerChangeItemListener extends ViaBukkitListener {
|
||||
public void onPlayerItemHeld(final PlayerItemHeldEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final ItemStack item = player.getInventory().getItem(event.getNewSlot());
|
||||
sendAttributeUpdate(player, item);
|
||||
sendAttributeUpdate(player, item, Slot.HAND);
|
||||
}
|
||||
|
||||
private void sendAttributeUpdate(final Player player, @Nullable final ItemStack item) {
|
||||
private void sendAttributeUpdate(final Player player, @Nullable final ItemStack item, final Slot slot) {
|
||||
final UserConnection connection = Via.getAPI().getConnection(player.getUniqueId());
|
||||
if (connection == null || !isOnPipe(player)) {
|
||||
return;
|
||||
@ -72,7 +82,23 @@ public final class PlayerChangeItemListener extends ViaBukkitListener {
|
||||
return;
|
||||
}
|
||||
|
||||
final int efficiencyLevel = item != null ? item.getEnchantmentLevel(efficiency) : 0;
|
||||
storage.setEfficiencyLevel(new EfficiencyAttributeStorage.StoredEfficiency(player.getEntityId(), efficiencyLevel), connection);
|
||||
final EfficiencyAttributeStorage.ActiveEnchants activeEnchants = storage.activeEnchants();
|
||||
int efficiencyLevel = activeEnchants.efficiency().level();
|
||||
int soulSpeedLevel = activeEnchants.soulSpeed().level();
|
||||
int swiftSneakLevel = activeEnchants.swiftSneak().level();
|
||||
int depthStriderLevel = activeEnchants.depthStrider().level();
|
||||
switch (slot) {
|
||||
case HAND -> efficiencyLevel = item != null ? item.getEnchantmentLevel(efficiency) : 0;
|
||||
case LEGGINGS -> swiftSneakLevel = item != null && swiftSneak != null ? item.getEnchantmentLevel(swiftSneak) : 0;
|
||||
case BOOTS -> {
|
||||
depthStriderLevel = item != null && depthStrider != null ? item.getEnchantmentLevel(depthStrider) : 0;
|
||||
soulSpeedLevel = item != null && soulSpeed != null ? item.getEnchantmentLevel(soulSpeed) : 0;
|
||||
}
|
||||
}
|
||||
storage.setEnchants(player.getEntityId(), connection, efficiencyLevel, soulSpeedLevel, swiftSneakLevel, depthStriderLevel);
|
||||
}
|
||||
|
||||
private enum Slot {
|
||||
HAND, BOOTS, LEGGINGS
|
||||
}
|
||||
}
|
||||
|
@ -23,57 +23,115 @@ import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
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.packet.ClientboundPackets1_21;
|
||||
import java.util.List;
|
||||
|
||||
public final class EfficiencyAttributeStorage implements StorableObject {
|
||||
|
||||
private static final int MINING_EFFICIENCY_ID = 19;
|
||||
private final Object lock = new Object(); // Slightly sloppy locking, but should be good enough
|
||||
public static final EnchantAttributeModifier EFFICIENCY = new EnchantAttributeModifier("minecraft:enchantment.efficiency/mainhand", 19, 0, level -> (level * level) + 1);
|
||||
public static final EnchantAttributeModifier SOUL_SPEED = new EnchantAttributeModifier("minecraft:enchantment.soul_speed", 21, 0.1, level -> 0.04D + ((level - 1) * 0.01D));
|
||||
public static final EnchantAttributeModifier SWIFT_SNEAK = new EnchantAttributeModifier("minecraft:enchantment.swift_sneak", 25, 0.3, level -> level * 0.15D);
|
||||
public static final EnchantAttributeModifier DEPTH_STRIDER = new EnchantAttributeModifier("minecraft:enchantment.depth_strider", 30, 0, level -> level / 3D);
|
||||
private static final ActiveEnchants DEFAULT = new ActiveEnchants(-1,
|
||||
new ActiveEnchant(EFFICIENCY, 0),
|
||||
new ActiveEnchant(SOUL_SPEED, 0),
|
||||
new ActiveEnchant(SWIFT_SNEAK, 0),
|
||||
new ActiveEnchant(DEPTH_STRIDER, 0)
|
||||
);
|
||||
private final Object lock = new Object();
|
||||
private volatile ActiveEnchants activeEnchants = DEFAULT;
|
||||
private volatile boolean attributesSent = true;
|
||||
private volatile boolean loginSent;
|
||||
private volatile StoredEfficiency efficiencyLevel;
|
||||
|
||||
public void setEfficiencyLevel(final StoredEfficiency efficiencyLevel, final UserConnection connection) {
|
||||
this.efficiencyLevel = efficiencyLevel;
|
||||
public void setEnchants(final int entityId, final UserConnection connection, final int efficiency, final int soulSpeed, final int swiftSneak, final int depthStrider) {
|
||||
// Always called from the main thread
|
||||
if (efficiency == activeEnchants.efficiency.level
|
||||
&& soulSpeed == activeEnchants.soulSpeed.level
|
||||
&& swiftSneak == activeEnchants.swiftSneak.level
|
||||
&& depthStrider == activeEnchants.depthStrider.level) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
this.activeEnchants = new ActiveEnchants(entityId,
|
||||
new ActiveEnchant(EFFICIENCY, efficiency),
|
||||
new ActiveEnchant(SOUL_SPEED, soulSpeed),
|
||||
new ActiveEnchant(SWIFT_SNEAK, swiftSneak),
|
||||
new ActiveEnchant(DEPTH_STRIDER, depthStrider)
|
||||
);
|
||||
this.attributesSent = false;
|
||||
}
|
||||
sendAttributesPacket(connection);
|
||||
}
|
||||
|
||||
public ActiveEnchants activeEnchants() {
|
||||
return activeEnchants;
|
||||
}
|
||||
|
||||
public void onLoginSent(final UserConnection connection) {
|
||||
// Always called from the netty thread
|
||||
this.loginSent = true;
|
||||
sendAttributesPacket(connection);
|
||||
}
|
||||
|
||||
private void sendAttributesPacket(final UserConnection connection) {
|
||||
final StoredEfficiency efficiency;
|
||||
final ActiveEnchants enchants;
|
||||
synchronized (lock) {
|
||||
// Older servers (and often Bungee) will send world state packets before sending the login packet
|
||||
if (!loginSent || efficiencyLevel == null) {
|
||||
if (!loginSent || attributesSent) {
|
||||
return;
|
||||
}
|
||||
|
||||
efficiency = efficiencyLevel;
|
||||
efficiencyLevel = null;
|
||||
enchants = this.activeEnchants;
|
||||
attributesSent = true;
|
||||
}
|
||||
|
||||
final PacketWrapper attributesPacket = PacketWrapper.create(ClientboundPackets1_21.UPDATE_ATTRIBUTES, connection);
|
||||
attributesPacket.write(Types.VAR_INT, efficiency.entityId());
|
||||
attributesPacket.write(Types.VAR_INT, enchants.entityId());
|
||||
|
||||
attributesPacket.write(Types.VAR_INT, 1); // Size
|
||||
attributesPacket.write(Types.VAR_INT, MINING_EFFICIENCY_ID); // Attribute ID
|
||||
attributesPacket.write(Types.DOUBLE, 0D); // Base
|
||||
final List<ActiveEnchant> list = List.of(enchants.efficiency(), enchants.soulSpeed(), enchants.swiftSneak(), enchants.depthStrider());
|
||||
attributesPacket.write(Types.VAR_INT, list.size());
|
||||
for (final ActiveEnchant enchant : list) {
|
||||
final EnchantAttributeModifier modifier = enchant.modifier;
|
||||
attributesPacket.write(Types.VAR_INT, modifier.attributeId);
|
||||
attributesPacket.write(Types.DOUBLE, modifier.baseValue);
|
||||
|
||||
final int level = efficiency.level;
|
||||
if (level > 0) {
|
||||
final double modifierAmount = (level * level) + 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
|
||||
if (enchant.level > 0) {
|
||||
attributesPacket.write(Types.VAR_INT, 1); // Modifiers
|
||||
attributesPacket.write(Types.STRING, modifier.key);
|
||||
attributesPacket.write(Types.DOUBLE, enchant.modifier.modifierFunction.get(enchant.level));
|
||||
attributesPacket.write(Types.BYTE, (byte) 0); // 'Add' operation
|
||||
} else {
|
||||
attributesPacket.write(Types.VAR_INT, 0); // Modifiers
|
||||
}
|
||||
}
|
||||
|
||||
attributesPacket.scheduleSend(Protocol1_20_5To1_21.class);
|
||||
}
|
||||
|
||||
public record StoredEfficiency(int entityId, int level) {
|
||||
public record ActiveEnchants(int entityId, ActiveEnchant efficiency, ActiveEnchant soulSpeed,
|
||||
ActiveEnchant swiftSneak, ActiveEnchant depthStrider) {
|
||||
}
|
||||
|
||||
public record ActiveEnchant(EnchantAttributeModifier modifier, int level) {
|
||||
}
|
||||
|
||||
public static final class EnchantAttributeModifier { // Private constructor, equals by reference
|
||||
private final String key;
|
||||
private final int attributeId;
|
||||
private final double baseValue;
|
||||
private final LevelToModifier modifierFunction;
|
||||
|
||||
private EnchantAttributeModifier(final String key, final int attributeId, final double baseValue, final LevelToModifier modifierFunction) {
|
||||
this.key = key;
|
||||
this.attributeId = attributeId;
|
||||
this.baseValue = baseValue;
|
||||
this.modifierFunction = modifierFunction;
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface LevelToModifier {
|
||||
|
||||
double get(int level);
|
||||
}
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren