Mirror von
https://github.com/ViaVersion/ViaVersion.git
synchronisiert 2024-11-19 14:30:16 +01:00
Ursprung
c098e24c4f
Commit
77d702bc9b
@ -31,6 +31,7 @@ import org.bukkit.event.EventHandler;
|
|||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,6 +41,9 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||||||
public final class PlayerChangeItemListener extends ViaBukkitListener {
|
public final class PlayerChangeItemListener extends ViaBukkitListener {
|
||||||
|
|
||||||
private final Enchantment efficiency = Enchantment.getByKey(NamespacedKey.minecraft("efficiency"));
|
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) {
|
public PlayerChangeItemListener(final ViaVersionPlugin plugin) {
|
||||||
super(plugin, Protocol1_20_5To1_21.class);
|
super(plugin, Protocol1_20_5To1_21.class);
|
||||||
@ -49,8 +53,14 @@ public final class PlayerChangeItemListener extends ViaBukkitListener {
|
|||||||
public void onPlayerInventorySlotChangedEvent(final PlayerInventorySlotChangeEvent event) {
|
public void onPlayerInventorySlotChangedEvent(final PlayerInventorySlotChangeEvent event) {
|
||||||
final Player player = event.getPlayer();
|
final Player player = event.getPlayer();
|
||||||
final ItemStack item = event.getNewItemStack();
|
final ItemStack item = event.getNewItemStack();
|
||||||
if (event.getSlot() == player.getInventory().getHeldItemSlot()) {
|
final PlayerInventory inventory = player.getInventory();
|
||||||
sendAttributeUpdate(player, item);
|
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) {
|
public void onPlayerItemHeld(final PlayerItemHeldEvent event) {
|
||||||
final Player player = event.getPlayer();
|
final Player player = event.getPlayer();
|
||||||
final ItemStack item = player.getInventory().getItem(event.getNewSlot());
|
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());
|
final UserConnection connection = Via.getAPI().getConnection(player.getUniqueId());
|
||||||
if (connection == null || !isOnPipe(player)) {
|
if (connection == null || !isOnPipe(player)) {
|
||||||
return;
|
return;
|
||||||
@ -72,7 +82,23 @@ public final class PlayerChangeItemListener extends ViaBukkitListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int efficiencyLevel = item != null ? item.getEnchantmentLevel(efficiency) : 0;
|
final EfficiencyAttributeStorage.ActiveEnchants activeEnchants = storage.activeEnchants();
|
||||||
storage.setEfficiencyLevel(new EfficiencyAttributeStorage.StoredEfficiency(player.getEntityId(), efficiencyLevel), connection);
|
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.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;
|
||||||
|
|
||||||
public final class EfficiencyAttributeStorage implements StorableObject {
|
public final class EfficiencyAttributeStorage implements StorableObject {
|
||||||
|
|
||||||
private static final int MINING_EFFICIENCY_ID = 19;
|
public static final EnchantAttributeModifier EFFICIENCY = new EnchantAttributeModifier("minecraft:enchantment.efficiency/mainhand", 19, 0, level -> (level * level) + 1);
|
||||||
private final Object lock = new Object(); // Slightly sloppy locking, but should be good enough
|
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 boolean loginSent;
|
||||||
private volatile StoredEfficiency efficiencyLevel;
|
|
||||||
|
|
||||||
public void setEfficiencyLevel(final StoredEfficiency efficiencyLevel, final UserConnection connection) {
|
public void setEnchants(final int entityId, final UserConnection connection, final int efficiency, final int soulSpeed, final int swiftSneak, final int depthStrider) {
|
||||||
this.efficiencyLevel = efficiencyLevel;
|
// 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);
|
sendAttributesPacket(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ActiveEnchants activeEnchants() {
|
||||||
|
return activeEnchants;
|
||||||
|
}
|
||||||
|
|
||||||
public void onLoginSent(final UserConnection connection) {
|
public void onLoginSent(final UserConnection connection) {
|
||||||
|
// Always called from the netty thread
|
||||||
this.loginSent = true;
|
this.loginSent = true;
|
||||||
sendAttributesPacket(connection);
|
sendAttributesPacket(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendAttributesPacket(final UserConnection connection) {
|
private void sendAttributesPacket(final UserConnection connection) {
|
||||||
final StoredEfficiency efficiency;
|
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 || efficiencyLevel == null) {
|
if (!loginSent || attributesSent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
efficiency = efficiencyLevel;
|
enchants = this.activeEnchants;
|
||||||
efficiencyLevel = null;
|
attributesSent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
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, efficiency.entityId());
|
attributesPacket.write(Types.VAR_INT, enchants.entityId());
|
||||||
|
|
||||||
attributesPacket.write(Types.VAR_INT, 1); // Size
|
final List<ActiveEnchant> list = List.of(enchants.efficiency(), enchants.soulSpeed(), enchants.swiftSneak(), enchants.depthStrider());
|
||||||
attributesPacket.write(Types.VAR_INT, MINING_EFFICIENCY_ID); // Attribute ID
|
attributesPacket.write(Types.VAR_INT, list.size());
|
||||||
attributesPacket.write(Types.DOUBLE, 0D); // Base
|
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 (enchant.level > 0) {
|
||||||
if (level > 0) {
|
|
||||||
final double modifierAmount = (level * level) + 1D;
|
|
||||||
attributesPacket.write(Types.VAR_INT, 1); // Modifiers
|
attributesPacket.write(Types.VAR_INT, 1); // Modifiers
|
||||||
attributesPacket.write(Types.STRING, "minecraft:enchantment.efficiency/mainhand"); // Id
|
attributesPacket.write(Types.STRING, modifier.key);
|
||||||
attributesPacket.write(Types.DOUBLE, modifierAmount);
|
attributesPacket.write(Types.DOUBLE, enchant.modifier.modifierFunction.get(enchant.level));
|
||||||
attributesPacket.write(Types.BYTE, (byte) 0); // 'Add' operation
|
attributesPacket.write(Types.BYTE, (byte) 0); // 'Add' operation
|
||||||
} else {
|
} else {
|
||||||
attributesPacket.write(Types.VAR_INT, 0); // Modifiers
|
attributesPacket.write(Types.VAR_INT, 0); // Modifiers
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
attributesPacket.scheduleSend(Protocol1_20_5To1_21.class);
|
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