diff --git a/api/build.gradle b/api/build.gradle index 1804836..f7aa8ea 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -3,10 +3,6 @@ plugins { id "maven-publish" } -dependencies { - compileOnly "org.spigotmc:spigot-api:1.19.4-R0.1-SNAPSHOT" -} - publishing { publications { mavenJava(MavenPublication) { diff --git a/api/src/main/java/lol/pyr/znpcsplus/api/entity/EntityProperty.java b/api/src/main/java/lol/pyr/znpcsplus/api/entity/EntityProperty.java index 7ae66cb..69db24e 100644 --- a/api/src/main/java/lol/pyr/znpcsplus/api/entity/EntityProperty.java +++ b/api/src/main/java/lol/pyr/znpcsplus/api/entity/EntityProperty.java @@ -3,4 +3,5 @@ package lol.pyr.znpcsplus.api.entity; public interface EntityProperty { T getDefaultValue(); String getName(); + boolean isPlayerModifiable(); } diff --git a/api/src/main/java/lol/pyr/znpcsplus/api/entity/PropertyHolder.java b/api/src/main/java/lol/pyr/znpcsplus/api/entity/PropertyHolder.java index b3d3b95..178b365 100644 --- a/api/src/main/java/lol/pyr/znpcsplus/api/entity/PropertyHolder.java +++ b/api/src/main/java/lol/pyr/znpcsplus/api/entity/PropertyHolder.java @@ -1,7 +1,10 @@ package lol.pyr.znpcsplus.api.entity; +import java.util.Set; + public interface PropertyHolder { T getProperty(EntityProperty key); boolean hasProperty(EntityProperty key); void setProperty(EntityProperty key, T value); + Set> getAppliedProperties(); } diff --git a/api/src/main/java/lol/pyr/znpcsplus/api/skin/SkinDescriptorFactory.java b/api/src/main/java/lol/pyr/znpcsplus/api/skin/SkinDescriptorFactory.java index ba67e88..086aa0c 100644 --- a/api/src/main/java/lol/pyr/znpcsplus/api/skin/SkinDescriptorFactory.java +++ b/api/src/main/java/lol/pyr/znpcsplus/api/skin/SkinDescriptorFactory.java @@ -1,8 +1,12 @@ package lol.pyr.znpcsplus.api.skin; +import java.net.URL; + public interface SkinDescriptorFactory { SkinDescriptor createMirrorDescriptor(); SkinDescriptor createRefreshingDescriptor(String playerName); SkinDescriptor createStaticDescriptor(String playerName); SkinDescriptor createStaticDescriptor(String texture, String signature); + SkinDescriptor createUrlDescriptor(String url, String variant); + SkinDescriptor createUrlDescriptor(URL url, String variant); } diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/AxolotlVariant.java b/api/src/main/java/lol/pyr/znpcsplus/util/AxolotlVariant.java new file mode 100644 index 0000000..b38b907 --- /dev/null +++ b/api/src/main/java/lol/pyr/znpcsplus/util/AxolotlVariant.java @@ -0,0 +1,9 @@ +package lol.pyr.znpcsplus.util; + +public enum AxolotlVariant { + LUCY, + WILD, + GOLD, + CYAN, + BLUE +} diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/CatVariant.java b/api/src/main/java/lol/pyr/znpcsplus/util/CatVariant.java index 843036f..9aaa7f4 100644 --- a/api/src/main/java/lol/pyr/znpcsplus/util/CatVariant.java +++ b/api/src/main/java/lol/pyr/znpcsplus/util/CatVariant.java @@ -1,25 +1,15 @@ package lol.pyr.znpcsplus.util; public enum CatVariant { - TABBY(0), - BLACK(1), - RED(2), - SIAMESE(3), - BRITISH_SHORTHAIR(4), - CALICO(5), - PERSIAN(6), - RAGDOLL(7), - WHITE(8), - JELLIE(9), - ALL_BLACK(10); - - private final int id; - - CatVariant(int id) { - this.id = id; - } - - public int getId() { - return id; - } + TABBY, + BLACK, + RED, + SIAMESE, + BRITISH_SHORTHAIR, + CALICO, + PERSIAN, + RAGDOLL, + WHITE, + JELLIE, + ALL_BLACK } diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/HorseArmor.java b/api/src/main/java/lol/pyr/znpcsplus/util/HorseArmor.java new file mode 100644 index 0000000..80fa2f2 --- /dev/null +++ b/api/src/main/java/lol/pyr/znpcsplus/util/HorseArmor.java @@ -0,0 +1,8 @@ +package lol.pyr.znpcsplus.util; + +public enum HorseArmor { + NONE, + IRON, + GOLD, + DIAMOND +} diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/HorseColor.java b/api/src/main/java/lol/pyr/znpcsplus/util/HorseColor.java new file mode 100644 index 0000000..ae6327a --- /dev/null +++ b/api/src/main/java/lol/pyr/znpcsplus/util/HorseColor.java @@ -0,0 +1,11 @@ +package lol.pyr.znpcsplus.util; + +public enum HorseColor { + WHITE, + CREAMY, + CHESTNUT, + BROWN, + BLACK, + GRAY, + DARK_BROWN +} diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/HorseStyle.java b/api/src/main/java/lol/pyr/znpcsplus/util/HorseStyle.java new file mode 100644 index 0000000..b5544c4 --- /dev/null +++ b/api/src/main/java/lol/pyr/znpcsplus/util/HorseStyle.java @@ -0,0 +1,9 @@ +package lol.pyr.znpcsplus.util; + +public enum HorseStyle { + NONE, + WHITE, + WHITEFIELD, + WHITE_DOTS, + BLACK_DOTS +} diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/HorseType.java b/api/src/main/java/lol/pyr/znpcsplus/util/HorseType.java new file mode 100644 index 0000000..9526d67 --- /dev/null +++ b/api/src/main/java/lol/pyr/znpcsplus/util/HorseType.java @@ -0,0 +1,9 @@ +package lol.pyr.znpcsplus.util; + +public enum HorseType { + HORSE, + DONKEY, + MULE, + ZOMBIE, + SKELETON +} diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/LlamaVariant.java b/api/src/main/java/lol/pyr/znpcsplus/util/LlamaVariant.java new file mode 100644 index 0000000..be5cdc9 --- /dev/null +++ b/api/src/main/java/lol/pyr/znpcsplus/util/LlamaVariant.java @@ -0,0 +1,8 @@ +package lol.pyr.znpcsplus.util; + +public enum LlamaVariant { + CREAMY, + WHITE, + BROWN, + GRAY +} diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/MooshroomVariant.java b/api/src/main/java/lol/pyr/znpcsplus/util/MooshroomVariant.java new file mode 100644 index 0000000..f79fa0b --- /dev/null +++ b/api/src/main/java/lol/pyr/znpcsplus/util/MooshroomVariant.java @@ -0,0 +1,10 @@ +package lol.pyr.znpcsplus.util; + +public enum MooshroomVariant { + RED, + BROWN; + + public static String getVariantName(MooshroomVariant variant) { + return variant.name().toLowerCase(); + } +} diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/OcelotType.java b/api/src/main/java/lol/pyr/znpcsplus/util/OcelotType.java new file mode 100644 index 0000000..593ec57 --- /dev/null +++ b/api/src/main/java/lol/pyr/znpcsplus/util/OcelotType.java @@ -0,0 +1,8 @@ +package lol.pyr.znpcsplus.util; + +public enum OcelotType { + OCELOT, + TUXEDO, + TABBY, + SIAMESE, +} diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/PandaGene.java b/api/src/main/java/lol/pyr/znpcsplus/util/PandaGene.java new file mode 100644 index 0000000..dcb3f47 --- /dev/null +++ b/api/src/main/java/lol/pyr/znpcsplus/util/PandaGene.java @@ -0,0 +1,11 @@ +package lol.pyr.znpcsplus.util; + +public enum PandaGene { + NORMAL, + LAZY, + WORRIED, + PLAYFUL, + BROWN, + WEAK, + AGGRESSIVE +} diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/ParrotVariant.java b/api/src/main/java/lol/pyr/znpcsplus/util/ParrotVariant.java index 5014e03..82d56b1 100644 --- a/api/src/main/java/lol/pyr/znpcsplus/util/ParrotVariant.java +++ b/api/src/main/java/lol/pyr/znpcsplus/util/ParrotVariant.java @@ -5,6 +5,5 @@ public enum ParrotVariant { BLUE, GREEN, YELLOW_BLUE, - GRAY, - NONE // only used to set empty nbt compound + GRAY } diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/PuffState.java b/api/src/main/java/lol/pyr/znpcsplus/util/PuffState.java new file mode 100644 index 0000000..0243932 --- /dev/null +++ b/api/src/main/java/lol/pyr/znpcsplus/util/PuffState.java @@ -0,0 +1,7 @@ +package lol.pyr.znpcsplus.util; + +public enum PuffState { + DEFLATED, + HALF_INFLATED, + FULLY_INFLATED, +} diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/VillagerProfession.java b/api/src/main/java/lol/pyr/znpcsplus/util/VillagerProfession.java index b083f55..f02a53c 100644 --- a/api/src/main/java/lol/pyr/znpcsplus/util/VillagerProfession.java +++ b/api/src/main/java/lol/pyr/znpcsplus/util/VillagerProfession.java @@ -2,28 +2,28 @@ package lol.pyr.znpcsplus.util; public enum VillagerProfession { NONE(0), - ARMORER(3), - BUTCHER(4), - CARTOGRAPHER(1), - CLERIC(2), - FARMER(0), - FISHERMAN(0), - FLETCHER(0), - LEATHER_WORKER(4), - LIBRARIAN(1), - MASON(-1), - NITWIT(5), - SHEPHERD(0), - TOOL_SMITH(3), - WEAPON_SMITH(3); + ARMORER(1), + BUTCHER(2), + CARTOGRAPHER(3), + CLERIC(4), + FARMER(5), + FISHERMAN(6), + FLETCHER(7), + LEATHER_WORKER(8), + LIBRARIAN(9), + MASON(10), + NITWIT(11), + SHEPHERD(12), + TOOL_SMITH(13), + WEAPON_SMITH(14); - private final int legacyId; + private final int id; - VillagerProfession(int legacyId) { - this.legacyId = legacyId; + VillagerProfession(int id) { + this.id = id; } - public int getLegacyId() { - return legacyId; + public int getId() { + return id; } } diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/VillagerType.java b/api/src/main/java/lol/pyr/znpcsplus/util/VillagerType.java index d29c12b..77623ff 100644 --- a/api/src/main/java/lol/pyr/znpcsplus/util/VillagerType.java +++ b/api/src/main/java/lol/pyr/znpcsplus/util/VillagerType.java @@ -1,11 +1,20 @@ package lol.pyr.znpcsplus.util; public enum VillagerType { - DESERT, - JUNGLE, - PLAINS, - SAVANNA, - SNOW, - SWAMP, - TAIGA + DESERT(0), + JUNGLE(1), + PLAINS(2), + SAVANNA(3), + SNOW(4), + SWAMP(5), + TAIGA(6); + private final int id; + + VillagerType(int id) { + this.id = id; + } + + public int getId() { + return id; + } } diff --git a/build.gradle b/build.gradle index aa4ee20..4785db9 100644 --- a/build.gradle +++ b/build.gradle @@ -8,6 +8,10 @@ subprojects { toolchain.languageVersion.set(JavaLanguageVersion.of(8)) } + dependencies { + compileOnly "org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT" + } + repositories { mavenCentral() maven { diff --git a/plugin/build.gradle b/plugin/build.gradle index f02091b..bf80167 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -16,8 +16,6 @@ processResources { } dependencies { - compileOnly "org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT" - compileOnly "me.clip:placeholderapi:2.11.3" // Placeholder support implementation "com.google.code.gson:gson:2.10.1" // JSON parsing implementation "org.bstats:bstats-bukkit:3.0.2" // Plugin stats diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java b/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java index dc376a0..8b822c1 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java @@ -28,9 +28,11 @@ import lol.pyr.znpcsplus.entity.EntityPropertyImpl; import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; import lol.pyr.znpcsplus.interaction.ActionRegistry; import lol.pyr.znpcsplus.interaction.InteractionPacketListener; -import lol.pyr.znpcsplus.metadata.*; import lol.pyr.znpcsplus.npc.*; -import lol.pyr.znpcsplus.packets.*; +import lol.pyr.znpcsplus.packets.PacketFactory; +import lol.pyr.znpcsplus.packets.V1_17PacketFactory; +import lol.pyr.znpcsplus.packets.V1_19PacketFactory; +import lol.pyr.znpcsplus.packets.V1_8PacketFactory; import lol.pyr.znpcsplus.parsers.*; import lol.pyr.znpcsplus.scheduling.FoliaScheduler; import lol.pyr.znpcsplus.scheduling.SpigotScheduler; @@ -126,8 +128,8 @@ public class ZNpcsPlus extends JavaPlugin { ConfigManager configManager = new ConfigManager(getDataFolder()); MojangSkinCache skinCache = new MojangSkinCache(configManager); EntityPropertyRegistryImpl propertyRegistry = new EntityPropertyRegistryImpl(skinCache); - MetadataFactory metadataFactory = setupMetadataFactory(); - PacketFactory packetFactory = setupPacketFactory(scheduler, metadataFactory, propertyRegistry); + PacketFactory packetFactory = setupPacketFactory(scheduler, propertyRegistry); + propertyRegistry.registerTypes(packetFactory); ActionRegistry actionRegistry = new ActionRegistry(); NpcTypeRegistryImpl typeRegistry = new NpcTypeRegistryImpl(); @@ -140,7 +142,7 @@ public class ZNpcsPlus extends JavaPlugin { DataImporterRegistry importerRegistry = new DataImporterRegistry(configManager, adventure, scheduler, packetFactory, textSerializer, typeRegistry, getDataFolder().getParentFile(), - propertyRegistry, skinCache); + propertyRegistry, skinCache, npcRegistry); log(ChatColor.WHITE + " * Registerring components..."); @@ -197,10 +199,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.setProperty(propertyRegistry.getByName("look", Boolean.class), true); + 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++; } } @@ -210,18 +211,15 @@ public class ZNpcsPlus extends JavaPlugin { public void onDisable() { NpcApiProvider.unregister(); for (Runnable runnable : shutdownTasks) runnable.run(); + shutdownTasks.clear(); PacketEvents.getAPI().terminate(); } - private PacketFactory setupPacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory, EntityPropertyRegistryImpl propertyRegistry) { + private PacketFactory setupPacketFactory(TaskScheduler scheduler, EntityPropertyRegistryImpl propertyRegistry) { HashMap> versions = new HashMap<>(); - versions.put(ServerVersion.V_1_8, LazyLoader.of(() -> new V1_8PacketFactory(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer))); - versions.put(ServerVersion.V_1_9, LazyLoader.of(() -> new V1_9PacketFactory(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer))); - versions.put(ServerVersion.V_1_10, LazyLoader.of(() -> new V1_10PacketFactory(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer))); - versions.put(ServerVersion.V_1_14, LazyLoader.of(() -> new V1_14PacketFactory(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer))); - versions.put(ServerVersion.V_1_16, LazyLoader.of(() -> new V1_16PacketFactory(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer))); - versions.put(ServerVersion.V_1_17, LazyLoader.of(() -> new V1_17PacketFactory(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer))); - versions.put(ServerVersion.V_1_19, LazyLoader.of(() -> new V1_19PacketFactory(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer))); + versions.put(ServerVersion.V_1_8, LazyLoader.of(() -> new V1_8PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer))); + versions.put(ServerVersion.V_1_17, LazyLoader.of(() -> new V1_17PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer))); + versions.put(ServerVersion.V_1_19, LazyLoader.of(() -> new V1_19PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer))); ServerVersion version = packetEvents.getServerManager().getVersion(); if (versions.containsKey(version)) return versions.get(version).get(); @@ -233,31 +231,6 @@ public class ZNpcsPlus extends JavaPlugin { throw new RuntimeException("Unsupported version!"); } - private MetadataFactory setupMetadataFactory() { - HashMap> versions = new HashMap<>(); - versions.put(ServerVersion.V_1_8, LazyLoader.of(V1_8MetadataFactory::new)); - versions.put(ServerVersion.V_1_9, LazyLoader.of(V1_9MetadataFactory::new)); - versions.put(ServerVersion.V_1_10, LazyLoader.of(V1_10MetadataFactory::new)); - versions.put(ServerVersion.V_1_11, LazyLoader.of(V1_11MetadataFactory::new)); - versions.put(ServerVersion.V_1_12, LazyLoader.of(V1_12MetadataFactory::new)); - versions.put(ServerVersion.V_1_13, LazyLoader.of(V1_13MetadataFactory::new)); - versions.put(ServerVersion.V_1_14, LazyLoader.of(V1_14MetadataFactory::new)); - versions.put(ServerVersion.V_1_15, LazyLoader.of(V1_15MetadataFactory::new)); - versions.put(ServerVersion.V_1_16, LazyLoader.of(V1_16MetadataFactory::new)); - versions.put(ServerVersion.V_1_17, LazyLoader.of(V1_17MetadataFactory::new)); - versions.put(ServerVersion.V_1_19, LazyLoader.of(V1_19MetadataFactory::new)); - - ServerVersion version = packetEvents.getServerManager().getVersion(); - if (versions.containsKey(version)) return versions.get(version).get(); - for (ServerVersion v : ServerVersion.reversedValues()) { - if (v.isNewerThan(version)) continue; - if (!versions.containsKey(v)) continue; - return versions.get(v).get(); - } - throw new RuntimeException("Unsupported version!"); - } - - private void registerCommands(NpcRegistryImpl npcRegistry, MojangSkinCache skinCache, BukkitAudiences adventure, ActionRegistry actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, DataImporterRegistry importerRegistry, @@ -277,6 +250,7 @@ public class ZNpcsPlus extends JavaPlugin { manager.registerParser(Color.class, new ColorParser(incorrectUsageMessage)); manager.registerParser(Vector3f.class, new Vector3fParser(incorrectUsageMessage)); + // TODO: Need to find a better way to do this registerEnumParser(manager, NpcPose.class, incorrectUsageMessage); registerEnumParser(manager, DyeColor.class, incorrectUsageMessage); registerEnumParser(manager, CatVariant.class, incorrectUsageMessage); @@ -288,6 +262,16 @@ public class ZNpcsPlus extends JavaPlugin { registerEnumParser(manager, VillagerType.class, incorrectUsageMessage); registerEnumParser(manager, VillagerProfession.class, incorrectUsageMessage); registerEnumParser(manager, VillagerLevel.class, incorrectUsageMessage); + registerEnumParser(manager, AxolotlVariant.class, incorrectUsageMessage); + registerEnumParser(manager, HorseType.class, incorrectUsageMessage); + registerEnumParser(manager, HorseStyle.class, incorrectUsageMessage); + registerEnumParser(manager, HorseColor.class, incorrectUsageMessage); + registerEnumParser(manager, HorseArmor.class, incorrectUsageMessage); + registerEnumParser(manager, LlamaVariant.class, incorrectUsageMessage); + registerEnumParser(manager, MooshroomVariant.class, incorrectUsageMessage); + registerEnumParser(manager, OcelotType.class, incorrectUsageMessage); + registerEnumParser(manager, PandaGene.class, incorrectUsageMessage); + registerEnumParser(manager, PuffState.class, incorrectUsageMessage); manager.registerCommand("npc", new MultiCommand(loadHelpMessage("root")) .addSubcommand("center", new CenterCommand(npcRegistry)) @@ -309,11 +293,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")) diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/SkinCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/SkinCommand.java index abe40fd..dc9832f 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/commands/SkinCommand.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/SkinCommand.java @@ -17,6 +17,8 @@ import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import java.net.MalformedURLException; +import java.net.URL; import java.util.Collections; import java.util.List; @@ -44,9 +46,7 @@ public class SkinCommand implements CommandHandler { npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), new MirrorDescriptor(skinCache)); npc.respawn(); context.halt(Component.text("The NPC's skin will now mirror the player that it's being displayed to", NamedTextColor.GREEN)); - } - - if (type.equalsIgnoreCase("static")) { + } else if (type.equalsIgnoreCase("static")) { context.ensureArgsNotEmpty(); String name = context.dumpAllArgs(); context.send(Component.text("Fetching skin \"" + name + "\"...", NamedTextColor.GREEN)); @@ -57,26 +57,51 @@ public class SkinCommand implements CommandHandler { } npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), skin); npc.respawn(); - context.send(Component.text("The NPC's skin has been set to \"" + name + "\"")); + context.send(Component.text("The NPC's skin has been set to \"" + name + "\"", NamedTextColor.GREEN)); }); return; - } - - if (type.equalsIgnoreCase("dynamic")) { + } else if (type.equalsIgnoreCase("dynamic")) { context.ensureArgsNotEmpty(); String name = context.dumpAllArgs(); npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), new FetchingDescriptor(skinCache, name)); npc.respawn(); context.halt(Component.text("The NPC's skin will now be resolved per-player from \"" + name + "\"")); + } else if (type.equalsIgnoreCase("url")) { + context.ensureArgsNotEmpty(); + String variant = context.popString().toLowerCase(); + if (!variant.equalsIgnoreCase("slim") && !variant.equalsIgnoreCase("classic")) { + context.send(Component.text("Invalid skin variant! Please use one of the following: slim, classic", NamedTextColor.RED)); + return; + } + String urlString = context.dumpAllArgs(); + try { + URL url = new URL(urlString); + context.send(Component.text("Fetching skin from url \"" + urlString + "\"...", NamedTextColor.GREEN)); + PrefetchedDescriptor.fromUrl(skinCache, url , variant).thenAccept(skin -> { + if (skin.getSkin() == null) { + context.send(Component.text("Failed to fetch skin, are you sure the url is valid?", NamedTextColor.RED)); + return; + } + npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), skin); + npc.respawn(); + context.send(Component.text("The NPC's skin has been set.", NamedTextColor.GREEN)); + }); + } catch (MalformedURLException e) { + context.send(Component.text("Invalid url!", NamedTextColor.RED)); + } + return; } - context.send(Component.text("Unknown skin type! Please use one of the following: mirror, static, dynamic")); + context.send(Component.text("Unknown skin type! Please use one of the following: mirror, static, dynamic, url")); } @Override public List suggest(CommandContext context) throws CommandExecutionException { if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds()); - if (context.argSize() == 2) return context.suggestLiteral("mirror", "static", "dynamic"); + if (context.argSize() == 2) return context.suggestLiteral("mirror", "static", "dynamic", "url"); if (context.matchSuggestion("*", "static")) return context.suggestPlayers(); + if (context.argSize() == 3 && context.matchSuggestion("*", "url")) { + return context.suggestLiteral("slim", "classic"); + } return Collections.emptyList(); } } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloAddCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloAddCommand.java index cf4ed32..f739d18 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloAddCommand.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloAddCommand.java @@ -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 "); 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)); } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloAddItemCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloAddItemCommand.java new file mode 100644 index 0000000..cb23a56 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloAddItemCommand.java @@ -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 "); + 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 suggest(CommandContext context) throws CommandExecutionException { + if (context.argSize() == 1) return context.suggestCollection(registry.getModifiableIds()); + return Collections.emptyList(); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloInfoCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloInfoCommand.java index f9e2c5e..20c5a6c 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloInfoCommand.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloInfoCommand.java @@ -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); } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloInsertCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloInsertCommand.java index 7429410..8bb8471 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloInsertCommand.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloInsertCommand.java @@ -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)); } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloInsertItemCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloInsertItemCommand.java new file mode 100644 index 0000000..68273e4 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloInsertItemCommand.java @@ -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 "); + 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 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(); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloSetCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloSetCommand.java index df3678a..7b106b0 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloSetCommand.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloSetCommand.java @@ -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(); } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloSetItemCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloSetItemCommand.java new file mode 100644 index 0000000..1e623ab --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/hologram/HoloSetItemCommand.java @@ -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 "); + 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 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(); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/property/PropertyRemoveCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/property/PropertyRemoveCommand.java index 4bf648d..b517d74 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/commands/property/PropertyRemoveCommand.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/property/PropertyRemoveCommand.java @@ -28,7 +28,8 @@ public class PropertyRemoveCommand implements CommandHandler { NpcImpl npc = entry.getNpc(); EntityPropertyImpl property = context.parse(EntityPropertyImpl.class); if (!npc.hasProperty(property)) context.halt(Component.text("This npc doesn't have the " + property.getName() + " property set", NamedTextColor.RED)); - npc.removeProperty(property); + if (!property.isPlayerModifiable()) context.halt(Component.text("This property is not modifiable by players", NamedTextColor.RED)); + npc.setProperty(property, null); context.send(Component.text("Removed property " + property.getName() + " from NPC " + entry.getId(), NamedTextColor.GREEN)); } @@ -36,7 +37,7 @@ public class PropertyRemoveCommand implements CommandHandler { public List suggest(CommandContext context) throws CommandExecutionException { if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds()); if (context.argSize() == 2) return context.suggestStream(context.suggestionParse(0, NpcEntryImpl.class) - .getNpc().getAppliedProperties().stream().map(EntityProperty::getName)); + .getNpc().getAppliedProperties().stream().filter(EntityProperty::isPlayerModifiable).map(EntityProperty::getName)); return Collections.emptyList(); } } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/property/PropertySetCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/property/PropertySetCommand.java index 1813ea4..0380025 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/commands/property/PropertySetCommand.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/property/PropertySetCommand.java @@ -1,8 +1,11 @@ package lol.pyr.znpcsplus.commands.property; +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState; import com.github.retrooper.packetevents.protocol.world.states.type.StateType; import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes; +import io.github.retrooper.packetevents.util.SpigotConversionUtil; import lol.pyr.director.adventure.command.CommandContext; import lol.pyr.director.adventure.command.CommandHandler; import lol.pyr.director.common.command.CommandExecutionException; @@ -15,9 +18,9 @@ import lol.pyr.znpcsplus.util.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Color; -import org.bukkit.DyeColor; -import org.bukkit.inventory.ItemStack; +import com.github.retrooper.packetevents.protocol.item.ItemStack; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -42,12 +45,12 @@ public class PropertySetCommand implements CommandHandler { Object value; String valueName; if (type == ItemStack.class) { - ItemStack bukkitStack = context.ensureSenderIsPlayer().getInventory().getItemInHand(); + org.bukkit.inventory.ItemStack bukkitStack = context.ensureSenderIsPlayer().getInventory().getItemInHand(); if (bukkitStack.getAmount() == 0) { value = null; valueName = "EMPTY"; } else { - value = bukkitStack; + value = SpigotConversionUtil.fromBukkitItemStack(bukkitStack); valueName = bukkitStack.toString(); } } @@ -60,7 +63,7 @@ public class PropertySetCommand implements CommandHandler { valueName = "NONE"; } else if (type == ParrotVariant.class && context.argSize() < 1 && npc.getProperty(property) != null) { - value = ParrotVariant.NONE; + value = null; valueName = "NONE"; } else if (type == BlockState.class) { @@ -96,6 +99,24 @@ public class PropertySetCommand implements CommandHandler { return; } } + else if (type == SpellType.class) { + if (PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_13)) { + value = context.parse(type); + valueName = String.valueOf(value); + if (((SpellType) value).ordinal() > 3) { + context.send(Component.text("Spell type " + valueName + " is not supported on this version", NamedTextColor.RED)); + return; + } + } + else { + value = context.parse(type); + valueName = String.valueOf(value); + } + } + else if (type == NpcEntryImpl.class) { + value = context.parse(type); + valueName = value == null ? "NONE" : ((NpcEntryImpl) value).getId(); + } else { value = context.parse(type); valueName = String.valueOf(value); @@ -117,19 +138,16 @@ public class PropertySetCommand implements CommandHandler { if (context.argSize() == 3) { if (type == Boolean.class) return context.suggestLiteral("true", "false"); if (type == NamedTextColor.class) return context.suggestCollection(NamedTextColor.NAMES.keys()); - if (type == NpcPose.class) return context.suggestEnum(NpcPose.values()); if (type == Color.class) return context.suggestLiteral("0x0F00FF", "#FFFFFF"); - if (type == DyeColor.class) return context.suggestEnum(DyeColor.values()); - if (type == CatVariant.class) return context.suggestEnum(CatVariant.values()); - if (type == CreeperState.class) return context.suggestEnum(CreeperState.values()); - if (type == ParrotVariant.class) return context.suggestEnum(ParrotVariant.values()); if (type == BlockState.class) return context.suggestLiteral("hand", "looking_at", "block"); - if (type == SpellType.class) return context.suggestEnum(SpellType.values()); - if (type == FoxVariant.class) return context.suggestEnum(FoxVariant.values()); - if (type == FrogVariant.class) return context.suggestEnum(FrogVariant.values()); - if (type == VillagerType.class) return context.suggestEnum(VillagerType.values()); - if (type == VillagerProfession.class) return context.suggestEnum(VillagerProfession.values()); - if (type == VillagerLevel.class) return context.suggestEnum(VillagerLevel.values()); + if (type == SpellType.class) return PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_13) ? + context.suggestEnum(Arrays.stream(SpellType.values()).filter(spellType -> spellType.ordinal() <= 3).toArray(SpellType[]::new)) : + context.suggestEnum(SpellType.values()); + + // Suggest enum values directly + if (type.isEnum()) { + return context.suggestEnum((Enum[]) type.getEnumConstants()); + } } else if (context.argSize() == 4) { if (type == BlockState.class) { diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/DataImporterRegistry.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/DataImporterRegistry.java index 7fc000e..98a7c0d 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/DataImporterRegistry.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/DataImporterRegistry.java @@ -1,8 +1,10 @@ package lol.pyr.znpcsplus.conversion; import lol.pyr.znpcsplus.config.ConfigManager; +import lol.pyr.znpcsplus.conversion.citizens.CitizensImporter; import lol.pyr.znpcsplus.conversion.znpcs.ZNpcImporter; import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; +import lol.pyr.znpcsplus.npc.NpcRegistryImpl; import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl; import lol.pyr.znpcsplus.packets.PacketFactory; import lol.pyr.znpcsplus.scheduling.TaskScheduler; @@ -23,14 +25,14 @@ public class DataImporterRegistry { public DataImporterRegistry(ConfigManager configManager, BukkitAudiences adventure, TaskScheduler taskScheduler, PacketFactory packetFactory, LegacyComponentSerializer textSerializer, NpcTypeRegistryImpl typeRegistry, File pluginsFolder, EntityPropertyRegistryImpl propertyRegistry, - MojangSkinCache skinCache) { + MojangSkinCache skinCache, NpcRegistryImpl npcRegistry) { register("znpcs", LazyLoader.of(() -> new ZNpcImporter(configManager, adventure, taskScheduler, packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "ServersNPC/data.json")))); register("znpcsplus_legacy", LazyLoader.of(() -> new ZNpcImporter(configManager, adventure, taskScheduler, packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "ZNPCsPlusLegacy/data.json")))); - /* register("citizens", LazyLoader.of(() -> new CitizensImporter(configManager, adventure, bungeeConnector, taskScheduler, - packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "Citizens/saves.yml")))); */ + register("citizens", LazyLoader.of(() -> new CitizensImporter(configManager, adventure, taskScheduler, + packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "Citizens/saves.yml"), npcRegistry))); } private void register(String id, LazyLoader loader) { diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/CitizensImporter.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/CitizensImporter.java index a5c2632..8a05461 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/CitizensImporter.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/CitizensImporter.java @@ -2,19 +2,28 @@ package lol.pyr.znpcsplus.conversion.citizens; import lol.pyr.znpcsplus.config.ConfigManager; import lol.pyr.znpcsplus.conversion.DataImporter; +import lol.pyr.znpcsplus.conversion.citizens.model.CitizensTrait; +import lol.pyr.znpcsplus.conversion.citizens.model.CitizensTraitsRegistry; import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; import lol.pyr.znpcsplus.npc.NpcEntryImpl; +import lol.pyr.znpcsplus.npc.NpcImpl; +import lol.pyr.znpcsplus.npc.NpcRegistryImpl; import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl; import lol.pyr.znpcsplus.packets.PacketFactory; import lol.pyr.znpcsplus.scheduling.TaskScheduler; import lol.pyr.znpcsplus.skin.cache.MojangSkinCache; +import lol.pyr.znpcsplus.util.NpcLocation; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.UUID; @SuppressWarnings("FieldCanBeLocal") public class CitizensImporter implements DataImporter { @@ -27,11 +36,13 @@ public class CitizensImporter implements DataImporter { private final EntityPropertyRegistryImpl propertyRegistry; private final MojangSkinCache skinCache; private final File dataFile; + private final CitizensTraitsRegistry traitsRegistry; + private final NpcRegistryImpl npcRegistry; public CitizensImporter(ConfigManager configManager, BukkitAudiences adventure, TaskScheduler taskScheduler, PacketFactory packetFactory, LegacyComponentSerializer textSerializer, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, MojangSkinCache skinCache, - File dataFile) { + File dataFile, NpcRegistryImpl npcRegistry) { this.configManager = configManager; this.adventure = adventure; this.scheduler = taskScheduler; @@ -41,13 +52,57 @@ public class CitizensImporter implements DataImporter { this.propertyRegistry = propertyRegistry; this.skinCache = skinCache; this.dataFile = dataFile; + this.traitsRegistry = new CitizensTraitsRegistry(typeRegistry, propertyRegistry, skinCache); + this.npcRegistry = npcRegistry; } @Override public Collection importData() { YamlConfiguration config = YamlConfiguration.loadConfiguration(dataFile); - // TODO - return Collections.emptyList(); + ConfigurationSection npcsSection = config.getConfigurationSection("npc"); + if (npcsSection == null) { + return Collections.emptyList(); + } + ArrayList entries = new ArrayList<>(); + npcsSection.getKeys(false).forEach(key -> { + ConfigurationSection npcSection = npcsSection.getConfigurationSection(key); + if (npcSection == null) { + return; + } + String name = npcSection.getString("name", "Citizens NPC"); + UUID uuid; + try { + uuid = UUID.fromString(npcSection.getString("uuid")); + } catch (IllegalArgumentException e) { + uuid = UUID.randomUUID(); + } + String world = npcSection.getString("traits.location.world"); + if (world == null) { + 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.getType().applyDefaultProperties(npc); + + npc.getHologram().addTextLineComponent(textSerializer.deserialize(name)); + ConfigurationSection traits = npcSection.getConfigurationSection("traits"); + if (traits != null) { + for (String traitName : traits.getKeys(false)) { + Object trait = traits.get(traitName); + CitizensTrait citizensTrait = traitsRegistry.getByName(traitName); + if (citizensTrait != null) { + npc = citizensTrait.apply(npc, trait); + } + } + } + String id = key.toLowerCase(); + while (npcRegistry.getById(id) != null) { + id += "_"; // TODO: make a backup of the old npc instead + } + NpcEntryImpl entry = new NpcEntryImpl(id, npc); + entry.enableEverything(); + entries.add(entry); + }); + return entries; } @Override diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/CitizensTrait.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/CitizensTrait.java new file mode 100644 index 0000000..0811589 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/CitizensTrait.java @@ -0,0 +1,19 @@ +package lol.pyr.znpcsplus.conversion.citizens.model; + +import lol.pyr.znpcsplus.npc.NpcImpl; +import org.jetbrains.annotations.NotNull; + +public abstract class CitizensTrait { + private final String identifier; + + public CitizensTrait(String identifier) { + this.identifier = identifier; + } + + public String getIdentifier() { + return identifier; + } + + public abstract @NotNull NpcImpl apply(NpcImpl npc, Object value); + +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/CitizensTraitsRegistry.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/CitizensTraitsRegistry.java new file mode 100644 index 0000000..ba3ba89 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/CitizensTraitsRegistry.java @@ -0,0 +1,31 @@ +package lol.pyr.znpcsplus.conversion.citizens.model; + +import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry; +import lol.pyr.znpcsplus.api.npc.NpcTypeRegistry; +import lol.pyr.znpcsplus.conversion.citizens.model.traits.*; +import lol.pyr.znpcsplus.skin.cache.MojangSkinCache; + +import java.util.HashMap; + +public class CitizensTraitsRegistry { + private final HashMap traitMap = new HashMap<>(); + + public CitizensTraitsRegistry(NpcTypeRegistry typeRegistry, EntityPropertyRegistry propertyRegistry, MojangSkinCache skinCache) { + register(new LocationTrait()); + register(new TypeTrait(typeRegistry)); + register(new ProfessionTrait(propertyRegistry)); + register(new VillagerTrait(propertyRegistry)); + register(new SkinTrait(propertyRegistry)); + register(new MirrorTrait(propertyRegistry, skinCache)); + register(new SkinLayersTrait(propertyRegistry)); + register(new LookTrait(propertyRegistry)); + } + + public CitizensTrait getByName(String name) { + return traitMap.get(name); + } + + public void register(CitizensTrait trait) { + traitMap.put(trait.getIdentifier(), trait); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/SectionCitizensTrait.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/SectionCitizensTrait.java new file mode 100644 index 0000000..123eca5 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/SectionCitizensTrait.java @@ -0,0 +1,19 @@ +package lol.pyr.znpcsplus.conversion.citizens.model; + +import lol.pyr.znpcsplus.npc.NpcImpl; +import org.bukkit.configuration.ConfigurationSection; +import org.jetbrains.annotations.NotNull; + +public abstract class SectionCitizensTrait extends CitizensTrait { + public SectionCitizensTrait(String identifier) { + super(identifier); + } + + @Override + public @NotNull NpcImpl apply(NpcImpl npc, Object value) { + if (!(value instanceof ConfigurationSection)) return npc; + return apply(npc, (ConfigurationSection) value); + } + + public abstract @NotNull NpcImpl apply(NpcImpl npc, ConfigurationSection section); +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/StringCitizensTrait.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/StringCitizensTrait.java new file mode 100644 index 0000000..58199a4 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/StringCitizensTrait.java @@ -0,0 +1,18 @@ +package lol.pyr.znpcsplus.conversion.citizens.model; + +import lol.pyr.znpcsplus.npc.NpcImpl; +import org.jetbrains.annotations.NotNull; + +public abstract class StringCitizensTrait extends CitizensTrait { + public StringCitizensTrait(String identifier) { + super(identifier); + } + + @Override + public @NotNull NpcImpl apply(NpcImpl npc, Object value) { + if (!(value instanceof String)) return npc; + return apply(npc, (String) value); + } + + public abstract @NotNull NpcImpl apply(NpcImpl npc, String string); +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/LocationTrait.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/LocationTrait.java new file mode 100644 index 0000000..c56793c --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/LocationTrait.java @@ -0,0 +1,25 @@ +package lol.pyr.znpcsplus.conversion.citizens.model.traits; + +import lol.pyr.znpcsplus.conversion.citizens.model.SectionCitizensTrait; +import lol.pyr.znpcsplus.npc.NpcImpl; +import lol.pyr.znpcsplus.util.NpcLocation; +import org.bukkit.configuration.ConfigurationSection; +import org.jetbrains.annotations.NotNull; + +public class LocationTrait extends SectionCitizensTrait { + public LocationTrait() { + super("location"); + } + + @Override + public @NotNull NpcImpl apply(NpcImpl npc, ConfigurationSection section) { + double x = Double.parseDouble(section.getString("x")); + double y = Double.parseDouble(section.getString("y")); + double z = Double.parseDouble(section.getString("z")); + float yaw = Float.parseFloat(section.getString("yaw")); + float pitch = Float.parseFloat(section.getString("pitch")); + NpcLocation location = new NpcLocation(x, y, z, yaw, pitch); + npc.setLocation(location); + return npc; + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/LookTrait.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/LookTrait.java new file mode 100644 index 0000000..0854124 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/LookTrait.java @@ -0,0 +1,22 @@ +package lol.pyr.znpcsplus.conversion.citizens.model.traits; + +import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry; +import lol.pyr.znpcsplus.conversion.citizens.model.SectionCitizensTrait; +import lol.pyr.znpcsplus.npc.NpcImpl; +import org.bukkit.configuration.ConfigurationSection; +import org.jetbrains.annotations.NotNull; + +public class LookTrait extends SectionCitizensTrait { + private final EntityPropertyRegistry registry; + + public LookTrait(EntityPropertyRegistry registry) { + super("lookclose"); + this.registry = registry; + } + + @Override + public @NotNull NpcImpl apply(NpcImpl npc, ConfigurationSection section) { + if (section.getBoolean("enabled")) npc.setProperty(registry.getByName("look", Boolean.class), true); + return npc; + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/MirrorTrait.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/MirrorTrait.java new file mode 100644 index 0000000..19360bf --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/MirrorTrait.java @@ -0,0 +1,27 @@ +package lol.pyr.znpcsplus.conversion.citizens.model.traits; + +import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry; +import lol.pyr.znpcsplus.api.skin.SkinDescriptor; +import lol.pyr.znpcsplus.conversion.citizens.model.SectionCitizensTrait; +import lol.pyr.znpcsplus.npc.NpcImpl; +import lol.pyr.znpcsplus.skin.cache.MojangSkinCache; +import lol.pyr.znpcsplus.skin.descriptor.MirrorDescriptor; +import org.bukkit.configuration.ConfigurationSection; +import org.jetbrains.annotations.NotNull; + +public class MirrorTrait extends SectionCitizensTrait { + private final EntityPropertyRegistry registry; + private final MojangSkinCache skinCache; + + public MirrorTrait(EntityPropertyRegistry registry, MojangSkinCache skinCache) { + super("mirrortrait"); + this.registry = registry; + this.skinCache = skinCache; + } + + @Override + public @NotNull NpcImpl apply(NpcImpl npc, ConfigurationSection section) { + if (section.getBoolean("enabled")) npc.setProperty(registry.getByName("skin", SkinDescriptor.class), new MirrorDescriptor(skinCache)); + return npc; + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/ProfessionTrait.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/ProfessionTrait.java new file mode 100644 index 0000000..551d9a8 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/ProfessionTrait.java @@ -0,0 +1,28 @@ +package lol.pyr.znpcsplus.conversion.citizens.model.traits; + +import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry; +import lol.pyr.znpcsplus.conversion.citizens.model.StringCitizensTrait; +import lol.pyr.znpcsplus.npc.NpcImpl; +import lol.pyr.znpcsplus.util.VillagerProfession; +import org.jetbrains.annotations.NotNull; + +public class ProfessionTrait extends StringCitizensTrait { + private final EntityPropertyRegistry registry; + + public ProfessionTrait(EntityPropertyRegistry registry) { + super("profession"); + this.registry = registry; + } + + @Override + public @NotNull NpcImpl apply(NpcImpl npc, String string) { + VillagerProfession profession; + try { + profession = VillagerProfession.valueOf(string.toUpperCase()); + } catch (IllegalArgumentException ignored) { + profession = VillagerProfession.NONE; + } + npc.setProperty(registry.getByName("villager_profession", VillagerProfession.class), profession); + return npc; + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/SkinLayersTrait.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/SkinLayersTrait.java new file mode 100644 index 0000000..f2d7ed0 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/SkinLayersTrait.java @@ -0,0 +1,38 @@ +package lol.pyr.znpcsplus.conversion.citizens.model.traits; + +import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry; +import lol.pyr.znpcsplus.conversion.citizens.model.SectionCitizensTrait; +import lol.pyr.znpcsplus.npc.NpcImpl; +import org.bukkit.configuration.ConfigurationSection; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +public class SkinLayersTrait extends SectionCitizensTrait { + private final EntityPropertyRegistry registry; + private final Map skinLayers; + + public SkinLayersTrait(EntityPropertyRegistry registry) { + super("skinlayers"); + this.registry = registry; + this.skinLayers = new HashMap<>(); + this.skinLayers.put("cape", "skin_cape"); + this.skinLayers.put("hat", "skin_hat"); + this.skinLayers.put("jacket", "skin_jacket"); + this.skinLayers.put("left_sleeve", "skin_left_sleeve"); + this.skinLayers.put("left_pants", "skin_left_leg"); + this.skinLayers.put("right_sleeve", "skin_right_sleeve"); + this.skinLayers.put("right_pants", "skin_right_leg"); + } + + @Override + public @NotNull NpcImpl apply(NpcImpl npc, ConfigurationSection section) { + for (Map.Entry entry : this.skinLayers.entrySet()) { + String key = entry.getKey(); + String property = entry.getValue(); + if (section.contains(key)) npc.setProperty(registry.getByName(property, Boolean.class), section.getBoolean(key)); + } + return npc; + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/SkinTrait.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/SkinTrait.java new file mode 100644 index 0000000..439c9ff --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/SkinTrait.java @@ -0,0 +1,27 @@ +package lol.pyr.znpcsplus.conversion.citizens.model.traits; + +import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry; +import lol.pyr.znpcsplus.api.skin.SkinDescriptor; +import lol.pyr.znpcsplus.conversion.citizens.model.SectionCitizensTrait; +import lol.pyr.znpcsplus.npc.NpcImpl; +import lol.pyr.znpcsplus.skin.Skin; +import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor; +import org.bukkit.configuration.ConfigurationSection; +import org.jetbrains.annotations.NotNull; + +public class SkinTrait extends SectionCitizensTrait { + private final EntityPropertyRegistry registry; + + public SkinTrait(EntityPropertyRegistry registry) { + super("skintrait"); + this.registry = registry; + } + + @Override + public @NotNull NpcImpl apply(NpcImpl npc, ConfigurationSection section) { + String texture = section.getString("textureRaw"); + String signature = section.getString("signature"); + if (texture != null && signature != null) npc.setProperty(registry.getByName("skin", SkinDescriptor.class), new PrefetchedDescriptor(new Skin(texture, signature))); + return npc; + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/TypeTrait.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/TypeTrait.java new file mode 100644 index 0000000..6af1d85 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/TypeTrait.java @@ -0,0 +1,31 @@ +package lol.pyr.znpcsplus.conversion.citizens.model.traits; + +import lol.pyr.znpcsplus.api.npc.NpcTypeRegistry; +import lol.pyr.znpcsplus.conversion.citizens.model.StringCitizensTrait; +import lol.pyr.znpcsplus.npc.NpcImpl; +import lol.pyr.znpcsplus.npc.NpcTypeImpl; +import org.jetbrains.annotations.NotNull; + +public class TypeTrait extends StringCitizensTrait { + private final NpcTypeRegistry registry; + + public TypeTrait(NpcTypeRegistry registry) { + super("type"); + this.registry = registry; + } + + @Override + public @NotNull NpcImpl apply(NpcImpl npc, String string) { + NpcTypeImpl type = warpNpcType(string); + if (type == null) return npc; + npc.setType(type); + return npc; + } + + private NpcTypeImpl warpNpcType(String name) { + name = name.toLowerCase(); +// if (name.equals("player")) name = "human"; +// else if (name.equals("zombievillager")) name = "zombie_villager"; + return (NpcTypeImpl) registry.getByName(name); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/VillagerTrait.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/VillagerTrait.java new file mode 100644 index 0000000..4998f78 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/citizens/model/traits/VillagerTrait.java @@ -0,0 +1,39 @@ +package lol.pyr.znpcsplus.conversion.citizens.model.traits; + +import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry; +import lol.pyr.znpcsplus.conversion.citizens.model.SectionCitizensTrait; +import lol.pyr.znpcsplus.npc.NpcImpl; +import lol.pyr.znpcsplus.util.VillagerLevel; +import lol.pyr.znpcsplus.util.VillagerType; +import org.bukkit.configuration.ConfigurationSection; +import org.jetbrains.annotations.NotNull; + +public class VillagerTrait extends SectionCitizensTrait { + private final EntityPropertyRegistry registry; + + public VillagerTrait(EntityPropertyRegistry registry) { + super("villagertrait"); + this.registry = registry; + } + + @Override + public @NotNull NpcImpl apply(NpcImpl npc, ConfigurationSection section) { + int level = section.getInt("level"); + String type = section.getString("type", "plains"); + VillagerLevel villagerLevel; + try { + villagerLevel = VillagerLevel.values()[level]; + } catch (ArrayIndexOutOfBoundsException ignored) { + villagerLevel = VillagerLevel.STONE; + } + VillagerType villagerType; + try { + villagerType = VillagerType.valueOf(type.toUpperCase()); + } catch (IllegalArgumentException ignored) { + villagerType = VillagerType.PLAINS; + } + npc.setProperty(registry.getByName("villager_level", VillagerLevel.class), villagerLevel); + npc.setProperty(registry.getByName("villager_type", VillagerType.class), villagerType); + return npc; + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/znpcs/ZNpcImporter.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/znpcs/ZNpcImporter.java index eef3c72..4e0553c 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/znpcs/ZNpcImporter.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/znpcs/ZNpcImporter.java @@ -98,13 +98,14 @@ public class ZNpcImporter implements DataImporter { ZNpcsLocation oldLoc = model.getLocation(); NpcLocation location = new NpcLocation(oldLoc.getX(), oldLoc.getY(), oldLoc.getZ(), oldLoc.getYaw(), oldLoc.getPitch()); UUID uuid = model.getUuid() == null ? UUID.randomUUID() : model.getUuid(); - NpcImpl npc = new NpcImpl(uuid, configManager, packetFactory, textSerializer, oldLoc.getWorld(), typeRegistry.getByName(type), location); + NpcImpl npc = new NpcImpl(uuid, propertyRegistry, configManager, packetFactory, textSerializer, oldLoc.getWorld(), typeRegistry.getByName(type), location); + npc.getType().applyDefaultProperties(npc); HologramImpl hologram = npc.getHologram(); 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()) { diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyImpl.java index d390c58..25786d4 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyImpl.java @@ -1,19 +1,23 @@ package lol.pyr.znpcsplus.entity; +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType; import lol.pyr.znpcsplus.api.entity.EntityProperty; -import lol.pyr.znpcsplus.api.entity.PropertyHolder; +import org.bukkit.entity.Player; -public class EntityPropertyImpl implements EntityProperty { +import java.util.*; + +public abstract class EntityPropertyImpl implements EntityProperty { private final String name; private final T defaultValue; private final Class clazz; - private final PropertySerializer serializer; + private final Set> dependencies = new HashSet<>(); + private boolean playerModifiable = true; - protected EntityPropertyImpl(String name, T defaultValue, Class clazz, PropertySerializer serializer) { + protected EntityPropertyImpl(String name, T defaultValue, Class clazz) { this.name = name.toLowerCase(); this.defaultValue = defaultValue; this.clazz = clazz; - this.serializer = serializer; } @Override @@ -21,24 +25,38 @@ public class EntityPropertyImpl implements EntityProperty { 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 serializer.deserialize(str); - } - @Override public T getDefaultValue() { return defaultValue; } + @Override + public boolean isPlayerModifiable() { + return playerModifiable; + } + + public void setPlayerModifiable(boolean playerModifiable) { + this.playerModifiable = playerModifiable; + } + public Class getType() { return clazz; } + + public void addDependency(EntityPropertyImpl property) { + dependencies.add(property); + } + + protected static EntityData newEntityData(int index, EntityDataType type, V value) { + return new EntityData(index, type, value); + } + + public List applyStandalone(Player player, PacketEntity packetEntity, boolean isSpawned) { + Map map = new HashMap<>(); + apply(player, packetEntity, isSpawned, map); + for (EntityPropertyImpl property : dependencies) property.apply(player, packetEntity, isSpawned, map); + return new ArrayList<>(map.values()); + } + + abstract public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties); } \ No newline at end of file diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java index 27c10eb..c5b08dc 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java @@ -1,23 +1,43 @@ package lol.pyr.znpcsplus.entity; -import org.bukkit.inventory.ItemStack; +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.manager.server.ServerVersion; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; +import com.github.retrooper.packetevents.protocol.nbt.NBTInt; +import com.github.retrooper.packetevents.protocol.nbt.NBTString; +import com.github.retrooper.packetevents.protocol.player.EquipmentSlot; import lol.pyr.znpcsplus.api.entity.EntityProperty; import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry; import lol.pyr.znpcsplus.api.skin.SkinDescriptor; +import lol.pyr.znpcsplus.entity.properties.*; +import lol.pyr.znpcsplus.entity.properties.villager.VillagerLevelProperty; +import lol.pyr.znpcsplus.entity.properties.villager.VillagerProfessionProperty; +import lol.pyr.znpcsplus.entity.properties.villager.VillagerTypeProperty; import lol.pyr.znpcsplus.entity.serializers.*; +import lol.pyr.znpcsplus.packets.PacketFactory; import lol.pyr.znpcsplus.skin.cache.MojangSkinCache; import lol.pyr.znpcsplus.util.*; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Color; import org.bukkit.DyeColor; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; +/** + * 1.8 ... + * 1.9 ... + * 1.10 ... + * 1.11 ... + * 1.12 ... + * 1.13 ... + * 1.14 ... + * 1.15 ... + * 1.16 ... + * 1.17 ... + * 1.18-1.19 ... + * 1.20 ... + */ @SuppressWarnings("unchecked") public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { private final Map, PropertySerializer> serializerMap = new HashMap<>(); @@ -32,6 +52,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { registerSerializer(new ColorPropertySerializer()); registerSerializer(new Vector3fPropertySerializer()); registerSerializer(new BlockStatePropertySerializer()); + registerSerializer(new IntegerPropertySerializer()); registerEnumSerializer(NpcPose.class); registerEnumSerializer(DyeColor.class); @@ -44,140 +65,41 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { registerEnumSerializer(VillagerType.class); registerEnumSerializer(VillagerProfession.class); registerEnumSerializer(VillagerLevel.class); + registerEnumSerializer(AxolotlVariant.class); + registerEnumSerializer(HorseType.class); + registerEnumSerializer(HorseColor.class); + registerEnumSerializer(HorseStyle.class); + registerEnumSerializer(HorseArmor.class); + registerEnumSerializer(LlamaVariant.class); + registerEnumSerializer(MooshroomVariant.class); + registerEnumSerializer(OcelotType.class); + registerEnumSerializer(PandaGene.class); + registerEnumSerializer(PuffState.class); - registerType("glow", NamedTextColor.class); - registerType("fire", false); - registerType("invisible", false); - registerType("silent", false); - registerType("skin", SkinDescriptor.class); - registerType("name", Component.class); - registerType("look", false); - registerType("dinnerbone", false); - - registerType("helmet", ItemStack.class); - registerType("chestplate", ItemStack.class); - registerType("leggings", ItemStack.class); - registerType("boots", ItemStack.class); - registerType("hand", ItemStack.class); - registerType("offhand", ItemStack.class); - + /* registerType("using_item", false); // TODO: fix it for 1.8 and add new property to use offhand item and riptide animation - registerType("potion_color", Color.BLACK); - registerType("potion_ambient", false); - registerType("shaking", false); - registerType("baby", false); // TODO - registerType("pose", NpcPose.STANDING); - - // Player - registerType("skin_cape", true); - registerType("skin_jacket", true); - registerType("skin_left_sleeve", true); - registerType("skin_right_sleeve", true); - registerType("skin_left_leg", true); - registerType("skin_right_leg", true); - registerType("skin_hat", true); - registerType("shoulder_entity_left", ParrotVariant.NONE); - registerType("shoulder_entity_right", ParrotVariant.NONE); // End Crystal registerType("beam_target", null); // TODO: Make a block pos class for this registerType("show_base", true); // TODO - // Armor Stand - registerType("small", false); - registerType("arms", false); - registerType("base_plate", true); - - registerType("head_rotation", Vector3f.zero()); - registerType("body_rotation", Vector3f.zero()); - registerType("left_arm_rotation", new Vector3f(-10, 0, -10)); - registerType("right_arm_rotation", new Vector3f(-15, 0, 10)); - registerType("left_leg_rotation", new Vector3f(-1 , 0, -1)); - registerType("right_leg_rotation", new Vector3f(1, 0, 1)); - - // Axolotl - registerType("axolotl_variant", 0); - registerType("playing_dead", false); // TODO fix disabling - - // Bat - registerType("hanging", false); - - // Bee - registerType("angry", false); - registerType("has_nectar", false); - - // Blaze - registerType("blaze_on_fire", false); - - // Cat - registerType("cat_variant", CatVariant.BLACK); - registerType("cat_lying", false); - registerType("cat_collar_color", DyeColor.RED); - - // Creeper - registerType("creeper_state", CreeperState.IDLE); - registerType("creeper_charged", false); - // Enderman registerType("enderman_held_block", new BlockState(0)); // TODO: figure out the type on this registerType("enderman_screaming", false); // TODO registerType("enderman_staring", false); // TODO - // Evoker - registerType("evoker_spell", SpellType.NONE); - - // Fox - registerType("fox_variant", FoxVariant.RED); - registerType("fox_sitting", false); - registerType("fox_crouching", false); - registerType("fox_sleeping", false); - registerType("fox_faceplanted", false); - - // Frog - registerType("frog_variant", FrogVariant.TEMPERATE); - - // Ghast - registerType("attacking", false); - // Guardian registerType("is_elder", false); // TODO: ensure it only works till 1.10. Note: index is wrong on wiki.vg - // Piglin / Hoglin - registerType("immune_to_zombification", true); - - // Pufferfish - registerType("puff_state", null); // TODO: Make a puff state enum class - // Tropical Fish registerType("tropical_fish_variant", null); // TODO: Maybe make an enum class for this? its just an int on wiki.vg // Sniffer registerType("sniffer_state", null); // TODO: Nothing on wiki.vg, look in mc source - // Horse - registerType("horse_style", 0); // TODO: Figure this out - registerType("horse_chest", false); // TODO - registerType("horse_saddle", false); // TODO - - // LLama - registerType("carpet_color", DyeColor.class); // TODO - registerType("llama_variant", 0); // TODO - - // Panda - registerType("panda_sneezing", false); // TODO - registerType("panda_rolling", false); // TODO - registerType("panda_sitting", false); // TODO - registerType("panda_on_back", false); // TODO - - // Pig - registerType("pig_saddle", false); // TODO - // Rabbit registerType("rabbit_type", 0); // TODO: Figure this out - // Polar Bear - registerType("polar_bear_standing", false); // TODO - // Sheep registerType("sheep_color", DyeColor.WHITE); // TODO: Figure this out registerType("sheep_sheared", false); // TODO @@ -190,14 +112,6 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { registerType("wolf_collar_color", DyeColor.RED); // TODO registerType("wolf_angry", false); // TODO - // Parrot - registerType("parrot_variant", 0); // TODO - - // Villager - registerType("villager_type", VillagerType.PLAINS); - registerType("villager_profession", VillagerProfession.NONE); - registerType("villager_level", VillagerLevel.STONE); - // Show Golem registerType("pumpkin", true); // TODO @@ -206,25 +120,391 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { registerType("shield_height", 0); // TODO: figure this out registerType("shulker_color", DyeColor.RED); // TODO - // Piglin - registerType("piglin_dancing", false); // TODO - registerType("piglin_charging_crossbow", false); // TODO - - // Goat - registerType("has_left_horn", true); - registerType("has_right_horn", true); - - // Vindicator - registerType("celebrating", false); // TODO - // Wither registerType("invulnerable_time", 0); // TODO - // Phantom - registerType("phantom_size", 0); // TODO + */ + } - // Slime - registerType("slime_size", 0); // TODO + public void registerTypes(PacketFactory packetFactory) { + ServerVersion ver = PacketEvents.getAPI().getServerManager().getVersion(); + boolean legacyBooleans = ver.isOlderThan(ServerVersion.V_1_9); + boolean legacyNames = ver.isOlderThan(ServerVersion.V_1_9); + boolean optionalComponents = ver.isNewerThanOrEquals(ServerVersion.V_1_13); + + register(new EquipmentProperty(packetFactory, "helmet", EquipmentSlot.HELMET)); + register(new EquipmentProperty(packetFactory, "chestplate", EquipmentSlot.CHEST_PLATE)); + register(new EquipmentProperty(packetFactory, "leggings", EquipmentSlot.LEGGINGS)); + register(new EquipmentProperty(packetFactory, "boots", EquipmentSlot.BOOTS)); + register(new EquipmentProperty(packetFactory, "hand", EquipmentSlot.MAIN_HAND)); + register(new EquipmentProperty(packetFactory, "offhand", EquipmentSlot.OFF_HAND)); + + register(new NameProperty(legacyNames, optionalComponents)); + register(new DinnerboneProperty(legacyNames, optionalComponents)); + + register(new DummyProperty<>("look", false)); + register(new GlowProperty(packetFactory)); + register(new BitsetProperty("fire", 0, 0x01)); + register(new BitsetProperty("invisible", 0, 0x20)); + register(new HologramItemProperty()); + linkProperties("glow", "fire", "invisible"); + register(new BooleanProperty("silent", 4, false, legacyBooleans)); + + final int tamedIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) tamedIndex = 17; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) tamedIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) tamedIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) tamedIndex = 13; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) tamedIndex = 12; + else tamedIndex = 16; + register(new BitsetProperty("tamed", tamedIndex, 0x04)); + + int potionIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) potionIndex = 10; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) potionIndex = 9; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) potionIndex = 8; + else potionIndex = 7; + register(new EncodedIntegerProperty<>("potion_color", Color.class, potionIndex++, Color::asRGB)); + register(new BooleanProperty("potion_ambient", potionIndex, false, legacyBooleans)); + + int babyIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) babyIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) babyIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) babyIndex = 14; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) babyIndex = 12; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) babyIndex = 11; + else babyIndex = 12; + register(new BooleanProperty("baby", babyIndex, false, legacyBooleans)); + + // Player + register(new DummyProperty<>("skin", SkinDescriptor.class, false)); + final int skinLayersIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) skinLayersIndex = 17; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_16)) skinLayersIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) skinLayersIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) skinLayersIndex = 13; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) skinLayersIndex = 12; + else skinLayersIndex = 10; + register(new BitsetProperty("skin_cape", skinLayersIndex, 0x01)); + register(new BitsetProperty("skin_jacket", skinLayersIndex, 0x02)); + register(new BitsetProperty("skin_left_sleeve", skinLayersIndex, 0x04)); + register(new BitsetProperty("skin_right_sleeve", skinLayersIndex, 0x08)); + register(new BitsetProperty("skin_left_leg", skinLayersIndex, 0x10)); + register(new BitsetProperty("skin_right_leg", skinLayersIndex, 0x20)); + register(new BitsetProperty("skin_hat", skinLayersIndex, 0x40)); + linkProperties("skin_cape", "skin_jacket", "skin_left_sleeve", "skin_right_sleeve", "skin_left_leg", "skin_right_leg", "skin_hat"); + + // Armor Stand + int armorStandIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) armorStandIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) armorStandIndex = 14; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) armorStandIndex = 13; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) armorStandIndex = 11; + else armorStandIndex = 10; + register(new BitsetProperty("small", armorStandIndex, 0x01)); + register(new BitsetProperty("arms", armorStandIndex, 0x04)); + register(new BitsetProperty("base_plate", armorStandIndex++, 0x08, true)); + linkProperties("small", "arms", "base_plate"); + register(new RotationProperty("head_rotation", armorStandIndex++, Vector3f.zero())); + register(new RotationProperty("body_rotation", armorStandIndex++, Vector3f.zero())); + register(new RotationProperty("left_arm_rotation", armorStandIndex++, new Vector3f(-10, 0, -10))); + register(new RotationProperty("right_arm_rotation", armorStandIndex++, new Vector3f(-15, 0, 10))); + register(new RotationProperty("left_leg_rotation", armorStandIndex++, new Vector3f(-1, 0, -1))); + register(new RotationProperty("right_leg_rotation", armorStandIndex, new Vector3f(1, 0, 1))); + + // Ghast + final int ghastAttackingIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) ghastAttackingIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) ghastAttackingIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) ghastAttackingIndex = 14; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) ghastAttackingIndex = 12; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) ghastAttackingIndex = 11; + else ghastAttackingIndex = 16; + register(new BooleanProperty("attacking", ghastAttackingIndex, false, legacyBooleans)); + + // Bat + final int batIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) batIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) batIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) batIndex = 14; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) batIndex = 12; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) batIndex = 11; + else batIndex = 16; + register(new BooleanProperty("hanging", batIndex, false, true /* This isn't a mistake */)); + + // Blaze + final int blazeIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) blazeIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) blazeIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) blazeIndex = 14; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) blazeIndex = 12; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) blazeIndex = 11; + else blazeIndex = 16; + register(new BitsetProperty("blaze_on_fire", blazeIndex, 0x01)); + + // Creeper + int creeperIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) creeperIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) creeperIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) creeperIndex = 14; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) creeperIndex = 12; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) creeperIndex = 11; + else creeperIndex= 16; + register(new EncodedIntegerProperty<>("creeper_state", CreeperState.IDLE, creeperIndex++, CreeperState::getState)); + register(new BooleanProperty("creeper_charged", creeperIndex, false, legacyBooleans)); + + // Abstract Horse + int horseIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) horseIndex = 17; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) horseIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) horseIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) horseIndex = 13; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) horseIndex = 12; + else horseIndex = 16; + int horseEating = ver.isNewerThanOrEquals(ServerVersion.V_1_12) ? 0x10 : 0x20; + register(new BitsetProperty("is_tame", horseIndex, 0x02, false, legacyBooleans)); + register(new BitsetProperty("is_saddled", horseIndex, 0x04, false, legacyBooleans)); + register(new BitsetProperty("is_eating", horseIndex, horseEating, false, legacyBooleans)); + register(new BitsetProperty("is_rearing", horseIndex, horseEating << 1, false, legacyBooleans)); + register(new BitsetProperty("has_mouth_open", horseIndex, horseEating << 2, false, legacyBooleans)); + + // Horse + if (ver.isNewerThanOrEquals(ServerVersion.V_1_8) && ver.isOlderThan(ServerVersion.V_1_9)) { + register(new EncodedByteProperty<>("horse_type", HorseType.HORSE, 19, obj -> (byte) obj.ordinal())); + } else if (ver.isOlderThan(ServerVersion.V_1_11)) { + int horseTypeIndex = 14; + if (ver.isOlderThan(ServerVersion.V_1_10)) horseTypeIndex = 13; + register(new EncodedIntegerProperty<>("horse_type", HorseType.HORSE, horseTypeIndex, Enum::ordinal)); + } + int horseVariantIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_18)) horseVariantIndex = 18; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) horseVariantIndex = 19; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) horseVariantIndex = 18; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) horseVariantIndex = 17; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) horseVariantIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) horseVariantIndex = 14; + else horseVariantIndex = 20; + register(new HorseStyleProperty(horseVariantIndex)); + register(new HorseColorProperty(horseVariantIndex)); + linkProperties("horse_style", "horse_color"); + + // Use chesteplate property for 1.14 and above + if (ver.isOlderThan(ServerVersion.V_1_14)) { + register(new EncodedIntegerProperty<>("horse_armor", HorseArmor.NONE, horseVariantIndex + 2, Enum::ordinal)); + } + + // Chested Horse + if (ver.isOlderThan(ServerVersion.V_1_11)) { + register(new BitsetProperty("has_chest", horseIndex, 0x08, false, legacyBooleans)); + linkProperties("is_saddled", "has_chest", "is_eating", "is_rearing", "has_mouth_open"); + } else { + register(new BooleanProperty("has_chest", horseVariantIndex, false, legacyBooleans)); + linkProperties("is_saddled", "is_eating", "is_rearing", "has_mouth_open"); + } + + // Slime, Magma Cube and Phantom + int sizeIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) sizeIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) sizeIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) sizeIndex = 14; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) sizeIndex = 12; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) sizeIndex = 11; + else sizeIndex = 16; + register(new IntegerProperty("size", sizeIndex, 1, legacyBooleans)); + + // Ocelot + if (ver.isOlderThan(ServerVersion.V_1_14)) { + int ocelotIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) ocelotIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) ocelotIndex = 14; + else ocelotIndex = 18; + if (legacyBooleans) register(new EncodedByteProperty<>("ocelot_type", OcelotType.OCELOT, ocelotIndex, obj -> (byte) obj.ordinal())); + else register(new EncodedIntegerProperty<>("ocelot_type", OcelotType.OCELOT, ocelotIndex, Enum::ordinal)); + } + + // Pig + int pigIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) pigIndex = 17; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) pigIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) pigIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) pigIndex = 13; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) pigIndex = 12; + else pigIndex = 16; + register(new BooleanProperty("pig_saddled", pigIndex, false, legacyBooleans)); + + if (!ver.isNewerThanOrEquals(ServerVersion.V_1_10)) return; + // Polar Bear + int polarBearIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) polarBearIndex = 17; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) polarBearIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) polarBearIndex = 15; + else polarBearIndex = 13; + register(new BooleanProperty("polar_bear_standing", polarBearIndex, false, false)); + + if (!ver.isNewerThanOrEquals(ServerVersion.V_1_11)) return; + // Spellcaster Illager + int spellIndex = 12; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) spellIndex = 17; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) spellIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) spellIndex = 15; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_12)) spellIndex = 13; + register(new EncodedByteProperty<>("spell", SpellType.NONE, spellIndex, obj -> (byte) Math.min(obj.ordinal(), ver.isOlderThan(ServerVersion.V_1_13) ? 3 : 5))); + + // Llama + int llamaIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_18)) llamaIndex = 20; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) llamaIndex = 21; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) llamaIndex = 20; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) llamaIndex = 19; + else llamaIndex = 17; + register(new EncodedIntegerProperty("carpet_color", DyeColor.class, llamaIndex++, obj -> obj == null ? -1 : obj.ordinal())); + register(new EncodedIntegerProperty<>("llama_variant", LlamaVariant.CREAMY, llamaIndex, Enum::ordinal)); + + if (!ver.isNewerThanOrEquals(ServerVersion.V_1_12)) return; + // Parrot + int parrotIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) parrotIndex = 19; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) parrotIndex = 18; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) parrotIndex = 17; + else parrotIndex = 15; + register(new EncodedIntegerProperty<>("parrot_variant", ParrotVariant.RED_BLUE, parrotIndex, Enum::ordinal)); + + // Player + NBTProperty.NBTDecoder parrotVariantDecoder = (variant) -> { + NBTCompound compound = new NBTCompound(); + compound.setTag("id", new NBTString("minecraft:parrot")); + compound.setTag("Variant", new NBTInt(variant.ordinal())); + return compound; + }; + int shoulderIndex = skinLayersIndex+2; + register(new NBTProperty<>("shoulder_entity_left", ParrotVariant.class, shoulderIndex++, parrotVariantDecoder)); + register(new NBTProperty<>("shoulder_entity_right", ParrotVariant.class, shoulderIndex, parrotVariantDecoder)); + + if (!ver.isNewerThanOrEquals(ServerVersion.V_1_13)) return; + // Pufferfish + int pufferfishIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) pufferfishIndex = 17; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) pufferfishIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) pufferfishIndex = 15; + else pufferfishIndex = 13; + register(new EncodedIntegerProperty<>("puff_state", PuffState.DEFLATED, pufferfishIndex, Enum::ordinal)); + + if (!ver.isNewerThanOrEquals(ServerVersion.V_1_14)) return; + // Pose + register(new NpcPoseProperty()); + + // Villager + final int villagerIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) villagerIndex = 18; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) villagerIndex = 17; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) villagerIndex = 16; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) villagerIndex = 13; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) villagerIndex = 12; + else villagerIndex = 16; + register(new VillagerTypeProperty("villager_type", villagerIndex, VillagerType.PLAINS)); + register(new VillagerProfessionProperty("villager_profession", villagerIndex, VillagerProfession.NONE)); + register(new VillagerLevelProperty("villager_level", villagerIndex, VillagerLevel.STONE)); + linkProperties("villager_type", "villager_profession", "villager_level"); + + // Cat + int catIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) catIndex = 19; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) catIndex = 18; + else catIndex = 17; + register(new EncodedIntegerProperty<>("cat_variant", CatVariant.BLACK, catIndex++, Enum::ordinal, EntityDataTypes.CAT_VARIANT)); + register(new BooleanProperty("cat_laying", catIndex++, false, legacyBooleans)); + register(new BooleanProperty("cat_relaxed", catIndex++, false, legacyBooleans)); + register(new EncodedIntegerProperty<>("cat_collar", DyeColor.RED, catIndex, Enum::ordinal)); + + // Fox + int foxIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) foxIndex = 17; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) foxIndex = 16; + else foxIndex = 15; + register(new EncodedIntegerProperty<>("fox_variant", FoxVariant.RED, foxIndex++, Enum::ordinal)); + register(new BitsetProperty("fox_sitting", foxIndex, 0x01)); + register(new BitsetProperty("fox_crouching", foxIndex, 0x04)); + register(new BitsetProperty("fox_sleeping", foxIndex, 0x20)); + linkProperties("fox_sitting", "fox_crouching", "fox_sleeping"); + + int mooshroomIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) mooshroomIndex = 17; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) mooshroomIndex = 16; + else mooshroomIndex = 15; + register(new EncodedStringProperty<>("mooshroom_variant", MooshroomVariant.RED, mooshroomIndex, MooshroomVariant::getVariantName)); + + // Panda + int pandaIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) pandaIndex = 20; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) pandaIndex = 19; + else pandaIndex = 18; + register(new EncodedByteProperty<>("panda_main_gene", PandaGene.NORMAL, pandaIndex++, obj -> (byte) obj.ordinal())); + register(new EncodedByteProperty<>("panda_hidden_gene", PandaGene.NORMAL, pandaIndex++, obj -> (byte) obj.ordinal())); + if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) { + register(new BitsetProperty("panda_sneezing", pandaIndex, 0x02)); + register(new BitsetProperty("panda_rolling", pandaIndex, 0x04)); + register(new BitsetProperty("panda_sitting", pandaIndex, 0x08)); + register(new BitsetProperty("panda_on_back", pandaIndex, 0x10)); + linkProperties("panda_sneezing", "panda_rolling", "panda_sitting", "panda_on_back"); + } else { + register(new BitsetProperty("panda_sneezing", pandaIndex, 0x02)); + register(new BitsetProperty("panda_eating", pandaIndex, 0x04)); + linkProperties("panda_sneezing", "panda_eating"); + } + + + if (!ver.isNewerThanOrEquals(ServerVersion.V_1_15)) return; + + register(new BitsetProperty("fox_faceplanted", foxIndex, 0x40)); + linkProperties("fox_sitting", "fox_crouching", "fox_sleeping", "fox_faceplanted"); + + // Bee + int beeIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) beeIndex = 17; + else beeIndex = 18; + register(new BitsetProperty("has_nectar", beeIndex++, 0x08)); + register(new EncodedIntegerProperty<>("angry", false, beeIndex, enabled -> enabled ? 1 : 0)); + + if (!ver.isNewerThanOrEquals(ServerVersion.V_1_16)) return; + + // Hoglin and Piglin Zombification + final int zombificationIndex; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) zombificationIndex = 17; // Change piglinIndex and pillagerIndex if you change this + else zombificationIndex = 16; + register(new BooleanProperty("hoglin_immune_to_zombification", zombificationIndex, false, legacyBooleans)); + register(new BooleanProperty("piglin_immune_to_zombification", zombificationIndex-1, false, legacyBooleans)); + + // Piglin + int piglinIndex = zombificationIndex; + register(new BooleanProperty("piglin_baby", piglinIndex++, false, legacyBooleans)); + register(new BooleanProperty("piglin_charging_crossbow", piglinIndex++, false, legacyBooleans)); + register(new BooleanProperty("piglin_dancing", piglinIndex, false, legacyBooleans)); + + // Pillager + register(new BooleanProperty("pillager_charging", zombificationIndex, false, legacyBooleans)); + + // Vindicator + int vindicatorIndex = zombificationIndex -1; + register(new BooleanProperty("celebrating", vindicatorIndex, false, legacyBooleans)); + + if (!ver.isNewerThanOrEquals(ServerVersion.V_1_17)) return; + // Axolotl + register(new EncodedIntegerProperty<>("axolotl_variant", AxolotlVariant.LUCY, 17, Enum::ordinal)); + register(new BooleanProperty("playing_dead", 18, false, legacyBooleans)); + + // Goat + register(new BooleanProperty("has_left_horn", 18, true, legacyBooleans)); + register(new BooleanProperty("has_right_horn", 19, true, legacyBooleans)); + + register(new EncodedIntegerProperty<>("shaking", false,7, enabled -> enabled ? 140 : 0)); + if (!ver.isNewerThanOrEquals(ServerVersion.V_1_19)) return; + // Frog + register(new EncodedIntegerProperty<>("frog_variant", FrogVariant.TEMPERATE, 17, Enum::ordinal, EntityDataTypes.FROG_VARIANT)); + + if (!ver.isNewerThanOrEquals(ServerVersion.V_1_20)) return; + + // Camel + register(new BooleanProperty("bashing", 18, false, legacyBooleans)); } private void registerSerializer(PropertySerializer serializer) { @@ -235,18 +515,27 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { serializerMap.put(clazz, new EnumPropertySerializer<>(clazz)); } - private void registerType(String name, Class type) { - registerType(name, null, type); + private void register(EntityPropertyImpl property) { + if (byName.containsKey(property.getName())) + throw new IllegalArgumentException("Duplicate property name: " + property.getName()); + byName.put(property.getName(), property); } - private void registerType(String name, T defaultValue) { - registerType(name, defaultValue, (Class) defaultValue.getClass()); + private void linkProperties(String... names) { + linkProperties(Arrays.stream(names) + .map(this::getByName) + .collect(Collectors.toSet())); } - private void registerType(String name, T defaultValue, Class clazz) { - if (clazz == null) return; - EntityPropertyImpl property = new EntityPropertyImpl<>(name, defaultValue, clazz, (PropertySerializer) serializerMap.get(clazz)); - byName.put(name.toLowerCase(), property); + private void linkProperties(Collection> properties) { + for (EntityPropertyImpl property : properties) for (EntityPropertyImpl dependency : properties) { + if (property.equals(dependency)) continue; + property.addDependency(dependency); + } + } + + public PropertySerializer getSerializer(Class type) { + return (PropertySerializer) serializerMap.get(type); } @Override diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EnumPropertySerializer.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EnumPropertySerializer.java index c9a93c8..d71fb07 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EnumPropertySerializer.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EnumPropertySerializer.java @@ -15,7 +15,11 @@ public class EnumPropertySerializer> implements PropertySerial @Override public T deserialize(String property) { - return Enum.valueOf(enumClass, property.toUpperCase()); + try { + return Enum.valueOf(enumClass, property.toUpperCase()); + } catch (IllegalArgumentException e) { + return null; + } } @Override diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/PacketEntity.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/PacketEntity.java index 3424f07..aef8b03 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/PacketEntity.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/PacketEntity.java @@ -4,6 +4,7 @@ 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 lol.pyr.znpcsplus.api.entity.PropertyHolder; import lol.pyr.znpcsplus.packets.PacketFactory; import lol.pyr.znpcsplus.reflection.Reflections; @@ -11,9 +12,10 @@ import lol.pyr.znpcsplus.util.NpcLocation; import org.bukkit.entity.Player; import java.util.Collection; +import java.util.Set; import java.util.UUID; -public class PacketEntity { +public class PacketEntity implements PropertyHolder { private final PacketFactory packetFactory; private final PropertyHolder properties; @@ -66,11 +68,6 @@ public class PacketEntity { packetFactory.sendAllMetadata(player, this, properties); } - public void remakeTeam(Player player) { - packetFactory.removeTeam(player, this); - packetFactory.createTeam(player, this, properties); - } - private static int reserveEntityID() { if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_14)) { return Reflections.ATOMIC_ENTITY_ID_FIELD.get().incrementAndGet(); @@ -80,4 +77,24 @@ public class PacketEntity { return id; } } + + @Override + public T getProperty(EntityProperty key) { + return properties.getProperty(key); + } + + @Override + public boolean hasProperty(EntityProperty key) { + return properties.hasProperty(key); + } + + @Override + public void setProperty(EntityProperty key, T value) { + properties.setProperty(key, value); + } + + @Override + public Set> getAppliedProperties() { + return properties.getAppliedProperties(); + } } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/PropertySerializer.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/PropertySerializer.java index 73c8182..abd2f39 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/PropertySerializer.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/PropertySerializer.java @@ -4,4 +4,9 @@ public interface PropertySerializer { String serialize(T property); T deserialize(String property); Class getTypeClass(); + + @SuppressWarnings("unchecked") + default String UNSAFE_serialize(Object property) { + return serialize((T) property); + } } \ No newline at end of file diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/BitsetProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/BitsetProperty.java new file mode 100644 index 0000000..1a1e5f2 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/BitsetProperty.java @@ -0,0 +1,43 @@ +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 lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class BitsetProperty extends EntityPropertyImpl { + private final int index; + private final int bitmask; + private final boolean inverted; + private boolean integer = false; + + public BitsetProperty(String name, int index, int bitmask, boolean inverted, boolean integer) { + this(name, index, bitmask, inverted); + this.integer = integer; + } + + public BitsetProperty(String name, int index, int bitmask, boolean inverted) { + super(name, inverted, Boolean.class); + this.index = index; + this.bitmask = bitmask; + this.inverted = inverted; + } + + public BitsetProperty(String name, int index, int bitmask) { + this(name, index, bitmask, false); + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + EntityData oldData = properties.get(index); + boolean enabled = entity.getProperty(this); + if (inverted) enabled = !enabled; + properties.put(index, + integer ? newEntityData(index, EntityDataTypes.INT, (oldData == null ? 0 : (int) oldData.getValue()) | (enabled ? bitmask : 0)) : + newEntityData(index, EntityDataTypes.BYTE, (byte) ((oldData == null ? 0 : (byte) oldData.getValue()) | (enabled ? bitmask : 0)))); + + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/BooleanProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/BooleanProperty.java new file mode 100644 index 0000000..5cdb880 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/BooleanProperty.java @@ -0,0 +1,34 @@ +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 lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class BooleanProperty extends EntityPropertyImpl { + private final int index; + private final boolean legacy; + private final boolean inverted; + + public BooleanProperty(String name, int index, boolean defaultValue, boolean legacy) { + this(name, index, defaultValue, legacy, false); + } + + public BooleanProperty(String name, int index, boolean defaultValue, boolean legacy, boolean inverted) { + super(name, defaultValue, Boolean.class); + this.index = index; + this.legacy = legacy; + this.inverted = inverted; + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + boolean enabled = entity.getProperty(this); + if (inverted) enabled = !enabled; + if (legacy) properties.put(index, newEntityData(index, EntityDataTypes.BYTE, (byte) (enabled ? 1 : 0))); + else properties.put(index, newEntityData(index, EntityDataTypes.BOOLEAN, enabled)); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/DinnerboneProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/DinnerboneProperty.java new file mode 100644 index 0000000..a729c63 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/DinnerboneProperty.java @@ -0,0 +1,33 @@ +package lol.pyr.znpcsplus.entity.properties; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.util.adventure.AdventureSerializer; +import lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; + +import java.util.Map; +import java.util.Optional; + +public class DinnerboneProperty extends EntityPropertyImpl { + private final Object serialized; + private final EntityDataType type; + + public DinnerboneProperty(boolean legacy, boolean optional) { + super("dinnerbone", false, Boolean.class); + Component name = Component.text("Dinnerbone"); + String serialized = legacy ? + AdventureSerializer.getLegacyGsonSerializer().serialize(name) : + AdventureSerializer.getGsonSerializer().serialize(name); + this.serialized = optional ? Optional.of(serialized) : serialized; + this.type = optional ? EntityDataTypes.OPTIONAL_COMPONENT : EntityDataTypes.STRING; + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + properties.put(2, new EntityData(2, type, entity.getProperty(this) ? serialized : null)); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/DummyProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/DummyProperty.java new file mode 100644 index 0000000..eba69a5 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/DummyProperty.java @@ -0,0 +1,33 @@ +package lol.pyr.znpcsplus.entity.properties; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class DummyProperty extends EntityPropertyImpl { + public DummyProperty(String name, T defaultValue) { + this(name, defaultValue, true); + } + + public DummyProperty(String name, Class clazz) { + this(name, clazz, true); + } + + @SuppressWarnings("unchecked") + public DummyProperty(String name, T defaultValue, boolean playerModifiable) { + super(name, defaultValue, (Class) defaultValue.getClass()); + setPlayerModifiable(playerModifiable); + } + + public DummyProperty(String name, Class clazz, boolean playerModifiable) { + super(name, null, clazz); + setPlayerModifiable(playerModifiable); + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/EncodedByteProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/EncodedByteProperty.java new file mode 100644 index 0000000..af64b11 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/EncodedByteProperty.java @@ -0,0 +1,48 @@ +package lol.pyr.znpcsplus.entity.properties; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType; +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 EncodedByteProperty extends EntityPropertyImpl { + private final EntityDataType type; + private final ByteDecoder decoder; + private final int index; + + protected EncodedByteProperty(String name, T defaultValue, Class clazz, int index, ByteDecoder decoder, EntityDataType type) { + super(name, defaultValue, clazz); + this.decoder = decoder; + this.index = index; + this.type = type; + } + + @SuppressWarnings("unchecked") + public EncodedByteProperty(String name, T defaultValue, int index, ByteDecoder decoder) { + this(name, defaultValue, (Class) defaultValue.getClass(), index, decoder, EntityDataTypes.BYTE); + } + + @SuppressWarnings("unchecked") + public EncodedByteProperty(String name, T defaultValue, int index, ByteDecoder decoder, EntityDataType type) { + this(name, defaultValue, (Class) defaultValue.getClass(), index, decoder, type); + } + + public EncodedByteProperty(String name, Class clazz, int index, ByteDecoder decoder) { + this(name, null, clazz, index, decoder, EntityDataTypes.BYTE); + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + T value = entity.getProperty(this); + if (value == null) return; + properties.put(index, newEntityData(index, type, decoder.decode(value))); + } + + public interface ByteDecoder { + byte decode(T obj); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/EncodedIntegerProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/EncodedIntegerProperty.java new file mode 100644 index 0000000..d089547 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/EncodedIntegerProperty.java @@ -0,0 +1,48 @@ +package lol.pyr.znpcsplus.entity.properties; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType; +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 EncodedIntegerProperty extends EntityPropertyImpl { + private final EntityDataType type; + private final IntegerDecoder decoder; + private final int index; + + protected EncodedIntegerProperty(String name, T defaultValue, Class clazz, int index, IntegerDecoder decoder, EntityDataType type) { + super(name, defaultValue, clazz); + this.decoder = decoder; + this.index = index; + this.type = type; + } + + @SuppressWarnings("unchecked") + public EncodedIntegerProperty(String name, T defaultValue, int index, IntegerDecoder decoder) { + this(name, defaultValue, (Class) defaultValue.getClass(), index, decoder, EntityDataTypes.INT); + } + + @SuppressWarnings("unchecked") + public EncodedIntegerProperty(String name, T defaultValue, int index, IntegerDecoder decoder, EntityDataType type) { + this(name, defaultValue, (Class) defaultValue.getClass(), index, decoder, type); + } + + public EncodedIntegerProperty(String name, Class clazz, int index, IntegerDecoder decoder) { + this(name, null, clazz, index, decoder, EntityDataTypes.INT); + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + T value = entity.getProperty(this); + if (value == null) return; + properties.put(index, newEntityData(index, type, decoder.decode(value))); + } + + public interface IntegerDecoder { + int decode(T obj); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/EncodedStringProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/EncodedStringProperty.java new file mode 100644 index 0000000..84e0cd1 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/EncodedStringProperty.java @@ -0,0 +1,48 @@ +package lol.pyr.znpcsplus.entity.properties; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType; +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 EncodedStringProperty extends EntityPropertyImpl { + private final EntityDataType type; + private final EncodedStringProperty.StringDecoder decoder; + private final int index; + + public EncodedStringProperty(String name, T defaultValue, Class clazz, int index, StringDecoder decoder, EntityDataType type) { + super(name, defaultValue, clazz); + this.decoder = decoder; + this.index = index; + this.type = type; + } + + @SuppressWarnings("unchecked") + public EncodedStringProperty(String name, T defaultValue, int index, StringDecoder decoder) { + this(name, defaultValue, (Class) defaultValue.getClass(), index, decoder, EntityDataTypes.STRING); + } + + @SuppressWarnings("unchecked") + public EncodedStringProperty(String name, T defaultValue, int index, StringDecoder decoder, EntityDataType type) { + this(name, defaultValue, (Class) defaultValue.getClass(), index, decoder, type); + } + + public EncodedStringProperty(String name, Class clazz, int index, StringDecoder decoder) { + this(name, null, clazz, index, decoder, EntityDataTypes.STRING); + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + T value = entity.getProperty(this); + if (value == null) return; + properties.put(index, newEntityData(index, type, decoder.decode(value))); + } + + public interface StringDecoder { + String decode(T obj); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/EquipmentProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/EquipmentProperty.java new file mode 100644 index 0000000..c0219a7 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/EquipmentProperty.java @@ -0,0 +1,28 @@ +package lol.pyr.znpcsplus.entity.properties; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.item.ItemStack; +import com.github.retrooper.packetevents.protocol.player.Equipment; +import com.github.retrooper.packetevents.protocol.player.EquipmentSlot; +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.Map; + +public class EquipmentProperty extends EntityPropertyImpl { + private final PacketFactory packetFactory; + private final EquipmentSlot slot; + + public EquipmentProperty(PacketFactory packetFactory, String name, EquipmentSlot slot) { + super(name, null, ItemStack.class); + this.packetFactory = packetFactory; + this.slot = slot; + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + packetFactory.sendEquipment(player, entity, new Equipment(slot, entity.getProperty(this))); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/GlowProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/GlowProperty.java new file mode 100644 index 0000000..13931d8 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/GlowProperty.java @@ -0,0 +1,30 @@ +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 lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import lol.pyr.znpcsplus.packets.PacketFactory; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class GlowProperty extends EntityPropertyImpl { + private final PacketFactory packetFactory; + + public GlowProperty(PacketFactory packetFactory) { + super("glow", null, NamedTextColor.class); + this.packetFactory = packetFactory; + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + NamedTextColor value = entity.getProperty(this); + EntityData oldData = properties.get(0); + byte oldValue = oldData == null ? 0 : (byte) oldData.getValue(); + properties.put(0, newEntityData(0, EntityDataTypes.BYTE, (byte) (oldValue | (value == null ? 0 : 0x40)))); + if (isSpawned) packetFactory.removeTeam(player, entity); + packetFactory.createTeam(player, entity, value); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/HologramItemProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/HologramItemProperty.java new file mode 100644 index 0000000..f97cbc4 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/HologramItemProperty.java @@ -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 HologramItemProperty extends EntityPropertyImpl { + + public HologramItemProperty() { + super("holo_item", null, ItemStack.class); + setPlayerModifiable(false); + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + properties.put(8, newEntityData(8, EntityDataTypes.ITEMSTACK, entity.getProperty(this))); + properties.put(5, newEntityData(5, EntityDataTypes.BOOLEAN, true)); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/HorseColorProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/HorseColorProperty.java new file mode 100644 index 0000000..b7b12ed --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/HorseColorProperty.java @@ -0,0 +1,26 @@ +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 lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import lol.pyr.znpcsplus.util.HorseColor; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class HorseColorProperty extends EntityPropertyImpl { + private final int index; + + public HorseColorProperty(int index) { + super("horse_color", HorseColor.WHITE, HorseColor.class); + this.index = index; + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + EntityData oldData = properties.get(index); + HorseColor value = entity.getProperty(this); + properties.put(index, newEntityData(index, EntityDataTypes.INT, value.ordinal() | (oldData == null ? 0 : ((int) oldData.getValue() & 0xFF00)))); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/HorseStyleProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/HorseStyleProperty.java new file mode 100644 index 0000000..ebb1b53 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/HorseStyleProperty.java @@ -0,0 +1,26 @@ +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 lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import lol.pyr.znpcsplus.util.HorseStyle; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class HorseStyleProperty extends EntityPropertyImpl { + private final int index; + + public HorseStyleProperty(int index) { + super("horse_style", HorseStyle.NONE, HorseStyle.class); + this.index = index; + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + EntityData oldData = properties.get(index); + HorseStyle value = entity.getProperty(this); + properties.put(index, newEntityData(index, EntityDataTypes.INT, (oldData == null ? 0 : ((int) oldData.getValue() & 0x00FF)) | (value.ordinal() << 8))); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/IntegerProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/IntegerProperty.java new file mode 100644 index 0000000..26f42c4 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/IntegerProperty.java @@ -0,0 +1,31 @@ +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 lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class IntegerProperty extends EntityPropertyImpl { + private final int index; + private final boolean legacy; + + public IntegerProperty(String name, int index, Integer defaultValue) { + this(name, index, defaultValue, false); + } + + public IntegerProperty(String name, int index, Integer defaultValue, boolean legacy) { + super(name, defaultValue, Integer.class); + this.index = index; + this.legacy = legacy; + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + properties.put(index, legacy ? + newEntityData(index, EntityDataTypes.BYTE, (byte) entity.getProperty(this).intValue()) : + newEntityData(index, EntityDataTypes.INT, entity.getProperty(this))); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/NBTProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/NBTProperty.java new file mode 100644 index 0000000..9829790 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/NBTProperty.java @@ -0,0 +1,49 @@ +package lol.pyr.znpcsplus.entity.properties; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; +import lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class NBTProperty extends EntityPropertyImpl { + private final EntityDataType type; + private final NBTDecoder decoder; + private final int index; + + public NBTProperty(String name, T defaultValue, Class clazz, int index, NBTDecoder decoder, EntityDataType type) { + super(name, defaultValue, clazz); + this.decoder = decoder; + this.index = index; + this.type = type; + } + + @SuppressWarnings("unchecked") + public NBTProperty(String name, T defaultValue, int index, NBTDecoder decoder) { + this(name, defaultValue, (Class) defaultValue.getClass(), index, decoder, EntityDataTypes.NBT); + } + + @SuppressWarnings("unchecked") + public NBTProperty(String name, T defaultValue, int index, NBTDecoder decoder, EntityDataType type) { + this(name, defaultValue, (Class) defaultValue.getClass(), index, decoder, type); + } + + public NBTProperty(String name, Class clazz, int index, NBTDecoder decoder) { + this(name, null, clazz, index, decoder, EntityDataTypes.NBT); + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + T value = entity.getProperty(this); + if (value == null) return; + properties.put(index, newEntityData(index, type, decoder.decode(value))); + } + + public interface NBTDecoder { + NBTCompound decode(T obj); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/NameProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/NameProperty.java new file mode 100644 index 0000000..e3b7230 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/NameProperty.java @@ -0,0 +1,41 @@ +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.util.adventure.AdventureSerializer; +import lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import lol.pyr.znpcsplus.util.PapiUtil; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; + +import java.util.Map; +import java.util.Optional; + +public class NameProperty extends EntityPropertyImpl { + private final boolean legacy; + private final boolean optional; + + public NameProperty(boolean legacy, boolean optional) { + super("name", null, Component.class); + + this.legacy = legacy; + this.optional = optional; + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + Component value = entity.getProperty(this); + if (value != null) { + String serialized = legacy ? + AdventureSerializer.getLegacyGsonSerializer().serialize(value) : + AdventureSerializer.getGsonSerializer().serialize(value); + serialized = PapiUtil.set(player, serialized); + if (optional) properties.put(2, newEntityData(2, EntityDataTypes.OPTIONAL_COMPONENT, Optional.of(serialized))); + else properties.put(2, newEntityData(2, EntityDataTypes.STRING, serialized)); + } + + if (legacy) properties.put(3, newEntityData(3, EntityDataTypes.BYTE, (byte) (value != null ? 1 : 0))); + else properties.put(3, newEntityData(3, EntityDataTypes.BOOLEAN, value != null)); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/NpcPoseProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/NpcPoseProperty.java new file mode 100644 index 0000000..3599f64 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/NpcPoseProperty.java @@ -0,0 +1,23 @@ +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.entity.pose.EntityPose; +import lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import lol.pyr.znpcsplus.util.NpcPose; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class NpcPoseProperty extends EntityPropertyImpl { + + public NpcPoseProperty() { + super("pose", NpcPose.STANDING, NpcPose.class); + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + properties.put(6, newEntityData(6, EntityDataTypes.ENTITY_POSE, EntityPose.valueOf(entity.getProperty(this).name()))); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/RotationProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/RotationProperty.java new file mode 100644 index 0000000..412197d --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/RotationProperty.java @@ -0,0 +1,25 @@ +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 lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import lol.pyr.znpcsplus.util.Vector3f; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class RotationProperty extends EntityPropertyImpl { + private final int index; + + public RotationProperty(String name, int index, Vector3f defaultValue) { + super(name, defaultValue, Vector3f.class); + this.index = index; + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + Vector3f vec = entity.getProperty(this); + properties.put(index, newEntityData(index, EntityDataTypes.ROTATION, new com.github.retrooper.packetevents.util.Vector3f(vec.getX(), vec.getY(), vec.getZ()))); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/TargetNpcProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/TargetNpcProperty.java new file mode 100644 index 0000000..fbe4beb --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/TargetNpcProperty.java @@ -0,0 +1,29 @@ +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 lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import lol.pyr.znpcsplus.npc.NpcEntryImpl; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class TargetNpcProperty extends EntityPropertyImpl { + private final int index; + + public TargetNpcProperty(String name, int index, NpcEntryImpl defaultValue) { + super(name, defaultValue, NpcEntryImpl.class); + this.index = index; + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + NpcEntryImpl value = entity.getProperty(this); + if (value == null) return; + if (value.getNpc().getEntity().getEntityId() == entity.getEntityId()) return; + if (value.getNpc().isVisibleTo(player)) { + properties.put(index, newEntityData(index, EntityDataTypes.INT, value.getNpc().getEntity().getEntityId())); + } + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/villager/VillagerDataProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/villager/VillagerDataProperty.java new file mode 100644 index 0000000..e86973b --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/villager/VillagerDataProperty.java @@ -0,0 +1,31 @@ +package lol.pyr.znpcsplus.entity.properties.villager; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.entity.villager.VillagerData; +import com.github.retrooper.packetevents.protocol.entity.villager.profession.VillagerProfessions; +import com.github.retrooper.packetevents.protocol.entity.villager.type.VillagerTypes; +import lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import org.bukkit.entity.Player; + +import java.util.Map; + +public abstract class VillagerDataProperty extends EntityPropertyImpl { + private final int index; + + @SuppressWarnings("unchecked") + public VillagerDataProperty(String name, int index, T def) { + super(name, def, (Class) def.getClass()); + this.index = index; + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + EntityData oldData = properties.get(index); + VillagerData old = oldData == null ? new VillagerData(VillagerTypes.PLAINS, VillagerProfessions.NONE, 1) : (VillagerData) oldData.getValue(); + properties.put(index, newEntityData(index, EntityDataTypes.VILLAGER_DATA, apply(old, entity.getProperty(this)))); + } + + protected abstract VillagerData apply(VillagerData data, T value); +} \ No newline at end of file diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/villager/VillagerLevelProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/villager/VillagerLevelProperty.java new file mode 100644 index 0000000..af81f40 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/villager/VillagerLevelProperty.java @@ -0,0 +1,16 @@ +package lol.pyr.znpcsplus.entity.properties.villager; + +import com.github.retrooper.packetevents.protocol.entity.villager.VillagerData; +import lol.pyr.znpcsplus.util.VillagerLevel; + +public class VillagerLevelProperty extends VillagerDataProperty { + public VillagerLevelProperty(String name, int index, VillagerLevel def) { + super(name, index, def); + } + + @Override + protected VillagerData apply(VillagerData data, VillagerLevel value) { + data.setLevel(value.ordinal() + 1); + return data; + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/villager/VillagerProfessionProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/villager/VillagerProfessionProperty.java new file mode 100644 index 0000000..6571676 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/villager/VillagerProfessionProperty.java @@ -0,0 +1,17 @@ +package lol.pyr.znpcsplus.entity.properties.villager; + +import com.github.retrooper.packetevents.protocol.entity.villager.VillagerData; +import com.github.retrooper.packetevents.protocol.entity.villager.profession.VillagerProfessions; +import lol.pyr.znpcsplus.util.VillagerProfession; + +public class VillagerProfessionProperty extends VillagerDataProperty { + public VillagerProfessionProperty(String name, int index, VillagerProfession def) { + super(name, index, def); + } + + @Override + protected VillagerData apply(VillagerData data, VillagerProfession value) { + data.setProfession(VillagerProfessions.getById(value.getId())); + return data; + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/villager/VillagerTypeProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/villager/VillagerTypeProperty.java new file mode 100644 index 0000000..a3d2448 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/villager/VillagerTypeProperty.java @@ -0,0 +1,17 @@ +package lol.pyr.znpcsplus.entity.properties.villager; + +import com.github.retrooper.packetevents.protocol.entity.villager.VillagerData; +import com.github.retrooper.packetevents.protocol.entity.villager.type.VillagerTypes; +import lol.pyr.znpcsplus.util.VillagerType; + +public class VillagerTypeProperty extends VillagerDataProperty { + public VillagerTypeProperty(String name, int index, VillagerType def) { + super(name, index, def); + } + + @Override + protected VillagerData apply(VillagerData data, VillagerType value) { + data.setType(VillagerTypes.getById(value.getId())); + return data; + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/serializers/IntegerPropertySerializer.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/serializers/IntegerPropertySerializer.java new file mode 100644 index 0000000..e918668 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/serializers/IntegerPropertySerializer.java @@ -0,0 +1,25 @@ +package lol.pyr.znpcsplus.entity.serializers; + +import lol.pyr.znpcsplus.entity.PropertySerializer; + +public class IntegerPropertySerializer implements PropertySerializer { + @Override + public String serialize(Integer property) { + return String.valueOf(property); + } + + @Override + public Integer deserialize(String property) { + try { + return Integer.parseInt(property); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public Class getTypeClass() { + return Integer.class; + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/serializers/ItemStackPropertySerializer.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/serializers/ItemStackPropertySerializer.java index d9f59d2..c6f1cb5 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/serializers/ItemStackPropertySerializer.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/serializers/ItemStackPropertySerializer.java @@ -1,18 +1,19 @@ package lol.pyr.znpcsplus.entity.serializers; +import com.github.retrooper.packetevents.protocol.item.ItemStack; +import io.github.retrooper.packetevents.util.SpigotConversionUtil; import lol.pyr.znpcsplus.entity.PropertySerializer; import lol.pyr.znpcsplus.util.ItemSerializationUtil; -import org.bukkit.inventory.ItemStack; public class ItemStackPropertySerializer implements PropertySerializer { @Override public String serialize(ItemStack property) { - return ItemSerializationUtil.itemToB64(property); + return ItemSerializationUtil.itemToB64(SpigotConversionUtil.toBukkitItemStack(property)); } @Override public ItemStack deserialize(String property) { - return ItemSerializationUtil.itemFromB64(property); + return SpigotConversionUtil.fromBukkitItemStack(ItemSerializationUtil.itemFromB64(property)); } @Override diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/serializers/TargetNpcPropertySerializer.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/serializers/TargetNpcPropertySerializer.java new file mode 100644 index 0000000..7cd3654 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/serializers/TargetNpcPropertySerializer.java @@ -0,0 +1,21 @@ +package lol.pyr.znpcsplus.entity.serializers; + +import lol.pyr.znpcsplus.entity.PropertySerializer; +import lol.pyr.znpcsplus.npc.NpcEntryImpl; + +public class TargetNpcPropertySerializer implements PropertySerializer { + @Override + public String serialize(NpcEntryImpl property) { + return property.getId(); + } + + @Override + public NpcEntryImpl deserialize(String property) { + return null; // TODO: find a way to do this + } + + @Override + public Class getTypeClass() { + return NpcEntryImpl.class; + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramImpl.java index 6a83251..89ed907 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramImpl.java @@ -1,10 +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; @@ -17,46 +20,75 @@ public class HologramImpl extends Viewable implements Hologram { private final ConfigManager configManager; private final PacketFactory packetFactory; private final LegacyComponentSerializer textSerializer; + private final EntityPropertyRegistryImpl propertyRegistry; private double offset = 0.0; private long refreshDelay = -1; private long lastRefresh = System.currentTimeMillis(); private NpcLocation location; - private final List lines = new ArrayList<>(); + private final List> lines = new ArrayList<>(); - public HologramImpl(ConfigManager configManager, PacketFactory packetFactory, LegacyComponentSerializer textSerializer, NpcLocation location) { + public HologramImpl(EntityPropertyRegistryImpl propertyRegistry, ConfigManager configManager, PacketFactory packetFactory, LegacyComponentSerializer textSerializer, NpcLocation location) { + this.propertyRegistry = propertyRegistry; this.configManager = configManager; this.packetFactory = packetFactory; this.textSerializer = textSerializer; this.location = location; } - public void addLineComponent(Component line) { - HologramLine newLine = new HologramLine(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 getLines() { + public List> getLines() { return Collections.unmodifiableList(lines); } @@ -65,25 +97,48 @@ public class HologramImpl extends Viewable implements Hologram { lines.clear(); } - public void insertLineComponent(int index, Component line) { - HologramLine newLine = new HologramLine(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() { @@ -100,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) { @@ -112,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; } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramItem.java b/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramItem.java new file mode 100644 index 0000000..c25e434 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramItem.java @@ -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 { + 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 getProperty(EntityProperty key) { + if (key.getName().equalsIgnoreCase("holo_item")) return (T) getValue(); + return super.getProperty(key); + } + + @Override + public void setLocation(NpcLocation location, Collection 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); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramLine.java b/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramLine.java index 883bacb..9bb695f 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramLine.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramLine.java @@ -1,64 +1,77 @@ 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.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 implements PropertyHolder { + private M value; + private final PacketEntity entity; + private final Set> properties; - public HologramLine(PacketFactory packetFactory, NpcLocation location, Component text) { - this.text = text; - armorStand = new PacketEntity(packetFactory, this, EntityTypes.ARMOR_STAND, location); + 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<>(); } - 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 viewers) { - armorStand.setLocation(location, viewers); + entity.setLocation(location, viewers); + } + + public int getEntityId() { + return entity.getEntityId(); + } + + public void addProperty(EntityProperty property) { + properties.add(property); } - @SuppressWarnings("unchecked") @Override public T getProperty(EntityProperty 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 void setProperty(EntityProperty 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 + public Set> getAppliedProperties() { + return properties; } } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramText.java b/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramText.java new file mode 100644 index 0000000..2c66aef --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/hologram/HologramText.java @@ -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 { + + 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 getProperty(EntityProperty 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"); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/MetadataFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/metadata/MetadataFactory.java deleted file mode 100644 index 9dcaae3..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/MetadataFactory.java +++ /dev/null @@ -1,102 +0,0 @@ -package lol.pyr.znpcsplus.metadata; - -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose; -import lol.pyr.znpcsplus.util.*; -import net.kyori.adventure.text.Component; -import org.bukkit.DyeColor; - -/** - * 1.8 ... - * 1.9 ... - * 1.10 ... - * 1.11 ... - * 1.12 ... - * 1.13 ... - * 1.14 ... - * 1.15 ... - * 1.16 ... - * 1.17 ... - * 1.18-1.19 ... - * 1.20 ... - */ -public interface MetadataFactory { - EntityData effects(boolean onFire, boolean glowing, boolean invisible, boolean usingElytra, boolean usingItemLegacy); - EntityData silent(boolean enabled); - EntityData name(Component name); - EntityData nameShown(); - EntityData noGravity(); - EntityData pose(EntityPose pose); - EntityData shaking(boolean enabled); - EntityData usingItem(boolean enabled, boolean offhand, boolean riptide); - EntityData potionColor(int color); - EntityData potionAmbient(boolean ambient); - - // Player - EntityData skinLayers(boolean cape, boolean jacket, boolean leftSleeve, boolean rightSleeve, boolean leftLeg, boolean rightLeg, boolean hat); - EntityData shoulderEntityLeft(ParrotVariant variant); - EntityData shoulderEntityRight(ParrotVariant variant); - - // Armor Stand - EntityData armorStandProperties(boolean small, boolean arms, boolean noBasePlate); - EntityData armorStandHeadRotation(Vector3f headRotation); - EntityData armorStandBodyRotation(Vector3f bodyRotation); - EntityData armorStandLeftArmRotation(Vector3f leftArmRotation); - EntityData armorStandRightArmRotation(Vector3f rightArmRotation); - EntityData armorStandLeftLegRotation(Vector3f leftLegRotation); - EntityData armorStandRightLegRotation(Vector3f rightLegRotation); - - // Axolotl - EntityData axolotlVariant(int variant); - EntityData playingDead(boolean playingDead); - - // Bat - EntityData batHanging(boolean hanging); - - // Bee - EntityData beeAngry(boolean angry); - EntityData beeHasNectar(boolean hasNectar); - - // Blaze - EntityData blazeOnFire(boolean onFire); - - // Cat - EntityData catVariant(CatVariant variant); - EntityData catLying(boolean lying); - EntityData catTamed(boolean tamed); - EntityData catCollarColor(DyeColor collarColor); - - // Creeper - EntityData creeperState(CreeperState state); - EntityData creeperCharged(boolean charged); - - // Enderman - EntityData endermanHeldBlock(int heldBlock); - EntityData endermanScreaming(boolean screaming); - EntityData endermanStaring(boolean staring); - - // Evoker - EntityData evokerSpell(int spell); - - // Fox - EntityData foxVariant(int variant); - EntityData foxProperties(boolean sitting, boolean crouching, boolean sleeping, boolean facePlanted); - - // Frog - EntityData frogVariant(int variant); - - // Ghast - EntityData ghastAttacking(boolean attacking); - - // Goat - EntityData goatHasLeftHorn(boolean hasLeftHorn); - EntityData goatHasRightHorn(boolean hasRightHorn); - - // Guardian - - // Hoglin - EntityData hoglinImmuneToZombification(boolean immuneToZombification); - - // Villager - EntityData villagerData(int type, int profession, int level); -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_10MetadataFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_10MetadataFactory.java deleted file mode 100644 index 903df8f..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_10MetadataFactory.java +++ /dev/null @@ -1,93 +0,0 @@ -package lol.pyr.znpcsplus.metadata; - -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; -import lol.pyr.znpcsplus.util.CreeperState; -import lol.pyr.znpcsplus.util.Vector3f; - -public class V1_10MetadataFactory extends V1_9MetadataFactory { - @Override - public EntityData skinLayers(boolean cape, boolean jacket, boolean leftSleeve, boolean rightSleeve, boolean leftLeg, boolean rightLeg, boolean hat) { - return createSkinLayers(13, cape, jacket, leftSleeve, rightSleeve, leftLeg, rightLeg, hat); - } - - @Override - public EntityData noGravity() { - return newEntityData(5, EntityDataTypes.BOOLEAN, true); - } - - @Override - public EntityData potionColor(int color) { - return newEntityData(8, EntityDataTypes.INT, color); - } - - @Override - public EntityData potionAmbient(boolean ambient) { - return newEntityData(9, EntityDataTypes.BOOLEAN, ambient); - } - - @Override - public EntityData armorStandProperties(boolean small, boolean arms, boolean noBasePlate) { - return newEntityData(11, EntityDataTypes.BYTE, (byte) ((small ? 0x01 : 0) | (arms ? 0x04 : 0) | (noBasePlate ? 0x08 : 0))); - } - - @Override - public EntityData armorStandHeadRotation(Vector3f headRotation) { - return createRotations(12, headRotation); - } - - @Override - public EntityData armorStandBodyRotation(Vector3f bodyRotation) { - return createRotations(13, bodyRotation); - } - - @Override - public EntityData armorStandLeftArmRotation(Vector3f leftArmRotation) { - return createRotations(14, leftArmRotation); - } - - @Override - public EntityData armorStandRightArmRotation(Vector3f rightArmRotation) { - return createRotations(15, rightArmRotation); - } - - @Override - public EntityData armorStandLeftLegRotation(Vector3f leftLegRotation) { - return createRotations(16, leftLegRotation); - } - - @Override - public EntityData armorStandRightLegRotation(Vector3f rightLegRotation) { - return createRotations(17, rightLegRotation); - } - - @Override - public EntityData batHanging(boolean hanging) { - return newEntityData(12, EntityDataTypes.BYTE, (byte) (hanging ? 0x01 : 0)); - } - - @Override - public EntityData blazeOnFire(boolean onFire) { - return newEntityData(12, EntityDataTypes.BYTE, (byte) (onFire ? 0x01 : 0)); - } - - @Override - public EntityData creeperState(CreeperState state) { - return newEntityData(12, EntityDataTypes.INT, state.getState()); - } - - @Override - public EntityData creeperCharged(boolean charged) { - return newEntityData(13, EntityDataTypes.BOOLEAN, charged); - } - - @Override - public EntityData ghastAttacking(boolean attacking) { - return newEntityData(12, EntityDataTypes.BOOLEAN, attacking); - } - - @Override - public EntityData villagerData(int type, int profession, int level) { - return newEntityData(13, EntityDataTypes.INT, profession); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_11MetadataFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_11MetadataFactory.java deleted file mode 100644 index c0ba2df..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_11MetadataFactory.java +++ /dev/null @@ -1,21 +0,0 @@ -package lol.pyr.znpcsplus.metadata; - -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; - -public class V1_11MetadataFactory extends V1_10MetadataFactory { - @Override - public EntityData effects(boolean onFire, boolean glowing, boolean invisible, boolean usingElytra, boolean usingItemLegacy) { - return super.effects(onFire, glowing, invisible, usingElytra, false); - } - - @Override - public EntityData usingItem(boolean usingItem, boolean offHand, boolean riptide) { - return newEntityData(6, EntityDataTypes.BYTE, (byte) ((usingItem ? 0x01 : 0) | (offHand ? 0x02 : 0))); - } - - @Override - public EntityData evokerSpell(int spell) { - return newEntityData(12, EntityDataTypes.BYTE, (byte) spell); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_12MetadataFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_12MetadataFactory.java deleted file mode 100644 index 9616a5e..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_12MetadataFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -package lol.pyr.znpcsplus.metadata; - -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; -import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; -import lol.pyr.znpcsplus.entity.ParrotNBTCompound; -import lol.pyr.znpcsplus.util.ParrotVariant; - -public class V1_12MetadataFactory extends V1_11MetadataFactory { - @Override - public EntityData shoulderEntityLeft(ParrotVariant variant) { - return createShoulderEntityLeft(15, variant); - } - - public EntityData createShoulderEntityLeft(int index, ParrotVariant variant) { - return newEntityData(index, EntityDataTypes.NBT, variant == ParrotVariant.NONE ? new NBTCompound() : new ParrotNBTCompound(variant).getTag()); - } - - @Override - public EntityData shoulderEntityRight(ParrotVariant variant) { - return createShoulderEntityRight(16, variant); - } - - public EntityData createShoulderEntityRight(int index, ParrotVariant variant) { - return newEntityData(index, EntityDataTypes.NBT, variant == ParrotVariant.NONE ? new NBTCompound() : new ParrotNBTCompound(variant).getTag()); - } - - @Override - public EntityData evokerSpell(int spell) { - return newEntityData(13, EntityDataTypes.BYTE, (byte) spell); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_13MetadataFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_13MetadataFactory.java deleted file mode 100644 index 854549c..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_13MetadataFactory.java +++ /dev/null @@ -1,20 +0,0 @@ -package lol.pyr.znpcsplus.metadata; - -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; -import com.github.retrooper.packetevents.util.adventure.AdventureSerializer; -import net.kyori.adventure.text.Component; - -import java.util.Optional; - -public class V1_13MetadataFactory extends V1_12MetadataFactory { - @Override - public EntityData name(Component name) { - return newEntityData(2, EntityDataTypes.OPTIONAL_COMPONENT, Optional.of(AdventureSerializer.getGsonSerializer().serialize(name))); - } - - @Override - public EntityData usingItem(boolean usingItem, boolean offHand, boolean riptide) { - return newEntityData(6, EntityDataTypes.BYTE, (byte) ((usingItem ? 0x01 : 0) | (offHand ? 0x02 : 0) | (riptide ? 0x04 : 0))); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_14MetadataFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_14MetadataFactory.java deleted file mode 100644 index bd34101..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_14MetadataFactory.java +++ /dev/null @@ -1,143 +0,0 @@ -package lol.pyr.znpcsplus.metadata; - -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; -import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose; -import com.github.retrooper.packetevents.protocol.entity.villager.VillagerData; -import lol.pyr.znpcsplus.util.CatVariant; -import lol.pyr.znpcsplus.util.CreeperState; -import lol.pyr.znpcsplus.util.ParrotVariant; -import lol.pyr.znpcsplus.util.Vector3f; -import org.bukkit.DyeColor; - -public class V1_14MetadataFactory extends V1_13MetadataFactory { - @Override - public EntityData skinLayers(boolean cape, boolean jacket, boolean leftSleeve, boolean rightSleeve, boolean leftLeg, boolean rightLeg, boolean hat) { - return createSkinLayers(15, cape, jacket, leftSleeve, rightSleeve, leftLeg, rightLeg, hat); - } - - @Override - public EntityData pose(EntityPose pose) { - return newEntityData(6, EntityDataTypes.ENTITY_POSE, pose); - } - - @Override - public EntityData usingItem(boolean usingItem, boolean offHand, boolean riptide) { - return newEntityData(7, EntityDataTypes.BYTE, (byte) ((usingItem ? 0x01 : 0) | (offHand ? 0x02 : 0) | (riptide ? 0x04 : 0))); - } - - @Override - public EntityData potionColor(int color) { - return newEntityData(9, EntityDataTypes.INT, color); - } - - @Override - public EntityData potionAmbient(boolean ambient) { - return newEntityData(10, EntityDataTypes.BOOLEAN, ambient); - } - - @Override - public EntityData shoulderEntityLeft(ParrotVariant variant) { - return createShoulderEntityLeft(17, variant); - } - - @Override - public EntityData shoulderEntityRight(ParrotVariant variant) { - return createShoulderEntityRight(18, variant); - } - - @Override - public EntityData armorStandProperties(boolean small, boolean arms, boolean noBasePlate) { - return newEntityData(13, EntityDataTypes.BYTE, (byte) ((small ? 0x01 : 0) | (arms ? 0x04 : 0) | (noBasePlate ? 0x08 : 0))); - } - - @Override - public EntityData armorStandHeadRotation(Vector3f headRotation) { - return createRotations(14, headRotation); - } - - @Override - public EntityData armorStandBodyRotation(Vector3f bodyRotation) { - return createRotations(15, bodyRotation); - } - - @Override - public EntityData armorStandLeftArmRotation(Vector3f leftArmRotation) { - return createRotations(16, leftArmRotation); - } - - @Override - public EntityData armorStandRightArmRotation(Vector3f rightArmRotation) { - return createRotations(17, rightArmRotation); - } - - @Override - public EntityData armorStandLeftLegRotation(Vector3f leftLegRotation) { - return createRotations(18, leftLegRotation); - } - - @Override - public EntityData armorStandRightLegRotation(Vector3f rightLegRotation) { - return createRotations(19, rightLegRotation); - } - - @Override - public EntityData batHanging(boolean hanging) { - return newEntityData(14, EntityDataTypes.BYTE, (byte) (hanging ? 0x01 : 0)); - } - - @Override - public EntityData blazeOnFire(boolean onFire) { - return newEntityData(14, EntityDataTypes.BYTE, (byte) (onFire ? 0x01 : 0)); - } - - @Override - public EntityData catVariant(CatVariant variant) { - return newEntityData(17, EntityDataTypes.CAT_VARIANT, variant.getId()); - } - - @Override - public EntityData catLying(boolean lying) { - throw new UnsupportedOperationException("The cat lying entity data isn't supported on this version"); - } - - @Override - public EntityData catCollarColor(DyeColor collarColor) { - return newEntityData(20, EntityDataTypes.INT, collarColor.ordinal()); - } - - @Override - public EntityData creeperState(CreeperState state) { - return newEntityData(14, EntityDataTypes.INT, state.getState()); - } - - @Override - public EntityData creeperCharged(boolean charged) { - return newEntityData(15, EntityDataTypes.BOOLEAN, charged); - } - - @Override - public EntityData evokerSpell(int spell) { - return newEntityData(15, EntityDataTypes.BYTE, (byte) spell); - } - - @Override - public EntityData foxVariant(int variant) { - return newEntityData(15, EntityDataTypes.INT, variant); - } - - @Override - public EntityData foxProperties(boolean sitting, boolean crouching, boolean sleeping, boolean facePlanted) { - return newEntityData(16, EntityDataTypes.BYTE, (byte) ((sitting ? 0x01 : 0) | (crouching ? 0x04 : 0) | (sleeping ? 0x20 : 0))); - } - - @Override - public EntityData ghastAttacking(boolean attacking) { - return newEntityData(14, EntityDataTypes.BOOLEAN, attacking); - } - - @Override - public EntityData villagerData(int type, int profession, int level) { - return newEntityData(16, EntityDataTypes.VILLAGER_DATA, new VillagerData(type, profession, level)); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_15MetadataFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_15MetadataFactory.java deleted file mode 100644 index 0b53db8..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_15MetadataFactory.java +++ /dev/null @@ -1,127 +0,0 @@ -package lol.pyr.znpcsplus.metadata; - -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; -import com.github.retrooper.packetevents.protocol.entity.villager.VillagerData; -import lol.pyr.znpcsplus.util.CatVariant; -import lol.pyr.znpcsplus.util.CreeperState; -import lol.pyr.znpcsplus.util.ParrotVariant; -import lol.pyr.znpcsplus.util.Vector3f; -import org.bukkit.DyeColor; - -public class V1_15MetadataFactory extends V1_14MetadataFactory { - @Override - public EntityData shoulderEntityLeft(ParrotVariant variant) { - return createShoulderEntityLeft(18, variant); - } - - @Override - public EntityData shoulderEntityRight(ParrotVariant variant) { - return createShoulderEntityRight(19, variant); - } - - @Override - public EntityData armorStandProperties(boolean small, boolean arms, boolean noBasePlate) { - return newEntityData(14, EntityDataTypes.BYTE, (byte) ((small ? 0x01 : 0) | (arms ? 0x04 : 0) | (!noBasePlate ? 0x08 : 0))); - } - - @Override - public EntityData armorStandHeadRotation(Vector3f headRotation) { - return createRotations(15, headRotation); - } - - @Override - public EntityData armorStandBodyRotation(Vector3f bodyRotation) { - return createRotations(16, bodyRotation); - } - - @Override - public EntityData armorStandLeftArmRotation(Vector3f leftArmRotation) { - return createRotations(17, leftArmRotation); - } - - @Override - public EntityData armorStandRightArmRotation(Vector3f rightArmRotation) { - return createRotations(18, rightArmRotation); - } - - @Override - public EntityData armorStandLeftLegRotation(Vector3f leftLegRotation) { - return createRotations(19, leftLegRotation); - } - - @Override - public EntityData armorStandRightLegRotation(Vector3f rightLegRotation) { - return createRotations(20, rightLegRotation); - } - - @Override - public EntityData batHanging(boolean hanging) { - return newEntityData(15, EntityDataTypes.BYTE, (byte) (hanging ? 0x01 : 0)); - } - - @Override - public EntityData beeAngry(boolean angry) { - return newEntityData(17, EntityDataTypes.INT, angry ? 1 : 0); - } - - @Override - public EntityData beeHasNectar(boolean hasNectar) { - return newEntityData(16, EntityDataTypes.BYTE, (byte) (hasNectar ? 0x08 : 0)); - } - - @Override - public EntityData blazeOnFire(boolean onFire) { - return newEntityData(15, EntityDataTypes.BYTE, (byte) (onFire ? 0x01 : 0)); - } - - @Override - public EntityData catVariant(CatVariant variant) { - return newEntityData(18, EntityDataTypes.CAT_VARIANT, variant.getId()); - } - - @Override - public EntityData catLying(boolean lying) { - return newEntityData(19, EntityDataTypes.BOOLEAN, lying); - } - - @Override - public EntityData catCollarColor(DyeColor collarColor) { - return newEntityData(21, EntityDataTypes.INT, collarColor.ordinal()); - } - - @Override - public EntityData creeperState(CreeperState state) { - return newEntityData(15, EntityDataTypes.INT, state.getState()); - } - - @Override - public EntityData creeperCharged(boolean charged) { - return newEntityData(16, EntityDataTypes.BOOLEAN, charged); - } - - @Override - public EntityData evokerSpell(int spell) { - return newEntityData(16, EntityDataTypes.BYTE, (byte) spell); - } - - @Override - public EntityData foxVariant(int variant) { - return newEntityData(16, EntityDataTypes.INT, variant); - } - - @Override - public EntityData foxProperties(boolean sitting, boolean crouching, boolean sleeping, boolean facePlanted) { - return newEntityData(17, EntityDataTypes.BYTE, (byte) ((sitting ? 0x01 : 0) | (crouching ? 0x04 : 0) | (sleeping ? 0x20 : 0) | (facePlanted ? 0x40 : 0))); - } - - @Override - public EntityData ghastAttacking(boolean attacking) { - return newEntityData(15, EntityDataTypes.BOOLEAN, attacking); - } - - @Override - public EntityData villagerData(int type, int profession, int level) { - return newEntityData(17, EntityDataTypes.VILLAGER_DATA, new VillagerData(type, profession, level)); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_16MetadataFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_16MetadataFactory.java deleted file mode 100644 index d728fa7..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_16MetadataFactory.java +++ /dev/null @@ -1,16 +0,0 @@ -package lol.pyr.znpcsplus.metadata; - -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; - -public class V1_16MetadataFactory extends V1_15MetadataFactory { - @Override - public EntityData skinLayers(boolean cape, boolean jacket, boolean leftSleeve, boolean rightSleeve, boolean leftLeg, boolean rightLeg, boolean hat) { - return createSkinLayers(16, cape, jacket, leftSleeve, rightSleeve, leftLeg, rightLeg, hat); - } - - @Override - public EntityData hoglinImmuneToZombification(boolean immuneToZombification) { - return newEntityData(16, EntityDataTypes.BOOLEAN, immuneToZombification); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_17MetadataFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_17MetadataFactory.java deleted file mode 100644 index 8fe26ef..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_17MetadataFactory.java +++ /dev/null @@ -1,202 +0,0 @@ -package lol.pyr.znpcsplus.metadata; - -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; -import com.github.retrooper.packetevents.protocol.entity.villager.VillagerData; -import lol.pyr.znpcsplus.util.CatVariant; -import lol.pyr.znpcsplus.util.CreeperState; -import lol.pyr.znpcsplus.util.ParrotVariant; -import lol.pyr.znpcsplus.util.Vector3f; -import org.bukkit.DyeColor; - -public class V1_17MetadataFactory extends V1_16MetadataFactory { - @Override - public EntityData skinLayers(boolean cape, boolean jacket, boolean leftSleeve, boolean rightSleeve, boolean leftLeg, boolean rightLeg, boolean hat) { - return createSkinLayers(17, cape, jacket, leftSleeve, rightSleeve, leftLeg, rightLeg, hat); - } - - @Override - public EntityData effects(boolean onFire, boolean glowing, boolean invisible, boolean usingElytra, boolean usingItemLegacy) { - return newEntityData(0, EntityDataTypes.BYTE, (byte) ((onFire ? 0x01 : 0) | (invisible ? 0x20 : 0) | (glowing ? 0x40 : 0) | (usingElytra ? 0x80 : 0))); - } - - @Override - public EntityData shaking(boolean enabled) { - return newEntityData(7, EntityDataTypes.INT, enabled ? 140 : 0); - } - - @Override - public EntityData usingItem(boolean usingItem, boolean offHand, boolean riptide) { - return newEntityData(8, EntityDataTypes.BYTE, (byte) ((usingItem ? 0x01 : 0) | (offHand ? 0x02 : 0) | (riptide ? 0x04 : 0))); - } - - @Override - public EntityData potionColor(int color) { - return newEntityData(10, EntityDataTypes.INT, color); - } - - @Override - public EntityData potionAmbient(boolean ambient) { - return newEntityData(11, EntityDataTypes.BOOLEAN, ambient); - } - - @Override - public EntityData shoulderEntityLeft(ParrotVariant variant) { - return createShoulderEntityLeft(19, variant); - } - - @Override - public EntityData shoulderEntityRight(ParrotVariant variant) { - return createShoulderEntityRight(20, variant); - } - - @Override - public EntityData armorStandProperties(boolean small, boolean arms, boolean noBasePlate) { - return newEntityData(15, EntityDataTypes.BYTE, (byte) ((small ? 0x01 : 0) | (arms ? 0x04 : 0) | (noBasePlate ? 0x08 : 0))); - } - - @Override - public EntityData armorStandHeadRotation(Vector3f headRotation) { - return createRotations(16, headRotation); - } - - @Override - public EntityData armorStandBodyRotation(Vector3f bodyRotation) { - return createRotations(17, bodyRotation); - } - - @Override - public EntityData armorStandLeftArmRotation(Vector3f leftArmRotation) { - return createRotations(18, leftArmRotation); - } - - @Override - public EntityData armorStandRightArmRotation(Vector3f rightArmRotation) { - return createRotations(19, rightArmRotation); - } - - @Override - public EntityData armorStandLeftLegRotation(Vector3f leftLegRotation) { - return createRotations(20, leftLegRotation); - } - - @Override - public EntityData armorStandRightLegRotation(Vector3f rightLegRotation) { - return createRotations(21, rightLegRotation); - } - - @Override - public EntityData axolotlVariant(int variant) { - return newEntityData(17, EntityDataTypes.INT, variant); - } - - @Override - public EntityData playingDead(boolean playingDead) { - return newEntityData(18, EntityDataTypes.BOOLEAN, playingDead); - } - - @Override - public EntityData batHanging(boolean hanging) { - return newEntityData(16, EntityDataTypes.BYTE, (byte) (hanging ? 0x01 : 0)); - } - - @Override - public EntityData beeAngry(boolean angry) { - return newEntityData(18, EntityDataTypes.INT, angry ? 1 : 0); - } - - @Override - public EntityData beeHasNectar(boolean hasNectar) { - return newEntityData(17, EntityDataTypes.BYTE, (byte) (hasNectar ? 0x08 : 0)); - } - - @Override - public EntityData blazeOnFire(boolean onFire) { - return newEntityData(16, EntityDataTypes.BYTE, (byte) (onFire ? 0x01 : 0)); - } - - @Override - public EntityData catVariant(CatVariant variant) { - return newEntityData(19, EntityDataTypes.CAT_VARIANT, variant.getId()); - } - - @Override - public EntityData catLying(boolean lying) { - return newEntityData(20, EntityDataTypes.BOOLEAN, lying); - } - - @Override - public EntityData catTamed(boolean tamed) { - return newEntityData(17, EntityDataTypes.BYTE, (byte) (tamed ? 0x04 : 0)); - } - - @Override - public EntityData catCollarColor(DyeColor collarColor) { - return newEntityData(22, EntityDataTypes.INT, collarColor.ordinal()); - } - - @Override - public EntityData creeperState(CreeperState state) { - return newEntityData(16, EntityDataTypes.INT, state.getState()); - } - - @Override - public EntityData creeperCharged(boolean charged) { - return newEntityData(17, EntityDataTypes.BOOLEAN, charged); - } - - @Override - public EntityData endermanHeldBlock(int carriedBlock) { - return newEntityData(16, EntityDataTypes.INT, carriedBlock); - } - - @Override - public EntityData endermanScreaming(boolean screaming) { - return newEntityData(17, EntityDataTypes.BOOLEAN, screaming); - } - - @Override - public EntityData endermanStaring(boolean staring) { - return newEntityData(18, EntityDataTypes.BOOLEAN, staring); - } - - @Override - public EntityData evokerSpell(int spell) { - return newEntityData(17, EntityDataTypes.BYTE, (byte) spell); - } - - @Override - public EntityData foxVariant(int variant) { - return newEntityData(17, EntityDataTypes.INT, variant); - } - - @Override - public EntityData foxProperties(boolean sitting, boolean crouching, boolean sleeping, boolean facePlanted) { - return newEntityData(18, EntityDataTypes.BYTE, (byte) ((sitting ? 0x01 : 0) | (crouching ? 0x04 : 0) | (sleeping ? 0x20 : 0) | (facePlanted ? 0x40 : 0))); - } - - @Override - public EntityData ghastAttacking(boolean attacking) { - return newEntityData(16, EntityDataTypes.BOOLEAN, attacking); - } - - @Override - public EntityData goatHasLeftHorn(boolean hasLeftHorn) { - return newEntityData(18, EntityDataTypes.BOOLEAN, hasLeftHorn); - } - - @Override - public EntityData goatHasRightHorn(boolean hasRightHorn) { - return newEntityData(19, EntityDataTypes.BOOLEAN, hasRightHorn); - } - - @Override - public EntityData hoglinImmuneToZombification(boolean immuneToZombification) { - return newEntityData(17, EntityDataTypes.BOOLEAN, immuneToZombification); - } - - @Override - public EntityData villagerData(int type, int profession, int level) { - return newEntityData(18, EntityDataTypes.VILLAGER_DATA, new VillagerData(type, profession, level)); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_19MetadataFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_19MetadataFactory.java deleted file mode 100644 index 562007d..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_19MetadataFactory.java +++ /dev/null @@ -1,12 +0,0 @@ -package lol.pyr.znpcsplus.metadata; - -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; -import lol.pyr.znpcsplus.util.FrogVariant; - -public class V1_19MetadataFactory extends V1_17MetadataFactory { - @Override - public EntityData frogVariant(int variant) { - return newEntityData(17, EntityDataTypes.FROG_VARIANT, variant); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_8MetadataFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_8MetadataFactory.java deleted file mode 100644 index 4ae8045..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_8MetadataFactory.java +++ /dev/null @@ -1,252 +0,0 @@ -package lol.pyr.znpcsplus.metadata; - -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; -import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose; -import com.github.retrooper.packetevents.util.adventure.AdventureSerializer; -import lol.pyr.znpcsplus.util.*; -import net.kyori.adventure.text.Component; -import org.bukkit.DyeColor; - -public class V1_8MetadataFactory implements MetadataFactory { - @Override - public EntityData skinLayers(boolean cape, boolean jacket, boolean leftSleeve, boolean rightSleeve, boolean leftLeg, boolean rightLeg, boolean hat) { - return createSkinLayers(10, cape, jacket, leftSleeve, rightSleeve, leftLeg, rightLeg, hat); - } - - @Override - public EntityData effects(boolean onFire, boolean glowing, boolean invisible, boolean usingElytra, boolean usingItemLegacy) { - return newEntityData(0, EntityDataTypes.BYTE, (byte) ((onFire ? 0x01 : 0) | (usingItemLegacy ? 0x10 : 0) | (invisible ? 0x20 : 0))); - } - - @Override - public EntityData name(Component name) { - return newEntityData(2, EntityDataTypes.STRING, AdventureSerializer.getLegacyGsonSerializer().serialize(name)); - } - - @Override - public EntityData nameShown() { - return newEntityData(3, EntityDataTypes.BYTE, (byte) 1); - } - - @Override - public EntityData noGravity() { - throw new UnsupportedOperationException("The gravity entity data isn't supported on this version"); - } - - @Override - public EntityData pose(EntityPose pose) { - throw new UnsupportedOperationException("The pose entity data isn't supported on this version"); - } - - @Override - public EntityData shaking(boolean enabled) { - throw new UnsupportedOperationException("The shaking entity data isn't supported on this version"); - } - - @Override - public EntityData usingItem(boolean enabled, boolean offHand, boolean riptide) { - throw new UnsupportedOperationException("The standalone using item data isn't supported on this version"); - } - - @Override - public EntityData potionColor(int color) { - return newEntityData(7, EntityDataTypes.INT, color); - } - - @Override - public EntityData potionAmbient(boolean ambient) { - return newEntityData(8, EntityDataTypes.BYTE, (byte) (ambient ? 1 : 0)); - } - - @Override - public EntityData shoulderEntityLeft(ParrotVariant variant) { - throw new UnsupportedOperationException("The shoulder entity data isn't supported on this version"); - } - - @Override - public EntityData shoulderEntityRight(ParrotVariant variant) { - throw new UnsupportedOperationException("The shoulder entity data isn't supported on this version"); - } - - @Override - public EntityData armorStandProperties(boolean small, boolean arms, boolean noBasePlate) { - return newEntityData(10, EntityDataTypes.BYTE, (byte) ((small ? 0x01 : 0) | (arms ? 0x04 : 0) | (noBasePlate ? 0x08 : 0))); - } - - @Override - public EntityData armorStandHeadRotation(Vector3f headRotation) { - return createRotations(11, headRotation); - } - - @Override - public EntityData armorStandBodyRotation(Vector3f bodyRotation) { - return createRotations(12, bodyRotation); - } - - @Override - public EntityData armorStandLeftArmRotation(Vector3f leftArmRotation) { - return createRotations(13, leftArmRotation); - } - - @Override - public EntityData armorStandRightArmRotation(Vector3f rightArmRotation) { - return createRotations(14, rightArmRotation); - } - - @Override - public EntityData armorStandLeftLegRotation(Vector3f leftLegRotation) { - return createRotations(15, leftLegRotation); - } - - @Override - public EntityData armorStandRightLegRotation(Vector3f rightLegRotation) { - return createRotations(16, rightLegRotation); - } - - @Override - public EntityData axolotlVariant(int variant) { - throw new UnsupportedOperationException("The axolotl variant entity data isn't supported on this version"); - } - - @Override - public EntityData playingDead(boolean playingDead) { - throw new UnsupportedOperationException("The playing dead entity data isn't supported on this version"); - } - - @Override - public EntityData batHanging(boolean hanging) { - return newEntityData(16, EntityDataTypes.BYTE, (byte) (hanging ? 1 : 0)); - } - - @Override - public EntityData beeAngry(boolean angry) { - throw new UnsupportedOperationException("The bee properties entity data isn't supported on this version"); - } - - @Override - public EntityData beeHasNectar(boolean hasNectar) { - throw new UnsupportedOperationException("The bee properties entity data isn't supported on this version"); - } - - @Override - public EntityData blazeOnFire(boolean onFire) { - return newEntityData(16, EntityDataTypes.BYTE, (byte) (onFire ? 1 : 0)); - } - - @Override - public EntityData catVariant(CatVariant variant) { - throw new UnsupportedOperationException("The cat variant entity data isn't supported on this version"); - } - - @Override - public EntityData catLying(boolean lying) { - throw new UnsupportedOperationException("The cat lying entity data isn't supported on this version"); - } - - @Override - public EntityData catTamed(boolean tamed) { - throw new UnsupportedOperationException("The cat tamed entity data isn't supported on this version"); - } - - @Override - public EntityData catCollarColor(DyeColor collarColor) { - throw new UnsupportedOperationException("The cat collar color entity data isn't supported on this version"); - } - - @Override - public EntityData creeperState(CreeperState state) { - return newEntityData(16, EntityDataTypes.BYTE, (byte) state.getState()); - } - - @Override - public EntityData creeperCharged(boolean charged) { - return newEntityData(17, EntityDataTypes.BYTE, (byte) (charged ? 1 : 0)); - } - - @Override - public EntityData endermanHeldBlock(int carriedBlock) { - throw new UnsupportedOperationException("The enderman carried block entity data isn't supported on this version"); - } - - @Override - public EntityData endermanScreaming(boolean screaming) { - throw new UnsupportedOperationException("The enderman screaming entity data isn't supported on this version"); - } - - @Override - public EntityData endermanStaring(boolean staring) { - return newEntityData(18, EntityDataTypes.BOOLEAN, staring); - } - - @Override - public EntityData evokerSpell(int spell) { - throw new UnsupportedOperationException("The evoker spell entity data isn't supported on this version"); - } - - @Override - public EntityData foxVariant(int variant) { - throw new UnsupportedOperationException("The fox variant entity data isn't supported on this version"); - } - - @Override - public EntityData foxProperties(boolean sitting, boolean crouching, boolean sleeping, boolean facePlanted) { - throw new UnsupportedOperationException("The fox properties entity data isn't supported on this version"); - } - - @Override - public EntityData frogVariant(int variant) { - throw new UnsupportedOperationException("The frog variant entity data isn't supported on this version"); - } - - @Override - public EntityData ghastAttacking(boolean attacking) { - return newEntityData(16, EntityDataTypes.BYTE, (byte) (attacking ? 1 : 0)); - } - - @Override - public EntityData goatHasLeftHorn(boolean hasLeftHorn) { - throw new UnsupportedOperationException("The goat horn entity data isn't supported on this version"); - } - - @Override - public EntityData goatHasRightHorn(boolean hasRightHorn) { - throw new UnsupportedOperationException("The goat horn entity data isn't supported on this version"); - } - - @Override - public EntityData hoglinImmuneToZombification(boolean immuneToZombification) { - throw new UnsupportedOperationException("The hoglin zombification entity data isn't supported on this version"); - } - - @Override - public EntityData villagerData(int type, int profession, int level) { - return newEntityData(16, EntityDataTypes.INT, profession); - } - - @Override - public EntityData silent(boolean enabled) { - return newEntityData(4, EntityDataTypes.BYTE, (byte) (enabled ? 1 : 0)); - } - - protected EntityData createSkinLayers(int index, boolean cape, boolean jacket, boolean leftSleeve, boolean rightSleeve, boolean leftLeg, boolean rightLeg, boolean hat) { - return newEntityData(index, EntityDataTypes.BYTE, (byte) ( - (cape ? 0x01 : 0) | - (jacket ? 0x02 : 0) | - (leftSleeve ? 0x04 : 0) | - (rightSleeve ? 0x08 : 0) | - (leftLeg ? 0x10 : 0) | - (rightLeg ? 0x20 : 0) | - (hat ? 0x40 : 0)) - ); - } - - protected EntityData newEntityData(int index, EntityDataType type, T value) { - return new EntityData(index, type, value); - } - - protected EntityData createRotations(int index, Vector3f rotations) { - return newEntityData(index, EntityDataTypes.ROTATION, new com.github.retrooper.packetevents.util.Vector3f(rotations.getX(), rotations.getY(), rotations.getZ())); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_9MetadataFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_9MetadataFactory.java deleted file mode 100644 index d368509..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/metadata/V1_9MetadataFactory.java +++ /dev/null @@ -1,75 +0,0 @@ -package lol.pyr.znpcsplus.metadata; - -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; -import com.github.retrooper.packetevents.util.adventure.AdventureSerializer; -import lol.pyr.znpcsplus.util.CreeperState; -import net.kyori.adventure.text.Component; - -public class V1_9MetadataFactory extends V1_8MetadataFactory { - @Override - public EntityData skinLayers(boolean cape, boolean jacket, boolean leftSleeve, boolean rightSleeve, boolean leftLeg, boolean rightLeg, boolean hat) { - return createSkinLayers(12, cape, jacket, leftSleeve, rightSleeve, leftLeg, rightLeg, hat); - } - - @Override - public EntityData effects(boolean onFire, boolean glowing, boolean invisible, boolean usingElytra, boolean usingItemLegacy) { - return newEntityData(0, EntityDataTypes.BYTE, (byte) ( - (onFire ? 0x01 : 0) | - (usingItemLegacy ? 0x10 : 0) | - (invisible ? 0x20 : 0) | - (glowing ? 0x40 : 0) | - (usingElytra ? 0x80 : 0) - )); - } - - @Override - public EntityData potionAmbient(boolean ambient) { - return newEntityData(8, EntityDataTypes.BOOLEAN, ambient); - } - - @Override - public EntityData batHanging(boolean hanging) { - return newEntityData(11, EntityDataTypes.BYTE, (byte) (hanging ? 0x01 : 0)); - } - - @Override - public EntityData blazeOnFire(boolean onFire) { - return newEntityData(16, EntityDataTypes.BYTE, (byte) (onFire ? 1 : 0)); - } - - @Override - public EntityData creeperState(CreeperState state) { - return newEntityData(11, EntityDataTypes.INT, state.getState()); - } - - @Override - public EntityData creeperCharged(boolean charged) { - return newEntityData(12, EntityDataTypes.BOOLEAN, charged); - } - - @Override - public EntityData name(Component name) { - return newEntityData(2, EntityDataTypes.STRING, AdventureSerializer.getGsonSerializer().serialize(name)); - } - - @Override - public EntityData nameShown() { - return newEntityData(3, EntityDataTypes.BOOLEAN, true); - } - - @Override - public EntityData silent(boolean enabled) { - return newEntityData(4, EntityDataTypes.BOOLEAN, enabled); - } - - @Override - public EntityData ghastAttacking(boolean attacking) { - return newEntityData(11, EntityDataTypes.BOOLEAN, attacking); - } - - @Override - public EntityData villagerData(int type, int profession, int level) { - return newEntityData(12, EntityDataTypes.INT, profession); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcImpl.java index 78f76b8..c41f151 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcImpl.java @@ -1,10 +1,12 @@ package lol.pyr.znpcsplus.npc; +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; import lol.pyr.znpcsplus.api.entity.EntityProperty; import lol.pyr.znpcsplus.api.npc.Npc; import lol.pyr.znpcsplus.api.npc.NpcType; 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.hologram.HologramImpl; import lol.pyr.znpcsplus.interaction.InteractionActionImpl; @@ -32,18 +34,18 @@ public class NpcImpl extends Viewable implements Npc { private final Map, Object> propertyMap = new HashMap<>(); private final List actions = new ArrayList<>(); - protected NpcImpl(UUID uuid, ConfigManager configManager, LegacyComponentSerializer textSerializer, World world, NpcTypeImpl type, NpcLocation location, PacketFactory packetFactory) { - this(uuid, configManager, packetFactory, textSerializer, world.getName(), type, location); + protected NpcImpl(UUID uuid, EntityPropertyRegistryImpl propertyRegistry, ConfigManager configManager, LegacyComponentSerializer textSerializer, World world, NpcTypeImpl type, NpcLocation location, PacketFactory packetFactory) { + this(uuid, propertyRegistry, configManager, packetFactory, textSerializer, world.getName(), type, location); } - public NpcImpl(UUID uuid, ConfigManager configManager, PacketFactory packetFactory, LegacyComponentSerializer textSerializer, String world, NpcTypeImpl type, NpcLocation location) { + public NpcImpl(UUID uuid, EntityPropertyRegistryImpl propertyRegistry, ConfigManager configManager, PacketFactory packetFactory, LegacyComponentSerializer textSerializer, String world, NpcTypeImpl type, NpcLocation location) { this.packetFactory = packetFactory; this.worldName = world; this.type = type; this.location = location; this.uuid = uuid; entity = new PacketEntity(packetFactory, this, type.getType(), location); - hologram = new HologramImpl(configManager, packetFactory, textSerializer, location.withY(location.getY() + type.getHologramOffset())); + hologram = new HologramImpl(propertyRegistry, configManager, packetFactory, textSerializer, location.withY(location.getY() + type.getHologramOffset())); } @@ -118,12 +120,11 @@ public class NpcImpl extends Viewable implements Npc { hologram.hide(player); } - private void UNSAFE_refreshMeta() { - for (Player viewer : getViewers()) entity.refreshMeta(viewer); - } - - private void UNSAFE_remakeTeam() { - for (Player viewer : getViewers()) entity.remakeTeam(viewer); + private void UNSAFE_refreshProperty(EntityPropertyImpl property) { + for (Player viewer : getViewers()) { + List data = property.applyStandalone(viewer, entity, true); + if (data.size() > 0) packetFactory.sendMetadata(viewer, entity, data); + } } @SuppressWarnings("unchecked") @@ -141,10 +142,10 @@ public class NpcImpl extends Viewable implements Npc { } public void setProperty(EntityPropertyImpl key, T value) { - if (value == null || value.equals(key.getDefaultValue())) removeProperty(key); + if (key == null) return; + if (value == null || value.equals(key.getDefaultValue())) propertyMap.remove(key); else propertyMap.put(key, value); - UNSAFE_refreshMeta(); - if (key.getName().equalsIgnoreCase("glow")) UNSAFE_remakeTeam(); + UNSAFE_refreshProperty(key); } @SuppressWarnings("unchecked") @@ -152,14 +153,8 @@ public class NpcImpl extends Viewable implements Npc { setProperty((EntityPropertyImpl) property, (T) value); } - public void removeProperty(EntityPropertyImpl key) { - propertyMap.remove(key); - UNSAFE_refreshMeta(); - if (key.getName().equalsIgnoreCase("glow")) UNSAFE_remakeTeam(); - else if (key.getName().equalsIgnoreCase("dinnerbone")) respawn(); - } - - public Set> getAppliedProperties() { + @Override + public Set> getAppliedProperties() { return Collections.unmodifiableSet(propertyMap.keySet()); } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcRegistryImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcRegistryImpl.java index 0f74eef..3017944 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcRegistryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcRegistryImpl.java @@ -22,6 +22,7 @@ public class NpcRegistryImpl implements NpcRegistry { private final PacketFactory packetFactory; private final ConfigManager configManager; private final LegacyComponentSerializer textSerializer; + private final EntityPropertyRegistryImpl propertyRegistry; private final List npcList = new ArrayList<>(); private final Map npcIdLookupMap = new HashMap<>(); @@ -29,6 +30,7 @@ public class NpcRegistryImpl implements NpcRegistry { public NpcRegistryImpl(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistry actionRegistry, TaskScheduler scheduler, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) { this.textSerializer = textSerializer; + this.propertyRegistry = propertyRegistry; storage = configManager.getConfig().storageType().create(configManager, plugin, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer); this.packetFactory = packetFactory; this.configManager = configManager; @@ -101,7 +103,9 @@ public class NpcRegistryImpl implements NpcRegistry { } public NpcEntryImpl getByEntityId(int id) { - return npcList.stream().filter(entry -> entry.getNpc().getEntity().getEntityId() == id).findFirst().orElse(null); + return npcList.stream().filter(entry -> entry.getNpc().getEntity().getEntityId() == id || + entry.getNpc().getHologram().getLines().stream().anyMatch(line -> line.getEntityId() == id)) // Also match the holograms of npcs + .findFirst().orElse(null); } public Collection getAllIds() { @@ -134,7 +138,8 @@ public class NpcRegistryImpl implements NpcRegistry { public NpcEntryImpl create(String id, World world, NpcTypeImpl type, NpcLocation location) { id = id.toLowerCase(); if (npcIdLookupMap.containsKey(id)) throw new IllegalArgumentException("An npc with the id " + id + " already exists!"); - NpcImpl npc = new NpcImpl(UUID.randomUUID(), configManager, textSerializer, world, type, location, packetFactory); + NpcImpl npc = new NpcImpl(UUID.randomUUID(), propertyRegistry, configManager, textSerializer, world, type, location, packetFactory); + type.applyDefaultProperties(npc); NpcEntryImpl entry = new NpcEntryImpl(id, npc); register(entry); return entry; diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java index dec2956..3bc2af7 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java @@ -3,25 +3,29 @@ 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.api.entity.EntityProperty; import lol.pyr.znpcsplus.api.npc.NpcType; import lol.pyr.znpcsplus.entity.EntityPropertyImpl; import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; import java.util.*; +import java.util.logging.Logger; import java.util.stream.Collectors; public class NpcTypeImpl implements NpcType { private final EntityType type; private final Set> allowedProperties; + private final Map, Object> defaultProperties; private final String name; private final double hologramOffset; - private NpcTypeImpl(String name, EntityType type, double hologramOffset, Set> allowedProperties) { + private NpcTypeImpl(String name, EntityType type, double hologramOffset, Set> allowedProperties, Map, Object> defaultProperties) { this.name = name.toLowerCase(); this.type = type; this.hologramOffset = hologramOffset; this.allowedProperties = allowedProperties; + this.defaultProperties = defaultProperties; } public String getName() { @@ -40,11 +44,20 @@ public class NpcTypeImpl implements NpcType { return allowedProperties.stream().map(property -> (EntityProperty) property).collect(Collectors.toSet()); } + public void applyDefaultProperties(NpcImpl npc) { + for (Map.Entry, Object> entry : defaultProperties.entrySet()) { + npc.UNSAFE_setProperty(entry.getKey(), entry.getValue()); + } + } + protected static final class Builder { + private final static Logger logger = Logger.getLogger("NpcTypeBuilder"); + private final EntityPropertyRegistryImpl propertyRegistry; private final String name; private final EntityType type; private final List> allowedProperties = new ArrayList<>(); + private final Map, Object> defaultProperties = new HashMap<>(); private double hologramOffset = 0; Builder(EntityPropertyRegistryImpl propertyRegistry, String name, EntityType type) { @@ -67,7 +80,26 @@ public class NpcTypeImpl implements NpcType { } public Builder addProperties(String... names) { - for (String name : names) allowedProperties.add(propertyRegistry.getByName(name)); + for (String name : names) { + if (propertyRegistry.getByName(name) == null) { + // Only for use in development, please comment this out in production because some properties are version-dependent + // logger.warning("Tried to register the non-existent \"" + name + "\" property to the \"" + this.name + "\" npc type"); + continue; + } + allowedProperties.add(propertyRegistry.getByName(name)); + } + return this; + } + + @SuppressWarnings("unchecked") + public Builder addDefaultProperty(String name, T value) { + EntityPropertyImpl property = (EntityPropertyImpl) propertyRegistry.getByName(name); + if (property == null) { + // Only for use in development, please comment this out in production because some properties are version-dependent + // logger.warning("Tried to register the non-existent \"" + name + "\" default property to the \"" + this.name + "\" npc type"); + return this; + } + defaultProperties.put(property, value); return this; } @@ -77,22 +109,51 @@ public class NpcTypeImpl implements NpcType { } public NpcTypeImpl build() { - allowedProperties.add(propertyRegistry.getByName("fire")); - allowedProperties.add(propertyRegistry.getByName("invisible")); - allowedProperties.add(propertyRegistry.getByName("silent")); - allowedProperties.add(propertyRegistry.getByName("look")); - allowedProperties.add(propertyRegistry.getByName("skin_cape")); - allowedProperties.add(propertyRegistry.getByName("using_item")); - allowedProperties.add(propertyRegistry.getByName("potion_color")); - allowedProperties.add(propertyRegistry.getByName("potion_ambient")); - allowedProperties.add(propertyRegistry.getByName("dinnerbone")); - if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) - allowedProperties.add(propertyRegistry.getByName("glow")); - if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_14)) - allowedProperties.add(propertyRegistry.getByName("pose")); - if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_17)) - allowedProperties.add(propertyRegistry.getByName("shaking")); - return new NpcTypeImpl(name, type, hologramOffset, new HashSet<>(allowedProperties)); + ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion(); + addProperties("fire", "invisible", "silent", "look", + "potion_color", "potion_ambient", "dinnerbone"); + // 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)) { + addProperties("pose"); + if (EntityTypes.isTypeInstanceOf(type, EntityTypes.HORSE)) { + addProperties("chestplate"); + } + } + if (version.isNewerThanOrEquals(ServerVersion.V_1_17)) addProperties("shaking"); + if (EntityTypes.isTypeInstanceOf(type, EntityTypes.ABSTRACT_AGEABLE) || EntityTypes.isTypeInstanceOf(type, EntityTypes.ZOMBIE) || EntityTypes.isTypeInstanceOf(type, EntityTypes.ZOGLIN)) { + addProperties("baby"); + } + if (EntityTypes.isTypeInstanceOf(type, EntityTypes.ABSTRACT_HORSE)) { + addProperties("is_saddled", "is_eating", "is_rearing", "has_mouth_open"); + } + if (EntityTypes.isTypeInstanceOf(type, EntityTypes.CHESTED_HORSE)) { + addProperties("has_chest"); + } else if (version.isOlderThan(ServerVersion.V_1_11) && type.equals(EntityTypes.HORSE)) { + addProperties("has_chest"); + } + if (EntityTypes.isTypeInstanceOf(type, EntityTypes.ABSTRACT_EVO_ILLU_ILLAGER)) { + addProperties("spell"); + } + if (EntityTypes.isTypeInstanceOf(type, EntityTypes.ABSTRACT_PIGLIN)) { + addProperties("piglin_immune_to_zombification"); + } + if (EntityTypes.isTypeInstanceOf(type, EntityTypes.SLIME) || EntityTypes.isTypeInstanceOf(type, EntityTypes.PHANTOM)) { + addProperties("size"); + } + if (version.isOlderThan(ServerVersion.V_1_14)) { + if (EntityTypes.isTypeInstanceOf(type, EntityTypes.OCELOT)) { + addProperties("ocelot_type"); + } + } + if (EntityTypes.isTypeInstanceOf(type, EntityTypes.PANDA)) { + if (version.isNewerThanOrEquals(ServerVersion.V_1_15)) { + addProperties("panda_rolling", "panda_sitting", "panda_on_back"); + } else { + addProperties("panda_eating"); + } + } + return new NpcTypeImpl(name, type, hologramOffset, new HashSet<>(allowedProperties), defaultProperties); } } } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeRegistryImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeRegistryImpl.java index 89cc48f..e12d9e2 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeRegistryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeRegistryImpl.java @@ -36,7 +36,14 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { register(builder(p, "player", EntityTypes.PLAYER) .setHologramOffset(-0.15D) .addEquipmentProperties() - .addProperties("skin_cape", "skin_jacket", "skin_left_sleeve", "skin_right_sleeve", "skin_left_leg", "skin_right_leg", "skin_hat", "shoulder_entity_left", "shoulder_entity_right")); + .addProperties("skin_cape", "skin_jacket", "skin_left_sleeve", "skin_right_sleeve", "skin_left_leg", "skin_right_leg", "skin_hat", "shoulder_entity_left", "shoulder_entity_right") + .addDefaultProperty("skin_cape", true) + .addDefaultProperty("skin_jacket", true) + .addDefaultProperty("skin_left_sleeve", true) + .addDefaultProperty("skin_right_sleeve", true) + .addDefaultProperty("skin_left_leg", true) + .addDefaultProperty("skin_right_leg", true) + .addDefaultProperty("skin_hat", true)); // Most hologram offsets generated using Entity#getHeight() in 1.19.4 @@ -88,7 +95,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { .setHologramOffset(-1.125)); register(builder(p, "horse", EntityTypes.HORSE) - .setHologramOffset(-0.375)); + .setHologramOffset(-0.375) + .addProperties("horse_type", "horse_style", "horse_color", "horse_armor")); register(builder(p, "iron_golem", EntityTypes.IRON_GOLEM) .setHologramOffset(0.725)); @@ -96,13 +104,15 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { register(builder(p, "magma_cube", EntityTypes.MAGMA_CUBE)); // TODO: Hologram offset scaling with size property register(builder(p, "mooshroom", EntityTypes.MOOSHROOM) - .setHologramOffset(-0.575)); + .setHologramOffset(-0.575) + .addProperties("mooshroom_variant")); register(builder(p, "ocelot", EntityTypes.OCELOT) .setHologramOffset(-1.275)); register(builder(p, "pig", EntityTypes.PIG) - .setHologramOffset(-1.075)); + .setHologramOffset(-1.075) + .addProperties("pig_saddled")); register(builder(p, "rabbit", EntityTypes.RABBIT) .setHologramOffset(-1.475)); @@ -143,7 +153,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { .setHologramOffset(1.525)); register(builder(p, "wolf", EntityTypes.WOLF) - .setHologramOffset(-1.125)); + .setHologramOffset(-1.125) + .addProperties("tamed")); register(builder(p, "zombie", EntityTypes.ZOMBIE) .setHologramOffset(-0.025) @@ -164,7 +175,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { if (!version.isNewerThanOrEquals(ServerVersion.V_1_10)) return; register(builder(p, "polar_bear", EntityTypes.POLAR_BEAR) - .setHologramOffset(-0.575)); + .setHologramOffset(-0.575) + .addProperties("polar_bear_standing")); if (!version.isNewerThanOrEquals(ServerVersion.V_1_11)) return; @@ -193,14 +205,16 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { .addProperties("evoker_spell")); register(builder(p, "llama", EntityTypes.LLAMA) - .setHologramOffset(-0.105)); + .setHologramOffset(-0.105) + .addProperties("carpet_color", "llama_variant")); register(builder(p, "vex", EntityTypes.VEX) .setHologramOffset(-1.175) .addHandProperties()); register(builder(p, "vindicator", EntityTypes.VINDICATOR) - .setHologramOffset(-0.025)); + .setHologramOffset(-0.025) + .addProperties("celebrating")); register(builder(p, "wither_skeleton", EntityTypes.WITHER_SKELETON) .setHologramOffset(0.425) @@ -216,7 +230,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { .setHologramOffset(-0.025)); register(builder(p, "parrot", EntityTypes.PARROT) - .setHologramOffset(-1.075)); + .setHologramOffset(-1.075) + .addProperties("parrot_variant")); if (!version.isNewerThanOrEquals(ServerVersion.V_1_13)) return; @@ -235,7 +250,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { .setHologramOffset(-1.475)); register(builder(p, "pufferfish", EntityTypes.PUFFERFISH) - .setHologramOffset(-1.625)); + .setHologramOffset(-1.625) + .addProperties("puff_state")); register(builder(p, "salmon", EntityTypes.SALMON) .setHologramOffset(-1.575)); @@ -250,24 +266,27 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { register(builder(p, "cat", EntityTypes.CAT) .setHologramOffset(-1.275) - .addProperties("cat_variant", "cat_lying", "cat_collar_color")); + .addProperties("cat_variant", "cat_laying", "cat_relaxed", "cat_collar", "tamed")); register(builder(p, "fox", EntityTypes.FOX) .setHologramOffset(-1.275) .addProperties("hand", "fox_variant", "fox_sitting", "fox_crouching", "fox_sleeping", "fox_faceplanted")); register(builder(p, "panda", EntityTypes.PANDA) - .setHologramOffset(-0.725)); + .setHologramOffset(-0.725) + .addProperties("panda_main_gene", "panda_hidden_gene", "panda_sneezing")); register(builder(p, "pillager", EntityTypes.PILLAGER) .setHologramOffset(-0.025) - .addHandProperties()); + .addHandProperties() + .addProperties("pillager_charging")); register(builder(p, "ravager", EntityTypes.RAVAGER) .setHologramOffset(0.225)); register(builder(p, "trader_llama", EntityTypes.TRADER_LLAMA) - .setHologramOffset(-0.105)); + .setHologramOffset(-0.105) + .addProperties("llama_variant")); register(builder(p, "wandering_trader", EntityTypes.WANDERING_TRADER) .setHologramOffset(-0.025) @@ -283,11 +302,12 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { register(builder(p, "hoglin", EntityTypes.HOGLIN) .setHologramOffset(-0.575) - .addProperties("immune_to_zombification")); + .addProperties("hoglin_immune_to_zombification")); register(builder(p, "piglin", EntityTypes.PIGLIN) .setHologramOffset(-1.0) - .addEquipmentProperties()); + .addEquipmentProperties() + .addProperties("piglin_baby", "piglin_charging_crossbow", "piglin_dancing")); register(builder(p, "piglin_brute", EntityTypes.PIGLIN_BRUTE) .setHologramOffset(-0.025) @@ -320,7 +340,7 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { register(builder(p, "frog", EntityTypes.FROG) .setHologramOffset(-1.475) - .addProperties("frog_variant")); + .addProperties("frog_variant", "frog_target_npc")); register(builder(p, "tadpole", EntityTypes.TADPOLE) .setHologramOffset(-1.675)); @@ -334,7 +354,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { .setHologramOffset(0.125)); register(builder(p, "camel", EntityTypes.CAMEL) - .setHologramOffset(0.25)); + .setHologramOffset(0.25) + .addProperties("bashing")); } public Collection getAll() { diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/packets/PacketFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/packets/PacketFactory.java index a7ae861..87df253 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/packets/PacketFactory.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/packets/PacketFactory.java @@ -1,12 +1,13 @@ package lol.pyr.znpcsplus.packets; import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.player.Equipment; import lol.pyr.znpcsplus.api.entity.PropertyHolder; import lol.pyr.znpcsplus.entity.PacketEntity; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import java.util.List; -import java.util.Map; import java.util.concurrent.CompletableFuture; public interface PacketFactory { @@ -16,10 +17,9 @@ public interface PacketFactory { void teleportEntity(Player player, PacketEntity entity); CompletableFuture addTabPlayer(Player player, PacketEntity entity, PropertyHolder properties); void removeTabPlayer(Player player, PacketEntity entity); - void createTeam(Player player, PacketEntity entity, PropertyHolder properties); + void createTeam(Player player, PacketEntity entity, NamedTextColor glowColor); void removeTeam(Player player, PacketEntity entity); - Map generateMetadata(Player player, PacketEntity entity, PropertyHolder properties); void sendAllMetadata(Player player, PacketEntity entity, PropertyHolder properties); + void sendEquipment(Player player, PacketEntity entity, Equipment equipment); void sendMetadata(Player player, PacketEntity entity, List data); - void sendEquipment(Player player, PacketEntity entity, PropertyHolder properties); } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_10PacketFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_10PacketFactory.java deleted file mode 100644 index bd3fe90..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_10PacketFactory.java +++ /dev/null @@ -1,27 +0,0 @@ -package lol.pyr.znpcsplus.packets; - -import com.github.retrooper.packetevents.PacketEventsAPI; -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import lol.pyr.znpcsplus.api.entity.PropertyHolder; -import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; -import lol.pyr.znpcsplus.entity.PacketEntity; -import lol.pyr.znpcsplus.metadata.MetadataFactory; -import lol.pyr.znpcsplus.scheduling.TaskScheduler; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; - -import java.util.Map; - -public class V1_10PacketFactory extends V1_9PacketFactory { - public V1_10PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory, PacketEventsAPI packetEvents, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) { - super(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer); - } - - @Override - public Map generateMetadata(Player player, PacketEntity entity, PropertyHolder properties) { - Map data = super.generateMetadata(player, entity, properties); - add(data, metadataFactory.noGravity()); - return data; - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_11PacketFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_11PacketFactory.java deleted file mode 100644 index de725ff..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_11PacketFactory.java +++ /dev/null @@ -1,27 +0,0 @@ -package lol.pyr.znpcsplus.packets; - -import com.github.retrooper.packetevents.PacketEventsAPI; -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import lol.pyr.znpcsplus.api.entity.PropertyHolder; -import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; -import lol.pyr.znpcsplus.entity.PacketEntity; -import lol.pyr.znpcsplus.metadata.MetadataFactory; -import lol.pyr.znpcsplus.scheduling.TaskScheduler; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; - -import java.util.Map; - -public class V1_11PacketFactory extends V1_10PacketFactory { - public V1_11PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory, PacketEventsAPI packetEvents, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) { - super(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer); - } - - @Override - public Map generateMetadata(Player player, PacketEntity entity, PropertyHolder properties) { - Map data = super.generateMetadata(player, entity, properties); - add(data, metadataFactory.usingItem(properties.getProperty(propertyRegistry.getByName("using_item", Boolean.class)), false, false)); - return data; - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_14PacketFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_14PacketFactory.java deleted file mode 100644 index 7e80157..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_14PacketFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -package lol.pyr.znpcsplus.packets; - -import com.github.retrooper.packetevents.PacketEventsAPI; -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose; -import lol.pyr.znpcsplus.api.entity.PropertyHolder; -import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; -import lol.pyr.znpcsplus.entity.PacketEntity; -import lol.pyr.znpcsplus.metadata.MetadataFactory; -import lol.pyr.znpcsplus.scheduling.TaskScheduler; -import lol.pyr.znpcsplus.util.NpcPose; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; - -import java.util.Map; - -public class V1_14PacketFactory extends V1_11PacketFactory { - public V1_14PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory, PacketEventsAPI packetEvents, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) { - super(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer); - } - - @Override - public Map generateMetadata(Player player, PacketEntity entity, PropertyHolder properties) { - Map data = super.generateMetadata(player, entity, properties); - add(data, metadataFactory.pose(adaptNpcPose(properties.getProperty(propertyRegistry.getByName("pose", NpcPose.class))))); - return data; - } - - protected EntityPose adaptNpcPose(NpcPose pose) { - return EntityPose.valueOf(pose.name()); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_16PacketFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_16PacketFactory.java deleted file mode 100644 index 3681218..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_16PacketFactory.java +++ /dev/null @@ -1,27 +0,0 @@ -package lol.pyr.znpcsplus.packets; - -import com.github.retrooper.packetevents.PacketEventsAPI; -import com.github.retrooper.packetevents.protocol.player.Equipment; -import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment; -import lol.pyr.znpcsplus.api.entity.PropertyHolder; -import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; -import lol.pyr.znpcsplus.entity.PacketEntity; -import lol.pyr.znpcsplus.metadata.MetadataFactory; -import lol.pyr.znpcsplus.scheduling.TaskScheduler; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; - -import java.util.List; - -public class V1_16PacketFactory extends V1_14PacketFactory { - public V1_16PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory, PacketEventsAPI packetEvents, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) { - super(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer); - } - - @Override - public void sendEquipment(Player player, PacketEntity entity, PropertyHolder properties) { - List equipments = generateEquipments(properties); - if (equipments.size() > 0) sendPacket(player, new WrapperPlayServerEntityEquipment(entity.getEntityId(), equipments)); - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_17PacketFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_17PacketFactory.java index 81aed5e..d86755a 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_17PacketFactory.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_17PacketFactory.java @@ -1,25 +1,23 @@ package lol.pyr.znpcsplus.packets; import com.github.retrooper.packetevents.PacketEventsAPI; -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; import com.github.retrooper.packetevents.util.Vector3d; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity; import lol.pyr.znpcsplus.api.entity.PropertyHolder; import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; import lol.pyr.znpcsplus.entity.PacketEntity; -import lol.pyr.znpcsplus.metadata.MetadataFactory; import lol.pyr.znpcsplus.scheduling.TaskScheduler; import lol.pyr.znpcsplus.util.NpcLocation; +import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import java.util.Map; import java.util.Optional; -public class V1_17PacketFactory extends V1_16PacketFactory { - public V1_17PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory, PacketEventsAPI packetEvents, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) { - super(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer); +public class V1_17PacketFactory extends V1_8PacketFactory { + public V1_17PacketFactory(TaskScheduler scheduler, PacketEventsAPI packetEvents, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) { + super(scheduler, packetEvents, propertyRegistry, textSerializer); } @Override @@ -28,13 +26,6 @@ public class V1_17PacketFactory extends V1_16PacketFactory { 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); - createTeam(player, entity, properties); - } - - @Override - public Map generateMetadata(Player player, PacketEntity entity, PropertyHolder properties) { - Map data = super.generateMetadata(player, entity, properties); - add(data, metadataFactory.shaking(properties.getProperty(propertyRegistry.getByName("shaking", Boolean.class)))); - return data; + createTeam(player, entity, properties.getProperty(propertyRegistry.getByName("glow", NamedTextColor.class))); } } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_19PacketFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_19PacketFactory.java index e078ebc..d7a552b 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_19PacketFactory.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_19PacketFactory.java @@ -7,10 +7,9 @@ import com.github.retrooper.packetevents.protocol.player.GameMode; import com.github.retrooper.packetevents.protocol.player.UserProfile; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoRemove; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoUpdate; +import lol.pyr.znpcsplus.api.entity.PropertyHolder; import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; import lol.pyr.znpcsplus.entity.PacketEntity; -import lol.pyr.znpcsplus.api.entity.PropertyHolder; -import lol.pyr.znpcsplus.metadata.MetadataFactory; import lol.pyr.znpcsplus.scheduling.TaskScheduler; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; @@ -22,8 +21,8 @@ import java.util.concurrent.CompletableFuture; public class V1_19PacketFactory extends V1_17PacketFactory { private final boolean oldTabPackets; - public V1_19PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory, PacketEventsAPI packetEvents, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) { - super(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer); + public V1_19PacketFactory(TaskScheduler scheduler, PacketEventsAPI packetEvents, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) { + super(scheduler, packetEvents, propertyRegistry, textSerializer); oldTabPackets = packetEvents.getServerManager().getVersion().isOlderThanOrEquals(ServerVersion.V_1_19_2); } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_8PacketFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_8PacketFactory.java index 37d3ccb..b0ec7de 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_8PacketFactory.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_8PacketFactory.java @@ -1,30 +1,28 @@ package lol.pyr.znpcsplus.packets; -import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.PacketEventsAPI; -import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.protocol.entity.data.EntityData; import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; -import io.github.retrooper.packetevents.util.SpigotConversionUtil; -import org.bukkit.inventory.ItemStack; -import com.github.retrooper.packetevents.protocol.player.*; +import com.github.retrooper.packetevents.protocol.player.ClientVersion; +import com.github.retrooper.packetevents.protocol.player.Equipment; +import com.github.retrooper.packetevents.protocol.player.GameMode; +import com.github.retrooper.packetevents.protocol.player.UserProfile; import com.github.retrooper.packetevents.util.Vector3d; import com.github.retrooper.packetevents.wrapper.PacketWrapper; import com.github.retrooper.packetevents.wrapper.play.server.*; +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.entity.EntityPropertyImpl; import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; import lol.pyr.znpcsplus.entity.PacketEntity; -import lol.pyr.znpcsplus.metadata.MetadataFactory; import lol.pyr.znpcsplus.scheduling.TaskScheduler; import lol.pyr.znpcsplus.skin.BaseSkinDescriptor; -import lol.pyr.znpcsplus.util.*; +import lol.pyr.znpcsplus.util.NpcLocation; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import org.bukkit.Color; -import org.bukkit.DyeColor; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; @@ -33,14 +31,12 @@ import java.util.concurrent.CompletableFuture; public class V1_8PacketFactory implements PacketFactory { protected final TaskScheduler scheduler; - protected final MetadataFactory metadataFactory; protected final PacketEventsAPI packetEvents; protected final EntityPropertyRegistryImpl propertyRegistry; protected final LegacyComponentSerializer textSerializer; - public V1_8PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory, PacketEventsAPI packetEvents, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) { + public V1_8PacketFactory(TaskScheduler scheduler, PacketEventsAPI packetEvents, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) { this.scheduler = scheduler; - this.metadataFactory = metadataFactory; this.packetEvents = packetEvents; this.propertyRegistry = propertyRegistry; this.textSerializer = textSerializer; @@ -49,7 +45,7 @@ public class V1_8PacketFactory implements PacketFactory { @Override public void spawnPlayer(Player player, PacketEntity entity, PropertyHolder properties) { addTabPlayer(player, entity, properties).thenAccept(ignored -> { - createTeam(player, entity, properties); + createTeam(player, entity, properties.getProperty(propertyRegistry.getByName("glow", NamedTextColor.class))); NpcLocation location = entity.getLocation(); sendPacket(player, new WrapperPlayServerSpawnPlayer(entity.getEntityId(), entity.getUuid(), npcLocationToVector(location), location.getYaw(), location.getPitch(), Collections.emptyList())); @@ -70,7 +66,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); - createTeam(player, entity, properties); + createTeam(player, entity, properties.getProperty(propertyRegistry.getByName("glow", NamedTextColor.class))); } protected Vector3d npcLocationToVector(NpcLocation location) { @@ -112,12 +108,12 @@ public class V1_8PacketFactory implements PacketFactory { } @Override - public void createTeam(Player player, PacketEntity entity, PropertyHolder properties) { + public void createTeam(Player player, PacketEntity entity, NamedTextColor glowColor) { sendPacket(player, new WrapperPlayServerTeams("npc_team_" + entity.getEntityId(), WrapperPlayServerTeams.TeamMode.CREATE, new WrapperPlayServerTeams.ScoreBoardTeamInfo( Component.empty(), Component.empty(), Component.empty(), WrapperPlayServerTeams.NameTagVisibility.NEVER, WrapperPlayServerTeams.CollisionRule.NEVER, - properties.hasProperty(propertyRegistry.getByName("glow")) ? properties.getProperty(propertyRegistry.getByName("glow", NamedTextColor.class)) : NamedTextColor.WHITE, + glowColor == null ? NamedTextColor.WHITE : glowColor, WrapperPlayServerTeams.OptionData.NONE ))); sendPacket(player, new WrapperPlayServerTeams("npc_team_" + entity.getEntityId(), WrapperPlayServerTeams.TeamMode.ADD_ENTITIES, (WrapperPlayServerTeams.ScoreBoardTeamInfo) null, @@ -129,162 +125,21 @@ public class V1_8PacketFactory implements PacketFactory { sendPacket(player, new WrapperPlayServerTeams("npc_team_" + entity.getEntityId(), WrapperPlayServerTeams.TeamMode.REMOVE, (WrapperPlayServerTeams.ScoreBoardTeamInfo) null)); } - @Override - public Map generateMetadata(Player player, PacketEntity entity, PropertyHolder properties) { - HashMap data = new HashMap<>(); - add(data, metadataFactory.effects( - properties.getProperty(propertyRegistry.getByName("fire", Boolean.class)), - false, - properties.getProperty(propertyRegistry.getByName("invisible", Boolean.class)), - false, - properties.getProperty(propertyRegistry.getByName("using_item", Boolean.class)) - )); - add(data, metadataFactory.silent(properties.getProperty(propertyRegistry.getByName("silent", Boolean.class)))); - add(data, metadataFactory.potionColor(properties.getProperty(propertyRegistry.getByName("potion_color", Color.class)).asRGB())); - add(data, metadataFactory.potionAmbient(properties.getProperty(propertyRegistry.getByName("potion_ambient", Boolean.class)))); - if (entity.getType().equals(EntityTypes.PLAYER)) { - add(data, metadataFactory.skinLayers( - properties.getProperty(propertyRegistry.getByName("skin_cape", Boolean.class)), - properties.getProperty(propertyRegistry.getByName("skin_jacket", Boolean.class)), - properties.getProperty(propertyRegistry.getByName("skin_left_sleeve", Boolean.class)), - properties.getProperty(propertyRegistry.getByName("skin_right_sleeve", Boolean.class)), - properties.getProperty(propertyRegistry.getByName("skin_left_leg", Boolean.class)), - properties.getProperty(propertyRegistry.getByName("skin_right_leg", Boolean.class)), - properties.getProperty(propertyRegistry.getByName("skin_hat", Boolean.class)) - )); - if (packetEvents.getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_12)) { - add(data, metadataFactory.shoulderEntityLeft(properties.getProperty(propertyRegistry.getByName("shoulder_entity_left", ParrotVariant.class)))); - add(data, metadataFactory.shoulderEntityRight(properties.getProperty(propertyRegistry.getByName("shoulder_entity_right", ParrotVariant.class)))); - } - } - else if (entity.getType().equals(EntityTypes.ARMOR_STAND)) { - add(data, metadataFactory.armorStandProperties( - properties.getProperty(propertyRegistry.getByName("small", Boolean.class)), - properties.getProperty(propertyRegistry.getByName("arms", Boolean.class)), - !properties.getProperty(propertyRegistry.getByName("base_plate", Boolean.class)) - )); - add(data, metadataFactory.armorStandHeadRotation(properties.getProperty(propertyRegistry.getByName("head_rotation", Vector3f.class)))); - add(data, metadataFactory.armorStandBodyRotation(properties.getProperty(propertyRegistry.getByName("body_rotation", Vector3f.class)))); - add(data, metadataFactory.armorStandLeftArmRotation(properties.getProperty(propertyRegistry.getByName("left_arm_rotation", Vector3f.class)))); - add(data, metadataFactory.armorStandRightArmRotation(properties.getProperty(propertyRegistry.getByName("right_arm_rotation", Vector3f.class)))); - add(data, metadataFactory.armorStandLeftLegRotation(properties.getProperty(propertyRegistry.getByName("left_leg_rotation", Vector3f.class)))); - add(data, metadataFactory.armorStandRightLegRotation(properties.getProperty(propertyRegistry.getByName("right_leg_rotation", Vector3f.class)))); - } - else if (entity.getType().equals(EntityTypes.AXOLOTL)) { - add(data, metadataFactory.axolotlVariant(properties.getProperty(propertyRegistry.getByName("axolotl_variant", Integer.class)))); - add(data, metadataFactory.playingDead(properties.getProperty(propertyRegistry.getByName("playing_dead", Boolean.class)))); - } - else if (entity.getType().equals(EntityTypes.BAT)) { - add(data, metadataFactory.batHanging(properties.getProperty(propertyRegistry.getByName("hanging", Boolean.class)))); - } - else if (entity.getType().equals(EntityTypes.BEE)) { - add(data, metadataFactory.beeAngry(properties.getProperty(propertyRegistry.getByName("angry", Boolean.class)))); - add(data, metadataFactory.beeHasNectar(properties.getProperty(propertyRegistry.getByName("has_nectar", Boolean.class)))); - } - else if (entity.getType().equals(EntityTypes.BLAZE)) { - add(data, metadataFactory.blazeOnFire(properties.getProperty(propertyRegistry.getByName("blaze_on_fire", Boolean.class)))); - } - else if (entity.getType().equals(EntityTypes.CAT)) { - add(data, metadataFactory.catVariant(properties.getProperty(propertyRegistry.getByName("cat_variant", CatVariant.class)))); - add(data, metadataFactory.catLying(properties.getProperty(propertyRegistry.getByName("cat_lying", Boolean.class)))); - add(data, metadataFactory.catCollarColor(properties.getProperty(propertyRegistry.getByName("cat_collar_color", DyeColor.class)))); - add(data, metadataFactory.catTamed(properties.hasProperty(propertyRegistry.getByName("cat_collar_color", DyeColor.class)))); - } - else if (entity.getType().equals(EntityTypes.CREEPER)) { - add(data, metadataFactory.creeperState(properties.getProperty(propertyRegistry.getByName("creeper_state", CreeperState.class)))); - add(data, metadataFactory.creeperCharged(properties.getProperty(propertyRegistry.getByName("creeper_charged", Boolean.class)))); - } - else if (entity.getType().equals(EntityTypes.ENDERMAN)) { - add(data, metadataFactory.endermanHeldBlock( - properties.getProperty(propertyRegistry.getByName("enderman_held_block", BlockState.class)).getGlobalId()) - ); - add(data, metadataFactory.endermanScreaming(properties.getProperty(propertyRegistry.getByName("enderman_screaming", Boolean.class)))); - add(data, metadataFactory.endermanStaring(properties.getProperty(propertyRegistry.getByName("enderman_staring", Boolean.class)))); - } - else if (entity.getType().equals(EntityTypes.EVOKER)) { - add(data, metadataFactory.evokerSpell(properties.getProperty(propertyRegistry.getByName("evoker_spell", SpellType.class)).ordinal())); - } - else if (entity.getType().equals(EntityTypes.FOX)) { - // Not sure if this should be in here or in 1.14 PacketFactory - add(data, metadataFactory.foxVariant(properties.getProperty(propertyRegistry.getByName("fox_variant", FoxVariant.class)).ordinal())); - add(data, metadataFactory.foxProperties( - properties.getProperty(propertyRegistry.getByName("fox_sitting", Boolean.class)), - properties.getProperty(propertyRegistry.getByName("fox_crouching", Boolean.class)), - properties.getProperty(propertyRegistry.getByName("fox_sleeping", Boolean.class)), - properties.getProperty(propertyRegistry.getByName("fox_faceplanted", Boolean.class)) - )); - } - else if (entity.getType().equals(EntityTypes.FROG)) { - add(data, metadataFactory.frogVariant(properties.getProperty(propertyRegistry.getByName("frog_variant", FrogVariant.class)).ordinal())); - } - else if (entity.getType().equals(EntityTypes.GHAST)) { - add(data, metadataFactory.ghastAttacking(properties.getProperty(propertyRegistry.getByName("attacking", Boolean.class)))); - } - else if (entity.getType().equals(EntityTypes.GOAT)) { - add(data, metadataFactory.goatHasLeftHorn(properties.getProperty(propertyRegistry.getByName("has_left_horn", Boolean.class)))); - add(data, metadataFactory.goatHasRightHorn(properties.getProperty(propertyRegistry.getByName("has_right_horn", Boolean.class)))); - } - else if (entity.getType().equals(EntityTypes.GUARDIAN)) { - // TODO - } - else if (entity.getType().equals(EntityTypes.HOGLIN)) { - add(data, metadataFactory.hoglinImmuneToZombification(properties.getProperty(propertyRegistry.getByName("immune_to_zombification", Boolean.class)))); - } - else if (entity.getType().equals(EntityTypes.VILLAGER)) { - VillagerProfession profession = properties.getProperty(propertyRegistry.getByName("villager_profession", VillagerProfession.class)); - int professionId = profession.ordinal(); - if (PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_14)) { - professionId = profession.getLegacyId(); - } - add(data, metadataFactory.villagerData( - properties.getProperty(propertyRegistry.getByName("villager_type", VillagerType.class)).ordinal(), - professionId, - properties.getProperty(propertyRegistry.getByName("villager_level", VillagerLevel.class)).ordinal() + 1 - )); - } - - if (properties.getProperty(propertyRegistry.getByName("dinnerbone", Boolean.class))) { - add(data, metadataFactory.name(Component.text("Dinnerbone"))); - } - else if (properties.hasProperty(propertyRegistry.getByName("name"))) { - add(data, metadataFactory.name(PapiUtil.set(textSerializer, player, properties.getProperty(propertyRegistry.getByName("name", Component.class))))); - add(data, metadataFactory.nameShown()); - } - return data; - } - @Override public void sendAllMetadata(Player player, PacketEntity entity, PropertyHolder properties) { - sendMetadata(player, entity, new ArrayList<>(generateMetadata(player, entity, properties).values())); - sendEquipment(player, entity, properties); + Map datas = new HashMap<>(); + for (EntityProperty property : properties.getAppliedProperties()) ((EntityPropertyImpl) property).apply(player, entity, false, datas); + sendMetadata(player, entity, new ArrayList<>(datas.values())); } @Override public void sendMetadata(Player player, PacketEntity entity, List data) { - packetEvents.getPlayerManager().sendPacket(player, new WrapperPlayServerEntityMetadata(entity.getEntityId(), data)); + sendPacket(player, new WrapperPlayServerEntityMetadata(entity.getEntityId(), data)); } @Override - public void sendEquipment(Player player, PacketEntity entity, PropertyHolder properties) { - for (Equipment equipment : generateEquipments(properties)) - sendPacket(player, new WrapperPlayServerEntityEquipment(entity.getEntityId(), Collections.singletonList(equipment))); - } - - protected List generateEquipments(PropertyHolder properties) { - HashMap equipmentSlotMap = new HashMap<>(); - equipmentSlotMap.put("helmet", EquipmentSlot.HELMET); - equipmentSlotMap.put("chestplate", EquipmentSlot.CHEST_PLATE); - equipmentSlotMap.put("leggings", EquipmentSlot.LEGGINGS); - equipmentSlotMap.put("boots", EquipmentSlot.BOOTS); - equipmentSlotMap.put("hand", EquipmentSlot.MAIN_HAND); - equipmentSlotMap.put("offhand", EquipmentSlot.OFF_HAND); - List equipements = new ArrayList<>(); - - for (Map.Entry entry : equipmentSlotMap.entrySet()) { - if (!properties.hasProperty(propertyRegistry.getByName(entry.getKey()))) continue; - equipements.add(new Equipment(entry.getValue(), SpigotConversionUtil.fromBukkitItemStack(properties.getProperty(propertyRegistry.getByName(entry.getKey(), ItemStack.class))))); - } - return equipements; + public void sendEquipment(Player player, PacketEntity entity, Equipment equipment) { + sendPacket(player, new WrapperPlayServerEntityEquipment(entity.getEntityId(), Collections.singletonList(equipment))); } protected void sendPacket(Player player, PacketWrapper packet) { diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_9PacketFactory.java b/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_9PacketFactory.java deleted file mode 100644 index d7c914b..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/packets/V1_9PacketFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -package lol.pyr.znpcsplus.packets; - -import com.github.retrooper.packetevents.PacketEventsAPI; -import com.github.retrooper.packetevents.protocol.entity.data.EntityData; -import lol.pyr.znpcsplus.api.entity.PropertyHolder; -import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; -import lol.pyr.znpcsplus.entity.PacketEntity; -import lol.pyr.znpcsplus.metadata.MetadataFactory; -import lol.pyr.znpcsplus.scheduling.TaskScheduler; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; - -import java.util.Map; - -public class V1_9PacketFactory extends V1_8PacketFactory { - public V1_9PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory, PacketEventsAPI packetEvents, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) { - super(scheduler, metadataFactory, packetEvents, propertyRegistry, textSerializer); - } - - @Override - public Map generateMetadata(Player player, PacketEntity entity, PropertyHolder properties) { - Map data = super.generateMetadata(player, entity, properties); - add(data, metadataFactory.effects(properties.getProperty(propertyRegistry.getByName("fire", Boolean.class)), - properties.hasProperty(propertyRegistry.getByName("glow", Boolean.class)), - properties.getProperty(propertyRegistry.getByName("invisible", Boolean.class)), - false, - properties.getProperty(propertyRegistry.getByName("using_item", Boolean.class)) - )); - return data; - } -} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/skin/SkinDescriptorFactoryImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/skin/SkinDescriptorFactoryImpl.java index ca52520..b6656ed 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/skin/SkinDescriptorFactoryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/skin/SkinDescriptorFactoryImpl.java @@ -7,6 +7,9 @@ import lol.pyr.znpcsplus.skin.descriptor.FetchingDescriptor; import lol.pyr.znpcsplus.skin.descriptor.MirrorDescriptor; import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor; +import java.net.MalformedURLException; +import java.net.URL; + public class SkinDescriptorFactoryImpl implements SkinDescriptorFactory { private final MojangSkinCache skinCache; private final MirrorDescriptor mirrorDescriptor; @@ -35,4 +38,18 @@ public class SkinDescriptorFactoryImpl implements SkinDescriptorFactory { public SkinDescriptor createStaticDescriptor(String texture, String signature) { return new PrefetchedDescriptor(new Skin(texture, signature)); } + + @Override + public SkinDescriptor createUrlDescriptor(String url, String variant) { + try { + return createUrlDescriptor(new URL(url), variant); + } catch (MalformedURLException e) { + return null; + } + } + + @Override + public SkinDescriptor createUrlDescriptor(URL url, String variant) { + return PrefetchedDescriptor.fromUrl(skinCache, url, variant).join(); + } } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/skin/cache/MojangSkinCache.java b/plugin/src/main/java/lol/pyr/znpcsplus/skin/cache/MojangSkinCache.java index 170e8ad..de90ca5 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/skin/cache/MojangSkinCache.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/skin/cache/MojangSkinCache.java @@ -8,9 +8,7 @@ import lol.pyr.znpcsplus.skin.Skin; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; +import java.io.*; import java.lang.reflect.InvocationTargetException; import java.net.HttpURLConnection; import java.net.MalformedURLException; @@ -107,6 +105,43 @@ public class MojangSkinCache { }); } + public CompletableFuture fetchByUrl(URL url, String variant) { + return CompletableFuture.supplyAsync(() -> { + URL apiUrl = parseUrl("https://api.mineskin.org/generate/url"); + HttpURLConnection connection = null; + try { + connection = (HttpURLConnection) apiUrl.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("accept", "application/json"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setDoOutput(true); + OutputStream outStream = connection.getOutputStream(); + DataOutputStream out = new DataOutputStream(outStream); + out.writeBytes("{\"variant\":\"" + variant + "\",\"url\":\"" + url.toString() + "\"}"); + out.flush(); + out.close(); + outStream.close(); + + try (Reader reader = new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)) { + JsonObject obj = JsonParser.parseReader(reader).getAsJsonObject(); + if (obj.has("error")) return null; + if (!obj.has("data")) return null; + JsonObject texture = obj.get("data").getAsJsonObject().get("texture").getAsJsonObject(); + return new Skin(texture.get("value").getAsString(), texture.get("signature").getAsString()); + } + + } catch (IOException exception) { + if (!configManager.getConfig().disableSkinFetcherWarnings()) { + logger.warning("Failed to get skin from url:"); + exception.printStackTrace(); + } + } finally { + if (connection != null) connection.disconnect(); + } + return null; + }); + } + public boolean isNameFullyCached(String s) { String name = s.toLowerCase(); if (!idCache.containsKey(name)) return false; diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/skin/descriptor/PrefetchedDescriptor.java b/plugin/src/main/java/lol/pyr/znpcsplus/skin/descriptor/PrefetchedDescriptor.java index 767757d..3e177dd 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/skin/descriptor/PrefetchedDescriptor.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/skin/descriptor/PrefetchedDescriptor.java @@ -7,6 +7,7 @@ import lol.pyr.znpcsplus.skin.Skin; import lol.pyr.znpcsplus.skin.cache.MojangSkinCache; import org.bukkit.entity.Player; +import java.net.URL; import java.util.concurrent.CompletableFuture; public class PrefetchedDescriptor implements BaseSkinDescriptor, SkinDescriptor { @@ -20,6 +21,10 @@ public class PrefetchedDescriptor implements BaseSkinDescriptor, SkinDescriptor return CompletableFuture.supplyAsync(() -> new PrefetchedDescriptor(cache.fetchByName(name).join())); } + public static CompletableFuture fromUrl(MojangSkinCache cache, URL url, String variant) { + return CompletableFuture.supplyAsync(() -> new PrefetchedDescriptor(cache.fetchByUrl(url, variant).join())); + } + @Override public CompletableFuture fetch(Player player) { return CompletableFuture.completedFuture(skin); diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/storage/yaml/YamlStorage.java b/plugin/src/main/java/lol/pyr/znpcsplus/storage/yaml/YamlStorage.java index 4b7d188..7c676b4 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/storage/yaml/YamlStorage.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/storage/yaml/YamlStorage.java @@ -1,10 +1,11 @@ package lol.pyr.znpcsplus.storage.yaml; +import lol.pyr.znpcsplus.api.entity.EntityProperty; import lol.pyr.znpcsplus.config.ConfigManager; 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; @@ -12,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; @@ -54,7 +54,7 @@ public class YamlStorage implements NpcStorage { for (File file : files) if (file.isFile() && file.getName().toLowerCase().endsWith(".yml")) { YamlConfiguration config = YamlConfiguration.loadConfiguration(file); UUID uuid = config.contains("uuid") ? UUID.fromString(config.getString("uuid")) : UUID.randomUUID(); - NpcImpl npc = new NpcImpl(uuid, configManager, packetFactory, textSerializer, config.getString("world"), + NpcImpl npc = new NpcImpl(uuid, propertyRegistry, configManager, packetFactory, textSerializer, config.getString("world"), typeRegistry.getByName(config.getString("type")), deserializeLocation(config.getConfigurationSection("location"))); if (config.isBoolean("enabled")) npc.setEnabled(config.getBoolean("enabled")); @@ -67,13 +67,23 @@ public class YamlStorage implements NpcStorage { Bukkit.getLogger().log(Level.WARNING, "Unknown property '" + key + "' for npc '" + config.getString("id") + "'. skipping ..."); continue; } - npc.UNSAFE_setProperty(property, property.deserialize(properties.getString(key))); + PropertySerializer serializer = propertyRegistry.getSerializer(property.getType()); + if (serializer == null) { + Bukkit.getLogger().log(Level.WARNING, "Unknown serializer for property '" + key + "' for npc '" + config.getString("id") + "'. skipping ..."); + continue; + } + Object value = serializer.deserialize(properties.getString(key)); + if (value == null) { + Bukkit.getLogger().log(Level.WARNING, "Failed to deserialize property '" + key + "' for npc '" + config.getString("id") + "'. Resetting to default ..."); + value = property.getDefaultValue(); + } + npc.UNSAFE_setProperty(property, value); } } 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); @@ -101,8 +111,13 @@ public class YamlStorage implements NpcStorage { config.set("location", serializeLocation(npc.getLocation())); config.set("type", npc.getType().getName()); - for (EntityPropertyImpl property : npc.getAppliedProperties()) try { - config.set("properties." + property.getName(), property.serialize(npc)); + for (EntityProperty property : npc.getAppliedProperties()) try { + PropertySerializer serializer = propertyRegistry.getSerializer(((EntityPropertyImpl) property).getType()); + if (serializer == null) { + Bukkit.getLogger().log(Level.WARNING, "Unknown serializer for property '" + property.getName() + "' for npc '" + entry.getId() + "'. skipping ..."); + continue; + } + config.set("properties." + property.getName(), serializer.UNSAFE_serialize(npc.getProperty(property))); } catch (Exception exception) { logger.severe("Failed to serialize property " + property.getName() + " for npc with id " + entry.getId()); exception.printStackTrace(); @@ -112,8 +127,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 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()