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/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java b/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java index d414ead..1e86537 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java @@ -145,7 +145,7 @@ public class ZNpcsPlus extends JavaPlugin { DataImporterRegistry importerRegistry = new DataImporterRegistry(configManager, adventure, bungeeConnector, scheduler, packetFactory, textSerializer, typeRegistry, getDataFolder().getParentFile(), - propertyRegistry, skinCache); + propertyRegistry, skinCache, npcRegistry); log(ChatColor.WHITE + " * Registerring components..."); @@ -270,6 +270,11 @@ public class ZNpcsPlus extends JavaPlugin { 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("create", new CreateCommand(npcRegistry, typeRegistry)) 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 752f8cb..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,5 +1,7 @@ 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; @@ -18,6 +20,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Color; import com.github.retrooper.packetevents.protocol.item.ItemStack; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -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); @@ -119,6 +140,9 @@ public class PropertySetCommand implements CommandHandler { if (type == NamedTextColor.class) return context.suggestCollection(NamedTextColor.NAMES.keys()); if (type == Color.class) return context.suggestLiteral("0x0F00FF", "#FFFFFF"); if (type == BlockState.class) return context.suggestLiteral("hand", "looking_at", "block"); + 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()) { 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 55d1012..a162529 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/DataImporterRegistry.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/DataImporterRegistry.java @@ -4,6 +4,7 @@ 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; @@ -25,14 +26,14 @@ public class DataImporterRegistry { public DataImporterRegistry(ConfigManager configManager, BukkitAudiences adventure, BungeeConnector bungeeConnector, 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, bungeeConnector, taskScheduler, packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "ServersNPC/data.json")))); register("znpcsplus_legacy", LazyLoader.of(() -> new ZNpcImporter(configManager, adventure, bungeeConnector, 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")))); + 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 86e3895..003ad69 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 @@ -1,6 +1,5 @@ package lol.pyr.znpcsplus.conversion.citizens; -import lol.pyr.znpcsplus.api.NpcApiProvider; import lol.pyr.znpcsplus.config.ConfigManager; import lol.pyr.znpcsplus.conversion.DataImporter; import lol.pyr.znpcsplus.conversion.citizens.model.CitizensTrait; @@ -8,6 +7,7 @@ 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; @@ -39,11 +39,12 @@ public class CitizensImporter implements DataImporter { private final MojangSkinCache skinCache; private final File dataFile; private final CitizensTraitsRegistry traitsRegistry; + private final NpcRegistryImpl npcRegistry; public CitizensImporter(ConfigManager configManager, BukkitAudiences adventure, BungeeConnector bungeeConnector, 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.bungeeConnector = bungeeConnector; @@ -55,6 +56,7 @@ public class CitizensImporter implements DataImporter { this.skinCache = skinCache; this.dataFile = dataFile; this.traitsRegistry = new CitizensTraitsRegistry(typeRegistry, propertyRegistry, skinCache); + this.npcRegistry = npcRegistry; } @Override @@ -96,8 +98,8 @@ public class CitizensImporter implements DataImporter { } } String id = key.toLowerCase(); - while (NpcApiProvider.get().getNpcRegistry().getById(id) != null) { - id += "_"; + while (npcRegistry.getById(id) != null) { + id += "_"; // TODO: make a backup of the old npc instead } NpcEntryImpl entry = new NpcEntryImpl(id, npc); entry.enableEverything(); 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 56d8788..b3f64c3 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java @@ -3,6 +3,9 @@ package lol.pyr.znpcsplus.entity; import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.protocol.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; @@ -46,6 +49,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { registerSerializer(new ColorPropertySerializer()); registerSerializer(new Vector3fPropertySerializer()); registerSerializer(new BlockStatePropertySerializer()); + registerSerializer(new IntegerPropertySerializer()); registerEnumSerializer(NpcPose.class); registerEnumSerializer(DyeColor.class); @@ -63,64 +67,36 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { 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("using_item", false); // TODO: fix it for 1.8 and add new property to use offhand item and riptide animation - // Player - 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 - // 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); - - // Frog - registerType("frog_variant", FrogVariant.TEMPERATE); - // Guardian registerType("is_elder", false); // TODO: ensure it only works till 1.10. Note: index is wrong on wiki.vg - // 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 - // 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 @@ -133,9 +109,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); @@ -149,21 +122,9 @@ 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 - - // Vindicator - registerType("celebrating", false); // TODO - // Wither registerType("invulnerable_time", 0); // TODO - // Phantom - registerType("phantom_size", 0); // TODO - - // Slime - registerType("slime_size", 0); // TODO */ } @@ -271,7 +232,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { 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 isnt a mistake */)); + register(new BooleanProperty("hanging", batIndex, false, true /* This isn't a mistake */)); // Blaze final int blazeIndex; @@ -303,12 +264,11 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) horseIndex = 12; else horseIndex = 16; int horseEating = ver.isNewerThanOrEquals(ServerVersion.V_1_12) ? 0x10 : 0x20; - boolean v1_8 = ver.isOlderThan(ServerVersion.V_1_9); - register(new BitsetProperty("is_tame", horseIndex, 0x02, false, v1_8)); - register(new BitsetProperty("is_saddled", horseIndex, 0x04, false, v1_8)); - register(new BitsetProperty("is_eating", horseIndex, horseEating, false, v1_8)); - register(new BitsetProperty("is_rearing", horseIndex, horseEating << 1, false, v1_8)); - register(new BitsetProperty("has_mouth_open", horseIndex, horseEating << 2, false, v1_8)); + 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)) { @@ -337,13 +297,100 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { // Chested Horse if (ver.isOlderThan(ServerVersion.V_1_11)) { - register(new BitsetProperty("has_chest", horseIndex, 0x08, false, v1_8)); + 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()); @@ -369,6 +416,32 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { 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)); @@ -383,10 +456,26 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { if (!ver.isNewerThanOrEquals(ServerVersion.V_1_16)) return; + // Hoglin and Piglin Zombification final int zombificationIndex; - if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) zombificationIndex = 17; + if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) zombificationIndex = 17; // Change piglinIndex and pillagerIndex if you change this else zombificationIndex = 16; - register(new BooleanProperty("immune_to_zombification", zombificationIndex, false, legacyBooleans)); + 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 + int pillagerIndex = zombificationIndex; + register(new BooleanProperty("pillager_charging", pillagerIndex, false, legacyBooleans)); + + // Vindicator + int vindicatorIndex = pillagerIndex-1; + register(new BooleanProperty("celebrating", vindicatorIndex, false, legacyBooleans)); if (!ver.isNewerThanOrEquals(ServerVersion.V_1_17)) return; // Axolotl @@ -398,6 +487,9 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { 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; 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/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/IntegerProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/IntegerProperty.java index 2fe1c35..26f42c4 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/IntegerProperty.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/IntegerProperty.java @@ -10,14 +10,22 @@ import java.util.Map; public class IntegerProperty extends EntityPropertyImpl { private final int index; + private final boolean legacy; - protected IntegerProperty(String name, int index, Integer defaultValue) { + 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, newEntityData(index, EntityDataTypes.INT, entity.getProperty(this))); + 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 index ec57fcd..e3b7230 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/NameProperty.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/NameProperty.java @@ -5,6 +5,7 @@ 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; @@ -29,6 +30,7 @@ public class NameProperty extends EntityPropertyImpl { 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)); } 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/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/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/npc/NpcTypeImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java index b22810a..f2d9b7b 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java @@ -110,6 +110,7 @@ public class NpcTypeImpl implements NpcType { 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"); @@ -118,7 +119,7 @@ public class NpcTypeImpl implements NpcType { } } if (version.isNewerThanOrEquals(ServerVersion.V_1_17)) addProperties("shaking"); - if (EntityTypes.isTypeInstanceOf(type, EntityTypes.ABSTRACT_AGEABLE)) { + 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)) { @@ -129,6 +130,27 @@ public class NpcTypeImpl implements NpcType { } 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 bcb0856..e12d9e2 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeRegistryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeRegistryImpl.java @@ -104,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)); @@ -173,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; @@ -202,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) @@ -225,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; @@ -244,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)); @@ -266,17 +273,20 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { .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) @@ -292,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) @@ -329,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)); 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 336deab..032a916 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 @@ -70,7 +70,12 @@ public class YamlStorage implements NpcStorage { Bukkit.getLogger().log(Level.WARNING, "Unknown serializer for property '" + key + "' for npc '" + config.getString("id") + "'. skipping ..."); continue; } - npc.UNSAFE_setProperty(property, serializer.deserialize(properties.getString(key))); + 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(); @@ -108,6 +113,10 @@ public class YamlStorage implements NpcStorage { for (EntityProperty property : npc.getAppliedProperties()) { 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))); }