Merge pull request #93 from D3v1s0m/2.X

More propertiessss
This commit is contained in:
Pyr 2023-10-04 16:03:58 +02:00 committed by GitHub
commit e79cfd7e62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 454 additions and 82 deletions

@ -6,4 +6,5 @@ public interface EntityPropertyRegistry {
Collection<EntityProperty<?>> getAll();
EntityProperty<?> getByName(String name);
<T> EntityProperty<T> getByName(String name, Class<T> type);
void registerDummy(String name, Class<?> type);
}

@ -0,0 +1,10 @@
package lol.pyr.znpcsplus.util;
public enum AttachDirection {
DOWN,
UP,
NORTH,
SOUTH,
WEST,
EAST
}

@ -0,0 +1,22 @@
package lol.pyr.znpcsplus.util;
public enum RabbitType {
BROWN(0),
WHITE(1),
BLACK(2),
BLACK_AND_WHITE(3),
GOLD(4),
SALT_AND_PEPPER(5),
THE_KILLER_BUNNY(99),
TOAST(100);
private final int id;
RabbitType(int id) {
this.id = id;
}
public int getId() {
return id;
}
}

@ -0,0 +1,11 @@
package lol.pyr.znpcsplus.util;
public enum SnifferState {
IDLING,
FEELING_HAPPY,
SCENTING,
SNIFFING,
SEARCHING,
DIGGING,
RISING
}

@ -0,0 +1,104 @@
package lol.pyr.znpcsplus.util;
import org.bukkit.DyeColor;
import java.util.function.IntFunction;
public class TropicalFishVariant {
private final TropicalFishPattern pattern;
private final DyeColor bodyColor;
private final DyeColor patternColor;
public TropicalFishVariant(TropicalFishPattern pattern, DyeColor bodyColor, DyeColor patternColor) {
this.pattern = pattern;
this.bodyColor = bodyColor;
this.patternColor = patternColor;
}
public int getVariant() {
return pattern.getId() & '\uffff' | (bodyColor.ordinal() & 255) << 16 | (patternColor.ordinal() & 255) << 24;
}
public enum TropicalFishPattern {
KOB(0, 0),
SUNSTREAK(0, 1),
SNOOPER(0, 2),
DASHER(0, 3),
BRINELY(0, 4),
SPOTTY(0, 5),
FLOPPER(1, 0),
STRIPEY(1, 1),
GLITTER(1, 2),
BLOCKFISH(1, 3),
BETTY(1, 4),
CLAYFISH(1, 5);
private final int size;
private final int id;
private static final IntFunction<TropicalFishPattern> BY_ID = (id) -> {
for (TropicalFishPattern pattern : values()) {
if (pattern.id == id) {
return pattern;
}
}
return null;
};
TropicalFishPattern(int size, int pattern) {
this.size = size;
this.id = size | pattern << 8;
}
public int getSize() {
return size;
}
public int getId() {
return id;
}
public static TropicalFishPattern fromVariant(int variant) {
return BY_ID.apply(variant & '\uffff');
}
}
public static class Builder {
private TropicalFishPattern pattern;
private DyeColor bodyColor;
private DyeColor patternColor;
public Builder() {
this.pattern = TropicalFishPattern.KOB;
this.bodyColor = DyeColor.WHITE;
this.patternColor = DyeColor.WHITE;
}
public Builder pattern(TropicalFishPattern pattern) {
this.pattern = pattern;
return this;
}
public Builder bodyColor(DyeColor bodyColor) {
this.bodyColor = bodyColor;
return this;
}
public Builder patternColor(DyeColor patternColor) {
this.patternColor = patternColor;
return this;
}
public static Builder fromInt(int variant) {
Builder builder = new Builder();
builder.pattern = TropicalFishPattern.fromVariant(variant);
builder.bodyColor = DyeColor.values()[(variant >> 16) & 0xFF];
builder.patternColor = DyeColor.values()[(variant >> 24) & 0xFF];
return builder;
}
public TropicalFishVariant build() {
return new TropicalFishVariant(pattern, bodyColor, patternColor);
}
}
}

@ -65,10 +65,7 @@ import java.io.PrintWriter;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.*;
public class ZNpcsPlus extends JavaPlugin {
private final LegacyComponentSerializer textSerializer = LegacyComponentSerializer.builder()
@ -253,6 +250,7 @@ public class ZNpcsPlus extends JavaPlugin {
manager.registerParser(InteractionType.class, new InteractionTypeParser(incorrectUsageMessage));
manager.registerParser(Color.class, new ColorParser(incorrectUsageMessage));
manager.registerParser(Vector3f.class, new Vector3fParser(incorrectUsageMessage));
manager.registerParser(String.class, new StringParser(incorrectUsageMessage));
// TODO: Need to find a better way to do this
registerEnumParser(manager, NpcPose.class, incorrectUsageMessage);
@ -277,6 +275,10 @@ public class ZNpcsPlus extends JavaPlugin {
registerEnumParser(manager, PandaGene.class, incorrectUsageMessage);
registerEnumParser(manager, PuffState.class, incorrectUsageMessage);
registerEnumParser(manager, LookType.class, incorrectUsageMessage);
registerEnumParser(manager, TropicalFishVariant.TropicalFishPattern.class, incorrectUsageMessage);
registerEnumParser(manager, SnifferState.class, incorrectUsageMessage);
registerEnumParser(manager, RabbitType.class, incorrectUsageMessage);
registerEnumParser(manager, AttachDirection.class, incorrectUsageMessage);
manager.registerCommand("npc", new MultiCommand(loadHelpMessage("root"))
.addSubcommand("center", new CenterCommand(npcRegistry))

@ -37,7 +37,7 @@ public class PropertyRemoveCommand implements CommandHandler {
public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
if (context.argSize() == 2) return context.suggestStream(context.suggestionParse(0, NpcEntryImpl.class)
.getNpc().getAppliedProperties().stream().filter(EntityProperty::isPlayerModifiable).map(EntityProperty::getName));
.getNpc().getAllProperties().stream().filter(EntityProperty::isPlayerModifiable).map(EntityProperty::getName));
return Collections.emptyList();
}
}

@ -3,10 +3,12 @@ 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.entity.pose.EntityPose;
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 com.github.retrooper.packetevents.protocol.world.BlockFace;
import lol.pyr.znpcsplus.api.entity.EntityProperty;
import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry;
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
@ -76,6 +78,10 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
registerEnumSerializer(OcelotType.class);
registerEnumSerializer(PandaGene.class);
registerEnumSerializer(PuffState.class);
registerEnumSerializer(TropicalFishVariant.TropicalFishPattern.class);
registerEnumSerializer(SnifferState.class);
registerEnumSerializer(RabbitType.class);
registerEnumSerializer(AttachDirection.class);
registerPrimitiveSerializers(Integer.class, Boolean.class, Double.class, Float.class, Long.class, Short.class, Byte.class, String.class);
@ -96,38 +102,6 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
// Guardian
registerType("is_elder", false); // TODO: ensure it only works till 1.10. Note: index is wrong on wiki.vg
// 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
// Rabbit
registerType("rabbit_type", 0); // TODO: Figure this out
// Sheep
registerType("sheep_color", DyeColor.WHITE); // TODO: Figure this out
registerType("sheep_sheared", false); // TODO
// Strider
registerType("strider_shaking", false); // TODO
registerType("strider_saddle", false); // TODO
// Wolf
registerType("wolf_collar_color", DyeColor.RED); // TODO
registerType("wolf_angry", false); // TODO
// Show Golem
registerType("pumpkin", true); // TODO
// Shulker
registerType("attach_direction", null); // TODO: make a direction enum
registerType("shield_height", 0); // TODO: figure this out
registerType("shulker_color", DyeColor.RED); // TODO
// Wither
registerType("invulnerable_time", 0); // TODO
*/
}
@ -158,14 +132,15 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
linkProperties("glow", "fire", "invisible");
register(new BooleanProperty("silent", 4, false, legacyBooleans));
final int tamedIndex;
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) tamedIndex = 17;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) tamedIndex = 16;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) tamedIndex = 15;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) tamedIndex = 13;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) tamedIndex = 12;
else tamedIndex = 16;
register(new BitsetProperty("tamed", tamedIndex, 0x04));
final int tameableIndex;
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) tameableIndex = 17;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) tameableIndex = 16;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) tameableIndex = 15;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) tameableIndex = 13;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) tameableIndex = 12;
else tameableIndex = 16;
register(new BitsetProperty("sitting", tameableIndex, 0x01));
register(new BitsetProperty("tamed", tameableIndex, 0x04));
int potionIndex;
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) potionIndex = 10;
@ -340,6 +315,82 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
else pigIndex = 16;
register(new BooleanProperty("pig_saddled", pigIndex, false, legacyBooleans));
// Rabbit
int rabbitIndex;
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) rabbitIndex = 17;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) rabbitIndex = 16;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) rabbitIndex = 15;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) rabbitIndex = 13;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) rabbitIndex = 12;
else rabbitIndex = 18;
register(new RabbitTypeProperty(rabbitIndex, legacyBooleans, legacyNames, optionalComponents));
// Sheep
int sheepIndex;
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) sheepIndex = 17;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) sheepIndex = 16;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) sheepIndex = 15;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) sheepIndex = 13;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) sheepIndex = 12;
else sheepIndex = 16;
// noinspection deprecation
register(new EncodedByteProperty<>("sheep_color", DyeColor.WHITE, sheepIndex, DyeColor::getWoolData));
register(new BitsetProperty("sheep_sheared", sheepIndex, 0x10, false, legacyBooleans)); // no need to link because sheep_sheared is only visible when sheep_color is WHITE
// Wolf
int wolfIndex;
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) wolfIndex = 19;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) wolfIndex = 18;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) wolfIndex = 16;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) wolfIndex = 15;
else wolfIndex = 19;
register(new BooleanProperty("wolf_begging", wolfIndex++, false, legacyBooleans));
if (legacyBooleans) {
// noinspection deprecation
register(new EncodedByteProperty<>("wolf_collar", DyeColor.BLUE, wolfIndex++, DyeColor::getDyeData));
} else register(new EncodedIntegerProperty<>("wolf_collar", DyeColor.RED, wolfIndex++, Enum::ordinal));
if (ver.isNewerThanOrEquals(ServerVersion.V_1_16)) {
register(new EncodedIntegerProperty<>("wolf_angry", false, wolfIndex, b -> b ? 1 : 0));
linkProperties("tamed", "sitting");
}
else {
register(new BitsetProperty("wolf_angry", tameableIndex, 0x02));
linkProperties("wolf_angry", "tamed", "sitting");
}
// Wither
int witherIndex;
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) witherIndex = 16; // using the first index, so we can add the other properties later if needed
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) witherIndex = 15;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) witherIndex = 14;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) witherIndex = 12;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) witherIndex = 11;
else witherIndex = 17;
witherIndex += 3; // skip the first 3 indexes, will be used for the other properties later
register(new IntegerProperty("invulnerable_time", witherIndex++, 0, false));
if (!ver.isNewerThanOrEquals(ServerVersion.V_1_9)) return;
// Shulker
int shulkerIndex;
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) shulkerIndex = 16;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) shulkerIndex = 15;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) shulkerIndex = 14;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) shulkerIndex = 12;
else shulkerIndex = 11;
register(new CustomTypeProperty<>("attach_direction", shulkerIndex++, AttachDirection.DOWN, EntityDataTypes.BLOCK_FACE, attachDir -> BlockFace.valueOf(attachDir.name())));
register(new EncodedByteProperty<>("shield_height", 0, shulkerIndex++, value -> (byte) Math.max(0, Math.min(100, value))));
// noinspection deprecation
register(new EncodedByteProperty<>("shulker_color", DyeColor.class, shulkerIndex, DyeColor::getWoolData));
// Snow Golem
int snowGolemIndex;
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) snowGolemIndex = 16;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) snowGolemIndex = 15;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) snowGolemIndex = 14;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) snowGolemIndex = 12;
else snowGolemIndex = 10;
register(new CustomTypeProperty<>("derpy_snowgolem", snowGolemIndex, false, EntityDataTypes.BYTE, b -> (byte) (b ? 0x00 : 0x10)));
if (!ver.isNewerThanOrEquals(ServerVersion.V_1_10)) return;
// Polar Bear
int polarBearIndex;
@ -398,9 +449,20 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
else pufferfishIndex = 13;
register(new EncodedIntegerProperty<>("puff_state", PuffState.DEFLATED, pufferfishIndex, Enum::ordinal));
// Tropical Fish
int tropicalFishIndex;
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) tropicalFishIndex = 17;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) tropicalFishIndex = 16;
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) tropicalFishIndex = 15;
else tropicalFishIndex = 13;
register(new TropicalFishVariantProperty<>("tropical_fish_pattern", TropicalFishVariant.TropicalFishPattern.KOB, tropicalFishIndex, TropicalFishVariant.Builder::pattern));
register(new TropicalFishVariantProperty<>("tropical_fish_body_color", DyeColor.WHITE, tropicalFishIndex, TropicalFishVariant.Builder::bodyColor));
register(new TropicalFishVariantProperty<>("tropical_fish_pattern_color", DyeColor.WHITE, tropicalFishIndex, TropicalFishVariant.Builder::patternColor));
linkProperties("tropical_fish_pattern", "tropical_fish_body_color", "tropical_fish_pattern_color");
if (!ver.isNewerThanOrEquals(ServerVersion.V_1_14)) return;
// Pose
register(new NpcPoseProperty());
register(new CustomTypeProperty<>("pose", 6, NpcPose.STANDING, EntityDataTypes.ENTITY_POSE, npcPose -> EntityPose.valueOf(npcPose.name())));
// Villager
final int villagerIndex;
@ -478,7 +540,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
// Hoglin and Piglin Zombification
final int zombificationIndex;
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) zombificationIndex = 17; // Change piglinIndex and pillagerIndex if you change this
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) zombificationIndex = 17; // Change piglinIndex, pillagerIndex, striderIndex and vindicatorIndex if you change this
else zombificationIndex = 16;
register(new BooleanProperty("hoglin_immune_to_zombification", zombificationIndex, false, legacyBooleans));
register(new BooleanProperty("piglin_immune_to_zombification", zombificationIndex-1, false, legacyBooleans));
@ -492,6 +554,11 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
// Pillager
register(new BooleanProperty("pillager_charging", zombificationIndex, false, legacyBooleans));
// Strider
int striderIndex = zombificationIndex + 1;
register(new BooleanProperty("strider_shaking", striderIndex++, false, legacyBooleans)); // TODO: Fix this, it needs to be set constantly i guess
register(new BooleanProperty("strider_saddled", striderIndex, false, legacyBooleans));
// Vindicator
int vindicatorIndex = zombificationIndex -1;
register(new BooleanProperty("celebrating", vindicatorIndex, false, legacyBooleans));
@ -514,6 +581,9 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
// Camel
register(new BooleanProperty("bashing", 18, false, legacyBooleans));
// Sniffer
register(new CustomTypeProperty<>("sniffer_state", 17, SnifferState.IDLING, EntityDataTypes.SNIFFER_STATE, state -> com.github.retrooper.packetevents.protocol.entity.sniffer.SnifferState.valueOf(state.name())));
}
private void registerSerializer(PropertySerializer<?> serializer) {
@ -569,6 +639,11 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
return (EntityPropertyImpl<T>) getByName(name);
}
@Override
public void registerDummy(String name, Class<?> type) {
register(new DummyProperty<>(name, type));
}
public EntityPropertyImpl<?> getByName(String name) {
return byName.get(name.toLowerCase());
}

@ -0,0 +1,32 @@
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 lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.entity.PacketEntity;
import org.bukkit.entity.Player;
import java.util.Map;
public class CustomTypeProperty<T, U> extends EntityPropertyImpl<T> {
private final int index;
private final EntityDataType<U> type;
private final TypeDecoder<T, U> decoder;
@SuppressWarnings("unchecked")
public CustomTypeProperty(String name, int index, T def, EntityDataType<U> type, TypeDecoder<T, U> decoder) {
super(name, def, (Class<T>) def.getClass());
this.index = index;
this.type = type;
this.decoder = decoder;
}
@Override
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
properties.put(index, newEntityData(index, type, decoder.decode(entity.getProperty(this))));
}
public interface TypeDecoder<T, U> {
U decode(T obj);
}
}

@ -1,23 +0,0 @@
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())));
}
}

@ -0,0 +1,47 @@
package lol.pyr.znpcsplus.entity.properties;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.util.RabbitType;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import java.util.Map;
import java.util.Optional;
public class RabbitTypeProperty extends EntityPropertyImpl<RabbitType> {
private final int index;
private final boolean legacyBooleans;
private final Object serialized;
private final EntityDataType<?> type;
public RabbitTypeProperty(int index, boolean legacyBooleans, boolean legacyNames, boolean optional) {
super("rabbit_type", RabbitType.BROWN, RabbitType.class);
this.index = index;
this.legacyBooleans = legacyBooleans;
Component name = Component.text("Toast");
String serialized = legacyNames ?
AdventureSerializer.getLegacyGsonSerializer().serialize(name) :
AdventureSerializer.getGsonSerializer().serialize(name);
this.serialized = optional ? Optional.of(serialized) : serialized;
this.type = optional ? EntityDataTypes.OPTIONAL_COMPONENT : EntityDataTypes.STRING;
}
@Override
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
RabbitType rabbitType = entity.getProperty(this);
if (rabbitType == null) return;
if (!rabbitType.equals(RabbitType.TOAST)) {
properties.put(index, legacyBooleans ?
newEntityData(index, EntityDataTypes.BYTE, (byte) rabbitType.getId()) :
newEntityData(index, EntityDataTypes.INT, rabbitType.getId()));
properties.put(2, new EntityData(2, type, null));
} else {
properties.put(2, new EntityData(2, type, serialized));
}
}
}

@ -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.EntityDataTypes;
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.util.TropicalFishVariant;
import org.bukkit.entity.Player;
import java.util.Map;
public class TropicalFishVariantProperty<T> extends EntityPropertyImpl<T> {
private final int index;
private final BuilderDecoder<T> decoder;
public TropicalFishVariantProperty(String name, T defaultValue, Class<T> type, int index, BuilderDecoder<T> decoder) {
super(name, defaultValue, type);
this.index = index;
this.decoder = decoder;
}
@SuppressWarnings("unchecked")
public TropicalFishVariantProperty(String name, T defaultValue, int index, BuilderDecoder<T> decoder) {
this(name, defaultValue, (Class<T>) defaultValue.getClass(), index, decoder);
}
@Override
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
T value = entity.getProperty(this);
if (value == null) {
return;
}
EntityData oldData = properties.get(index);
TropicalFishVariant.Builder builder;
if (oldData != null && oldData.getType() == EntityDataTypes.INT && oldData.getValue() != null) {
int oldVal = (int) oldData.getValue();
builder = TropicalFishVariant.Builder.fromInt(oldVal);
} else {
builder = new TropicalFishVariant.Builder();
}
builder = decoder.decode(builder, value);
int variant = builder.build().getVariant();
properties.put(index, newEntityData(index, EntityDataTypes.INT, variant));
}
public interface BuilderDecoder<T> {
TropicalFishVariant.Builder decode(TropicalFishVariant.Builder builder, T obj);
}
}

@ -20,6 +20,7 @@ import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.*;
import java.util.stream.Collectors;
public class NpcImpl extends Viewable implements Npc {
private final PacketFactory packetFactory;
@ -163,9 +164,13 @@ public class NpcImpl extends Viewable implements Npc {
setProperty((EntityPropertyImpl<T>) property, (T) value);
}
public Set<EntityProperty<?>> getAllProperties() {
return Collections.unmodifiableSet(propertyMap.keySet());
}
@Override
public Set<EntityProperty<?>> getAppliedProperties() {
return Collections.unmodifiableSet(propertyMap.keySet());
return Collections.unmodifiableSet(propertyMap.keySet()).stream().filter(type::isAllowedProperty).collect(Collectors.toSet());
}
public List<InteractionActionImpl> getActions() {

@ -50,6 +50,10 @@ public class NpcTypeImpl implements NpcType {
}
}
public boolean isAllowedProperty(EntityPropertyImpl<?> entityProperty) {
return !entityProperty.isPlayerModifiable() || allowedProperties.contains(entityProperty);
}
protected static final class Builder {
private final static Logger logger = Logger.getLogger("NpcTypeBuilder");
@ -154,6 +158,9 @@ public class NpcTypeImpl implements NpcType {
addProperties("panda_eating");
}
}
if (EntityTypes.isTypeInstanceOf(type, EntityTypes.ABSTRACT_TAMEABLE_ANIMAL)) {
addProperties("tamed", "sitting");
}
return new NpcTypeImpl(name, type, hologramOffset, new HashSet<>(allowedProperties), defaultProperties);
}
}

@ -115,10 +115,12 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
.addProperties("pig_saddled"));
register(builder(p, "rabbit", EntityTypes.RABBIT)
.setHologramOffset(-1.475));
.setHologramOffset(-1.475)
.addProperties("rabbit_type"));
register(builder(p, "sheep", EntityTypes.SHEEP)
.setHologramOffset(-0.675));
.setHologramOffset(-0.675)
.addProperties("sheep_color", "sheep_sheared"));
register(builder(p, "silverfish", EntityTypes.SILVERFISH)
.setHologramOffset(-1.675));
@ -133,7 +135,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
register(builder(p, "slime", EntityTypes.SLIME)); // TODO: Hologram offset scaling with size property
register(builder(p, "snow_golem", EntityTypes.SNOW_GOLEM)
.setHologramOffset(-0.075));
.setHologramOffset(-0.075)
.addProperties("derpy_snowgolem"));
register(builder(p, "spider", EntityTypes.SPIDER)
.setHologramOffset(-1.075));
@ -150,11 +153,12 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
.addProperties("hand"));
register(builder(p, "wither", EntityTypes.WITHER)
.setHologramOffset(1.525));
.setHologramOffset(1.525)
.addProperties("invulnerable_time"));
register(builder(p, "wolf", EntityTypes.WOLF)
.setHologramOffset(-1.125)
.addProperties("tamed"));
.addProperties("wolf_begging", "wolf_collar", "wolf_angry"));
register(builder(p, "zombie", EntityTypes.ZOMBIE)
.setHologramOffset(-0.025)
@ -170,7 +174,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
if (!version.isNewerThanOrEquals(ServerVersion.V_1_9)) return;
register(builder(p, "shulker", EntityTypes.SHULKER)
.setHologramOffset(-0.975));
.setHologramOffset(-0.975)
.addProperties("attach_direction", "shield_height", "shulker_color"));
if (!version.isNewerThanOrEquals(ServerVersion.V_1_10)) return;
@ -257,7 +262,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
.setHologramOffset(-1.575));
register(builder(p, "tropical_fish", EntityTypes.TROPICAL_FISH)
.setHologramOffset(-1.575));
.setHologramOffset(-1.575)
.addProperties("tropical_fish_pattern", "tropical_fish_body_color", "tropical_fish_pattern_color"));
register(builder(p, "turtle", EntityTypes.TURTLE)
.setHologramOffset(-1.575));
@ -266,7 +272,7 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
register(builder(p, "cat", EntityTypes.CAT)
.setHologramOffset(-1.275)
.addProperties("cat_variant", "cat_laying", "cat_relaxed", "cat_collar", "tamed"));
.addProperties("cat_variant", "cat_laying", "cat_relaxed", "cat_collar"));
register(builder(p, "fox", EntityTypes.FOX)
.setHologramOffset(-1.275)
@ -314,7 +320,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
.addEquipmentProperties());
register(builder(p, "strider", EntityTypes.STRIDER)
.setHologramOffset(-0.275));
.setHologramOffset(-0.275)
.addProperties("strider_shaking", "strider_saddled"));
register(builder(p, "zoglin", EntityTypes.ZOGLIN)
.setHologramOffset(-0.575));
@ -351,7 +358,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
if (!version.isNewerThanOrEquals(ServerVersion.V_1_20)) return;
register(builder(p, "sniffer", EntityTypes.SNIFFER)
.setHologramOffset(0.125));
.setHologramOffset(0.125)
.addProperties("sniffer_state"));
register(builder(p, "camel", EntityTypes.CAMEL)
.setHologramOffset(0.25)

@ -0,0 +1,19 @@
package lol.pyr.znpcsplus.parsers;
import lol.pyr.director.adventure.command.CommandContext;
import lol.pyr.director.adventure.parse.ParserType;
import lol.pyr.director.common.command.CommandExecutionException;
import lol.pyr.director.common.message.Message;
import java.util.Deque;
public class StringParser extends ParserType<String> {
public StringParser(Message<CommandContext> message) {
super(message);
}
@Override
public String parse(Deque<String> deque) throws CommandExecutionException {
return deque.pollFirst();
}
}

@ -111,7 +111,7 @@ public class YamlStorage implements NpcStorage {
config.set("location", serializeLocation(npc.getLocation()));
config.set("type", npc.getType().getName());
for (EntityProperty<?> property : npc.getAppliedProperties()) try {
for (EntityProperty<?> property : npc.getAllProperties()) try {
PropertySerializer<?> serializer = propertyRegistry.getSerializer(((EntityPropertyImpl<?>) property).getType());
if (serializer == null) {
Bukkit.getLogger().log(Level.WARNING, "Unknown serializer for property '" + property.getName() + "' for npc '" + entry.getId() + "'. skipping ...");

@ -21,6 +21,9 @@ softdepend:
- ViaRewind
- Geyser-Spigot
loadbefore:
- Quests
commands:
npc:
aliases: