mirror of
https://github.com/Minestom/Minestom.git
synced 2024-11-15 07:05:52 +01:00
Implement attribute instances
This commit is contained in:
parent
089f9a30aa
commit
d738f9fddd
@ -1,53 +1,69 @@
|
|||||||
package net.minestom.server.attribute;
|
package net.minestom.server.attribute;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public enum Attribute {
|
public class Attribute {
|
||||||
|
|
||||||
MAX_HEALTH("generic.max_health", 20, 1024),
|
private static final Map<String, Attribute> ATTRIBUTES = new HashMap<>();
|
||||||
FOLLOW_RANGE("generic.follow_range", 32, 2048),
|
|
||||||
KNOCKBACK_RESISTANCE("generic.knockback_resistance", 0, 1),
|
|
||||||
MOVEMENT_SPEED("generic.movement_speed", 0.25f, 1024),
|
|
||||||
ATTACK_DAMAGE("generic.attack_damage", 2, 2048),
|
|
||||||
ATTACK_SPEED("generic.attack_speed", 4, 1024),
|
|
||||||
FLYING_SPEED("generic.flying_speed", 0.4f, 1024),
|
|
||||||
ARMOR("generic.armor", 0, 30),
|
|
||||||
ARMOR_TOUGHNESS("generic.armor_toughness", 0, 20),
|
|
||||||
ATTACK_KNOCKBACK("generic.attack_knockback", 0, 5),
|
|
||||||
LUCK("generic.luck", 0, 1024),
|
|
||||||
HORSE_JUMP_STRENGTH("horse.jump_strength", 0.7f, 2),
|
|
||||||
ZOMBIE_SPAWN_REINFORCEMENTS("zombie.spawn_reinforcements", 0, 1);
|
|
||||||
|
|
||||||
private final String key;
|
private final String key;
|
||||||
private final float defaultValue;
|
private final float defaultValue;
|
||||||
private final float maxVanillaValue;
|
private final float maxValue;
|
||||||
|
private final boolean shareWithClient;
|
||||||
|
|
||||||
Attribute(@NotNull String key, float defaultValue, float maxVanillaValue) {
|
public Attribute(@NotNull String key, float defaultValue, float maxValue) {
|
||||||
this.key = key;
|
this(key, false, defaultValue, maxValue);
|
||||||
this.defaultValue = defaultValue;
|
}
|
||||||
this.maxVanillaValue = maxVanillaValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
public Attribute(@NotNull String key, boolean shareWithClient, float defaultValue, float maxValue) {
|
||||||
public String getKey() {
|
if (defaultValue > maxValue) {
|
||||||
return key;
|
throw new IllegalArgumentException("Default value cannot be greater than the maximum allowed");
|
||||||
}
|
}
|
||||||
|
this.key = key;
|
||||||
|
this.shareWithClient = shareWithClient;
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
this.maxValue = maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
public float getDefaultValue() {
|
@NotNull
|
||||||
return defaultValue;
|
public String getKey() {
|
||||||
}
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
public float getMaxVanillaValue() {
|
public float getDefaultValue() {
|
||||||
return maxVanillaValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
public float getMaxValue() {
|
||||||
public static Attribute fromKey(@NotNull String key) {
|
return maxValue;
|
||||||
for (Attribute attribute : values()) {
|
}
|
||||||
if (attribute.getKey().equals(key))
|
|
||||||
return attribute;
|
public boolean isShared() {
|
||||||
}
|
return shareWithClient;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
@NotNull
|
||||||
|
public Attribute register() {
|
||||||
|
ATTRIBUTES.put(key, this);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Attribute fromKey(@NotNull String key) {
|
||||||
|
return ATTRIBUTES.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static Attribute[] values() {
|
||||||
|
return ATTRIBUTES.values().toArray(new Attribute[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static Attribute[] sharedAttributes() {
|
||||||
|
return ATTRIBUTES.values().stream().filter(Attribute::isShared).toArray(Attribute[]::new);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
package net.minestom.server.attribute;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class AttributeInstance {
|
||||||
|
|
||||||
|
private final Attribute attribute;
|
||||||
|
private final Map<UUID, AttributeModifier> modifiers = new HashMap<>();
|
||||||
|
private final Consumer<AttributeInstance> propertyChangeListener;
|
||||||
|
private float baseValue;
|
||||||
|
private boolean dirty = true;
|
||||||
|
private float cachedValue = 0.0f;
|
||||||
|
|
||||||
|
public AttributeInstance(@NotNull Attribute attribute, @Nullable Consumer<AttributeInstance> listener) {
|
||||||
|
this.attribute = attribute;
|
||||||
|
this.propertyChangeListener = listener;
|
||||||
|
this.baseValue = attribute.getDefaultValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public Attribute getAttribute() {
|
||||||
|
return attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getBaseValue() {
|
||||||
|
return baseValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDirty() {
|
||||||
|
if (!dirty) {
|
||||||
|
dirty = true;
|
||||||
|
if (propertyChangeListener != null) {
|
||||||
|
propertyChangeListener.accept(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBaseValue(float baseValue) {
|
||||||
|
if (this.baseValue != baseValue) {
|
||||||
|
this.baseValue = baseValue;
|
||||||
|
setDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addModifier(@NotNull AttributeModifier modifier) {
|
||||||
|
if (modifiers.putIfAbsent(modifier.getId(), modifier) == null) {
|
||||||
|
setDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeModifier(@NotNull AttributeModifier modifier) {
|
||||||
|
if (modifiers.remove(modifier.getId()) != null) {
|
||||||
|
setDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<AttributeModifier> getModifiers() {
|
||||||
|
return modifiers.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getValue() {
|
||||||
|
if (dirty) {
|
||||||
|
cachedValue = processModifiers();
|
||||||
|
dirty = false;
|
||||||
|
}
|
||||||
|
return cachedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float processModifiers() {
|
||||||
|
float base = getBaseValue();
|
||||||
|
|
||||||
|
for (var modifier : modifiers.values().stream().filter(mod -> mod.getOperation() == AttributeOperation.ADDITION).toArray(AttributeModifier[]::new)) {
|
||||||
|
base += modifier.getAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
float result = base;
|
||||||
|
|
||||||
|
for (var modifier : modifiers.values().stream().filter(mod -> mod.getOperation() == AttributeOperation.MULTIPLY_BASE).toArray(AttributeModifier[]::new)) {
|
||||||
|
result += (base * modifier.getAmount());
|
||||||
|
}
|
||||||
|
for (var modifier : modifiers.values().stream().filter(mod -> mod.getOperation() == AttributeOperation.MULTIPLY_TOTAL).toArray(AttributeModifier[]::new)) {
|
||||||
|
result *= (1.0f + modifier.getAmount());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.min(result, getAttribute().getMaxValue());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package net.minestom.server.attribute;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import io.netty.util.internal.ThreadLocalRandom;
|
||||||
|
import net.minestom.server.utils.UniqueIdUtils;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class AttributeModifier {
|
||||||
|
|
||||||
|
private final float amount;
|
||||||
|
private final String name;
|
||||||
|
private final AttributeOperation operation;
|
||||||
|
private final UUID id;
|
||||||
|
|
||||||
|
public AttributeModifier(@NotNull String name, float amount, @NotNull AttributeOperation operation) {
|
||||||
|
this(UniqueIdUtils.createRandomUUID(ThreadLocalRandom.current()), name, amount, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttributeModifier(@NotNull UUID id, @NotNull String name, float amount, @NotNull AttributeOperation operation) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.amount = amount;
|
||||||
|
this.operation = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public AttributeOperation getOperation() {
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
}
|
18
src/main/java/net/minestom/server/attribute/Attributes.java
Normal file
18
src/main/java/net/minestom/server/attribute/Attributes.java
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package net.minestom.server.attribute;
|
||||||
|
|
||||||
|
public final class Attributes
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
@ -3,7 +3,7 @@ package net.minestom.server.entity;
|
|||||||
import com.extollit.gaming.ai.path.HydrazinePathFinder;
|
import com.extollit.gaming.ai.path.HydrazinePathFinder;
|
||||||
import com.extollit.gaming.ai.path.model.IPath;
|
import com.extollit.gaming.ai.path.model.IPath;
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.attribute.Attribute;
|
import net.minestom.server.attribute.Attributes;
|
||||||
import net.minestom.server.entity.ai.GoalSelector;
|
import net.minestom.server.entity.ai.GoalSelector;
|
||||||
import net.minestom.server.entity.ai.TargetSelector;
|
import net.minestom.server.entity.ai.TargetSelector;
|
||||||
import net.minestom.server.entity.pathfinding.PFPathingEntity;
|
import net.minestom.server.entity.pathfinding.PFPathingEntity;
|
||||||
@ -134,7 +134,7 @@ public abstract class EntityCreature extends LivingEntity {
|
|||||||
this.path = pathFinder.updatePathFor(pathingEntity);
|
this.path = pathFinder.updatePathFor(pathingEntity);
|
||||||
|
|
||||||
if (path != null) {
|
if (path != null) {
|
||||||
final float speed = getAttributeValue(Attribute.MOVEMENT_SPEED);
|
final float speed = getAttributeValue(Attributes.MOVEMENT_SPEED);
|
||||||
final Position targetPosition = pathingEntity.getTargetPosition();
|
final Position targetPosition = pathingEntity.getTargetPosition();
|
||||||
moveTowards(targetPosition, speed);
|
moveTowards(targetPosition, speed);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package net.minestom.server.entity;
|
package net.minestom.server.entity;
|
||||||
|
|
||||||
import net.minestom.server.attribute.Attribute;
|
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.collision.BoundingBox;
|
||||||
import net.minestom.server.entity.damage.DamageType;
|
import net.minestom.server.entity.damage.DamageType;
|
||||||
import net.minestom.server.event.entity.EntityDamageEvent;
|
import net.minestom.server.event.entity.EntityDamageEvent;
|
||||||
@ -26,9 +28,12 @@ import net.minestom.server.utils.validate.Check;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
//TODO: Default attributes registration (and limitation ?)
|
||||||
public abstract class LivingEntity extends Entity implements EquipmentHandler {
|
public abstract class LivingEntity extends Entity implements EquipmentHandler {
|
||||||
|
|
||||||
// Item pickup
|
// Item pickup
|
||||||
@ -44,7 +49,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
|
|||||||
// Bounding box used for items' pickup (see LivingEntity#setBoundingBox)
|
// Bounding box used for items' pickup (see LivingEntity#setBoundingBox)
|
||||||
protected BoundingBox expandedBoundingBox;
|
protected BoundingBox expandedBoundingBox;
|
||||||
|
|
||||||
private final float[] attributeValues = new float[Attribute.values().length];
|
private final Map<String, AttributeInstance> attributeModifiers = new HashMap<>(Attribute.values().length);
|
||||||
|
|
||||||
private boolean isHandActive;
|
private boolean isHandActive;
|
||||||
private boolean offHand;
|
private boolean offHand;
|
||||||
@ -369,41 +374,48 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the entity max health from {@link #getAttributeValue(Attribute)} {@link Attribute#MAX_HEALTH}.
|
* Gets the entity max health from {@link #getAttributeValue(Attribute)} {@link Attributes#MAX_HEALTH}.
|
||||||
*
|
*
|
||||||
* @return the entity max health
|
* @return the entity max health
|
||||||
*/
|
*/
|
||||||
public float getMaxHealth() {
|
public float getMaxHealth() {
|
||||||
return getAttributeValue(Attribute.MAX_HEALTH);
|
return getAttributeValue(Attributes.MAX_HEALTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the heal of the entity as its max health.
|
* Sets the heal of the entity as its max health.
|
||||||
* <p>
|
* <p>
|
||||||
* Retrieved from {@link #getAttributeValue(Attribute)} with the attribute {@link Attribute#MAX_HEALTH}.
|
* Retrieved from {@link #getAttributeValue(Attribute)} with the attribute {@link Attributes#MAX_HEALTH}.
|
||||||
*/
|
*/
|
||||||
public void heal() {
|
public void heal() {
|
||||||
setHealth(getAttributeValue(Attribute.MAX_HEALTH));
|
setHealth(getAttributeValue(Attributes.MAX_HEALTH));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the specified attribute value to {@code value}.
|
* Retrieves the attribute instance and its modifiers.
|
||||||
*
|
*
|
||||||
* @param attribute The attribute to change
|
* @param attribute the attribute instance to get
|
||||||
* @param value the new value of the attribute
|
* @return the attribute instance
|
||||||
*/
|
*/
|
||||||
public void setAttribute(@NotNull Attribute attribute, float value) {
|
@NotNull
|
||||||
this.attributeValues[attribute.ordinal()] = value;
|
public AttributeInstance getAttribute(@NotNull Attribute attribute) {
|
||||||
|
if (!attributeModifiers.containsKey(attribute.getKey())) {
|
||||||
|
attributeModifiers.put(attribute.getKey(), new AttributeInstance(attribute, this::onAttributeChanged));
|
||||||
|
}
|
||||||
|
return attributeModifiers.get(attribute.getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void onAttributeChanged(@NotNull AttributeInstance instance) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the attribute value set by {@link #setAttribute(Attribute, float)}.
|
* Retrieves the attribute value.
|
||||||
*
|
*
|
||||||
* @param attribute the attribute value to get
|
* @param attribute the attribute value to get
|
||||||
* @return the attribute value
|
* @return the attribute value
|
||||||
*/
|
*/
|
||||||
public float getAttributeValue(@NotNull Attribute attribute) {
|
public float getAttributeValue(@NotNull Attribute attribute) {
|
||||||
return this.attributeValues[attribute.ordinal()];
|
AttributeInstance instance = attributeModifiers.get(attribute.getKey());
|
||||||
|
return (instance != null) ? instance.getValue() : attribute.getDefaultValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -488,15 +500,16 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
|
|||||||
EntityPropertiesPacket propertiesPacket = new EntityPropertiesPacket();
|
EntityPropertiesPacket propertiesPacket = new EntityPropertiesPacket();
|
||||||
propertiesPacket.entityId = getEntityId();
|
propertiesPacket.entityId = getEntityId();
|
||||||
|
|
||||||
final int length = Attribute.values().length;
|
AttributeInstance[] instances = attributeModifiers.values().stream()
|
||||||
EntityPropertiesPacket.Property[] properties = new EntityPropertiesPacket.Property[length];
|
.filter(i -> i.getAttribute().isShared())
|
||||||
for (int i = 0; i < length; i++) {
|
.toArray(AttributeInstance[]::new);
|
||||||
|
EntityPropertiesPacket.Property[] properties = new EntityPropertiesPacket.Property[instances.length];
|
||||||
|
for (int i = 0; i < properties.length; ++i) {
|
||||||
EntityPropertiesPacket.Property property = new EntityPropertiesPacket.Property();
|
EntityPropertiesPacket.Property property = new EntityPropertiesPacket.Property();
|
||||||
|
|
||||||
final Attribute attribute = Attribute.values()[i];
|
final float value = instances[i].getBaseValue();
|
||||||
final float value = getAttributeValue(attribute);
|
|
||||||
|
|
||||||
property.attribute = attribute;
|
property.attribute = instances[i].getAttribute();
|
||||||
property.value = value;
|
property.value = value;
|
||||||
|
|
||||||
properties[i] = property;
|
properties[i] = property;
|
||||||
@ -511,7 +524,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
|
|||||||
*/
|
*/
|
||||||
private void setupAttributes() {
|
private void setupAttributes() {
|
||||||
for (Attribute attribute : Attribute.values()) {
|
for (Attribute attribute : Attribute.values()) {
|
||||||
setAttribute(attribute, attribute.getDefaultValue());
|
attributeModifiers.put(attribute.getKey(), new AttributeInstance(attribute, this::onAttributeChanged));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ package net.minestom.server.entity;
|
|||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.advancements.AdvancementTab;
|
import net.minestom.server.advancements.AdvancementTab;
|
||||||
import net.minestom.server.attribute.Attribute;
|
import net.minestom.server.attribute.Attribute;
|
||||||
|
import net.minestom.server.attribute.AttributeInstance;
|
||||||
|
import net.minestom.server.attribute.Attributes;
|
||||||
import net.minestom.server.bossbar.BossBar;
|
import net.minestom.server.bossbar.BossBar;
|
||||||
import net.minestom.server.chat.ChatParser;
|
import net.minestom.server.chat.ChatParser;
|
||||||
import net.minestom.server.chat.ColoredText;
|
import net.minestom.server.chat.ColoredText;
|
||||||
@ -288,7 +290,7 @@ public class Player extends LivingEntity implements CommandSender {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getAttributeValue(@NotNull Attribute attribute) {
|
public float getAttributeValue(@NotNull Attribute attribute) {
|
||||||
if (attribute == Attribute.MOVEMENT_SPEED) {
|
if (attribute == Attributes.MOVEMENT_SPEED) {
|
||||||
return walkingSpeed;
|
return walkingSpeed;
|
||||||
}
|
}
|
||||||
return super.getAttributeValue(attribute);
|
return super.getAttributeValue(attribute);
|
||||||
@ -1020,9 +1022,8 @@ public class Player extends LivingEntity implements CommandSender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAttribute(@NotNull Attribute attribute, float value) {
|
protected void onAttributeChanged(@NotNull final AttributeInstance instance) {
|
||||||
super.setAttribute(attribute, value);
|
if (instance.getAttribute().isShared() && playerConnection != null)
|
||||||
if (playerConnection != null)
|
|
||||||
playerConnection.sendPacket(getPropertiesPacket());
|
playerConnection.sendPacket(getPropertiesPacket());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import com.extollit.gaming.ai.path.model.Gravitation;
|
|||||||
import com.extollit.gaming.ai.path.model.IPathingEntity;
|
import com.extollit.gaming.ai.path.model.IPathingEntity;
|
||||||
import com.extollit.gaming.ai.path.model.Passibility;
|
import com.extollit.gaming.ai.path.model.Passibility;
|
||||||
import com.extollit.linalg.immutable.Vec3d;
|
import com.extollit.linalg.immutable.Vec3d;
|
||||||
import net.minestom.server.attribute.Attribute;
|
import net.minestom.server.attribute.Attributes;
|
||||||
import net.minestom.server.entity.EntityCreature;
|
import net.minestom.server.entity.EntityCreature;
|
||||||
import net.minestom.server.utils.Position;
|
import net.minestom.server.utils.Position;
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ public class PFPathingEntity implements IPathingEntity {
|
|||||||
|
|
||||||
public PFPathingEntity(EntityCreature entity) {
|
public PFPathingEntity(EntityCreature entity) {
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
this.searchRange = entity.getAttributeValue(Attribute.FOLLOW_RANGE);
|
this.searchRange = entity.getAttributeValue(Attributes.FOLLOW_RANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position getTargetPosition() {
|
public Position getTargetPosition() {
|
||||||
@ -113,7 +113,7 @@ public class PFPathingEntity implements IPathingEntity {
|
|||||||
return new Capabilities() {
|
return new Capabilities() {
|
||||||
@Override
|
@Override
|
||||||
public float speed() {
|
public float speed() {
|
||||||
return entity.getAttributeValue(Attribute.MOVEMENT_SPEED);
|
return entity.getAttributeValue(Attributes.MOVEMENT_SPEED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package net.minestom.server.network.packet.server.play;
|
package net.minestom.server.network.packet.server.play;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import net.minestom.server.attribute.Attribute;
|
import net.minestom.server.attribute.Attribute;
|
||||||
|
import net.minestom.server.attribute.AttributeInstance;
|
||||||
|
import net.minestom.server.attribute.AttributeModifier;
|
||||||
import net.minestom.server.network.packet.server.ServerPacket;
|
import net.minestom.server.network.packet.server.ServerPacket;
|
||||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||||
import net.minestom.server.utils.binary.BinaryWriter;
|
import net.minestom.server.utils.binary.BinaryWriter;
|
||||||
@ -30,9 +34,14 @@ public class EntityPropertiesPacket implements ServerPacket {
|
|||||||
|
|
||||||
public Attribute attribute;
|
public Attribute attribute;
|
||||||
public double value;
|
public double value;
|
||||||
|
public AttributeInstance instance;
|
||||||
|
|
||||||
private void write(BinaryWriter writer) {
|
private void write(BinaryWriter writer) {
|
||||||
float maxValue = attribute.getMaxVanillaValue();
|
if (instance != null) {
|
||||||
|
attribute = instance.getAttribute();
|
||||||
|
value = instance.getBaseValue();
|
||||||
|
}
|
||||||
|
float maxValue = attribute.getMaxValue();
|
||||||
|
|
||||||
// Bypass vanilla limit client-side if needed (by sending the max value allowed)
|
// Bypass vanilla limit client-side if needed (by sending the max value allowed)
|
||||||
final double v = value > maxValue ? maxValue : value;
|
final double v = value > maxValue ? maxValue : value;
|
||||||
@ -40,8 +49,16 @@ public class EntityPropertiesPacket implements ServerPacket {
|
|||||||
writer.writeSizedString(attribute.getKey());
|
writer.writeSizedString(attribute.getKey());
|
||||||
writer.writeDouble(v);
|
writer.writeDouble(v);
|
||||||
|
|
||||||
// TODO support for AttributeOperation
|
{
|
||||||
writer.writeVarInt(0);
|
Collection<AttributeModifier> modifiers = instance.getModifiers();
|
||||||
|
writer.writeVarInt(modifiers.size());
|
||||||
|
|
||||||
|
for (var modifier : modifiers) {
|
||||||
|
writer.writeUuid(modifier.getId());
|
||||||
|
writer.writeDouble(modifier.getAmount());
|
||||||
|
writer.writeByte((byte) modifier.getOperation().getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.minestom.server.utils;
|
package net.minestom.server.utils;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -20,4 +21,11 @@ public final class UniqueIdUtils {
|
|||||||
return input.matches(UNIQUE_ID_PATTERN.pattern());
|
return input.matches(UNIQUE_ID_PATTERN.pattern());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UUID createRandomUUID(Random random) {
|
||||||
|
long most = random.nextLong() & -61441L | 16384L;
|
||||||
|
long least = random.nextLong() & 4611686018427387903L | Long.MAX_VALUE;
|
||||||
|
|
||||||
|
return new UUID(most, least);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package demo.entity;
|
package demo.entity;
|
||||||
|
|
||||||
import net.minestom.server.attribute.Attribute;
|
import net.minestom.server.attribute.Attributes;
|
||||||
import net.minestom.server.entity.LivingEntity;
|
import net.minestom.server.entity.LivingEntity;
|
||||||
import net.minestom.server.entity.ai.goal.RandomStrollGoal;
|
import net.minestom.server.entity.ai.goal.RandomStrollGoal;
|
||||||
import net.minestom.server.entity.damage.DamageType;
|
import net.minestom.server.entity.damage.DamageType;
|
||||||
@ -37,7 +37,7 @@ public class ChickenCreature extends EntityChicken {
|
|||||||
//targetSelectors.add(new ClosestEntityTarget(this, 15, LivingEntity.class));
|
//targetSelectors.add(new ClosestEntityTarget(this, 15, LivingEntity.class));
|
||||||
|
|
||||||
|
|
||||||
setAttribute(Attribute.MOVEMENT_SPEED, 0.1f);
|
getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.1f);
|
||||||
|
|
||||||
addEventCallback(EntityAttackEvent.class, event -> {
|
addEventCallback(EntityAttackEvent.class, event -> {
|
||||||
//System.out.println("CALL ATTACK");
|
//System.out.println("CALL ATTACK");
|
||||||
|
Loading…
Reference in New Issue
Block a user