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

More work on properties
This commit is contained in:
Pyr 2023-08-22 23:42:02 +02:00 committed by GitHub
commit 793959b59a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 319 additions and 36 deletions

@ -0,0 +1,9 @@
package lol.pyr.znpcsplus.util;
public enum AxolotlVariant {
LUCY,
WILD,
GOLD,
CYAN,
BLUE
}

@ -0,0 +1,8 @@
package lol.pyr.znpcsplus.util;
public enum HorseArmor {
NONE,
IRON,
GOLD,
DIAMOND
}

@ -0,0 +1,11 @@
package lol.pyr.znpcsplus.util;
public enum HorseColor {
WHITE,
CREAMY,
CHESTNUT,
BROWN,
BLACK,
GRAY,
DARK_BROWN
}

@ -0,0 +1,9 @@
package lol.pyr.znpcsplus.util;
public enum HorseStyle {
NONE,
WHITE,
WHITEFIELD,
WHITE_DOTS,
BLACK_DOTS
}

@ -0,0 +1,9 @@
package lol.pyr.znpcsplus.util;
public enum HorseType {
HORSE,
DONKEY,
MULE,
ZOMBIE,
SKELETON
}

@ -253,6 +253,7 @@ public class ZNpcsPlus extends JavaPlugin {
manager.registerParser(Color.class, new ColorParser(incorrectUsageMessage)); manager.registerParser(Color.class, new ColorParser(incorrectUsageMessage));
manager.registerParser(Vector3f.class, new Vector3fParser(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, NpcPose.class, incorrectUsageMessage);
registerEnumParser(manager, DyeColor.class, incorrectUsageMessage); registerEnumParser(manager, DyeColor.class, incorrectUsageMessage);
registerEnumParser(manager, CatVariant.class, incorrectUsageMessage); registerEnumParser(manager, CatVariant.class, incorrectUsageMessage);
@ -264,6 +265,11 @@ public class ZNpcsPlus extends JavaPlugin {
registerEnumParser(manager, VillagerType.class, incorrectUsageMessage); registerEnumParser(manager, VillagerType.class, incorrectUsageMessage);
registerEnumParser(manager, VillagerProfession.class, incorrectUsageMessage); registerEnumParser(manager, VillagerProfession.class, incorrectUsageMessage);
registerEnumParser(manager, VillagerLevel.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);
manager.registerCommand("npc", new MultiCommand(loadHelpMessage("root")) manager.registerCommand("npc", new MultiCommand(loadHelpMessage("root"))
.addSubcommand("create", new CreateCommand(npcRegistry, typeRegistry)) .addSubcommand("create", new CreateCommand(npcRegistry, typeRegistry))

@ -16,7 +16,6 @@ import lol.pyr.znpcsplus.util.*;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.DyeColor;
import com.github.retrooper.packetevents.protocol.item.ItemStack; import com.github.retrooper.packetevents.protocol.item.ItemStack;
import java.util.Collections; import java.util.Collections;
@ -118,19 +117,13 @@ public class PropertySetCommand implements CommandHandler {
if (context.argSize() == 3) { if (context.argSize() == 3) {
if (type == Boolean.class) return context.suggestLiteral("true", "false"); if (type == Boolean.class) return context.suggestLiteral("true", "false");
if (type == NamedTextColor.class) return context.suggestCollection(NamedTextColor.NAMES.keys()); 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 == 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 == 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()); // Suggest enum values directly
if (type == FrogVariant.class) return context.suggestEnum(FrogVariant.values()); if (type.isEnum()) {
if (type == VillagerType.class) return context.suggestEnum(VillagerType.values()); return context.suggestEnum((Enum<?>[]) type.getEnumConstants());
if (type == VillagerProfession.class) return context.suggestEnum(VillagerProfession.values()); }
if (type == VillagerLevel.class) return context.suggestEnum(VillagerLevel.values());
} }
else if (context.argSize() == 4) { else if (context.argSize() == 4) {
if (type == BlockState.class) { if (type == BlockState.class) {

@ -58,12 +58,15 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
registerEnumSerializer(VillagerType.class); registerEnumSerializer(VillagerType.class);
registerEnumSerializer(VillagerProfession.class); registerEnumSerializer(VillagerProfession.class);
registerEnumSerializer(VillagerLevel.class); registerEnumSerializer(VillagerLevel.class);
registerEnumSerializer(AxolotlVariant.class);
registerEnumSerializer(HorseType.class);
registerEnumSerializer(HorseColor.class);
registerEnumSerializer(HorseStyle.class);
registerEnumSerializer(HorseArmor.class);
/* /*
registerType("using_item", false); // TODO: fix it for 1.8 and add new property to use offhand item and riptide animation registerType("using_item", false); // TODO: fix it for 1.8 and add new property to use offhand item and riptide animation
registerType("baby", false); // TODO
registerType("pose", NpcPose.STANDING);
// Player // Player
registerType("shoulder_entity_left", ParrotVariant.NONE); registerType("shoulder_entity_left", ParrotVariant.NONE);
registerType("shoulder_entity_right", ParrotVariant.NONE); registerType("shoulder_entity_right", ParrotVariant.NONE);
@ -72,13 +75,6 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
registerType("beam_target", null); // TODO: Make a block pos class for this registerType("beam_target", null); // TODO: Make a block pos class for this
registerType("show_base", true); // TODO registerType("show_base", true); // TODO
// Axolotl
registerType("axolotl_variant", 0);
registerType("playing_dead", false); // TODO fix disabling
// Blaze
registerType("blaze_on_fire", false);
// Creeper // Creeper
registerType("creeper_state", CreeperState.IDLE); registerType("creeper_state", CreeperState.IDLE);
registerType("creeper_charged", false); registerType("creeper_charged", false);
@ -106,11 +102,6 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
// Sniffer // Sniffer
registerType("sniffer_state", null); // TODO: Nothing on wiki.vg, look in mc source 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 // LLama
registerType("carpet_color", DyeColor.class); // TODO registerType("carpet_color", DyeColor.class); // TODO
registerType("llama_variant", 0); // TODO registerType("llama_variant", 0); // TODO
@ -217,6 +208,15 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
register(new EncodedIntegerProperty<>("potion_color", Color.class, potionIndex++, Color::asRGB)); register(new EncodedIntegerProperty<>("potion_color", Color.class, potionIndex++, Color::asRGB));
register(new BooleanProperty("potion_ambient", potionIndex, false, legacyBooleans)); 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 // Player
register(new DummyProperty<>("skin", SkinDescriptor.class, false)); register(new DummyProperty<>("skin", SkinDescriptor.class, false));
final int skinLayersIndex; final int skinLayersIndex;
@ -273,7 +273,80 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
else batIndex = 16; else batIndex = 16;
register(new BooleanProperty("hanging", batIndex, false, true /* This isnt a mistake */)); register(new BooleanProperty("hanging", batIndex, false, true /* This isnt 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;
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));
// 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, v1_8));
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");
}
if (!ver.isNewerThanOrEquals(ServerVersion.V_1_14)) return; if (!ver.isNewerThanOrEquals(ServerVersion.V_1_14)) return;
// Pose
register(new NpcPoseProperty());
// Cat // Cat
int catIndex; int catIndex;
@ -301,6 +374,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
register(new BitsetProperty("fox_faceplanted", foxIndex, 0x40)); register(new BitsetProperty("fox_faceplanted", foxIndex, 0x40));
linkProperties("fox_sitting", "fox_crouching", "fox_sleeping", "fox_faceplanted"); linkProperties("fox_sitting", "fox_crouching", "fox_sleeping", "fox_faceplanted");
// Bee
int beeIndex; int beeIndex;
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) beeIndex = 17; if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) beeIndex = 17;
else beeIndex = 18; else beeIndex = 18;
@ -315,12 +389,20 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
register(new BooleanProperty("immune_to_zombification", zombificationIndex, false, legacyBooleans)); register(new BooleanProperty("immune_to_zombification", zombificationIndex, false, legacyBooleans));
if (!ver.isNewerThanOrEquals(ServerVersion.V_1_17)) return; 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 // Goat
register(new BooleanProperty("has_left_horn", 18, true, legacyBooleans)); register(new BooleanProperty("has_left_horn", 18, true, legacyBooleans));
register(new BooleanProperty("has_right_horn", 19, true, legacyBooleans)); register(new BooleanProperty("has_right_horn", 19, true, legacyBooleans));
register(new EncodedIntegerProperty<>("shaking", false,7, enabled -> enabled ? 140 : 0)); register(new EncodedIntegerProperty<>("shaking", false,7, enabled -> enabled ? 140 : 0));
if (!ver.isNewerThanOrEquals(ServerVersion.V_1_20)) return;
// Camel
register(new BooleanProperty("bashing", 18, false, legacyBooleans));
} }
private void registerSerializer(PropertySerializer<?> serializer) { private void registerSerializer(PropertySerializer<?> serializer) {

@ -12,6 +12,12 @@ public class BitsetProperty extends EntityPropertyImpl<Boolean> {
private final int index; private final int index;
private final int bitmask; private final int bitmask;
private final boolean inverted; 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) { public BitsetProperty(String name, int index, int bitmask, boolean inverted) {
super(name, inverted, Boolean.class); super(name, inverted, Boolean.class);
@ -27,9 +33,11 @@ public class BitsetProperty extends EntityPropertyImpl<Boolean> {
@Override @Override
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) { public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
EntityData oldData = properties.get(index); EntityData oldData = properties.get(index);
byte oldValue = oldData == null ? 0 : (byte) oldData.getValue();
boolean enabled = entity.getProperty(this); boolean enabled = entity.getProperty(this);
if (inverted) enabled = !enabled; if (inverted) enabled = !enabled;
properties.put(index, newEntityData(index, EntityDataTypes.BYTE, (byte) (oldValue | (enabled ? bitmask : 0)))); 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))));
} }
} }

@ -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<T> extends EntityPropertyImpl<T> {
private final EntityDataType<Byte> type;
private final ByteDecoder<T> decoder;
private final int index;
protected EncodedByteProperty(String name, T defaultValue, Class<T> clazz, int index, ByteDecoder<T> decoder, EntityDataType<Byte> 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<T> decoder) {
this(name, defaultValue, (Class<T>) defaultValue.getClass(), index, decoder, EntityDataTypes.BYTE);
}
@SuppressWarnings("unchecked")
public EncodedByteProperty(String name, T defaultValue, int index, ByteDecoder<T> decoder, EntityDataType<Byte> type) {
this(name, defaultValue, (Class<T>) defaultValue.getClass(), index, decoder, type);
}
public EncodedByteProperty(String name, Class<T> clazz, int index, ByteDecoder<T> decoder) {
this(name, null, clazz, index, decoder, EntityDataTypes.BYTE);
}
@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 ByteDecoder<T> {
byte decode(T obj);
}
}

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

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

@ -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<NpcPose> {
public NpcPoseProperty() {
super("pose", NpcPose.STANDING, NpcPose.class);
}
@Override
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
properties.put(6, newEntityData(6, EntityDataTypes.ENTITY_POSE, EntityPose.valueOf(entity.getProperty(this).name())));
}
}

@ -1,18 +1,19 @@
package lol.pyr.znpcsplus.entity.serializers; 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.entity.PropertySerializer;
import lol.pyr.znpcsplus.util.ItemSerializationUtil; import lol.pyr.znpcsplus.util.ItemSerializationUtil;
import org.bukkit.inventory.ItemStack;
public class ItemStackPropertySerializer implements PropertySerializer<ItemStack> { public class ItemStackPropertySerializer implements PropertySerializer<ItemStack> {
@Override @Override
public String serialize(ItemStack property) { public String serialize(ItemStack property) {
return ItemSerializationUtil.itemToB64(property); return ItemSerializationUtil.itemToB64(SpigotConversionUtil.toBukkitItemStack(property));
} }
@Override @Override
public ItemStack deserialize(String property) { public ItemStack deserialize(String property) {
return ItemSerializationUtil.itemFromB64(property); return SpigotConversionUtil.fromBukkitItemStack(ItemSerializationUtil.itemFromB64(property));
} }
@Override @Override

@ -3,6 +3,7 @@ package lol.pyr.znpcsplus.npc;
import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion; 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.EntityType;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import lol.pyr.znpcsplus.api.entity.EntityProperty; import lol.pyr.znpcsplus.api.entity.EntityProperty;
import lol.pyr.znpcsplus.api.npc.NpcType; import lol.pyr.znpcsplus.api.npc.NpcType;
import lol.pyr.znpcsplus.entity.EntityPropertyImpl; import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
@ -90,8 +91,24 @@ public class NpcTypeImpl implements NpcType {
addProperties("fire", "invisible", "silent", "look", addProperties("fire", "invisible", "silent", "look",
"using_item", "potion_color", "potion_ambient", "dinnerbone"); "using_item", "potion_color", "potion_ambient", "dinnerbone");
if (version.isNewerThanOrEquals(ServerVersion.V_1_9)) addProperties("glow"); if (version.isNewerThanOrEquals(ServerVersion.V_1_9)) addProperties("glow");
if (version.isNewerThanOrEquals(ServerVersion.V_1_14)) addProperties("pose"); 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 (version.isNewerThanOrEquals(ServerVersion.V_1_17)) addProperties("shaking");
if (EntityTypes.isTypeInstanceOf(type, EntityTypes.ABSTRACT_AGEABLE)) {
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");
}
return new NpcTypeImpl(name, type, hologramOffset, new HashSet<>(allowedProperties)); return new NpcTypeImpl(name, type, hologramOffset, new HashSet<>(allowedProperties));
} }
} }

@ -88,7 +88,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
.setHologramOffset(-1.125)); .setHologramOffset(-1.125));
register(builder(p, "horse", EntityTypes.HORSE) 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) register(builder(p, "iron_golem", EntityTypes.IRON_GOLEM)
.setHologramOffset(0.725)); .setHologramOffset(0.725));
@ -335,7 +336,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
.setHologramOffset(0.125)); .setHologramOffset(0.125));
register(builder(p, "camel", EntityTypes.CAMEL) register(builder(p, "camel", EntityTypes.CAMEL)
.setHologramOffset(0.25)); .setHologramOffset(0.25)
.addProperties("bashing"));
} }
public Collection<NpcType> getAll() { public Collection<NpcType> getAll() {

@ -65,7 +65,12 @@ public class YamlStorage implements NpcStorage {
Bukkit.getLogger().log(Level.WARNING, "Unknown property '" + key + "' for npc '" + config.getString("id") + "'. skipping ..."); Bukkit.getLogger().log(Level.WARNING, "Unknown property '" + key + "' for npc '" + config.getString("id") + "'. skipping ...");
continue; continue;
} }
npc.UNSAFE_setProperty(property, propertyRegistry.getSerializer(property.getType()).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;
}
npc.UNSAFE_setProperty(property, serializer.deserialize(properties.getString(key)));
} }
} }
HologramImpl hologram = npc.getHologram(); HologramImpl hologram = npc.getHologram();