From 6aaf5aa0ce43e625366d6887606ec97e44a72b9f Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 24 Dec 2021 10:03:03 +0100 Subject: [PATCH] Remove the concept of non-shared attribute --- .../minestom/server/attribute/Attribute.java | 125 +++--------------- .../server/attribute/AttributeInstance.java | 12 +- .../server/attribute/AttributeOperation.java | 3 +- .../minestom/server/attribute/Attributes.java | 32 ----- .../minestom/server/entity/LivingEntity.java | 63 ++++----- .../minestom/server/item/ItemMetaBuilder.java | 2 +- .../server/play/EntityPropertiesPacket.java | 2 +- 7 files changed, 54 insertions(+), 185 deletions(-) delete mode 100644 src/main/java/net/minestom/server/attribute/Attributes.java diff --git a/src/main/java/net/minestom/server/attribute/Attribute.java b/src/main/java/net/minestom/server/attribute/Attribute.java index a2cbd3f6a..ed97a493c 100644 --- a/src/main/java/net/minestom/server/attribute/Attribute.java +++ b/src/main/java/net/minestom/server/attribute/Attribute.java @@ -3,102 +3,34 @@ package net.minestom.server.attribute; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.HashMap; +import java.util.Collection; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * Represents a {@link net.minestom.server.entity.LivingEntity living entity} attribute. */ -public class Attribute { +public record Attribute(String key, float defaultValue, float maxValue) { + private static final Map ATTRIBUTES = new ConcurrentHashMap<>(); - private static final Map ATTRIBUTES = new HashMap<>(); + public static final Attribute MAX_HEALTH = (new Attribute("generic.max_health", 20, 1024)).register(); + public static final Attribute FOLLOW_RANGE = (new Attribute("generic.follow_range", 32, 2048)).register(); + public static final Attribute KNOCKBACK_RESISTANCE = (new Attribute("generic.knockback_resistance", 0, 1)).register(); + public static final Attribute MOVEMENT_SPEED = (new Attribute("generic.movement_speed", 0.25f, 1024)).register(); + public static final Attribute ATTACK_DAMAGE = (new Attribute("generic.attack_damage", 2, 2048)).register(); + public static final Attribute ATTACK_SPEED = (new Attribute("generic.attack_speed", 4, 1024)).register(); + public static final Attribute FLYING_SPEED = (new Attribute("generic.flying_speed", 0.4f, 1024)).register(); + public static final Attribute ARMOR = (new Attribute("generic.armor", 0, 30)).register(); + public static final Attribute ARMOR_TOUGHNESS = (new Attribute("generic.armor_toughness", 0, 20)).register(); + public static final Attribute ATTACK_KNOCKBACK = (new Attribute("generic.attack_knockback", 0, 5)).register(); + public static final Attribute LUCK = (new Attribute("generic.luck", 0, 1024)).register(); + public static final Attribute HORSE_JUMP_STRENGTH = (new Attribute("horse.jump_strength", 0.7f, 2)).register(); + public static final Attribute ZOMBIE_SPAWN_REINFORCEMENTS = (new Attribute("zombie.spawn_reinforcements", 0, 1)).register(); - public static final Attribute MAX_HEALTH = (new Attribute("generic.max_health", true, 20, 1024)).register(); - public static final Attribute FOLLOW_RANGE = (new Attribute("generic.follow_range", true, 32, 2048)).register(); - public static final Attribute KNOCKBACK_RESISTANCE = (new Attribute("generic.knockback_resistance", true, 0, 1)).register(); - public static final Attribute MOVEMENT_SPEED = (new Attribute("generic.movement_speed", true, 0.25f, 1024)).register(); - public static final Attribute ATTACK_DAMAGE = (new Attribute("generic.attack_damage", true, 2, 2048)).register(); - public static final Attribute ATTACK_SPEED = (new Attribute("generic.attack_speed", true, 4, 1024)).register(); - public static final Attribute FLYING_SPEED = (new Attribute("generic.flying_speed", true, 0.4f, 1024)).register(); - public static final Attribute ARMOR = (new Attribute("generic.armor", true, 0, 30)).register(); - public static final Attribute ARMOR_TOUGHNESS = (new Attribute("generic.armor_toughness", true, 0, 20)).register(); - public static final Attribute ATTACK_KNOCKBACK = (new Attribute("generic.attack_knockback", true, 0, 5)).register(); - public static final Attribute LUCK = (new Attribute("generic.luck", true, 0, 1024)).register(); - public static final Attribute HORSE_JUMP_STRENGTH = (new Attribute("horse.jump_strength", true, 0.7f, 2)).register(); - public static final Attribute ZOMBIE_SPAWN_REINFORCEMENTS = (new Attribute("zombie.spawn_reinforcements", true, 0, 1)).register(); - - private final String key; - private final float defaultValue; - private final float maxValue; - private final boolean shareWithClient; - - /** - * Create a new attribute with a given key and default. - *

- * By default, this attribute will be sent to the client. - *

- * - * @param key the attribute registry key - * @param defaultValue the default value - * @param maxValue the maximum allowed value - */ - public Attribute(@NotNull String key, float defaultValue, float maxValue) { - this(key, true, defaultValue, maxValue); - } - - /** - * Create a new attribute with a given key and default. - * - * @param key the attribute registry key - * @param shareWithClient whether to send this attribute to the client - * @param defaultValue the default value - * @param maxValue the maximum allowed value - */ - public Attribute(@NotNull String key, boolean shareWithClient, float defaultValue, float maxValue) { + public Attribute { if (defaultValue > maxValue) { throw new IllegalArgumentException("Default value cannot be greater than the maximum allowed"); } - this.key = key; - this.shareWithClient = shareWithClient; - this.defaultValue = defaultValue; - this.maxValue = maxValue; - } - - /** - * Gets the attribute unique key. - * - * @return the attribute key - */ - @NotNull - public String getKey() { - return key; - } - - /** - * Gets the attribute default value that should be applied. - * - * @return the attribute default value - */ - public float getDefaultValue() { - return defaultValue; - } - - /** - * Gets the maximum value applicable to an entity for this attribute. - * - * @return the maximum value of this attribute - */ - public float getMaxValue() { - return maxValue; - } - - /** - * Gets whether this attribute's instances should be sent to clients. - * - * @return if this attribute is to be shared - */ - public boolean isShared() { - return shareWithClient; } /** @@ -108,8 +40,7 @@ public class Attribute { * @see #fromKey(String) * @see #values() */ - @NotNull - public Attribute register() { + public @NotNull Attribute register() { ATTRIBUTES.put(key, this); return this; } @@ -120,8 +51,7 @@ public class Attribute { * @param key the key of the attribute * @return the attribute for the key or null if not any */ - @Nullable - public static Attribute fromKey(@NotNull String key) { + public static @Nullable Attribute fromKey(@NotNull String key) { return ATTRIBUTES.get(key); } @@ -130,18 +60,7 @@ public class Attribute { * * @return an array containing all registered attributes */ - @NotNull - public static Attribute[] values() { - return ATTRIBUTES.values().toArray(new Attribute[0]); - } - - /** - * Retrieves registered attributes that are shared with the client. - * - * @return an array containing registered, sharable attributes - */ - @NotNull - public static Attribute[] sharedAttributes() { - return ATTRIBUTES.values().stream().filter(Attribute::isShared).toArray(Attribute[]::new); + public static @NotNull Collection<@NotNull Attribute> values() { + return ATTRIBUTES.values(); } } diff --git a/src/main/java/net/minestom/server/attribute/AttributeInstance.java b/src/main/java/net/minestom/server/attribute/AttributeInstance.java index c8d7d3716..cff5e63ea 100644 --- a/src/main/java/net/minestom/server/attribute/AttributeInstance.java +++ b/src/main/java/net/minestom/server/attribute/AttributeInstance.java @@ -12,8 +12,7 @@ import java.util.function.Consumer; /** * Represents an instance of an attribute and its modifiers. */ -public class AttributeInstance { - +public final class AttributeInstance { private final Attribute attribute; private final Map modifiers = new HashMap<>(); private final Consumer propertyChangeListener; @@ -23,7 +22,7 @@ public class AttributeInstance { public AttributeInstance(@NotNull Attribute attribute, @Nullable Consumer listener) { this.attribute = attribute; this.propertyChangeListener = listener; - this.baseValue = attribute.getDefaultValue(); + this.baseValue = attribute.defaultValue(); refreshCachedValue(); } @@ -32,8 +31,7 @@ public class AttributeInstance { * * @return the associated attribute */ - @NotNull - public Attribute getAttribute() { + public @NotNull Attribute getAttribute() { return attribute; } @@ -104,7 +102,7 @@ public class AttributeInstance { /** * Recalculate the value of this attribute instance using the modifiers. */ - protected void refreshCachedValue() { + private void refreshCachedValue() { final Collection modifiers = getModifiers(); float base = getBaseValue(); @@ -121,7 +119,7 @@ public class AttributeInstance { result *= (1.0f + modifier.getAmount()); } - this.cachedValue = Math.min(result, getAttribute().getMaxValue()); + this.cachedValue = Math.min(result, getAttribute().maxValue()); // Signal entity if (propertyChangeListener != null) { diff --git a/src/main/java/net/minestom/server/attribute/AttributeOperation.java b/src/main/java/net/minestom/server/attribute/AttributeOperation.java index 0eaf81831..33da291c7 100644 --- a/src/main/java/net/minestom/server/attribute/AttributeOperation.java +++ b/src/main/java/net/minestom/server/attribute/AttributeOperation.java @@ -18,8 +18,7 @@ public enum AttributeOperation { return this.id; } - @Nullable - public static AttributeOperation fromId(int id) { + public static @Nullable AttributeOperation fromId(int id) { if (id >= 0 && id < VALUES.length) { return VALUES[id]; } diff --git a/src/main/java/net/minestom/server/attribute/Attributes.java b/src/main/java/net/minestom/server/attribute/Attributes.java deleted file mode 100644 index 0da784e10..000000000 --- a/src/main/java/net/minestom/server/attribute/Attributes.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.minestom.server.attribute; - -/** - * The Minecraft, vanilla, standards attributes. - * - * @deprecated use the constants in {@link Attribute} - */ -@Deprecated -public final class Attributes { - - public static final Attribute MAX_HEALTH = Attribute.MAX_HEALTH; - public static final Attribute FOLLOW_RANGE = Attribute.FOLLOW_RANGE; - public static final Attribute KNOCKBACK_RESISTANCE = Attribute.KNOCKBACK_RESISTANCE; - public static final Attribute MOVEMENT_SPEED = Attribute.MOVEMENT_SPEED; - public static final Attribute ATTACK_DAMAGE = Attribute.ATTACK_DAMAGE; - public static final Attribute ATTACK_SPEED = Attribute.ATTACK_SPEED; - public static final Attribute FLYING_SPEED = Attribute.FLYING_SPEED; - public static final Attribute ARMOR = Attribute.ARMOR; - public static final Attribute ARMOR_TOUGHNESS = Attribute.ARMOR_TOUGHNESS; - public static final Attribute ATTACK_KNOCKBACK = Attribute.ATTACK_KNOCKBACK; - public static final Attribute LUCK = Attribute.LUCK; - public static final Attribute HORSE_JUMP_STRENGTH = Attribute.HORSE_JUMP_STRENGTH; - public static final Attribute ZOMBIE_SPAWN_REINFORCEMENTS = Attribute.ZOMBIE_SPAWN_REINFORCEMENTS; - - private Attributes() throws IllegalAccessException { - throw new IllegalAccessException("Cannot instantiate a static class"); - } - - protected static void init() { - // Empty, here to register all the vanilla attributes - } -} diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index 71022cd3b..f124d8d0e 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -3,7 +3,6 @@ package net.minestom.server.entity; import net.kyori.adventure.sound.Sound.Source; import net.minestom.server.attribute.Attribute; import net.minestom.server.attribute.AttributeInstance; -import net.minestom.server.attribute.Attributes; import net.minestom.server.collision.BoundingBox; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; @@ -35,7 +34,10 @@ import org.jetbrains.annotations.Nullable; import java.time.Duration; import java.time.temporal.TemporalUnit; -import java.util.*; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public class LivingEntity extends Entity implements EquipmentHandler { @@ -51,7 +53,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { // Bounding box used for items' pickup (see LivingEntity#setBoundingBox) protected BoundingBox expandedBoundingBox; - private final Map attributeModifiers = new ConcurrentHashMap<>(Attribute.values().length); + private final Map attributeModifiers = new ConcurrentHashMap<>(); // Abilities protected boolean invulnerable; @@ -423,7 +425,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { } /** - * Gets the entity max health from {@link #getAttributeValue(Attribute)} {@link Attributes#MAX_HEALTH}. + * Gets the entity max health from {@link #getAttributeValue(Attribute)} {@link Attribute#MAX_HEALTH}. * * @return the entity max health */ @@ -434,7 +436,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { /** * Sets the heal of the entity as its max health. *

- * Retrieved from {@link #getAttributeValue(Attribute)} with the attribute {@link Attributes#MAX_HEALTH}. + * Retrieved from {@link #getAttributeValue(Attribute)} with the attribute {@link Attribute#MAX_HEALTH}. */ public void heal() { setHealth(getAttributeValue(Attribute.MAX_HEALTH)); @@ -446,9 +448,8 @@ public class LivingEntity extends Entity implements EquipmentHandler { * @param attribute the attribute instance to get * @return the attribute instance */ - @NotNull - public AttributeInstance getAttribute(@NotNull Attribute attribute) { - return attributeModifiers.computeIfAbsent(attribute.getKey(), + public @NotNull AttributeInstance getAttribute(@NotNull Attribute attribute) { + return attributeModifiers.computeIfAbsent(attribute.key(), s -> new AttributeInstance(attribute, this::onAttributeChanged)); } @@ -458,19 +459,17 @@ public class LivingEntity extends Entity implements EquipmentHandler { * @param attributeInstance the modified attribute instance */ protected void onAttributeChanged(@NotNull AttributeInstance attributeInstance) { - if (attributeInstance.getAttribute().isShared()) { - boolean self = false; - if (this instanceof Player player) { - PlayerConnection playerConnection = player.playerConnection; - // connection null during Player initialization (due to #super call) - self = playerConnection != null && playerConnection.getConnectionState() == ConnectionState.PLAY; - } - EntityPropertiesPacket propertiesPacket = getPropertiesPacket(Collections.singleton(attributeInstance)); - if (self) { - sendPacketToViewersAndSelf(propertiesPacket); - } else { - sendPacketToViewers(propertiesPacket); - } + boolean self = false; + if (this instanceof Player player) { + PlayerConnection playerConnection = player.playerConnection; + // connection null during Player initialization (due to #super call) + self = playerConnection != null && playerConnection.getConnectionState() == ConnectionState.PLAY; + } + EntityPropertiesPacket propertiesPacket = new EntityPropertiesPacket(getEntityId(), List.of(attributeInstance)); + if (self) { + sendPacketToViewersAndSelf(propertiesPacket); + } else { + sendPacketToViewers(propertiesPacket); } } @@ -481,8 +480,8 @@ public class LivingEntity extends Entity implements EquipmentHandler { * @return the attribute value */ public float getAttributeValue(@NotNull Attribute attribute) { - AttributeInstance instance = attributeModifiers.get(attribute.getKey()); - return (instance != null) ? instance.getValue() : attribute.getDefaultValue(); + AttributeInstance instance = attributeModifiers.get(attribute.key()); + return (instance != null) ? instance.getValue() : attribute.defaultValue(); } /** @@ -575,22 +574,8 @@ public class LivingEntity extends Entity implements EquipmentHandler { * * @return an {@link EntityPropertiesPacket} linked to this entity */ - @NotNull - protected EntityPropertiesPacket getPropertiesPacket() { - return getPropertiesPacket(attributeModifiers.values()); - } - - /** - * Gets an {@link EntityPropertiesPacket} for this entity with the specified attribute values. - * - * @param attributes the attributes to include in the packet - * @return an {@link EntityPropertiesPacket} linked to this entity - */ - protected @NotNull EntityPropertiesPacket getPropertiesPacket(@NotNull Collection attributes) { - // Get all the attributes which should be sent to the client - final List properties = attributes.stream() - .filter(i -> i.getAttribute().isShared()).toList(); - return new EntityPropertiesPacket(getEntityId(), properties); + protected @NotNull EntityPropertiesPacket getPropertiesPacket() { + return new EntityPropertiesPacket(getEntityId(), List.copyOf(attributeModifiers.values())); } @Override diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index d228b7127..97fc9e57c 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -128,7 +128,7 @@ public abstract class ItemMetaBuilder implements TagWritable { "UUID", NBT.IntArray(Utils.uuidToIntArray(itemAttribute.getUuid())), "Amount", NBT.Double(itemAttribute.getValue()), "Slot", NBT.String(itemAttribute.getSlot().name().toLowerCase()), - "AttributeName", NBT.String(itemAttribute.getAttribute().getKey()), + "AttributeName", NBT.String(itemAttribute.getAttribute().key()), "Operation", NBT.Int(itemAttribute.getOperation().getId()), "Name", NBT.String(itemAttribute.getInternalName())))) .toList() diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityPropertiesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityPropertiesPacket.java index e0f98c5b0..ce2360d5a 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityPropertiesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityPropertiesPacket.java @@ -39,7 +39,7 @@ public record EntityPropertiesPacket(int entityId, List prope for (AttributeInstance instance : properties) { final Attribute attribute = instance.getAttribute(); - writer.writeSizedString(attribute.getKey()); + writer.writeSizedString(attribute.key()); writer.writeDouble(instance.getBaseValue()); {