start work on persistence
This commit is contained in:
parent
464b5716fa
commit
53ad7a73d6
29 changed files with 548 additions and 210 deletions
|
@ -6,6 +6,7 @@ plugins {
|
|||
dependencies {
|
||||
compileOnly "org.spigotmc:spigot-api:1.19.4-R0.1-SNAPSHOT"
|
||||
compileOnly "net.kyori:adventure-platform-bukkit:4.3.0"
|
||||
compileOnly "net.kyori:adventure-text-minimessage:4.13.1"
|
||||
compileOnly "com.github.retrooper.packetevents:spigot:2.0.0-SNAPSHOT"
|
||||
}
|
||||
|
||||
|
|
|
@ -1,45 +1,5 @@
|
|||
package lol.pyr.znpcsplus.api.entity;
|
||||
|
||||
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class EntityProperty<T> {
|
||||
private final String name;
|
||||
private final T defaultValue;
|
||||
|
||||
public EntityProperty(String name) {
|
||||
this(name, null);
|
||||
}
|
||||
|
||||
public EntityProperty(String name, T defaultValue) {
|
||||
this.name = name.toUpperCase();
|
||||
this.defaultValue = defaultValue;
|
||||
BY_NAME.put(this.name, this);
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public T getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private final static Map<String, EntityProperty<?>> BY_NAME = new HashMap<>();
|
||||
|
||||
public static EntityProperty<?> getByName(String name) {
|
||||
return BY_NAME.get(name.toUpperCase());
|
||||
}
|
||||
|
||||
public static EntityProperty<Boolean> SKIN_LAYERS = new EntityProperty<>("skin_layers", true);
|
||||
public static EntityProperty<SkinDescriptor> SKIN = new EntityProperty<>("skin");
|
||||
public static EntityProperty<NamedTextColor> GLOW = new EntityProperty<>("glow");
|
||||
public static EntityProperty<Boolean> FIRE = new EntityProperty<>("fire", false);
|
||||
public static EntityProperty<Boolean> INVISIBLE = new EntityProperty<>("invisible", false);
|
||||
public static EntityProperty<Boolean> SILENT = new EntityProperty<>("silent", false);
|
||||
public static EntityProperty<Component> NAME = new EntityProperty<>("name");
|
||||
}
|
||||
public interface EntityProperty<T> {
|
||||
T getDefaultValue();
|
||||
}
|
||||
|
|
|
@ -1,114 +1,4 @@
|
|||
package lol.pyr.znpcsplus.api.npc;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class NpcType {
|
||||
private final static Map<String, NpcType> BY_NAME = new HashMap<>();
|
||||
|
||||
public static Collection<NpcType> values() {
|
||||
return BY_NAME.values();
|
||||
}
|
||||
|
||||
public static NpcType byName(String name) {
|
||||
return BY_NAME.get(name.toUpperCase());
|
||||
}
|
||||
|
||||
private final EntityType type;
|
||||
private final Set<EntityProperty<?>> allowedProperties;
|
||||
private final String name;
|
||||
private final double hologramOffset;
|
||||
|
||||
private NpcType(String name, EntityType type, double hologramOffset, Set<EntityProperty<?>> allowedProperties) {
|
||||
this.name = name.toUpperCase();
|
||||
this.type = type;
|
||||
this.hologramOffset = hologramOffset;
|
||||
this.allowedProperties = allowedProperties;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public EntityType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public double getHologramOffset() {
|
||||
return hologramOffset;
|
||||
}
|
||||
|
||||
public Set<EntityProperty<?>> getAllowedProperties() {
|
||||
return allowedProperties;
|
||||
}
|
||||
|
||||
private static NpcType define(Builder builder) {
|
||||
return define(builder.build());
|
||||
}
|
||||
|
||||
private static NpcType define(NpcType type) {
|
||||
BY_NAME.put(type.getName(), type);
|
||||
return type;
|
||||
}
|
||||
|
||||
public static final NpcType PLAYER = define(
|
||||
new Builder("player", EntityTypes.PLAYER)
|
||||
.addProperties(EntityProperty.SKIN, EntityProperty.SKIN_LAYERS)
|
||||
.setHologramOffset(-0.45D));
|
||||
|
||||
public static final NpcType CREEPER = define(
|
||||
new Builder("creeper", EntityTypes.CREEPER)
|
||||
.setHologramOffset(-0.6D));
|
||||
|
||||
public static final NpcType ZOMBIE = define(
|
||||
new Builder("zombie", EntityTypes.ZOMBIE)
|
||||
.setHologramOffset(-0.3D));
|
||||
|
||||
public static final NpcType SKELETON = define(
|
||||
new Builder("skeleton", EntityTypes.SKELETON)
|
||||
.setHologramOffset(-0.3D));
|
||||
|
||||
private static final class Builder {
|
||||
private final String name;
|
||||
private final EntityType type;
|
||||
private final List<EntityProperty<?>> allowedProperties = new ArrayList<>();
|
||||
private boolean globalProperties = true;
|
||||
private double hologramOffset = 0;
|
||||
|
||||
private Builder(String name, EntityType type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Builder addProperties(EntityProperty<?>... properties) {
|
||||
allowedProperties.addAll(Arrays.asList(properties));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEnableGlobalProperties(boolean enabled) {
|
||||
globalProperties = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setHologramOffset(double hologramOffset) {
|
||||
this.hologramOffset = hologramOffset;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NpcType build() {
|
||||
if (globalProperties) {
|
||||
allowedProperties.add(EntityProperty.FIRE);
|
||||
allowedProperties.add(EntityProperty.INVISIBLE);
|
||||
allowedProperties.add(EntityProperty.SILENT);
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9))
|
||||
allowedProperties.add(EntityProperty.GLOW);
|
||||
}
|
||||
return new NpcType(name, type, hologramOffset, new HashSet<>(allowedProperties));
|
||||
}
|
||||
}
|
||||
public interface NpcType {
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder
|
|||
import lol.pyr.director.adventure.command.CommandManager;
|
||||
import lol.pyr.director.adventure.command.MultiCommand;
|
||||
import lol.pyr.znpcsplus.api.ZApiProvider;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.api.npc.NpcType;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcTypeImpl;
|
||||
import lol.pyr.znpcsplus.config.Configs;
|
||||
import lol.pyr.znpcsplus.interaction.InteractionPacketListener;
|
||||
import lol.pyr.znpcsplus.interaction.types.ConsoleCommandAction;
|
||||
|
@ -143,15 +143,15 @@ public class ZNpcsPlus extends JavaPlugin {
|
|||
int z = 0;
|
||||
World world = Bukkit.getWorld("world");
|
||||
if (world == null) world = Bukkit.getWorlds().get(0);
|
||||
for (NpcType type : NpcType.values()) {
|
||||
for (NpcTypeImpl type : NpcTypeImpl.values()) {
|
||||
NpcEntryImpl entry = NpcRegistryImpl.get().create("debug_npc" + (z * wrap + x), world, type, new ZLocation(x * 3, 200, z * 3, 0, 0));
|
||||
entry.setProcessed(true);
|
||||
NpcImpl npc = entry.getNpc();
|
||||
if (type.getType() == EntityTypes.PLAYER) {
|
||||
SkinCache.fetchByName("Notch").thenAccept(skin -> npc.setProperty(EntityProperty.SKIN, new PrefetchedDescriptor(skin)));
|
||||
npc.setProperty(EntityProperty.INVISIBLE, true);
|
||||
SkinCache.fetchByName("Notch").thenAccept(skin -> npc.setProperty(EntityPropertyImpl.SKIN, new PrefetchedDescriptor(skin)));
|
||||
npc.setProperty(EntityPropertyImpl.INVISIBLE, true);
|
||||
}
|
||||
npc.setProperty(EntityProperty.GLOW, NamedTextColor.RED);
|
||||
npc.setProperty(EntityPropertyImpl.GLOW, NamedTextColor.RED);
|
||||
// npc.setProperty(EntityProperty.FIRE, true);
|
||||
npc.getHologram().addLine(Component.text("Hello, World!"));
|
||||
if (x++ > wrap) {
|
||||
|
@ -159,16 +159,16 @@ public class ZNpcsPlus extends JavaPlugin {
|
|||
z++;
|
||||
}
|
||||
}
|
||||
NpcEntryImpl entry = NpcRegistryImpl.get().create("debug_npc" + (z * wrap + x), world, NpcType.byName("player"), new ZLocation(x * 3, 200, z * 3, 0, 0));
|
||||
NpcEntryImpl entry = NpcRegistryImpl.get().create("debug_npc" + (z * wrap + x), world, NpcTypeImpl.byName("player"), new ZLocation(x * 3, 200, z * 3, 0, 0));
|
||||
entry.setProcessed(true);
|
||||
NpcImpl npc = entry.getNpc();
|
||||
npc.setProperty(EntityProperty.SKIN, new FetchingDescriptor("jeb_"));
|
||||
npc.setProperty(EntityPropertyImpl.SKIN, new FetchingDescriptor("jeb_"));
|
||||
npc.addAction(new MessageAction(1000L, "<red>Hi, I'm jeb!"));
|
||||
x++;
|
||||
entry = NpcRegistryImpl.get().create("debug_npc" + (z * wrap + x), world, NpcType.byName("player"), new ZLocation(x * 3, 200, z * 3, 0, 0));
|
||||
entry = NpcRegistryImpl.get().create("debug_npc" + (z * wrap + x), world, NpcTypeImpl.byName("player"), new ZLocation(x * 3, 200, z * 3, 0, 0));
|
||||
entry.setProcessed(true);
|
||||
npc = entry.getNpc();
|
||||
npc.setProperty(EntityProperty.SKIN, new MirrorDescriptor());
|
||||
npc.setProperty(EntityPropertyImpl.SKIN, new MirrorDescriptor());
|
||||
npc.addAction(new ConsoleCommandAction(1000L, "kick {player}"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,24 +12,24 @@ package lol.pyr.znpcsplus.config;
|
|||
* TOO_FEW_ARGUMENTS("messages", "&cThis command does not contain enough arguments. Type &f/znpcs&c or view our documentation for a list/examples of existing arguments.", String.class),
|
||||
* PATH_START("messages", "&aSuccess! Move to create a path for your NPC. When finished, type &f/znpcs path exit&c to exit path creation.", String.class),
|
||||
* EXIT_PATH("messages", "&cYou have exited path creation.", String.class),
|
||||
* PATH_FOUND("messages", "&cThere is already a path with this name.", String.class),
|
||||
* PATH_FOUND("messages", "&cThere is already a path with this getName.", String.class),
|
||||
* NPC_FOUND("messages", "&cThere is already an NPC with this ID.", String.class),
|
||||
* NO_PATH_FOUND("messages", "&cThe path you have specified does not exist.", String.class),
|
||||
* NO_SKIN_FOUND("messages", "&cThe skin username/URL you have specified does not exist or is invalid.", String.class),
|
||||
* NO_NPC_FOUND("messages", "&cThe NPC you have specified does not exist.", String.class),
|
||||
* NO_ACTION_FOUND("messages", "&cThis action does not exist! Type &f/znpcs&c or view our documentation for a list/examples of existing action types.", String.class),
|
||||
* METHOD_NOT_FOUND("messages", "&cThis method does not exist! Type &f/znpcs&c or view our documentation for a list/examples of existing methods.", String.class),
|
||||
* INVALID_NAME_LENGTH("messages", "&cThe name you specified either too short or long. Please enter a positive integer of (3 to 16) characters.", String.class),
|
||||
* INVALID_NAME_LENGTH("messages", "&cThe getName you specified either too short or long. Please enter a positive integer of (3 to 16) characters.", String.class),
|
||||
* UNSUPPORTED_ENTITY("messages", "&cThis entity type not available in your current server version.", String.class),
|
||||
* PATH_SET_INCORRECT_USAGE("messages", "&eUsage: &aset <npc_id> <path_name>", String.class),
|
||||
* ACTION_ADD_INCORRECT_USAGE("messages", "&eUsage: &a<SERVER/CMD/MESSAGE/CONSOLE> <actionValue>", String.class),
|
||||
* ACTION_DELAY_INCORRECT_USAGE("messages", "&eUsage: &a<action_id> <delay>", String.class),
|
||||
* CONVERSATION_SET_INCORRECT_USAGE("messages", "&cUsage: <npc_id> <conversation_name> <RADIUS/CLICK>", String.class),
|
||||
* NO_CONVERSATION_FOUND("messages", "&cThe conversation you have specified does not exist!", String.class),
|
||||
* CONVERSATION_FOUND("messages", "&cThere is already a conversation with this name.", String.class),
|
||||
* CONVERSATION_FOUND("messages", "&cThere is already a conversation with this getName.", String.class),
|
||||
* INVALID_SIZE("messages", "&cThe position you have specified cannot exceed the limit.", String.class),
|
||||
* FETCHING_SKIN("messages", "&aFetching skin for name: &f%s&a. Please wait...", String.class),
|
||||
* CANT_GET_SKIN("messages", "&cCould not fetch skin for name: %s.", String.class),
|
||||
* FETCHING_SKIN("messages", "&aFetching skin for getName: &f%s&a. Please wait...", String.class),
|
||||
* CANT_GET_SKIN("messages", "&cCould not fetch skin for getName: %s.", String.class),
|
||||
* GET_SKIN("messages", "&aSkin successfully fetched!", String.class),
|
||||
* NOT_SUPPORTED_NPC_TYPE("messages", "&cThis NPC type doesn't exists or is not supported in your current server version.", String.class);
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
package lol.pyr.znpcsplus.entity;
|
||||
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
|
||||
import lol.pyr.znpcsplus.skin.BaseSkinDescriptor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class EntityPropertyImpl<T> implements EntityProperty<T> {
|
||||
private final String name;
|
||||
private final T defaultValue;
|
||||
|
||||
private final PropertySerializer<T> serializer;
|
||||
private final PropertyDeserializer<T> deserializer;
|
||||
|
||||
public EntityPropertyImpl(String name, PropertySerializer<T> serializer, PropertyDeserializer<T> deserializer) {
|
||||
this(name, null, serializer, deserializer);
|
||||
}
|
||||
|
||||
public EntityPropertyImpl(String name, T defaultValue, PropertySerializer<T> serializer, PropertyDeserializer<T> deserializer) {
|
||||
this.name = name.toUpperCase();
|
||||
this.defaultValue = defaultValue;
|
||||
this.serializer = serializer;
|
||||
this.deserializer = deserializer;
|
||||
BY_NAME.put(this.name, this);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String serialize(PropertyHolder holder) {
|
||||
return serialize(holder.getProperty(this));
|
||||
}
|
||||
|
||||
public String serialize(T value) {
|
||||
return serializer.serialize(value);
|
||||
}
|
||||
|
||||
public T deserialize(String str) {
|
||||
return deserializer.deserialize(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private final static Map<String, EntityPropertyImpl<?>> BY_NAME = new HashMap<>();
|
||||
|
||||
public static EntityPropertyImpl<?> getByName(String name) {
|
||||
return BY_NAME.get(name.toUpperCase());
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface PropertySerializer<T> {
|
||||
String serialize(T property);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface PropertyDeserializer<T> {
|
||||
T deserialize(String property);
|
||||
}
|
||||
|
||||
|
||||
private final static PropertySerializer<Boolean> BOOLEAN_SERIALIZER = Object::toString;
|
||||
private final static PropertyDeserializer<Boolean> BOOLEAN_DESERIALIZER = Boolean::valueOf;
|
||||
|
||||
private final static PropertySerializer<NamedTextColor> COLOR_SERIALIZER = color -> String.valueOf(color.value());
|
||||
private final static PropertyDeserializer<NamedTextColor> COLOR_DESERIALIZER = str -> NamedTextColor.namedColor(Integer.parseInt(str));
|
||||
|
||||
private final static PropertySerializer<Component> COMPONENT_SERIALIZER = component -> MiniMessage.miniMessage().serialize(component);
|
||||
private final static PropertyDeserializer<Component> COMPONENT_DESERIALIZER = str -> MiniMessage.miniMessage().deserialize(str);
|
||||
|
||||
private final static PropertySerializer<SkinDescriptor> DESCRIPTOR_SERIALIZER = descriptor -> ((BaseSkinDescriptor) descriptor).serialize();
|
||||
private final static PropertyDeserializer<SkinDescriptor> DESCRIPTOR_DESERIALIZER = BaseSkinDescriptor::deserialize;
|
||||
|
||||
public static EntityPropertyImpl<Boolean> SKIN_LAYERS = new EntityPropertyImpl<>("skin_layers", true, BOOLEAN_SERIALIZER, BOOLEAN_DESERIALIZER);
|
||||
public static EntityPropertyImpl<SkinDescriptor> SKIN = new EntityPropertyImpl<>("skin", DESCRIPTOR_SERIALIZER, DESCRIPTOR_DESERIALIZER);
|
||||
public static EntityPropertyImpl<NamedTextColor> GLOW = new EntityPropertyImpl<>("glow", COLOR_SERIALIZER, COLOR_DESERIALIZER);
|
||||
public static EntityPropertyImpl<Boolean> FIRE = new EntityPropertyImpl<>("fire", false, BOOLEAN_SERIALIZER, BOOLEAN_DESERIALIZER);
|
||||
public static EntityPropertyImpl<Boolean> INVISIBLE = new EntityPropertyImpl<>("invisible", false, BOOLEAN_SERIALIZER, BOOLEAN_DESERIALIZER);
|
||||
public static EntityPropertyImpl<Boolean> SILENT = new EntityPropertyImpl<>("silent", false, BOOLEAN_SERIALIZER, BOOLEAN_DESERIALIZER);
|
||||
public static EntityPropertyImpl<Component> NAME = new EntityPropertyImpl<>("name", COMPONENT_SERIALIZER, COMPONENT_DESERIALIZER);
|
||||
}
|
|
@ -36,6 +36,10 @@ public class HologramImpl extends Viewable implements Hologram {
|
|||
relocateLines();
|
||||
}
|
||||
|
||||
public List<HologramLine> getLines() {
|
||||
return Collections.unmodifiableList(lines);
|
||||
}
|
||||
|
||||
public void clearLines() {
|
||||
UNSAFE_hideAll();
|
||||
lines.clear();
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package lol.pyr.znpcsplus.hologram;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import lol.pyr.znpcsplus.util.ZLocation;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
@ -42,13 +43,13 @@ public class HologramLine implements PropertyHolder {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T getProperty(EntityProperty<T> key) {
|
||||
if (key == EntityProperty.INVISIBLE) return (T) Boolean.TRUE;
|
||||
if (key == EntityProperty.NAME) return (T) text;
|
||||
if (key == EntityPropertyImpl.INVISIBLE) return (T) Boolean.TRUE;
|
||||
if (key == EntityPropertyImpl.NAME) return (T) text;
|
||||
return key.getDefaultValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasProperty(EntityProperty<?> key) {
|
||||
return key == EntityProperty.NAME || key == EntityProperty.INVISIBLE;
|
||||
return key == EntityPropertyImpl.NAME || key == EntityPropertyImpl.INVISIBLE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,5 +23,11 @@ public abstract class NpcAction {
|
|||
return delay;
|
||||
}
|
||||
|
||||
public String getArgument() {
|
||||
return argument;
|
||||
}
|
||||
|
||||
public abstract void run(Player player);
|
||||
|
||||
public abstract NpcActionType getType();
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package lol.pyr.znpcsplus.interaction.types;
|
|||
|
||||
import lol.pyr.znpcsplus.ZNpcsPlus;
|
||||
import lol.pyr.znpcsplus.interaction.NpcAction;
|
||||
import lol.pyr.znpcsplus.interaction.NpcActionType;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
@ -16,4 +17,9 @@ public class ConsoleCommandAction extends NpcAction {
|
|||
String cmd = argument.replace("{player}", player.getName()).replace("{uuid}", player.getUniqueId().toString());
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), ZNpcsPlus.PLACEHOLDERS_SUPPORTED ? PlaceholderAPI.setPlaceholders(player, cmd) : cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NpcActionType getType() {
|
||||
return NpcActionType.CONSOLE_CMD;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package lol.pyr.znpcsplus.interaction.types;
|
|||
|
||||
import lol.pyr.znpcsplus.ZNpcsPlus;
|
||||
import lol.pyr.znpcsplus.interaction.NpcAction;
|
||||
import lol.pyr.znpcsplus.interaction.NpcActionType;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.bukkit.entity.Player;
|
||||
|
@ -18,4 +19,9 @@ public class MessageAction extends NpcAction {
|
|||
public void run(Player player) {
|
||||
ZNpcsPlus.ADVENTURE.player(player).sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NpcActionType getType() {
|
||||
return NpcActionType.MESSAGE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package lol.pyr.znpcsplus.interaction.types;
|
|||
|
||||
import lol.pyr.znpcsplus.ZNpcsPlus;
|
||||
import lol.pyr.znpcsplus.interaction.NpcAction;
|
||||
import lol.pyr.znpcsplus.interaction.NpcActionType;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
@ -16,4 +17,9 @@ public class PlayerCommandAction extends NpcAction {
|
|||
String cmd = argument.replace("{player}", player.getName()).replace("{uuid}", player.getUniqueId().toString());
|
||||
Bukkit.dispatchCommand(player, ZNpcsPlus.PLACEHOLDERS_SUPPORTED ? PlaceholderAPI.setPlaceholders(player, cmd) : cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NpcActionType getType() {
|
||||
return NpcActionType.PLAYER_CMD;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package lol.pyr.znpcsplus.interaction.types;
|
|||
|
||||
import lol.pyr.znpcsplus.ZNpcsPlus;
|
||||
import lol.pyr.znpcsplus.interaction.NpcAction;
|
||||
import lol.pyr.znpcsplus.interaction.NpcActionType;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class SwitchServerAction extends NpcAction {
|
||||
|
@ -13,4 +14,9 @@ public class SwitchServerAction extends NpcAction {
|
|||
public void run(Player player) {
|
||||
ZNpcsPlus.BUNGEE_UTILS.sendPlayerToServer(player, argument);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NpcActionType getType() {
|
||||
return NpcActionType.SERVER;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,15 @@ package lol.pyr.znpcsplus.npc;
|
|||
import lol.pyr.znpcsplus.api.npc.NpcEntry;
|
||||
|
||||
public class NpcEntryImpl implements NpcEntry {
|
||||
private final String id;
|
||||
private final NpcImpl npc;
|
||||
|
||||
private boolean process = false;
|
||||
private boolean save = false;
|
||||
private boolean modify = false;
|
||||
|
||||
public NpcEntryImpl(NpcImpl npc) {
|
||||
public NpcEntryImpl(String id, NpcImpl npc) {
|
||||
this.id = id.toLowerCase();
|
||||
this.npc = npc;
|
||||
}
|
||||
|
||||
|
@ -54,4 +56,8 @@ public class NpcEntryImpl implements NpcEntry {
|
|||
setProcessed(true);
|
||||
setAllowCommandModification(true);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package lol.pyr.znpcsplus.npc;
|
||||
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.api.npc.NpcType;
|
||||
import lol.pyr.znpcsplus.api.npc.Npc;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import lol.pyr.znpcsplus.hologram.HologramImpl;
|
||||
import lol.pyr.znpcsplus.interaction.NpcAction;
|
||||
|
@ -19,28 +19,33 @@ public class NpcImpl extends Viewable implements Npc {
|
|||
private final String worldName;
|
||||
private PacketEntity entity;
|
||||
private ZLocation location;
|
||||
private NpcType type;
|
||||
private NpcTypeImpl type;
|
||||
private final HologramImpl hologram;
|
||||
|
||||
private final Map<EntityProperty<?>, Object> propertyMap = new HashMap<>();
|
||||
private final Map<EntityPropertyImpl<?>, Object> propertyMap = new HashMap<>();
|
||||
private final Set<NpcAction> actions = new HashSet<>();
|
||||
|
||||
protected NpcImpl(World world, NpcType type, ZLocation location) {
|
||||
this.worldName = world.getName();
|
||||
protected NpcImpl(World world, NpcTypeImpl type, ZLocation location) {
|
||||
this(world.getName(), type, location);
|
||||
}
|
||||
|
||||
public NpcImpl(String world, NpcTypeImpl type, ZLocation location) {
|
||||
this.worldName = world;
|
||||
this.type = type;
|
||||
this.location = location;
|
||||
entity = new PacketEntity(this, type.getType(), location);
|
||||
hologram = new HologramImpl(location.withY(location.getY() + type.getHologramOffset()));
|
||||
}
|
||||
|
||||
public void setType(NpcType type) {
|
||||
|
||||
public void setType(NpcTypeImpl type) {
|
||||
UNSAFE_hideAll();
|
||||
this.type = type;
|
||||
entity = new PacketEntity(this, type.getType(), entity.getLocation());
|
||||
UNSAFE_showAll();
|
||||
}
|
||||
|
||||
public NpcType getType() {
|
||||
public NpcTypeImpl getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -66,6 +71,10 @@ public class NpcImpl extends Viewable implements Npc {
|
|||
return Bukkit.getWorld(worldName);
|
||||
}
|
||||
|
||||
public String getWorldName() {
|
||||
return worldName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _show(Player player) {
|
||||
entity.spawn(player);
|
||||
|
@ -84,14 +93,14 @@ public class NpcImpl extends Viewable implements Npc {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getProperty(EntityProperty<T> key) {
|
||||
return hasProperty(key) ? (T) propertyMap.get(key) : key.getDefaultValue();
|
||||
return hasProperty(key) ? (T) propertyMap.get((EntityPropertyImpl<?>) key) : key.getDefaultValue();
|
||||
}
|
||||
|
||||
public boolean hasProperty(EntityProperty<?> key) {
|
||||
return propertyMap.containsKey(key);
|
||||
return propertyMap.containsKey((EntityPropertyImpl<?>) key);
|
||||
}
|
||||
|
||||
public <T> void setProperty(EntityProperty<T> key, T value) {
|
||||
public <T> void setProperty(EntityPropertyImpl<T> key, T value) {
|
||||
if (value.equals(key.getDefaultValue())) removeProperty(key);
|
||||
else {
|
||||
propertyMap.put(key, value);
|
||||
|
@ -99,11 +108,15 @@ public class NpcImpl extends Viewable implements Npc {
|
|||
}
|
||||
}
|
||||
|
||||
public void removeProperty(EntityProperty<?> key) {
|
||||
public void removeProperty(EntityPropertyImpl<?> key) {
|
||||
propertyMap.remove(key);
|
||||
_refreshMeta();
|
||||
}
|
||||
|
||||
public Set<EntityPropertyImpl<?>> getAppliedProperties() {
|
||||
return Collections.unmodifiableSet(propertyMap.keySet());
|
||||
}
|
||||
|
||||
public Collection<NpcAction> getActions() {
|
||||
return Collections.unmodifiableSet(actions);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class NpcRegistryImpl implements NpcRegistry {
|
|||
private final Map<String, NpcEntryImpl> npcMap = new HashMap<>();
|
||||
|
||||
public NpcEntryImpl get(String id) {
|
||||
return npcMap.get(id.toUpperCase());
|
||||
return npcMap.get(id.toLowerCase());
|
||||
}
|
||||
|
||||
public Collection<NpcEntryImpl> all() {
|
||||
|
@ -39,19 +39,22 @@ public class NpcRegistryImpl implements NpcRegistry {
|
|||
return Collections.unmodifiableSet(npcMap.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NpcEntryImpl create(String id, World world, NpcType type, ZLocation location) {
|
||||
id = id.toUpperCase();
|
||||
return create(id, world, (NpcTypeImpl) type, location);
|
||||
}
|
||||
|
||||
public NpcEntryImpl create(String id, World world, NpcTypeImpl type, ZLocation location) {
|
||||
id = id.toLowerCase();
|
||||
if (npcMap.containsKey(id)) throw new IllegalArgumentException("An npc with the id " + id + " already exists!");
|
||||
NpcImpl npc = new NpcImpl(world, type, location);
|
||||
NpcEntryImpl entry = new NpcEntryImpl(npc);
|
||||
NpcEntryImpl entry = new NpcEntryImpl(id, npc);
|
||||
npcMap.put(id, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String id) {
|
||||
id = id.toUpperCase();
|
||||
id = id.toLowerCase();
|
||||
if (!npcMap.containsKey(id)) return;
|
||||
npcMap.remove(id).getNpc().delete();
|
||||
}
|
||||
|
|
114
plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java
Normal file
114
plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java
Normal file
|
@ -0,0 +1,114 @@
|
|||
package lol.pyr.znpcsplus.npc;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class NpcTypeImpl {
|
||||
private final static Map<String, NpcTypeImpl> BY_NAME = new HashMap<>();
|
||||
|
||||
public static Collection<NpcTypeImpl> values() {
|
||||
return BY_NAME.values();
|
||||
}
|
||||
|
||||
public static NpcTypeImpl byName(String name) {
|
||||
return BY_NAME.get(name.toUpperCase());
|
||||
}
|
||||
|
||||
private final EntityType type;
|
||||
private final Set<EntityPropertyImpl<?>> allowedProperties;
|
||||
private final String name;
|
||||
private final double hologramOffset;
|
||||
|
||||
private NpcTypeImpl(String name, EntityType type, double hologramOffset, Set<EntityPropertyImpl<?>> allowedProperties) {
|
||||
this.name = name.toUpperCase();
|
||||
this.type = type;
|
||||
this.hologramOffset = hologramOffset;
|
||||
this.allowedProperties = allowedProperties;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public EntityType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public double getHologramOffset() {
|
||||
return hologramOffset;
|
||||
}
|
||||
|
||||
public Set<EntityPropertyImpl<?>> getAllowedProperties() {
|
||||
return allowedProperties;
|
||||
}
|
||||
|
||||
private static NpcTypeImpl define(Builder builder) {
|
||||
return define(builder.build());
|
||||
}
|
||||
|
||||
private static NpcTypeImpl define(NpcTypeImpl type) {
|
||||
BY_NAME.put(type.getName(), type);
|
||||
return type;
|
||||
}
|
||||
|
||||
public static final NpcTypeImpl PLAYER = define(
|
||||
new Builder("player", EntityTypes.PLAYER)
|
||||
.addProperties(EntityPropertyImpl.SKIN, EntityPropertyImpl.SKIN_LAYERS)
|
||||
.setHologramOffset(-0.45D));
|
||||
|
||||
public static final NpcTypeImpl CREEPER = define(
|
||||
new Builder("creeper", EntityTypes.CREEPER)
|
||||
.setHologramOffset(-0.6D));
|
||||
|
||||
public static final NpcTypeImpl ZOMBIE = define(
|
||||
new Builder("zombie", EntityTypes.ZOMBIE)
|
||||
.setHologramOffset(-0.3D));
|
||||
|
||||
public static final NpcTypeImpl SKELETON = define(
|
||||
new Builder("skeleton", EntityTypes.SKELETON)
|
||||
.setHologramOffset(-0.3D));
|
||||
|
||||
private static final class Builder {
|
||||
private final String name;
|
||||
private final EntityType type;
|
||||
private final List<EntityPropertyImpl<?>> allowedProperties = new ArrayList<>();
|
||||
private boolean globalProperties = true;
|
||||
private double hologramOffset = 0;
|
||||
|
||||
private Builder(String name, EntityType type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Builder addProperties(EntityPropertyImpl<?>... properties) {
|
||||
allowedProperties.addAll(Arrays.asList(properties));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEnableGlobalProperties(boolean enabled) {
|
||||
globalProperties = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setHologramOffset(double hologramOffset) {
|
||||
this.hologramOffset = hologramOffset;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NpcTypeImpl build() {
|
||||
if (globalProperties) {
|
||||
allowedProperties.add(EntityPropertyImpl.FIRE);
|
||||
allowedProperties.add(EntityPropertyImpl.INVISIBLE);
|
||||
allowedProperties.add(EntityPropertyImpl.SILENT);
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9))
|
||||
allowedProperties.add(EntityPropertyImpl.GLOW);
|
||||
}
|
||||
return new NpcTypeImpl(name, type, hologramOffset, new HashSet<>(allowedProperties));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ package lol.pyr.znpcsplus.packets;
|
|||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import lol.pyr.znpcsplus.util.ZLocation;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
|
@ -15,7 +15,7 @@ public class V1_14Factory extends V1_9Factory {
|
|||
ZLocation location = entity.getLocation();
|
||||
sendPacket(player, new WrapperPlayServerSpawnEntity(entity.getEntityId(), Optional.of(entity.getUuid()), entity.getType(),
|
||||
location.toVector3d(), location.getPitch(), location.getYaw(), location.getYaw(), 0, Optional.empty()));
|
||||
if (properties.hasProperty(EntityProperty.GLOW)) createTeam(player, entity, properties);
|
||||
if (properties.hasProperty(EntityPropertyImpl.GLOW)) createTeam(player, entity, properties);
|
||||
sendAllMetadata(player, entity, properties);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
|||
import com.github.retrooper.packetevents.wrapper.play.server.*;
|
||||
import lol.pyr.znpcsplus.ZNpcsPlus;
|
||||
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import lol.pyr.znpcsplus.metadata.MetadataFactory;
|
||||
import lol.pyr.znpcsplus.skin.BaseSkinDescriptor;
|
||||
|
@ -94,7 +94,7 @@ public class V1_8Factory implements PacketFactory {
|
|||
Component.empty(), Component.empty(), Component.empty(),
|
||||
WrapperPlayServerTeams.NameTagVisibility.NEVER,
|
||||
WrapperPlayServerTeams.CollisionRule.NEVER,
|
||||
properties.hasProperty(EntityProperty.GLOW) ? properties.getProperty(EntityProperty.GLOW) : NamedTextColor.WHITE,
|
||||
properties.hasProperty(EntityPropertyImpl.GLOW) ? properties.getProperty(EntityPropertyImpl.GLOW) : NamedTextColor.WHITE,
|
||||
WrapperPlayServerTeams.OptionData.NONE
|
||||
)));
|
||||
sendPacket(player, new WrapperPlayServerTeams("npc_team_" + entity.getEntityId(), WrapperPlayServerTeams.TeamMode.ADD_ENTITIES, (WrapperPlayServerTeams.ScoreBoardTeamInfo) null,
|
||||
|
@ -109,12 +109,12 @@ public class V1_8Factory implements PacketFactory {
|
|||
@Override
|
||||
public void sendAllMetadata(Player player, PacketEntity entity, PropertyHolder properties) {
|
||||
ArrayList<EntityData> data = new ArrayList<>();
|
||||
if (entity.getType() == EntityTypes.PLAYER && properties.getProperty(EntityProperty.SKIN_LAYERS)) data.add(MetadataFactory.get().skinLayers());
|
||||
boolean fire = properties.getProperty(EntityProperty.FIRE);
|
||||
boolean invisible = properties.getProperty(EntityProperty.INVISIBLE);
|
||||
if (entity.getType() == EntityTypes.PLAYER && properties.getProperty(EntityPropertyImpl.SKIN_LAYERS)) data.add(MetadataFactory.get().skinLayers());
|
||||
boolean fire = properties.getProperty(EntityPropertyImpl.FIRE);
|
||||
boolean invisible = properties.getProperty(EntityPropertyImpl.INVISIBLE);
|
||||
if (fire || invisible) data.add(MetadataFactory.get().effects(fire, false, invisible));
|
||||
if (properties.getProperty(EntityProperty.SILENT)) data.add(MetadataFactory.get().silent());
|
||||
if (properties.hasProperty(EntityProperty.NAME)) data.addAll(MetadataFactory.get().name(properties.getProperty(EntityProperty.NAME)));
|
||||
if (properties.getProperty(EntityPropertyImpl.SILENT)) data.add(MetadataFactory.get().silent());
|
||||
if (properties.hasProperty(EntityPropertyImpl.NAME)) data.addAll(MetadataFactory.get().name(properties.getProperty(EntityPropertyImpl.NAME)));
|
||||
sendMetadata(player, entity, data);
|
||||
}
|
||||
|
||||
|
@ -128,8 +128,8 @@ public class V1_8Factory implements PacketFactory {
|
|||
}
|
||||
|
||||
protected CompletableFuture<UserProfile> skinned(Player player, PropertyHolder properties, UserProfile profile) {
|
||||
if (!properties.hasProperty(EntityProperty.SKIN)) return CompletableFuture.completedFuture(profile);
|
||||
BaseSkinDescriptor descriptor = (BaseSkinDescriptor) properties.getProperty(EntityProperty.SKIN);
|
||||
if (!properties.hasProperty(EntityPropertyImpl.SKIN)) return CompletableFuture.completedFuture(profile);
|
||||
BaseSkinDescriptor descriptor = (BaseSkinDescriptor) properties.getProperty(EntityPropertyImpl.SKIN);
|
||||
if (descriptor.supportsInstant(player)) {
|
||||
descriptor.fetchInstant(player).apply(profile);
|
||||
return CompletableFuture.completedFuture(profile);
|
||||
|
|
|
@ -4,7 +4,7 @@ import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
|
|||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import lol.pyr.znpcsplus.metadata.MetadataFactory;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
|
@ -14,13 +14,13 @@ public class V1_9Factory extends V1_8Factory {
|
|||
@Override
|
||||
public void sendAllMetadata(Player player, PacketEntity entity, PropertyHolder properties) {
|
||||
ArrayList<EntityData> data = new ArrayList<>();
|
||||
if (entity.getType() == EntityTypes.PLAYER && properties.getProperty(EntityProperty.SKIN_LAYERS)) data.add(MetadataFactory.get().skinLayers());
|
||||
boolean glow = properties.hasProperty(EntityProperty.GLOW);
|
||||
boolean fire = properties.getProperty(EntityProperty.FIRE);
|
||||
boolean invisible = properties.getProperty(EntityProperty.INVISIBLE);
|
||||
if (entity.getType() == EntityTypes.PLAYER && properties.getProperty(EntityPropertyImpl.SKIN_LAYERS)) data.add(MetadataFactory.get().skinLayers());
|
||||
boolean glow = properties.hasProperty(EntityPropertyImpl.GLOW);
|
||||
boolean fire = properties.getProperty(EntityPropertyImpl.FIRE);
|
||||
boolean invisible = properties.getProperty(EntityPropertyImpl.INVISIBLE);
|
||||
if (glow || fire || invisible) data.add(MetadataFactory.get().effects(fire, glow, invisible));
|
||||
if (properties.getProperty(EntityProperty.SILENT)) data.add(MetadataFactory.get().silent());
|
||||
if (properties.hasProperty(EntityProperty.NAME)) data.addAll(MetadataFactory.get().name(properties.getProperty(EntityProperty.NAME)));
|
||||
if (properties.getProperty(EntityPropertyImpl.SILENT)) data.add(MetadataFactory.get().silent());
|
||||
if (properties.hasProperty(EntityPropertyImpl.NAME)) data.addAll(MetadataFactory.get().name(properties.getProperty(EntityPropertyImpl.NAME)));
|
||||
sendMetadata(player, entity, data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,33 @@
|
|||
package lol.pyr.znpcsplus.skin;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.TextureProperty;
|
||||
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
|
||||
import lol.pyr.znpcsplus.skin.descriptor.FetchingDescriptor;
|
||||
import lol.pyr.znpcsplus.skin.descriptor.MirrorDescriptor;
|
||||
import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface BaseSkinDescriptor {
|
||||
public interface BaseSkinDescriptor extends SkinDescriptor {
|
||||
CompletableFuture<Skin> fetch(Player player);
|
||||
Skin fetchInstant(Player player);
|
||||
boolean supportsInstant(Player player);
|
||||
String serialize();
|
||||
|
||||
static BaseSkinDescriptor deserialize(String str) {
|
||||
String[] arr = str.split(";");
|
||||
if (arr[0].equalsIgnoreCase("mirror")) return new MirrorDescriptor();
|
||||
else if (arr[0].equalsIgnoreCase("fetching")) return new FetchingDescriptor(arr[1]);
|
||||
else if (arr[0].equalsIgnoreCase("prefetched")) {
|
||||
List<TextureProperty> properties = new ArrayList<>();
|
||||
for (int i = 0; i < (arr.length - 1) / 3; i++) {
|
||||
properties.add(new TextureProperty(arr[i + 1], arr[i + 2], arr[i + 3]));
|
||||
}
|
||||
return new PrefetchedDescriptor(new Skin(properties));
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown SkinDescriptor type!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.mojang.authlib.properties.PropertyMap;
|
|||
import lol.pyr.znpcsplus.util.list.ListUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -23,6 +24,10 @@ public class Skin {
|
|||
this.properties.addAll(ListUtil.immutableList(properties));
|
||||
}
|
||||
|
||||
public Skin(Collection<TextureProperty> properties) {
|
||||
this.properties.addAll(properties);
|
||||
}
|
||||
|
||||
public Skin(PropertyMap properties) {
|
||||
this.properties.addAll(properties.values().stream()
|
||||
.map(property -> new TextureProperty(property.getName(), property.getValue(), property.getSignature()))
|
||||
|
@ -32,7 +37,7 @@ public class Skin {
|
|||
public Skin(JsonObject obj) {
|
||||
for (JsonElement e : obj.get("properties").getAsJsonArray()) {
|
||||
JsonObject o = e.getAsJsonObject();
|
||||
properties.add(new TextureProperty(o.get("name").getAsString(), o.get("value").getAsString(), o.has("signature") ? o.get("signature").getAsString() : null));
|
||||
properties.add(new TextureProperty(o.get("getName").getAsString(), o.get("value").getAsString(), o.has("signature") ? o.get("signature").getAsString() : null));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,6 +46,10 @@ public class Skin {
|
|||
return profile;
|
||||
}
|
||||
|
||||
public List<TextureProperty> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return System.currentTimeMillis() - timestamp > 60000L;
|
||||
}
|
||||
|
|
|
@ -36,4 +36,13 @@ public class FetchingDescriptor implements BaseSkinDescriptor, SkinDescriptor {
|
|||
if (ZNpcsPlus.PLACEHOLDERS_SUPPORTED) return PlaceholderAPI.setPlaceholders(player, name);
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize() {
|
||||
return "fetching;" + name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,4 +26,9 @@ public class MirrorDescriptor implements BaseSkinDescriptor, SkinDescriptor {
|
|||
public boolean supportsInstant(Player player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize() {
|
||||
return "mirror";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lol.pyr.znpcsplus.skin.descriptor;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.TextureProperty;
|
||||
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
|
||||
import lol.pyr.znpcsplus.skin.BaseSkinDescriptor;
|
||||
import lol.pyr.znpcsplus.skin.Skin;
|
||||
|
@ -28,4 +29,20 @@ public class PrefetchedDescriptor implements BaseSkinDescriptor, SkinDescriptor
|
|||
public boolean supportsInstant(Player player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Skin getSkin() {
|
||||
return skin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("prefetched;");
|
||||
for (TextureProperty property : skin.getProperties()) {
|
||||
sb.append(property.getName()).append(";");
|
||||
sb.append(property.getValue()).append(";");
|
||||
sb.append(property.getSignature()).append(";");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package lol.pyr.znpcsplus.storage;
|
||||
|
||||
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface NpcStorage {
|
||||
Collection<NpcEntryImpl> loadNpcs();
|
||||
void saveNpcs(Collection<NpcEntryImpl> npcs);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package lol.pyr.znpcsplus.storage;
|
||||
|
||||
import lol.pyr.znpcsplus.storage.yaml.YamlStorage;
|
||||
|
||||
public enum NpcStorageType {
|
||||
YAML {
|
||||
@Override
|
||||
public NpcStorage create() {
|
||||
return new YamlStorage();
|
||||
}
|
||||
};
|
||||
|
||||
public abstract NpcStorage create();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package lol.pyr.znpcsplus.storage;
|
||||
|
||||
public class SerializationException extends RuntimeException {
|
||||
public SerializationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
package lol.pyr.znpcsplus.storage.yaml;
|
||||
|
||||
import lol.pyr.znpcsplus.ZNpcsPlus;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.hologram.HologramLine;
|
||||
import lol.pyr.znpcsplus.interaction.NpcAction;
|
||||
import lol.pyr.znpcsplus.interaction.NpcActionType;
|
||||
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcTypeImpl;
|
||||
import lol.pyr.znpcsplus.storage.NpcStorage;
|
||||
import lol.pyr.znpcsplus.util.ZLocation;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class YamlStorage implements NpcStorage {
|
||||
private final File npcsFolder;
|
||||
|
||||
public YamlStorage() {
|
||||
npcsFolder = new File(ZNpcsPlus.PLUGIN_FOLDER, "npcs");
|
||||
if (npcsFolder.exists()) npcsFolder.mkdirs();
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public Collection<NpcEntryImpl> loadNpcs() {
|
||||
File[] files = npcsFolder.listFiles();
|
||||
if (files == null || files.length == 0) return Collections.emptyList();
|
||||
List<NpcEntryImpl> npcs = new ArrayList<>();
|
||||
for (File file : files) if (file.isFile() && file.getName().toLowerCase().endsWith(".yml")) {
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
|
||||
NpcImpl npc = new NpcImpl(config.getString("world"), NpcTypeImpl.byName(config.getString("type")),
|
||||
deserializeLocation(config.getConfigurationSection("location")));
|
||||
|
||||
ConfigurationSection properties = config.getConfigurationSection("properties");
|
||||
for (String key : properties.getKeys(false)) {
|
||||
EntityPropertyImpl<?> property = EntityPropertyImpl.getByName(key);
|
||||
_setProperty(npc, property, property.deserialize(properties.getString(key)));
|
||||
}
|
||||
|
||||
for (String line : config.getStringList("hologram")) {
|
||||
npc.getHologram().addLine(MiniMessage.miniMessage().deserialize(line));
|
||||
}
|
||||
|
||||
int amt = config.getInt("action-amount");
|
||||
for (int i = 1; i <= amt; i++) {
|
||||
String key = "actions." + i;
|
||||
npc.addAction(NpcActionType.valueOf(config.getString(key + ".type"))
|
||||
.deserialize(config.getInt(key + ".cooldown"), config.getString(key + ".argument")));
|
||||
}
|
||||
|
||||
NpcEntryImpl entry = new NpcEntryImpl(config.getString("id"), npc);
|
||||
entry.setProcessed(config.getBoolean("is-processed"));
|
||||
entry.setAllowCommandModification(config.getBoolean("allow-commands"));
|
||||
entry.setSave(true);
|
||||
|
||||
npcs.add(entry);
|
||||
}
|
||||
return npcs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> void _setProperty(NpcImpl npc, EntityPropertyImpl<?> property, Object value) {
|
||||
npc.setProperty((EntityPropertyImpl<T>) property, (T) value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void saveNpcs(Collection<NpcEntryImpl> npcs) {
|
||||
for (NpcEntryImpl entry : npcs) if (entry.isSave()) try {
|
||||
YamlConfiguration config = new YamlConfiguration();
|
||||
config.set("id", entry.getId());
|
||||
config.set("is-processed", entry.isProcessed());
|
||||
config.set("allow-commands", entry.isAllowCommandModification());
|
||||
|
||||
NpcImpl npc = entry.getNpc();
|
||||
config.set("world", npc.getWorldName());
|
||||
config.set("location", serializeLocation(npc.getLocation()));
|
||||
config.set("type", npc.getType().getName());
|
||||
|
||||
for (EntityPropertyImpl<?> property : npc.getAppliedProperties()) {
|
||||
config.set("properties." + property.getName(), property.serialize(npc));
|
||||
}
|
||||
|
||||
List<String> lines = new ArrayList<>();
|
||||
for (HologramLine line : npc.getHologram().getLines()) {
|
||||
lines.add(MiniMessage.miniMessage().serialize(line.getText()));
|
||||
}
|
||||
config.set("hologram", lines);
|
||||
|
||||
int i = 0;
|
||||
for (NpcAction action : npc.getActions()) { i++;
|
||||
String key = "actions." + i;
|
||||
config.set(key + ".type", action.getType().name());
|
||||
config.set(key + ".cooldown", action.getCooldown());
|
||||
config.set(key + ".argument", action.getArgument());
|
||||
}
|
||||
config.set("action-amount", i);
|
||||
|
||||
config.save(new File(entry.getId() + ".yml"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ZLocation deserializeLocation(ConfigurationSection section) {
|
||||
return new ZLocation(
|
||||
section.getDouble("x"),
|
||||
section.getDouble("y"),
|
||||
section.getDouble("z"),
|
||||
(float) section.getDouble("yaw"),
|
||||
(float) section.getDouble("pitch")
|
||||
);
|
||||
}
|
||||
|
||||
public YamlConfiguration serializeLocation(ZLocation location) {
|
||||
YamlConfiguration config = new YamlConfiguration();
|
||||
config.set("x", location.getX());
|
||||
config.set("y", location.getY());
|
||||
config.set("z", location.getZ());
|
||||
config.set("yaw", location.getYaw());
|
||||
config.set("pitch", location.getPitch());
|
||||
return config;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue