Merge pull request #89 from D3v1s0m/modular-property-system

Properties
This commit is contained in:
Pyr 2023-09-12 22:09:33 +02:00 committed by GitHub
commit fb3a22a355
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 481 additions and 86 deletions

View file

@ -0,0 +1,8 @@
package lol.pyr.znpcsplus.util;
public enum LlamaVariant {
CREAMY,
WHITE,
BROWN,
GRAY
}

View file

@ -0,0 +1,10 @@
package lol.pyr.znpcsplus.util;
public enum MooshroomVariant {
RED,
BROWN;
public static String getVariantName(MooshroomVariant variant) {
return variant.name().toLowerCase();
}
}

View file

@ -0,0 +1,8 @@
package lol.pyr.znpcsplus.util;
public enum OcelotType {
OCELOT,
TUXEDO,
TABBY,
SIAMESE,
}

View file

@ -0,0 +1,11 @@
package lol.pyr.znpcsplus.util;
public enum PandaGene {
NORMAL,
LAZY,
WORRIED,
PLAYFUL,
BROWN,
WEAK,
AGGRESSIVE
}

View file

@ -5,6 +5,5 @@ public enum ParrotVariant {
BLUE,
GREEN,
YELLOW_BLUE,
GRAY,
NONE // only used to set empty nbt compound
GRAY
}

View file

@ -0,0 +1,7 @@
package lol.pyr.znpcsplus.util;
public enum PuffState {
DEFLATED,
HALF_INFLATED,
FULLY_INFLATED,
}

View file

@ -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))

View file

@ -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()) {

View file

@ -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<DataImporter> loader) {

View file

@ -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();

View file

@ -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<DyeColor>("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<ParrotVariant> 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;

View file

@ -15,7 +15,11 @@ public class EnumPropertySerializer<T extends Enum<T>> 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

View file

@ -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<T> extends EntityPropertyImpl<T> {
private final EntityDataType<String> type;
private final EncodedStringProperty.StringDecoder<T> decoder;
private final int index;
public EncodedStringProperty(String name, T defaultValue, Class<T> clazz, int index, StringDecoder<T> decoder, EntityDataType<String> 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<T> decoder) {
this(name, defaultValue, (Class<T>) defaultValue.getClass(), index, decoder, EntityDataTypes.STRING);
}
@SuppressWarnings("unchecked")
public EncodedStringProperty(String name, T defaultValue, int index, StringDecoder<T> decoder, EntityDataType<String> type) {
this(name, defaultValue, (Class<T>) defaultValue.getClass(), index, decoder, type);
}
public EncodedStringProperty(String name, Class<T> clazz, int index, StringDecoder<T> decoder) {
this(name, null, clazz, index, decoder, EntityDataTypes.STRING);
}
@Override
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
T value = entity.getProperty(this);
if (value == null) return;
properties.put(index, newEntityData(index, type, decoder.decode(value)));
}
public interface StringDecoder<T> {
String decode(T obj);
}
}

View file

@ -10,14 +10,22 @@ import java.util.Map;
public class IntegerProperty extends EntityPropertyImpl<Integer> {
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<Integer, EntityData> 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)));
}
}

View file

@ -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<T> extends EntityPropertyImpl<T> {
private final EntityDataType<NBTCompound> type;
private final NBTDecoder<T> decoder;
private final int index;
public NBTProperty(String name, T defaultValue, Class<T> clazz, int index, NBTDecoder<T> decoder, EntityDataType<NBTCompound> 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<T> decoder) {
this(name, defaultValue, (Class<T>) defaultValue.getClass(), index, decoder, EntityDataTypes.NBT);
}
@SuppressWarnings("unchecked")
public NBTProperty(String name, T defaultValue, int index, NBTDecoder<T> decoder, EntityDataType<NBTCompound> type) {
this(name, defaultValue, (Class<T>) defaultValue.getClass(), index, decoder, type);
}
public NBTProperty(String name, Class<T> clazz, int index, NBTDecoder<T> decoder) {
this(name, null, clazz, index, decoder, EntityDataTypes.NBT);
}
@Override
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
T value = entity.getProperty(this);
if (value == null) return;
properties.put(index, newEntityData(index, type, decoder.decode(value)));
}
public interface NBTDecoder<T> {
NBTCompound decode(T obj);
}
}

View file

@ -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<Component> {
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));
}

View file

@ -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<NpcEntryImpl> {
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<Integer, EntityData> 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()));
}
}
}

View file

@ -0,0 +1,25 @@
package lol.pyr.znpcsplus.entity.serializers;
import lol.pyr.znpcsplus.entity.PropertySerializer;
public class IntegerPropertySerializer implements PropertySerializer<Integer> {
@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<Integer> getTypeClass() {
return Integer.class;
}
}

View file

@ -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<NpcEntryImpl> {
@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<NpcEntryImpl> getTypeClass() {
return NpcEntryImpl.class;
}
}

View file

@ -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);
}
}

View file

@ -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));

View file

@ -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)));
}