Merge branch 'modular-property-system' into upstream-modular-property-system

# Conflicts:
#	plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java
This commit is contained in:
Pyrbu 2023-08-07 16:03:08 +02:00
commit 4e584b8d46
17 changed files with 431 additions and 75 deletions

@ -202,9 +202,9 @@ public class ZNpcsPlus extends JavaPlugin {
NpcEntryImpl entry = npcRegistry.create("debug_npc_" + i, world, type, new NpcLocation(i * 3, 200, 0, 0, 0));
entry.setProcessed(true);
NpcImpl npc = entry.getNpc();
npc.getHologram().addLineComponent(Component.text("Hello, World!", TextColor.color(255, 0, 0)));
npc.getHologram().addLineComponent(Component.text("Hello, World!", TextColor.color(0, 255, 0)));
npc.getHologram().addLineComponent(Component.text("Hello, World!", TextColor.color(0, 0, 255)));
npc.getHologram().addTextLineComponent(Component.text("Hello, World!", TextColor.color(255, 0, 0)));
npc.getHologram().addTextLineComponent(Component.text("Hello, World!", TextColor.color(0, 255, 0)));
npc.getHologram().addTextLineComponent(Component.text("Hello, World!", TextColor.color(0, 0, 255)));
i++;
}
}
@ -214,6 +214,7 @@ public class ZNpcsPlus extends JavaPlugin {
public void onDisable() {
NpcApiProvider.unregister();
for (Runnable runnable : shutdownTasks) runnable.run();
shutdownTasks.clear();
PacketEvents.getAPI().terminate();
}
@ -283,11 +284,14 @@ public class ZNpcsPlus extends JavaPlugin {
.addSubcommand("reload", new LoadAllCommand(npcRegistry))
.addSubcommand("import", new ImportCommand(npcRegistry, importerRegistry)))
.addSubcommand("holo", new MultiCommand(loadHelpMessage("holo"))
.addSubcommand("add", new HoloAddCommand(npcRegistry, textSerializer))
.addSubcommand("add", new HoloAddCommand(npcRegistry))
.addSubcommand("additem", new HoloAddItemCommand(npcRegistry))
.addSubcommand("delete", new HoloDeleteCommand(npcRegistry))
.addSubcommand("info", new HoloInfoCommand(npcRegistry))
.addSubcommand("insert", new HoloInsertCommand(npcRegistry, textSerializer))
.addSubcommand("set", new HoloSetCommand(npcRegistry, textSerializer))
.addSubcommand("insert", new HoloInsertCommand(npcRegistry))
.addSubcommand("insertitem", new HoloInsertItemCommand(npcRegistry))
.addSubcommand("set", new HoloSetCommand(npcRegistry))
.addSubcommand("setitem", new HoloSetItemCommand(npcRegistry))
.addSubcommand("offset", new HoloOffsetCommand(npcRegistry))
.addSubcommand("refreshdelay", new HoloRefreshDelayCommand(npcRegistry)))
.addSubcommand("action", new MultiCommand(loadHelpMessage("action"))

@ -4,22 +4,20 @@ 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.hologram.HologramImpl;
import lol.pyr.znpcsplus.hologram.HologramItem;
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.Collections;
import java.util.List;
public class HoloAddCommand implements CommandHandler {
private final NpcRegistryImpl registry;
private final LegacyComponentSerializer textSerializer;
public HoloAddCommand(NpcRegistryImpl registry, LegacyComponentSerializer textSerializer) {
public HoloAddCommand(NpcRegistryImpl registry) {
this.registry = registry;
this.textSerializer = textSerializer;
}
@Override
@ -27,7 +25,13 @@ public class HoloAddCommand implements CommandHandler {
context.setUsage(context.getLabel() + " holo add <id> <text>");
HologramImpl hologram = context.parse(NpcEntryImpl.class).getNpc().getHologram();
context.ensureArgsNotEmpty();
hologram.addLineComponent(textSerializer.deserialize(context.dumpAllArgs()));
String in = context.dumpAllArgs();
if (in.toLowerCase().startsWith("item:")) {
if (!HologramItem.ensureValidItemInput(in.substring(5))) {
context.halt(Component.text("The item input is invalid!", NamedTextColor.RED));
}
}
hologram.addLine(in);
context.send(Component.text("NPC line added!", NamedTextColor.GREEN));
}

@ -0,0 +1,39 @@
package lol.pyr.znpcsplus.commands.hologram;
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.hologram.HologramImpl;
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.entity.Player;
import java.util.Collections;
import java.util.List;
public class HoloAddItemCommand implements CommandHandler {
private final NpcRegistryImpl registry;
public HoloAddItemCommand(NpcRegistryImpl registry) {
this.registry = registry;
}
@Override
public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " holo additem <id>");
Player player = context.ensureSenderIsPlayer();
org.bukkit.inventory.ItemStack itemStack = player.getInventory().getItemInHand();
if (itemStack == null) context.halt(Component.text("You must be holding an item!", NamedTextColor.RED));
HologramImpl hologram = context.parse(NpcEntryImpl.class).getNpc().getHologram();
hologram.addItemLineStack(itemStack);
context.send(Component.text("NPC item line added!", NamedTextColor.GREEN));
}
@Override
public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(registry.getModifiableIds());
return Collections.emptyList();
}
}

@ -4,7 +4,6 @@ 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.hologram.HologramImpl;
import lol.pyr.znpcsplus.hologram.HologramLine;
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import net.kyori.adventure.text.Component;
@ -26,7 +25,11 @@ public class HoloInfoCommand implements CommandHandler {
NpcEntryImpl entry = context.parse(NpcEntryImpl.class);
HologramImpl hologram = entry.getNpc().getHologram();
Component component = Component.text("NPC Hologram Info of ID " + entry.getId() + ":", NamedTextColor.GREEN).appendNewline();
for (HologramLine line : hologram.getLines()) component = component.append(line.getText()).appendNewline();
for (int i = 0; i < hologram.getLines().size(); i++) {
component = component.append(Component.text(i + ") ", NamedTextColor.GREEN))
.append(Component.text(hologram.getLine(i), NamedTextColor.WHITE))
.appendNewline();
}
context.send(component);
}

@ -4,11 +4,11 @@ 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.hologram.HologramImpl;
import lol.pyr.znpcsplus.hologram.HologramItem;
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.Collections;
import java.util.List;
@ -16,11 +16,9 @@ import java.util.stream.Stream;
public class HoloInsertCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
private final LegacyComponentSerializer componentSerializer;
public HoloInsertCommand(NpcRegistryImpl npcRegistry, LegacyComponentSerializer componentSerializer) {
public HoloInsertCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
this.componentSerializer = componentSerializer;
}
@Override
@ -30,7 +28,13 @@ public class HoloInsertCommand implements CommandHandler {
int line = context.parse(Integer.class);
if (line < 0 || line >= hologram.getLines().size()) context.halt(Component.text("Invalid line number!", NamedTextColor.RED));
context.ensureArgsNotEmpty();
hologram.insertLineComponent(line, componentSerializer.deserialize(context.dumpAllArgs()));
String in = context.dumpAllArgs();
if (in.toLowerCase().startsWith("item:")) {
if (!HologramItem.ensureValidItemInput(in.substring(5))) {
context.halt(Component.text("The item input is invalid!", NamedTextColor.RED));
}
}
hologram.insertLine(line, in);
context.send(Component.text("NPC line inserted!", NamedTextColor.GREEN));
}

@ -0,0 +1,45 @@
package lol.pyr.znpcsplus.commands.hologram;
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.hologram.HologramImpl;
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.entity.Player;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
public class HoloInsertItemCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
public HoloInsertItemCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
}
@Override
public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " holo insertitem <id> <line>");
HologramImpl hologram = context.parse(NpcEntryImpl.class).getNpc().getHologram();
int line = context.parse(Integer.class);
if (line < 0 || line >= hologram.getLines().size()) context.halt(Component.text("Invalid line number!", NamedTextColor.RED));
Player player = context.ensureSenderIsPlayer();
org.bukkit.inventory.ItemStack itemStack = player.getInventory().getItemInHand();
if (itemStack == null) context.halt(Component.text("You must be holding an item!", NamedTextColor.RED));
hologram.insertItemLineStack(line, itemStack);
context.send(Component.text("NPC item line inserted!", NamedTextColor.GREEN));
}
@Override
public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
if (context.argSize() == 2) return context.suggestStream(Stream.iterate(0, n -> n + 1)
.limit(context.suggestionParse(0, NpcEntryImpl.class).getNpc().getHologram().getLines().size())
.map(String::valueOf));
return Collections.emptyList();
}
}

@ -8,7 +8,6 @@ import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.Collections;
import java.util.List;
@ -16,11 +15,9 @@ import java.util.stream.Stream;
public class HoloSetCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
private final LegacyComponentSerializer componentSerializer;
public HoloSetCommand(NpcRegistryImpl npcRegistry, LegacyComponentSerializer componentSerializer) {
public HoloSetCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
this.componentSerializer = componentSerializer;
}
@Override
@ -31,7 +28,7 @@ public class HoloSetCommand implements CommandHandler {
if (line < 0 || line >= hologram.getLines().size()) context.halt(Component.text("Invalid line number!", NamedTextColor.RED));
context.ensureArgsNotEmpty();
hologram.removeLine(line);
hologram.insertLineComponent(line, componentSerializer.deserialize(context.dumpAllArgs()));
hologram.insertLine(line, context.dumpAllArgs());
context.send(Component.text("NPC line set!", NamedTextColor.GREEN));
}
@ -42,8 +39,7 @@ public class HoloSetCommand implements CommandHandler {
HologramImpl hologram = context.suggestionParse(0, NpcEntryImpl.class).getNpc().getHologram();
if (context.argSize() == 2) return context.suggestStream(Stream.iterate(0, n -> n + 1)
.limit(hologram.getLines().size()).map(String::valueOf));
if (context.argSize() == 3) return context.suggestLiteral(componentSerializer.serialize(
hologram.getLineComponent(context.suggestionParse(1, Integer.class))));
if (context.argSize() == 3) return context.suggestLiteral(hologram.getLine(context.suggestionParse(1, Integer.class)));
}
return Collections.emptyList();
}

@ -0,0 +1,48 @@
package lol.pyr.znpcsplus.commands.hologram;
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.hologram.HologramImpl;
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.entity.Player;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
public class HoloSetItemCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
public HoloSetItemCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
}
@Override
public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " holo setitem <id> <line>");
HologramImpl hologram = context.parse(NpcEntryImpl.class).getNpc().getHologram();
int line = context.parse(Integer.class);
if (line < 0 || line >= hologram.getLines().size()) context.halt(Component.text("Invalid line number!", NamedTextColor.RED));
Player player = context.ensureSenderIsPlayer();
org.bukkit.inventory.ItemStack itemStack = player.getInventory().getItemInHand();
if (itemStack == null) context.halt(Component.text("You must be holding an item!", NamedTextColor.RED));
hologram.removeLine(line);
hologram.insertItemLineStack(line, itemStack);
context.send(Component.text("NPC item line set!", NamedTextColor.GREEN));
}
@Override
public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
if (context.argSize() >= 2) {
HologramImpl hologram = context.suggestionParse(0, NpcEntryImpl.class).getNpc().getHologram();
if (context.argSize() == 2) return context.suggestStream(Stream.iterate(0, n -> n + 1)
.limit(hologram.getLines().size()).map(String::valueOf));
}
return Collections.emptyList();
}
}

@ -82,7 +82,7 @@ public class CitizensImporter implements DataImporter {
world = Bukkit.getWorlds().get(0).getName();
}
NpcImpl npc = new NpcImpl(uuid, propertyRegistry, configManager, packetFactory, textSerializer, world, typeRegistry.getByName("armor_stand"), new NpcLocation(0, 0, 0, 0, 0));
npc.getHologram().addLineComponent(textSerializer.deserialize(name));
npc.getHologram().addTextLineComponent(textSerializer.deserialize(name));
ConfigurationSection traits = npcSection.getConfigurationSection("traits");
if (traits != null) {
for (String traitName : traits.getKeys(false)) {

@ -106,7 +106,7 @@ public class ZNpcImporter implements DataImporter {
hologram.setOffset(model.getHologramHeight());
for (String raw : model.getHologramLines()) {
Component line = textSerializer.deserialize(raw);
hologram.addLineComponent(line);
hologram.addTextLineComponent(line);
}
for (ZNpcsAction action : model.getClickActions()) {

@ -224,6 +224,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
register(new GlowProperty(packetFactory));
register(new SimpleBitsetProperty("fire", 0, 0x01));
register(new SimpleBitsetProperty("invisible", 0, 0x20));
register(new HoloItemProperty());
linkProperties("glow", "fire", "invisible");
register(new SimpleBooleanProperty("silent", 4, false, legacyBooleans));

@ -0,0 +1,24 @@
package lol.pyr.znpcsplus.entity.properties;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.entity.PacketEntity;
import org.bukkit.entity.Player;
import java.util.Map;
public class HoloItemProperty extends EntityPropertyImpl<ItemStack> {
public HoloItemProperty() {
super("holo_item", null, ItemStack.class);
setPlayerModifiable(false);
}
@Override
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
properties.put(8, newEntityData(8, EntityDataTypes.ITEMSTACK, entity.getProperty(this)));
properties.put(5, newEntityData(5, EntityDataTypes.BOOLEAN, true));
}
}

@ -1,11 +1,13 @@
package lol.pyr.znpcsplus.hologram;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import lol.pyr.znpcsplus.api.hologram.Hologram;
import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.util.Viewable;
import lol.pyr.znpcsplus.util.NpcLocation;
import lol.pyr.znpcsplus.util.Viewable;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.entity.Player;
@ -24,7 +26,7 @@ public class HologramImpl extends Viewable implements Hologram {
private long refreshDelay = -1;
private long lastRefresh = System.currentTimeMillis();
private NpcLocation location;
private final List<HologramLine> lines = new ArrayList<>();
private final List<HologramLine<?>> lines = new ArrayList<>();
public HologramImpl(EntityPropertyRegistryImpl propertyRegistry, ConfigManager configManager, PacketFactory packetFactory, LegacyComponentSerializer textSerializer, NpcLocation location) {
this.propertyRegistry = propertyRegistry;
@ -34,32 +36,59 @@ public class HologramImpl extends Viewable implements Hologram {
this.location = location;
}
public void addLineComponent(Component line) {
HologramLine newLine = new HologramLine(propertyRegistry, packetFactory, null, line);
public void addTextLineComponent(Component line) {
HologramText newLine = new HologramText(propertyRegistry, packetFactory, null, line);
lines.add(newLine);
relocateLines(newLine);
for (Player viewer : getViewers()) newLine.show(viewer.getPlayer());
}
public void addTextLine(String line) {
addTextLineComponent(textSerializer.deserialize(line));
}
public void addItemLineStack(org.bukkit.inventory.ItemStack item) {
addItemLinePEStack(SpigotConversionUtil.fromBukkitItemStack(item));
}
public void addItemLine(String serializedItem) {
addItemLinePEStack(HologramItem.deserialize(serializedItem));
}
public void addItemLinePEStack(ItemStack item) {
HologramItem newLine = new HologramItem(propertyRegistry, packetFactory, null, item);
lines.add(newLine);
relocateLines(newLine);
for (Player viewer : getViewers()) newLine.show(viewer.getPlayer());
}
public void addLine(String line) {
addLineComponent(textSerializer.deserialize(line));
if (line.toLowerCase().startsWith("item:")) {
addItemLine(line.substring(5));
} else {
addTextLine(line);
}
}
public Component getLineComponent(int index) {
return lines.get(index).getText();
public Component getLineTextComponent(int index) {
return ((HologramText) lines.get(index)).getValue();
}
public String getLine(int index) {
return textSerializer.serialize(getLineComponent(index));
if (lines.get(index) instanceof HologramItem) {
return ((HologramItem) lines.get(index)).serialize();
} else {
return textSerializer.serialize(getLineTextComponent(index));
}
}
public void removeLine(int index) {
HologramLine line = lines.remove(index);
HologramLine<?> line = lines.remove(index);
for (Player viewer : getViewers()) line.hide(viewer);
relocateLines();
}
public List<HologramLine> getLines() {
public List<HologramLine<?>> getLines() {
return Collections.unmodifiableList(lines);
}
@ -68,25 +97,48 @@ public class HologramImpl extends Viewable implements Hologram {
lines.clear();
}
public void insertLineComponent(int index, Component line) {
HologramLine newLine = new HologramLine(propertyRegistry, packetFactory, null, line);
public void insertTextLineComponent(int index, Component line) {
HologramText newLine = new HologramText(propertyRegistry, packetFactory, null, line);
lines.add(index, newLine);
relocateLines(newLine);
for (Player viewer : getViewers()) newLine.show(viewer.getPlayer());
}
public void insertTextLine(int index, String line) {
insertTextLineComponent(index, textSerializer.deserialize(line));
}
public void insertItemLineStack(int index, org.bukkit.inventory.ItemStack item) {
insertItemLinePEStack(index, SpigotConversionUtil.fromBukkitItemStack(item));
}
public void insertItemLinePEStack(int index, ItemStack item) {
HologramItem newLine = new HologramItem(propertyRegistry, packetFactory, null, item);
lines.add(index, newLine);
relocateLines(newLine);
for (Player viewer : getViewers()) newLine.show(viewer.getPlayer());
}
public void insertItemLine(int index, String item) {
insertItemLinePEStack(index, HologramItem.deserialize(item));
}
public void insertLine(int index, String line) {
insertLineComponent(index, textSerializer.deserialize(line));
if (line.toLowerCase().startsWith("item:")) {
insertItemLine(index, line.substring(5));
} else {
insertTextLine(index, line);
}
}
@Override
protected void UNSAFE_show(Player player) {
for (HologramLine line : lines) line.show(player);
for (HologramLine<?> line : lines) line.show(player);
}
@Override
protected void UNSAFE_hide(Player player) {
for (HologramLine line : lines) line.hide(player);
for (HologramLine<?> line : lines) line.hide(player);
}
public long getRefreshDelay() {
@ -103,7 +155,7 @@ public class HologramImpl extends Viewable implements Hologram {
public void refresh() {
lastRefresh = System.currentTimeMillis();
for (HologramLine line : lines) for (Player viewer : getViewers()) line.refreshMeta(viewer);
for (HologramLine<?> line : lines) for (Player viewer : getViewers()) line.refreshMeta(viewer);
}
public void setLocation(NpcLocation location) {
@ -115,10 +167,10 @@ public class HologramImpl extends Viewable implements Hologram {
relocateLines(null);
}
private void relocateLines(HologramLine newLine) {
private void relocateLines(HologramLine<?> newLine) {
final double lineSpacing = configManager.getConfig().lineSpacing();
double height = location.getY() + (lines.size() - 1) * lineSpacing + getOffset();
for (HologramLine line : lines) {
for (HologramLine<?> line : lines) {
line.setLocation(location.withY(height), line == newLine ? Collections.emptySet() : getViewers());
height -= lineSpacing;
}

@ -0,0 +1,111 @@
package lol.pyr.znpcsplus.hologram;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
import com.github.retrooper.packetevents.protocol.nbt.NBTNumber;
import com.github.retrooper.packetevents.protocol.nbt.codec.NBTCodec;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import lol.pyr.znpcsplus.api.entity.EntityProperty;
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.util.NpcLocation;
import org.bukkit.entity.Player;
import java.util.Collection;
public class HologramItem extends HologramLine<ItemStack> {
public HologramItem(EntityPropertyRegistryImpl propertyRegistry, PacketFactory packetFactory, NpcLocation location, ItemStack item) {
super(item, packetFactory, EntityTypes.ITEM, location);
addProperty(propertyRegistry.getByName("holo_item"));
}
@SuppressWarnings("unchecked")
@Override
public <T> T getProperty(EntityProperty<T> key) {
if (key.getName().equalsIgnoreCase("holo_item")) return (T) getValue();
return super.getProperty(key);
}
@Override
public void setLocation(NpcLocation location, Collection<Player> viewers) {
super.setLocation(location.withY(location.getY() + 2.05), viewers);
}
public static boolean ensureValidItemInput(String in) {
if (in == null || in.isEmpty()) {
return false;
}
int indexOfNbt = in.indexOf("{");
if (indexOfNbt != -1) {
String typeName = in.substring(0, indexOfNbt);
ItemType type = ItemTypes.getByName("minecraft:" + typeName.toLowerCase());
if (type == null) {
return false;
}
String nbtString = in.substring(indexOfNbt);
return ensureValidNbt(nbtString);
} else {
ItemType type = ItemTypes.getByName("minecraft:" + in.toLowerCase());
return type != null;
}
}
private static boolean ensureValidNbt(String nbtString) {
JsonElement nbtJson;
try {
nbtJson = JsonParser.parseString(nbtString);
} catch (JsonSyntaxException e) {
return false;
}
try {
NBTCodec.jsonToNBT(nbtJson);
} catch (Exception ignored) {
return false;
}
return true;
}
public static ItemStack deserialize(String serializedItem) {
int indexOfNbt = serializedItem.indexOf("{");
String typeName = serializedItem;
int amount = 1;
NBTCompound nbt = new NBTCompound();
if (indexOfNbt != -1) {
typeName = serializedItem.substring(0, indexOfNbt);
String nbtString = serializedItem.substring(indexOfNbt);
JsonElement nbtJson = null;
try {
nbtJson = JsonParser.parseString(nbtString);
} catch (Exception ignored) {
}
if (nbtJson != null) {
nbt = (NBTCompound) NBTCodec.jsonToNBT(nbtJson);
NBTNumber nbtAmount = nbt.getNumberTagOrNull("Count");
if (nbtAmount != null) {
nbt.removeTag("Count");
amount = nbtAmount.getAsInt();
if (amount <= 0) amount = 1;
if (amount > 127) amount = 127;
}
}
}
ItemType type = ItemTypes.getByName("minecraft:" + typeName.toLowerCase());
if (type == null) type = ItemTypes.STONE;
return ItemStack.builder().type(type).amount(amount).nbt(nbt).build();
}
public String serialize() {
NBTCompound nbt = getValue().getNBT();
if (nbt == null) nbt = new NBTCompound();
if (getValue().getAmount() > 1) nbt.setTag("Count", new NBTInt(getValue().getAmount()));
if (nbt.isEmpty()) return "item:" + getValue().getType().getName().toString().replace("minecraft:", "");
return "item:" + getValue().getType().getName().toString().replace("minecraft:", "") + NBTCodec.nbtToJson(nbt, true);
}
}

@ -1,76 +1,73 @@
package lol.pyr.znpcsplus.hologram;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import lol.pyr.znpcsplus.api.entity.EntityProperty;
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.util.NpcLocation;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
public class HologramLine implements PropertyHolder {
private Component text;
private final PacketEntity armorStand;
public class HologramLine<M> implements PropertyHolder {
private M value;
private final PacketEntity entity;
private final Set<EntityProperty<?>> properties;
public HologramLine(EntityPropertyRegistryImpl propertyRegistry, PacketFactory packetFactory, NpcLocation location, Component text) {
this.text = text;
public HologramLine(M value, PacketFactory packetFactory, EntityType type, NpcLocation location) {
this.value = value;
this.entity = new PacketEntity(packetFactory, this, type, location);
this.properties = new HashSet<>();
this.properties.add(propertyRegistry.getByName("name"));
this.properties.add(propertyRegistry.getByName("invisible"));
armorStand = new PacketEntity(packetFactory, this, EntityTypes.ARMOR_STAND, location);
}
public Component getText() {
return text;
public M getValue() {
return value;
}
public void setText(Component text) {
this.text = text;
public void setValue(M value) {
this.value = value;
}
public void refreshMeta(Player player) {
armorStand.refreshMeta(player);
entity.refreshMeta(player);
}
protected void show(Player player) {
armorStand.spawn(player);
entity.spawn(player);
}
protected void hide(Player player) {
armorStand.despawn(player);
entity.despawn(player);
}
public void setLocation(NpcLocation location, Collection<Player> viewers) {
armorStand.setLocation(location, viewers);
entity.setLocation(location, viewers);
}
public int getEntityId() {
return armorStand.getEntityId();
return entity.getEntityId();
}
public <T> void addProperty(EntityProperty<T> property) {
properties.add(property);
}
@SuppressWarnings("unchecked")
@Override
public <T> T getProperty(EntityProperty<T> key) {
if (key.getName().equalsIgnoreCase("invisible")) return (T) Boolean.TRUE;
if (key.getName().equalsIgnoreCase("name")) return (T) text;
return key.getDefaultValue();
}
@Override
public boolean hasProperty(EntityProperty<?> key) {
return key.getName().equalsIgnoreCase("name") || key.getName().equalsIgnoreCase("invisible");
return properties.contains(key);
}
@Override
public <T> void setProperty(EntityProperty<T> key, T value) {
throw new UnsupportedOperationException("Can't set properties on a hologram");
throw new UnsupportedOperationException("Can't set properties on a hologram line");
}
@Override

@ -0,0 +1,30 @@
package lol.pyr.znpcsplus.hologram;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import lol.pyr.znpcsplus.api.entity.EntityProperty;
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.util.NpcLocation;
import net.kyori.adventure.text.Component;
public class HologramText extends HologramLine<Component> {
public HologramText(EntityPropertyRegistryImpl propertyRegistry, PacketFactory packetFactory, NpcLocation location, Component text) {
super(text, packetFactory, EntityTypes.ARMOR_STAND, location);
addProperty(propertyRegistry.getByName("name"));
addProperty(propertyRegistry.getByName("invisible"));
}
@SuppressWarnings("unchecked")
@Override
public <T> T getProperty(EntityProperty<T> key) {
if (key.getName().equalsIgnoreCase("invisible")) return (T) Boolean.TRUE;
if (key.getName().equalsIgnoreCase("name")) return (T) getValue();
return super.getProperty(key);
}
@Override
public boolean hasProperty(EntityProperty<?> key) {
return key.getName().equalsIgnoreCase("name") || key.getName().equalsIgnoreCase("invisible");
}
}

@ -6,7 +6,6 @@ import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
import lol.pyr.znpcsplus.entity.PropertySerializer;
import lol.pyr.znpcsplus.hologram.HologramImpl;
import lol.pyr.znpcsplus.hologram.HologramLine;
import lol.pyr.znpcsplus.interaction.ActionRegistry;
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcImpl;
@ -14,7 +13,6 @@ import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.storage.NpcStorage;
import lol.pyr.znpcsplus.util.NpcLocation;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
@ -73,7 +71,7 @@ public class YamlStorage implements NpcStorage {
HologramImpl hologram = npc.getHologram();
hologram.setOffset(config.getDouble("hologram.offset", 0.0));
hologram.setRefreshDelay(config.getLong("hologram.refresh-delay", -1));
for (String line : config.getStringList("hologram.lines")) hologram.addLineComponent(MiniMessage.miniMessage().deserialize(line));
for (String line : config.getStringList("hologram.lines")) hologram.addLine(line);
for (String s : config.getStringList("actions")) npc.addAction(actionRegistry.deserialize(s));
NpcEntryImpl entry = new NpcEntryImpl(config.getString("id"), npc);
@ -112,8 +110,8 @@ public class YamlStorage implements NpcStorage {
if (hologram.getOffset() != 0.0) config.set("hologram.offset", hologram.getOffset());
if (hologram.getRefreshDelay() != -1) config.set("hologram.refresh-delay", hologram.getRefreshDelay());
List<String> lines = new ArrayList<>(npc.getHologram().getLines().size());
for (HologramLine line : hologram.getLines()) {
lines.add(MiniMessage.miniMessage().serialize(line.getText()));
for (int i = 0; i < hologram.getLines().size(); i++) {
lines.add(hologram.getLine(i));
}
config.set("hologram.lines", lines);
config.set("actions", npc.getActions().stream()