diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 977adff6e1..fd7385663a 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -7,6 +7,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -61,7 +62,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player { private final Set channels = new HashSet(); private final Map hiddenPlayers = new MapMaker().softValues().makeMap(); private int hash = 0; - private boolean scaledHealth; + private double health = 20; + private boolean scaledHealth = false; + private double healthScale = 20; public CraftPlayer(CraftServer server, EntityPlayer entity) { super(server, entity); @@ -973,6 +976,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void setMaxHealth(double amount) { super.setMaxHealth(amount); + this.health = Math.min(this.health, health); getHandle().triggerHealthUpdate(); } @@ -999,15 +1003,66 @@ public class CraftPlayer extends CraftHumanEntity implements Player { this.server.getScoreboardManager().setPlayerBoard(this, scoreboard); } + public void setHealthScale(double value) { + Validate.isTrue((float) value > 0F, "Must be greater than 0"); + healthScale = value; + scaledHealth = true; + updateScaledHealth(); + } + + public double getHealthScale() { + return healthScale; + } + + public void setHealthScaled(boolean scale) { + if (scaledHealth != (scaledHealth = scale)) { + updateScaledHealth(); + } + } + + public boolean isHealthScaled() { + return scaledHealth; + } + public float getScaledHealth() { - return (float) (this.scaledHealth ? getHealth() / getMaxHealth() * 20.0D : getHealth()); + return (float) (isHealthScaled() ? getHealth() * getHealthScale() / getMaxHealth() : getHealth()); } - public void setScaleHealth(boolean scale) { - this.scaledHealth = scale; + @Override + public double getHealth() { + return health; } - public boolean isScaledHealth() { - return this.scaledHealth; + public void setRealHealth(double health) { + this.health = health; + } + + public void updateScaledHealth() { + AttributeMapServer attributemapserver = (AttributeMapServer) getHandle().aW(); + Set set = attributemapserver.b(); + + injectScaledMaxHealth(set, true); + + getHandle().getDataWatcher().watch(6, (float) getScaledHealth()); + getHandle().playerConnection.sendPacket(new Packet8UpdateHealth(getScaledHealth(), getHandle().getFoodData().a(), getHandle().getFoodData().e())); + getHandle().playerConnection.sendPacket(new Packet44UpdateAttributes(getHandle().id, set)); + + set.clear(); + getHandle().maxHealthCache = getMaxHealth(); + } + + public void injectScaledMaxHealth(Collection collection, boolean force) { + if (!scaledHealth && !force) { + return; + } + for (Object genericInstance : collection) { + IAttribute attribute = ((AttributeInstance) genericInstance).a(); + if (attribute.a().equals("generic.maxHealth")) { + collection.remove(genericInstance); + break; + } + continue; + } + collection.add(new AttributeModifiable(getHandle().aW(), (new AttributeRanged("generic.maxHealth", scaledHealth ? healthScale : getMaxHealth(), 0.0D, Float.MAX_VALUE)).a("Max Health").a(true))); } }