Merge pull request #166 from D3v1s0m/feat/health_attribute
Health properties and version command
This commit is contained in:
commit
f1cedb3836
12 changed files with 222 additions and 0 deletions
|
@ -30,10 +30,28 @@ dependencies {
|
|||
implementation project(":api")
|
||||
}
|
||||
|
||||
ext {
|
||||
gitBranch = System.getenv('GIT_BRANCH') ?: ''
|
||||
gitCommitHash = System.getenv('GIT_COMMIT') ?: ''
|
||||
buildId = System.getenv('BUILD_ID') ?: ''
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
archivesBaseName = "ZNPCsPlus"
|
||||
archiveClassifier.set ""
|
||||
|
||||
manifest {
|
||||
if (gitBranch?.trim()) {
|
||||
attributes('Git-Branch': gitBranch)
|
||||
}
|
||||
if (gitCommitHash?.trim()) {
|
||||
attributes('Git-Commit': gitCommitHash)
|
||||
}
|
||||
if (buildId?.trim()) {
|
||||
attributes('Build-Id': buildId)
|
||||
}
|
||||
}
|
||||
|
||||
relocate "org.objectweb.asm", "lol.pyr.znpcsplus.libraries.asm"
|
||||
relocate "me.lucko.jarrelocator", "lol.pyr.znpcsplus.libraries.jarrelocator"
|
||||
|
||||
|
|
|
@ -342,6 +342,7 @@ public class ZNpcsPlus {
|
|||
.addSubcommand("delete", new ActionDeleteCommand(npcRegistry))
|
||||
.addSubcommand("edit", new ActionEditCommand(npcRegistry, actionRegistry))
|
||||
.addSubcommand("list", new ActionListCommand(npcRegistry)))
|
||||
.addSubcommand("version", new VersionCommand(this))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package lol.pyr.znpcsplus.commands;
|
||||
|
||||
import lol.pyr.director.adventure.command.CommandContext;
|
||||
import lol.pyr.director.adventure.command.CommandHandler;
|
||||
import lol.pyr.director.common.command.CommandExecutionException;
|
||||
import lol.pyr.znpcsplus.ZNpcsPlus;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public class VersionCommand implements CommandHandler {
|
||||
|
||||
private final String pluginVersion;
|
||||
private final String gitBranch;
|
||||
private final String gitCommitHash;
|
||||
private final String buildId;
|
||||
|
||||
public VersionCommand(ZNpcsPlus plugin) {
|
||||
pluginVersion = plugin.getDescription().getVersion();
|
||||
String gitBranch = "";
|
||||
String gitCommitHash = "";
|
||||
String buildId = "";
|
||||
try {
|
||||
URL jarUrl = getClass().getProtectionDomain().getCodeSource().getLocation();
|
||||
JarFile jarFile = new JarFile(jarUrl.toURI().getPath());
|
||||
Attributes attributes = jarFile.getManifest().getMainAttributes();
|
||||
gitBranch = attributes.getValue("Git-Branch");
|
||||
gitCommitHash = attributes.getValue("Git-Commit-Hash");
|
||||
buildId = attributes.getValue("Build-Id");
|
||||
} catch (IOException | URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.gitBranch = gitBranch;
|
||||
this.gitCommitHash = gitCommitHash;
|
||||
this.buildId = buildId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(CommandContext context) throws CommandExecutionException {
|
||||
|
||||
StringBuilder versionBuilder = new StringBuilder("This server is running ZNPCsPlus version ").append(pluginVersion);
|
||||
if (gitBranch != null && !gitBranch.isEmpty()) {
|
||||
versionBuilder.append("-").append(gitBranch);
|
||||
}
|
||||
if (gitCommitHash != null && !gitCommitHash.isEmpty()) {
|
||||
versionBuilder.append("@").append(gitCommitHash);
|
||||
}
|
||||
if (buildId != null && !buildId.isEmpty()) {
|
||||
versionBuilder.append(" (Build #").append(buildId).append(")");
|
||||
}
|
||||
|
||||
String version = versionBuilder.toString();
|
||||
|
||||
context.send(Component.text(version, NamedTextColor.GREEN)
|
||||
.hoverEvent(Component.text("Click to copy version to clipboard"))
|
||||
.clickEvent(ClickEvent.copyToClipboard(version)));
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import lol.pyr.director.adventure.command.CommandHandler;
|
|||
import lol.pyr.director.common.command.CommandExecutionException;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.entity.properties.attributes.AttributeProperty;
|
||||
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||
|
@ -124,6 +125,15 @@ public class PropertySetCommand implements CommandHandler {
|
|||
value = context.parse(type);
|
||||
valueName = value == null ? "NONE" : ((Vector3i) value).toPrettyString();
|
||||
}
|
||||
else if (property instanceof AttributeProperty) {
|
||||
value = context.parse(type);
|
||||
if ((double) value < ((AttributeProperty) property).getMinValue() || (double) value > ((AttributeProperty) property).getMaxValue()) {
|
||||
double sanitizedValue = ((AttributeProperty) property).sanitizeValue((double) value);
|
||||
context.send(Component.text("WARNING: Value " + value + " is out of range for property " + property.getName() + ", setting to " + sanitizedValue, NamedTextColor.YELLOW));
|
||||
value = sanitizedValue;
|
||||
}
|
||||
valueName = String.valueOf(value);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
value = context.parse(type);
|
||||
|
|
|
@ -2,6 +2,7 @@ package lol.pyr.znpcsplus.entity;
|
|||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
|
||||
import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
|
@ -15,6 +16,7 @@ import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry;
|
|||
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
|
||||
import lol.pyr.znpcsplus.config.ConfigManager;
|
||||
import lol.pyr.znpcsplus.entity.properties.*;
|
||||
import lol.pyr.znpcsplus.entity.properties.attributes.AttributeProperty;
|
||||
import lol.pyr.znpcsplus.entity.properties.villager.VillagerLevelProperty;
|
||||
import lol.pyr.znpcsplus.entity.properties.villager.VillagerProfessionProperty;
|
||||
import lol.pyr.znpcsplus.entity.properties.villager.VillagerTypeProperty;
|
||||
|
@ -154,6 +156,16 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
linkProperties("glow", "fire", "invisible");
|
||||
register(new BooleanProperty("silent", 4, false, legacyBooleans));
|
||||
|
||||
// Attribute Max Health
|
||||
register(new AttributeProperty(packetFactory, "attribute_max_health", Attributes.MAX_HEALTH));
|
||||
|
||||
// Health - LivingEntity
|
||||
int healthIndex = 6;
|
||||
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) healthIndex = 9;
|
||||
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) healthIndex = 8;
|
||||
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) healthIndex = 7;
|
||||
register(new HealthProperty(healthIndex));
|
||||
|
||||
final int tameableIndex;
|
||||
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) tameableIndex = 17;
|
||||
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) tameableIndex = 16;
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package lol.pyr.znpcsplus.entity.properties;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
|
||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class HealthProperty extends EntityPropertyImpl<Float> {
|
||||
private final int index;
|
||||
|
||||
public HealthProperty(int index) {
|
||||
super("health", 20f, Float.class);
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
|
||||
float health = entity.getProperty(this);
|
||||
health = (float) Attributes.MAX_HEALTH.sanitizeValue(health);
|
||||
properties.put(index, new EntityData(index, EntityDataTypes.FLOAT, health));
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package lol.pyr.znpcsplus.entity.properties.attributes;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attribute;
|
||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import lol.pyr.znpcsplus.packets.PacketFactory;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AttributeProperty extends EntityPropertyImpl<Double> {
|
||||
private final PacketFactory packetFactory;
|
||||
private final Attribute attribute;
|
||||
|
||||
public AttributeProperty(PacketFactory packetFactory, String name, Attribute attribute) {
|
||||
super(name, attribute.getDefaultValue(), Double.class);
|
||||
this.packetFactory = packetFactory;
|
||||
this.attribute = attribute;
|
||||
}
|
||||
|
||||
public double getMinValue() {
|
||||
return attribute.getMinValue();
|
||||
}
|
||||
|
||||
public double getMaxValue() {
|
||||
return attribute.getMaxValue();
|
||||
}
|
||||
|
||||
public double sanitizeValue(double value) {
|
||||
return attribute.sanitizeValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EntityData> applyStandalone(Player player, PacketEntity packetEntity, boolean isSpawned) {
|
||||
apply(player, packetEntity, isSpawned, Collections.emptyList());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
|
||||
}
|
||||
|
||||
public void apply(Player player, PacketEntity entity, boolean isSpawned, List<WrapperPlayServerUpdateAttributes.Property> properties) {
|
||||
Double value = entity.getProperty(this);
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
value = attribute.sanitizeValue(value);
|
||||
if (isSpawned) {
|
||||
packetFactory.sendAttribute(player, entity, new WrapperPlayServerUpdateAttributes.Property(attribute, value, Collections.emptyList()));
|
||||
} else {
|
||||
properties.add(new WrapperPlayServerUpdateAttributes.Property(attribute, value, Collections.emptyList()));
|
||||
}
|
||||
}
|
||||
|
||||
public Attribute getAttribute() {
|
||||
return attribute;
|
||||
}
|
||||
}
|
|
@ -120,6 +120,9 @@ public class NpcTypeImpl implements NpcType {
|
|||
"player_knockback_horizontal", "player_knockback_cooldown", "player_knockback_sound", "player_knockback_sound_name",
|
||||
"player_knockback_sound_volume", "player_knockback_sound_pitch");
|
||||
if (!type.equals(EntityTypes.PLAYER)) addProperties("dinnerbone");
|
||||
if (EntityTypes.isTypeInstanceOf(type, EntityTypes.LIVINGENTITY)) {
|
||||
addProperties("health", "attribute_max_health");
|
||||
}
|
||||
// TODO: make this look nicer after completing the rest of the properties
|
||||
if (version.isNewerThanOrEquals(ServerVersion.V_1_9)) addProperties("glow");
|
||||
if (version.isNewerThanOrEquals(ServerVersion.V_1_14)) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package lol.pyr.znpcsplus.packets;
|
|||
|
||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
|
||||
import com.github.retrooper.packetevents.protocol.player.Equipment;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
|
||||
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import lol.pyr.znpcsplus.util.NamedColor;
|
||||
|
@ -25,4 +26,6 @@ public interface PacketFactory {
|
|||
void sendHeadRotation(Player player, PacketEntity entity, float yaw, float pitch);
|
||||
void sendHandSwing(Player player, PacketEntity entity, boolean offHand);
|
||||
void setPassengers(Player player, int vehicle, int... passengers);
|
||||
void sendAllAttributes(Player player, PacketEntity entity, PropertyHolder properties);
|
||||
void sendAttribute(Player player, PacketEntity entity, WrapperPlayServerUpdateAttributes.Property property);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package lol.pyr.znpcsplus.packets;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEventsAPI;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
|
||||
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||
|
@ -27,6 +28,7 @@ public class V1_17PacketFactory extends V1_8PacketFactory {
|
|||
sendPacket(player, new WrapperPlayServerSpawnEntity(entity.getEntityId(), Optional.of(entity.getUuid()), entity.getType(),
|
||||
npcLocationToVector(location), location.getPitch(), location.getYaw(), location.getYaw(), 0, Optional.of(new Vector3d())));
|
||||
sendAllMetadata(player, entity, properties);
|
||||
if (EntityTypes.isTypeInstanceOf(entity.getType(), EntityTypes.LIVINGENTITY)) sendAllAttributes(player, entity, properties);
|
||||
createTeam(player, entity, properties.getProperty(propertyRegistry.getByName("glow", NamedColor.class)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ public class V1_20_2PacketFactory extends V1_19_3PacketFactory {
|
|||
npcLocationToVector(location), location.getPitch(), location.getYaw(), location.getYaw(), 0, Optional.of(new Vector3d())));
|
||||
sendPacket(player, new WrapperPlayServerEntityHeadLook(entity.getEntityId(), location.getYaw()));
|
||||
sendAllMetadata(player, entity, properties);
|
||||
sendAllAttributes(player, entity, properties);
|
||||
scheduler.runLaterAsync(() -> removeTabPlayer(player, entity), configManager.getConfig().tabHideDelay());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import lol.pyr.znpcsplus.config.ConfigManager;
|
|||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import lol.pyr.znpcsplus.entity.properties.attributes.AttributeProperty;
|
||||
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||
import lol.pyr.znpcsplus.skin.BaseSkinDescriptor;
|
||||
import lol.pyr.znpcsplus.util.NamedColor;
|
||||
|
@ -55,6 +56,7 @@ public class V1_8PacketFactory implements PacketFactory {
|
|||
entity.getUuid(), npcLocationToVector(location), location.getYaw(), location.getPitch(), Collections.emptyList()));
|
||||
sendPacket(player, new WrapperPlayServerEntityHeadLook(entity.getEntityId(), location.getYaw()));
|
||||
sendAllMetadata(player, entity, properties);
|
||||
sendAllAttributes(player, entity, properties);
|
||||
scheduler.runLaterAsync(() -> removeTabPlayer(player, entity), configManager.getConfig().tabHideDelay());
|
||||
});
|
||||
}
|
||||
|
@ -70,6 +72,7 @@ public class V1_8PacketFactory implements PacketFactory {
|
|||
new WrapperPlayServerSpawnEntity(entity.getEntityId(), Optional.of(entity.getUuid()), entity.getType(), npcLocationToVector(location),
|
||||
location.getPitch(), location.getYaw(), location.getYaw(), 0, Optional.empty()));
|
||||
sendAllMetadata(player, entity, properties);
|
||||
if (EntityTypes.isTypeInstanceOf(type, EntityTypes.LIVINGENTITY)) sendAllAttributes(player, entity, properties);
|
||||
createTeam(player, entity, properties.getProperty(propertyRegistry.getByName("glow", NamedColor.class)));
|
||||
}
|
||||
|
||||
|
@ -187,4 +190,19 @@ public class V1_8PacketFactory implements PacketFactory {
|
|||
WrapperPlayServerEntityAnimation.EntityAnimationType.SWING_OFF_HAND :
|
||||
WrapperPlayServerEntityAnimation.EntityAnimationType.SWING_MAIN_ARM));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAllAttributes(Player player, PacketEntity entity, PropertyHolder properties) {
|
||||
List<WrapperPlayServerUpdateAttributes.Property> attributesList = new ArrayList<>();
|
||||
properties.getAppliedProperties()
|
||||
.stream()
|
||||
.filter(property -> property instanceof AttributeProperty)
|
||||
.forEach(property -> ((AttributeProperty) property).apply(player, entity, false, attributesList));
|
||||
sendPacket(player, new WrapperPlayServerUpdateAttributes(entity.getEntityId(), attributesList));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAttribute(Player player, PacketEntity entity, WrapperPlayServerUpdateAttributes.Property property) {
|
||||
sendPacket(player, new WrapperPlayServerUpdateAttributes(entity.getEntityId(), Collections.singletonList(property)));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue