diff --git a/src/main/java/io/github/znetworkw/znpcservers/commands/list/DefaultCommand.java b/src/main/java/io/github/znetworkw/znpcservers/commands/list/DefaultCommand.java index 2c9d8e1..4dc7bfd 100644 --- a/src/main/java/io/github/znetworkw/znpcservers/commands/list/DefaultCommand.java +++ b/src/main/java/io/github/znetworkw/znpcservers/commands/list/DefaultCommand.java @@ -39,14 +39,14 @@ public class DefaultCommand extends Command { private static final Joiner SPACE_JOINER = Joiner.on(" "); - private static final SkinFunction DO_APPLY_SKIN = (sender, npc, skin) -> NPCSkin.forName(skin, (value, signature, ex) -> { + private static final SkinFunction DO_APPLY_SKIN = (sender, npc, skin) -> NPCSkin.forName(skin, (npcSkin, ex) -> { if (ex != null) { Configuration.MESSAGES.sendMessage(sender, ConfigurationValue.CANT_GET_SKIN, skin); ZNPCsPlus.LOGGER.warning("Failed to fetch skin:"); ex.printStackTrace(); return; } - npc.changeSkin(NPCSkin.forValues(value, signature)); + npc.changeSkin(npcSkin); Configuration.MESSAGES.sendMessage(sender, ConfigurationValue.GET_SKIN); }); diff --git a/src/main/java/io/github/znetworkw/znpcservers/npc/NPCSkin.java b/src/main/java/io/github/znetworkw/znpcservers/npc/NPCSkin.java index 94baaa9..9a51541 100644 --- a/src/main/java/io/github/znetworkw/znpcservers/npc/NPCSkin.java +++ b/src/main/java/io/github/znetworkw/znpcservers/npc/NPCSkin.java @@ -9,7 +9,7 @@ public class NPCSkin { private final String texture; private final String signature; - protected NPCSkin(String texture, String signature) { + public NPCSkin(String texture, String signature) { this.texture = texture; this.signature = signature; } diff --git a/src/main/java/io/github/znetworkw/znpcservers/skin/SkinFetcher.java b/src/main/java/io/github/znetworkw/znpcservers/skin/SkinFetcher.java index 0421af9..9984a0b 100644 --- a/src/main/java/io/github/znetworkw/znpcservers/skin/SkinFetcher.java +++ b/src/main/java/io/github/znetworkw/znpcservers/skin/SkinFetcher.java @@ -2,6 +2,7 @@ package io.github.znetworkw.znpcservers.skin; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import io.github.znetworkw.znpcservers.npc.NPCSkin; import java.io.DataOutputStream; import java.io.InputStreamReader; @@ -46,11 +47,11 @@ public class SkinFetcher { }); completableFuture.whenComplete((response, throwable) -> { if (completableFuture.isCompletedExceptionally()) { - skinFetcherResult.onDone(null, null, throwable); + skinFetcherResult.onDone(null, throwable); } else { JsonObject jsonObject = response.getAsJsonObject(this.builder.getAPIServer().getValueKey()); JsonObject properties = jsonObject.getAsJsonObject(this.builder.getAPIServer().getSignatureKey()); - skinFetcherResult.onDone(properties.get("value").getAsString(), properties.get("signature").getAsString(), null); + skinFetcherResult.onDone(new NPCSkin(properties.get("value").getAsString(), properties.get("signature").getAsString()), null); } }); return completableFuture; diff --git a/src/main/java/io/github/znetworkw/znpcservers/skin/SkinFetcherResult.java b/src/main/java/io/github/znetworkw/znpcservers/skin/SkinFetcherResult.java index ec55efa..f1c54d6 100644 --- a/src/main/java/io/github/znetworkw/znpcservers/skin/SkinFetcherResult.java +++ b/src/main/java/io/github/znetworkw/znpcservers/skin/SkinFetcherResult.java @@ -1,5 +1,7 @@ package io.github.znetworkw.znpcservers.skin; +import io.github.znetworkw.znpcservers.npc.NPCSkin; + public interface SkinFetcherResult { - void onDone(String value, String signature, Throwable paramThrowable); + void onDone(NPCSkin npcSkin, Throwable paramThrowable); } diff --git a/src/main/java/lol/pyr/znpcsplus/ZNPCsPlus.java b/src/main/java/lol/pyr/znpcsplus/ZNPCsPlus.java index 2c39893..43764f4 100644 --- a/src/main/java/lol/pyr/znpcsplus/ZNPCsPlus.java +++ b/src/main/java/lol/pyr/znpcsplus/ZNPCsPlus.java @@ -2,6 +2,7 @@ package lol.pyr.znpcsplus; import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.event.PacketListenerPriority; +import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder; @@ -11,6 +12,7 @@ import io.github.znetworkw.znpcservers.configuration.ConfigurationConstants; import io.github.znetworkw.znpcservers.listeners.InventoryListener; import io.github.znetworkw.znpcservers.listeners.PlayerListener; import io.github.znetworkw.znpcservers.npc.NPCPath; +import io.github.znetworkw.znpcservers.npc.NPCSkin; import io.github.znetworkw.znpcservers.npc.interaction.InteractionPacketListener; import io.github.znetworkw.znpcservers.npc.task.NPCPositionTask; import io.github.znetworkw.znpcservers.npc.task.NPCSaveTask; @@ -21,6 +23,7 @@ import io.github.znetworkw.znpcservers.utility.itemstack.ItemStackSerializer; import io.github.znetworkw.znpcservers.utility.location.ZLocation; import lol.pyr.znpcsplus.entity.PacketLocation; import lol.pyr.znpcsplus.npc.NPC; +import lol.pyr.znpcsplus.npc.NPCProperty; import lol.pyr.znpcsplus.npc.NPCRegistry; import lol.pyr.znpcsplus.npc.NPCType; import lol.pyr.znpcsplus.tasks.NPCVisibilityTask; @@ -135,7 +138,9 @@ public class ZNPCsPlus extends JavaPlugin { World world = Bukkit.getWorld("world"); if (world == null) world = Bukkit.getWorlds().get(0); for (NPCType type : NPCType.values()) { - NPCRegistry.register("debug_npc" + (z * wrap + x), new NPC(world, type, new PacketLocation(x * 3, 200, z * 3, 0, 0))); + NPC npc = new NPC(world, type, new PacketLocation(x * 3, 200, z * 3, 0, 0)); + if (type.getType() == EntityTypes.PLAYER) NPCSkin.forName("Pyrbu", (skin, ex) -> npc.setProperty(NPCProperty.SKIN, skin)); + NPCRegistry.register("debug_npc" + (z * wrap + x), npc); if (x++ > wrap) { x = 0; z++; diff --git a/src/main/java/lol/pyr/znpcsplus/entity/PacketEntity.java b/src/main/java/lol/pyr/znpcsplus/entity/PacketEntity.java index a77aab9..bfe8075 100644 --- a/src/main/java/lol/pyr/znpcsplus/entity/PacketEntity.java +++ b/src/main/java/lol/pyr/znpcsplus/entity/PacketEntity.java @@ -4,6 +4,7 @@ import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; import io.github.znetworkw.znpcservers.reflection.Reflections; import io.github.znetworkw.znpcservers.utility.Utils; +import lol.pyr.znpcsplus.npc.NPC; import lol.pyr.znpcsplus.packets.PacketFactory; import org.bukkit.entity.Player; @@ -11,14 +12,15 @@ import java.util.Set; import java.util.UUID; public class PacketEntity { + private final NPC owner; private final int entityId; private final UUID uuid; private final EntityType type; private PacketLocation location; - public PacketEntity(EntityType type, PacketLocation location) { - if (type == EntityTypes.PLAYER) throw new RuntimeException("Wrong class used for player"); + public PacketEntity(NPC owner, EntityType type, PacketLocation location) { + this.owner = owner; this.entityId = reserveEntityID(); this.uuid = UUID.randomUUID(); this.type = type; @@ -41,13 +43,18 @@ public class PacketEntity { return type; } + public NPC getOwner() { + return owner; + } + public void setLocation(PacketLocation location, Set viewers) { this.location = location; for (Player viewer : viewers) PacketFactory.get().teleportEntity(viewer, this); } public void spawn(Player player) { - PacketFactory.get().spawnEntity(player, this); + if (type == EntityTypes.PLAYER) PacketFactory.get().spawnPlayer(player, this); + else PacketFactory.get().spawnEntity(player, this); } public void despawn(Player player) { diff --git a/src/main/java/lol/pyr/znpcsplus/entity/PacketPlayer.java b/src/main/java/lol/pyr/znpcsplus/entity/PacketPlayer.java deleted file mode 100644 index 373944f..0000000 --- a/src/main/java/lol/pyr/znpcsplus/entity/PacketPlayer.java +++ /dev/null @@ -1,24 +0,0 @@ -package lol.pyr.znpcsplus.entity; - -import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; -import com.github.retrooper.packetevents.protocol.player.UserProfile; -import lol.pyr.znpcsplus.packets.PacketFactory; -import org.bukkit.entity.Player; - -public class PacketPlayer extends PacketEntity { - private final UserProfile gameProfile; - - public PacketPlayer(PacketLocation location) { - super(EntityTypes.PLAYER, location); - this.gameProfile = new UserProfile(getUuid(), Integer.toString(getEntityId())); - } - - @Override - public void spawn(Player player) { - PacketFactory.get().spawnPlayer(player, this); - } - - public UserProfile getGameProfile() { - return gameProfile; - } -} diff --git a/src/main/java/lol/pyr/znpcsplus/metadata/MetadataFactory.java b/src/main/java/lol/pyr/znpcsplus/metadata/MetadataFactory.java new file mode 100644 index 0000000..7800961 --- /dev/null +++ b/src/main/java/lol/pyr/znpcsplus/metadata/MetadataFactory.java @@ -0,0 +1,38 @@ +package lol.pyr.znpcsplus.metadata; + +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.manager.server.ServerVersion; +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import lol.pyr.znpcsplus.util.LazyLoader; + +import java.util.HashMap; +import java.util.Map; + +public interface MetadataFactory { + EntityData skinLayers(); + + MetadataFactory factory = get(); + + static MetadataFactory get() { + if (factory != null) return factory; + ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion(); + Map> factories = buildFactoryMap(); + if (factories.containsKey(version)) return factories.get(version).get(); + for (ServerVersion v : ServerVersion.reversedValues()) { + if (v.isNewerThan(version)) continue; + if (!factories.containsKey(v)) continue; + return factories.get(v).get(); + } + throw new RuntimeException("Unsupported version!"); + } + + private static Map> buildFactoryMap() { + HashMap> map = new HashMap<>(); + map.put(ServerVersion.V_1_8, LazyLoader.of(V1_8Factory::new)); + map.put(ServerVersion.V_1_9, LazyLoader.of(V1_9Factory::new)); + map.put(ServerVersion.V_1_14, LazyLoader.of(V1_14Factory::new)); + map.put(ServerVersion.V_1_16, LazyLoader.of(V1_16Factory::new)); + map.put(ServerVersion.V_1_17, LazyLoader.of(V1_17Factory::new)); + return map; + } +} diff --git a/src/main/java/lol/pyr/znpcsplus/metadata/V1_14Factory.java b/src/main/java/lol/pyr/znpcsplus/metadata/V1_14Factory.java new file mode 100644 index 0000000..af0efe8 --- /dev/null +++ b/src/main/java/lol/pyr/znpcsplus/metadata/V1_14Factory.java @@ -0,0 +1,10 @@ +package lol.pyr.znpcsplus.metadata; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; + +public class V1_14Factory extends V1_9Factory { + @Override + public EntityData skinLayers() { + return createSkinLayers(15); + } +} diff --git a/src/main/java/lol/pyr/znpcsplus/metadata/V1_16Factory.java b/src/main/java/lol/pyr/znpcsplus/metadata/V1_16Factory.java new file mode 100644 index 0000000..da7c8d7 --- /dev/null +++ b/src/main/java/lol/pyr/znpcsplus/metadata/V1_16Factory.java @@ -0,0 +1,10 @@ +package lol.pyr.znpcsplus.metadata; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; + +public class V1_16Factory extends V1_14Factory { + @Override + public EntityData skinLayers() { + return createSkinLayers(16); + } +} diff --git a/src/main/java/lol/pyr/znpcsplus/metadata/V1_17Factory.java b/src/main/java/lol/pyr/znpcsplus/metadata/V1_17Factory.java new file mode 100644 index 0000000..b83b796 --- /dev/null +++ b/src/main/java/lol/pyr/znpcsplus/metadata/V1_17Factory.java @@ -0,0 +1,10 @@ +package lol.pyr.znpcsplus.metadata; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; + +public class V1_17Factory extends V1_16Factory { + @Override + public EntityData skinLayers() { + return createSkinLayers(17); + } +} diff --git a/src/main/java/lol/pyr/znpcsplus/metadata/V1_8Factory.java b/src/main/java/lol/pyr/znpcsplus/metadata/V1_8Factory.java new file mode 100644 index 0000000..c368fc5 --- /dev/null +++ b/src/main/java/lol/pyr/znpcsplus/metadata/V1_8Factory.java @@ -0,0 +1,15 @@ +package lol.pyr.znpcsplus.metadata; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; + +public class V1_8Factory implements MetadataFactory { + @Override + public EntityData skinLayers() { + return createSkinLayers(12); + } + + protected EntityData createSkinLayers(int index) { + return new EntityData(index, EntityDataTypes.BYTE, Byte.MAX_VALUE); + } +} diff --git a/src/main/java/lol/pyr/znpcsplus/metadata/V1_9Factory.java b/src/main/java/lol/pyr/znpcsplus/metadata/V1_9Factory.java new file mode 100644 index 0000000..0d5bd78 --- /dev/null +++ b/src/main/java/lol/pyr/znpcsplus/metadata/V1_9Factory.java @@ -0,0 +1,10 @@ +package lol.pyr.znpcsplus.metadata; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; + +public class V1_9Factory extends V1_8Factory { + @Override + public EntityData skinLayers() { + return createSkinLayers(13); + } +} diff --git a/src/main/java/lol/pyr/znpcsplus/npc/NPC.java b/src/main/java/lol/pyr/znpcsplus/npc/NPC.java index 9dee875..0be9acc 100644 --- a/src/main/java/lol/pyr/znpcsplus/npc/NPC.java +++ b/src/main/java/lol/pyr/znpcsplus/npc/NPC.java @@ -1,9 +1,7 @@ package lol.pyr.znpcsplus.npc; -import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; import lol.pyr.znpcsplus.entity.PacketEntity; import lol.pyr.znpcsplus.entity.PacketLocation; -import lol.pyr.znpcsplus.entity.PacketPlayer; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Player; @@ -20,19 +18,19 @@ public class NPC { private PacketLocation location; private NPCType type; - private final Map, Object> propertyMap = new HashMap<>(); + private final Map, Object> propertyMap = new HashMap<>(); public NPC(World world, NPCType type, PacketLocation location) { this.worldName = world.getName(); this.type = type; this.location = location; - entity = new PacketEntity(type.getType(), location); + entity = new PacketEntity(this, type.getType(), location); } public void setType(NPCType type) { _hideAll(); this.type = type; - entity = type.getType() == EntityTypes.PLAYER ? new PacketPlayer(entity.getLocation()) : new PacketEntity(type.getType(), entity.getLocation()); + entity = new PacketEntity(this, type.getType(), entity.getLocation()); _showAll(); } @@ -100,20 +98,20 @@ public class NPC { } @SuppressWarnings("unchecked") - public T getProperty(NPCPropertyKey key) { - return (T) propertyMap.get(key); + public T getProperty(NPCProperty key) { + return hasProperty(key) ? (T) propertyMap.get(key) : key.getDefaultValue(); } - public boolean hasProperty(NPCPropertyKey key) { + public boolean hasProperty(NPCProperty key) { return propertyMap.containsKey(key); } - public void setProperty(NPCPropertyKey key, T value) { - propertyMap.put(key, value); - key.update(this, value); + public void setProperty(NPCProperty key, T value) { + if (value.equals(key.getDefaultValue())) removeProperty(key); + else propertyMap.put(key, value); } - public void removeProperty(NPCPropertyKey key) { + public void removeProperty(NPCProperty key) { propertyMap.remove(key); } } diff --git a/src/main/java/lol/pyr/znpcsplus/npc/NPCProperty.java b/src/main/java/lol/pyr/znpcsplus/npc/NPCProperty.java new file mode 100644 index 0000000..2752ed2 --- /dev/null +++ b/src/main/java/lol/pyr/znpcsplus/npc/NPCProperty.java @@ -0,0 +1,38 @@ +package lol.pyr.znpcsplus.npc; + +import io.github.znetworkw.znpcservers.npc.NPCSkin; + +import java.util.HashMap; +import java.util.Map; + +public class NPCProperty { + private final String name; + private final T defaultValue; + + public NPCProperty(String name) { + this(name, null); + } + + public NPCProperty(String name, T defaultValue) { + this.name = name.toUpperCase(); + this.defaultValue = defaultValue; + BY_NAME.put(this.name, this); + } + + public String getName() { + return name; + } + + protected T getDefaultValue() { + return defaultValue; + } + + private final static Map> BY_NAME = new HashMap<>(); + + public static NPCProperty getByName(String name) { + return BY_NAME.get(name.toUpperCase()); + } + + public static NPCProperty SKIN_LAYERS = new NPCProperty<>("skin_layers", true); + public static NPCProperty SKIN = new NPCProperty<>("skin"); +} \ No newline at end of file diff --git a/src/main/java/lol/pyr/znpcsplus/npc/NPCPropertyKey.java b/src/main/java/lol/pyr/znpcsplus/npc/NPCPropertyKey.java deleted file mode 100644 index 4cc09ca..0000000 --- a/src/main/java/lol/pyr/znpcsplus/npc/NPCPropertyKey.java +++ /dev/null @@ -1,35 +0,0 @@ -package lol.pyr.znpcsplus.npc; - -import com.github.retrooper.packetevents.protocol.player.TextureProperty; -import io.github.znetworkw.znpcservers.npc.NPCSkin; -import lol.pyr.znpcsplus.entity.PacketPlayer; - -import java.util.List; - -public class NPCPropertyKey { - private final UpdateCallback updateCallback; - - public NPCPropertyKey() { - this(null); - } - - public NPCPropertyKey(UpdateCallback updateCallback) { - this.updateCallback = updateCallback; - } - - public void update(NPC npc, T value) { - if (updateCallback != null) updateCallback.onUpdate(npc, value); - } - - @FunctionalInterface - public interface UpdateCallback { - void onUpdate(NPC npc, T value); - } - - public static NPCPropertyKey NPC_SKIN = new NPCPropertyKey<>((npc, skin) -> { - if (!(npc.getEntity() instanceof PacketPlayer entity)) - throw new RuntimeException("Tried to set a skin on an entity that isn't a player"); - entity.getGameProfile().setTextureProperties(List.of(new TextureProperty("textures", skin.getTexture(), skin.getSignature()))); - npc.respawn(); - }); -} diff --git a/src/main/java/lol/pyr/znpcsplus/npc/NPCType.java b/src/main/java/lol/pyr/znpcsplus/npc/NPCType.java index 4f90fe4..3d81460 100644 --- a/src/main/java/lol/pyr/znpcsplus/npc/NPCType.java +++ b/src/main/java/lol/pyr/znpcsplus/npc/NPCType.java @@ -1,4 +1,43 @@ package lol.pyr.znpcsplus.npc; +import com.github.retrooper.packetevents.protocol.entity.type.EntityType; +import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.Set; + public class NPCType { + private final static ImmutableList npcTypes; + + public static List values() { + return npcTypes; + } + + private final EntityType type; + private final Set> allowedProperties; + + public NPCType(EntityType type, NPCProperty... allowedProperties) { + this.type = type; + this.allowedProperties = Set.of(allowedProperties); + } + + public EntityType getType() { + return type; + } + + public Set> getAllowedProperties() { + return allowedProperties; + } + + static { + ImmutableList.Builder builder = new ImmutableList.Builder<>(); + + builder.add(new NPCType(EntityTypes.PLAYER, NPCProperty.SKIN)); + builder.add(new NPCType(EntityTypes.CREEPER)); + builder.add(new NPCType(EntityTypes.ZOMBIE)); + builder.add(new NPCType(EntityTypes.SKELETON)); + + npcTypes = builder.build(); + } } diff --git a/src/main/java/lol/pyr/znpcsplus/packets/PacketFactory.java b/src/main/java/lol/pyr/znpcsplus/packets/PacketFactory.java index e79702b..2005987 100644 --- a/src/main/java/lol/pyr/znpcsplus/packets/PacketFactory.java +++ b/src/main/java/lol/pyr/znpcsplus/packets/PacketFactory.java @@ -2,8 +2,8 @@ package lol.pyr.znpcsplus.packets; import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.manager.server.ServerVersion; +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; import lol.pyr.znpcsplus.entity.PacketEntity; -import lol.pyr.znpcsplus.entity.PacketPlayer; import lol.pyr.znpcsplus.util.LazyLoader; import org.bukkit.entity.Player; @@ -11,14 +11,15 @@ import java.util.HashMap; import java.util.Map; public interface PacketFactory { - void spawnPlayer(Player player, PacketPlayer entity); + void spawnPlayer(Player player, PacketEntity entity); void spawnEntity(Player player, PacketEntity entity); void destroyEntity(Player player, PacketEntity entity); void teleportEntity(Player player, PacketEntity entity); - void addTabPlayer(Player player, PacketPlayer entity); - void removeTabPlayer(Player player, PacketPlayer entity); - void createTeam(Player player, PacketPlayer entity); - void removeTeam(Player player, PacketPlayer entity); + void addTabPlayer(Player player, PacketEntity entity); + void removeTabPlayer(Player player, PacketEntity entity); + void createTeam(Player player, PacketEntity entity); + void removeTeam(Player player, PacketEntity entity); + void sendMetadata(Player player, PacketEntity entity, EntityData... data); PacketFactory factory = get(); diff --git a/src/main/java/lol/pyr/znpcsplus/packets/V1_19Factory.java b/src/main/java/lol/pyr/znpcsplus/packets/V1_19Factory.java index 230b3bc..3cd2a13 100644 --- a/src/main/java/lol/pyr/znpcsplus/packets/V1_19Factory.java +++ b/src/main/java/lol/pyr/znpcsplus/packets/V1_19Factory.java @@ -2,9 +2,10 @@ package lol.pyr.znpcsplus.packets; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; import com.github.retrooper.packetevents.protocol.player.GameMode; +import com.github.retrooper.packetevents.protocol.player.UserProfile; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoRemove; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoUpdate; -import lol.pyr.znpcsplus.entity.PacketPlayer; +import lol.pyr.znpcsplus.entity.PacketEntity; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -12,17 +13,17 @@ import java.util.EnumSet; public class V1_19Factory extends V1_14Factory { @Override - public void addTabPlayer(Player player, PacketPlayer entity) { + public void addTabPlayer(Player player, PacketEntity entity) { if (entity.getType() != EntityTypes.PLAYER) return; WrapperPlayServerPlayerInfoUpdate.PlayerInfo info = new WrapperPlayServerPlayerInfoUpdate.PlayerInfo( - entity.getGameProfile(), false, 1, GameMode.CREATIVE, - Component.empty(), null); + skinned(entity, new UserProfile(entity.getUuid(), Integer.toString(entity.getEntityId()))), false, + 1, GameMode.CREATIVE, Component.empty(), null); sendPacket(player, new WrapperPlayServerPlayerInfoUpdate(EnumSet.of(WrapperPlayServerPlayerInfoUpdate.Action.ADD_PLAYER, WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_LISTED), info, info)); } @Override - public void removeTabPlayer(Player player, PacketPlayer entity) { + public void removeTabPlayer(Player player, PacketEntity entity) { if (entity.getType() != EntityTypes.PLAYER) return; sendPacket(player, new WrapperPlayServerPlayerInfoRemove(entity.getUuid())); } diff --git a/src/main/java/lol/pyr/znpcsplus/packets/V1_8Factory.java b/src/main/java/lol/pyr/znpcsplus/packets/V1_8Factory.java index 2951d1d..2a55199 100644 --- a/src/main/java/lol/pyr/znpcsplus/packets/V1_8Factory.java +++ b/src/main/java/lol/pyr/znpcsplus/packets/V1_8Factory.java @@ -1,17 +1,23 @@ package lol.pyr.znpcsplus.packets; import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; import com.github.retrooper.packetevents.protocol.player.ClientVersion; import com.github.retrooper.packetevents.protocol.player.GameMode; +import com.github.retrooper.packetevents.protocol.player.TextureProperty; +import com.github.retrooper.packetevents.protocol.player.UserProfile; import com.github.retrooper.packetevents.util.Vector3d; import com.github.retrooper.packetevents.wrapper.PacketWrapper; import com.github.retrooper.packetevents.wrapper.play.server.*; +import io.github.znetworkw.znpcservers.npc.NPCSkin; import lol.pyr.znpcsplus.ZNPCsPlus; import lol.pyr.znpcsplus.entity.PacketEntity; import lol.pyr.znpcsplus.entity.PacketLocation; -import lol.pyr.znpcsplus.entity.PacketPlayer; +import lol.pyr.znpcsplus.metadata.MetadataFactory; +import lol.pyr.znpcsplus.npc.NPC; +import lol.pyr.znpcsplus.npc.NPCProperty; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; @@ -21,12 +27,14 @@ import java.util.Optional; public class V1_8Factory implements PacketFactory { @Override - public void spawnPlayer(Player player, PacketPlayer entity) { + public void spawnPlayer(Player player, PacketEntity entity) { + NPC owner = entity.getOwner(); addTabPlayer(player, entity); createTeam(player, entity); PacketLocation location = entity.getLocation(); sendPacket(player, new WrapperPlayServerSpawnPlayer(entity.getEntityId(), entity.getUuid(), location.toVector3d(), location.getYaw(), location.getPitch(), List.of())); + if (owner.getProperty(NPCProperty.SKIN_LAYERS)) sendMetadata(player, entity, MetadataFactory.get().skinLayers()); ZNPCsPlus.SCHEDULER.scheduleSyncDelayedTask(() -> removeTabPlayer(player, entity), 60); } @@ -45,7 +53,7 @@ public class V1_8Factory implements PacketFactory { @Override public void destroyEntity(Player player, PacketEntity entity) { sendPacket(player, new WrapperPlayServerDestroyEntities(entity.getEntityId())); - if (entity.getType() == EntityTypes.PLAYER) removeTeam(player, (PacketPlayer) entity); + if (entity.getType() == EntityTypes.PLAYER) removeTeam(player, entity); } @Override @@ -56,22 +64,23 @@ public class V1_8Factory implements PacketFactory { } @Override - public void addTabPlayer(Player player, PacketPlayer entity) { + public void addTabPlayer(Player player, PacketEntity entity) { if (entity.getType() != EntityTypes.PLAYER) return; sendPacket(player, new WrapperPlayServerPlayerInfo( - WrapperPlayServerPlayerInfo.Action.ADD_PLAYER, new WrapperPlayServerPlayerInfo.PlayerData(Component.text(""), entity.getGameProfile(), GameMode.CREATIVE, 1))); + WrapperPlayServerPlayerInfo.Action.ADD_PLAYER, new WrapperPlayServerPlayerInfo.PlayerData(Component.text(""), + skinned(entity, new UserProfile(entity.getUuid(), Integer.toString(entity.getEntityId()))), GameMode.CREATIVE, 1))); } @Override - public void removeTabPlayer(Player player, PacketPlayer entity) { + public void removeTabPlayer(Player player, PacketEntity entity) { if (entity.getType() != EntityTypes.PLAYER) return; sendPacket(player, new WrapperPlayServerPlayerInfo( WrapperPlayServerPlayerInfo.Action.REMOVE_PLAYER, new WrapperPlayServerPlayerInfo.PlayerData(null, - entity.getGameProfile(), null, -1))); + new UserProfile(entity.getUuid(), null), null, -1))); } @Override - public void createTeam(Player player, PacketPlayer entity) { + public void createTeam(Player player, PacketEntity entity) { sendPacket(player, new WrapperPlayServerTeams("npc_team_" + entity.getEntityId(), WrapperPlayServerTeams.TeamMode.CREATE, new WrapperPlayServerTeams.ScoreBoardTeamInfo( Component.empty(), Component.empty(), Component.empty(), WrapperPlayServerTeams.NameTagVisibility.NEVER, @@ -83,11 +92,24 @@ public class V1_8Factory implements PacketFactory { } @Override - public void removeTeam(Player player, PacketPlayer entity) { + public void removeTeam(Player player, PacketEntity entity) { sendPacket(player, new WrapperPlayServerTeams("npc_team_" + entity.getEntityId(), WrapperPlayServerTeams.TeamMode.REMOVE, (WrapperPlayServerTeams.ScoreBoardTeamInfo) null)); } + @Override + public void sendMetadata(Player player, PacketEntity entity, EntityData... data) { + PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityMetadata(entity.getEntityId(), List.of(data))); + } + protected void sendPacket(Player player, PacketWrapper packet) { PacketEvents.getAPI().getPlayerManager().sendPacket(player, packet); } + + protected UserProfile skinned(PacketEntity entity, UserProfile profile) { + NPC owner = entity.getOwner(); + if (!owner.hasProperty(NPCProperty.SKIN)) return profile; + NPCSkin skin = owner.getProperty(NPCProperty.SKIN); + profile.setTextureProperties(List.of(new TextureProperty("textures", skin.getTexture(), skin.getSignature()))); + return profile; + } }