skin layers & metadata

This commit is contained in:
Pyrbu 2023-04-24 22:31:48 +01:00
parent f7b69318b2
commit e7687959df
20 changed files with 249 additions and 101 deletions

@ -39,14 +39,14 @@ public class DefaultCommand extends Command {
private static final Joiner SPACE_JOINER = Joiner.on(" "); 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) { if (ex != null) {
Configuration.MESSAGES.sendMessage(sender, ConfigurationValue.CANT_GET_SKIN, skin); Configuration.MESSAGES.sendMessage(sender, ConfigurationValue.CANT_GET_SKIN, skin);
ZNPCsPlus.LOGGER.warning("Failed to fetch skin:"); ZNPCsPlus.LOGGER.warning("Failed to fetch skin:");
ex.printStackTrace(); ex.printStackTrace();
return; return;
} }
npc.changeSkin(NPCSkin.forValues(value, signature)); npc.changeSkin(npcSkin);
Configuration.MESSAGES.sendMessage(sender, ConfigurationValue.GET_SKIN); Configuration.MESSAGES.sendMessage(sender, ConfigurationValue.GET_SKIN);
}); });

@ -9,7 +9,7 @@ public class NPCSkin {
private final String texture; private final String texture;
private final String signature; private final String signature;
protected NPCSkin(String texture, String signature) { public NPCSkin(String texture, String signature) {
this.texture = texture; this.texture = texture;
this.signature = signature; this.signature = signature;
} }

@ -2,6 +2,7 @@ package io.github.znetworkw.znpcservers.skin;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import io.github.znetworkw.znpcservers.npc.NPCSkin;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@ -46,11 +47,11 @@ public class SkinFetcher {
}); });
completableFuture.whenComplete((response, throwable) -> { completableFuture.whenComplete((response, throwable) -> {
if (completableFuture.isCompletedExceptionally()) { if (completableFuture.isCompletedExceptionally()) {
skinFetcherResult.onDone(null, null, throwable); skinFetcherResult.onDone(null, throwable);
} else { } else {
JsonObject jsonObject = response.getAsJsonObject(this.builder.getAPIServer().getValueKey()); JsonObject jsonObject = response.getAsJsonObject(this.builder.getAPIServer().getValueKey());
JsonObject properties = jsonObject.getAsJsonObject(this.builder.getAPIServer().getSignatureKey()); 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; return completableFuture;

@ -1,5 +1,7 @@
package io.github.znetworkw.znpcservers.skin; package io.github.znetworkw.znpcservers.skin;
import io.github.znetworkw.znpcservers.npc.NPCSkin;
public interface SkinFetcherResult { public interface SkinFetcherResult {
void onDone(String value, String signature, Throwable paramThrowable); void onDone(NPCSkin npcSkin, Throwable paramThrowable);
} }

@ -2,6 +2,7 @@ package lol.pyr.znpcsplus;
import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketListenerPriority; 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.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder; 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.InventoryListener;
import io.github.znetworkw.znpcservers.listeners.PlayerListener; import io.github.znetworkw.znpcservers.listeners.PlayerListener;
import io.github.znetworkw.znpcservers.npc.NPCPath; 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.interaction.InteractionPacketListener;
import io.github.znetworkw.znpcservers.npc.task.NPCPositionTask; import io.github.znetworkw.znpcservers.npc.task.NPCPositionTask;
import io.github.znetworkw.znpcservers.npc.task.NPCSaveTask; 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 io.github.znetworkw.znpcservers.utility.location.ZLocation;
import lol.pyr.znpcsplus.entity.PacketLocation; import lol.pyr.znpcsplus.entity.PacketLocation;
import lol.pyr.znpcsplus.npc.NPC; import lol.pyr.znpcsplus.npc.NPC;
import lol.pyr.znpcsplus.npc.NPCProperty;
import lol.pyr.znpcsplus.npc.NPCRegistry; import lol.pyr.znpcsplus.npc.NPCRegistry;
import lol.pyr.znpcsplus.npc.NPCType; import lol.pyr.znpcsplus.npc.NPCType;
import lol.pyr.znpcsplus.tasks.NPCVisibilityTask; import lol.pyr.znpcsplus.tasks.NPCVisibilityTask;
@ -135,7 +138,9 @@ public class ZNPCsPlus extends JavaPlugin {
World world = Bukkit.getWorld("world"); World world = Bukkit.getWorld("world");
if (world == null) world = Bukkit.getWorlds().get(0); if (world == null) world = Bukkit.getWorlds().get(0);
for (NPCType type : NPCType.values()) { 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) { if (x++ > wrap) {
x = 0; x = 0;
z++; z++;

@ -4,6 +4,7 @@ import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import io.github.znetworkw.znpcservers.reflection.Reflections; import io.github.znetworkw.znpcservers.reflection.Reflections;
import io.github.znetworkw.znpcservers.utility.Utils; import io.github.znetworkw.znpcservers.utility.Utils;
import lol.pyr.znpcsplus.npc.NPC;
import lol.pyr.znpcsplus.packets.PacketFactory; import lol.pyr.znpcsplus.packets.PacketFactory;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -11,14 +12,15 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
public class PacketEntity { public class PacketEntity {
private final NPC owner;
private final int entityId; private final int entityId;
private final UUID uuid; private final UUID uuid;
private final EntityType type; private final EntityType type;
private PacketLocation location; private PacketLocation location;
public PacketEntity(EntityType type, PacketLocation location) { public PacketEntity(NPC owner, EntityType type, PacketLocation location) {
if (type == EntityTypes.PLAYER) throw new RuntimeException("Wrong class used for player"); this.owner = owner;
this.entityId = reserveEntityID(); this.entityId = reserveEntityID();
this.uuid = UUID.randomUUID(); this.uuid = UUID.randomUUID();
this.type = type; this.type = type;
@ -41,13 +43,18 @@ public class PacketEntity {
return type; return type;
} }
public NPC getOwner() {
return owner;
}
public void setLocation(PacketLocation location, Set<Player> viewers) { public void setLocation(PacketLocation location, Set<Player> viewers) {
this.location = location; this.location = location;
for (Player viewer : viewers) PacketFactory.get().teleportEntity(viewer, this); for (Player viewer : viewers) PacketFactory.get().teleportEntity(viewer, this);
} }
public void spawn(Player player) { 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) { public void despawn(Player player) {

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

@ -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<ServerVersion, LazyLoader<? extends MetadataFactory>> 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<ServerVersion, LazyLoader<? extends MetadataFactory>> buildFactoryMap() {
HashMap<ServerVersion, LazyLoader<? extends MetadataFactory>> 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;
}
}

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

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

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

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

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

@ -1,9 +1,7 @@
package lol.pyr.znpcsplus.npc; 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.PacketEntity;
import lol.pyr.znpcsplus.entity.PacketLocation; import lol.pyr.znpcsplus.entity.PacketLocation;
import lol.pyr.znpcsplus.entity.PacketPlayer;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -20,19 +18,19 @@ public class NPC {
private PacketLocation location; private PacketLocation location;
private NPCType type; private NPCType type;
private final Map<NPCPropertyKey<?>, Object> propertyMap = new HashMap<>(); private final Map<NPCProperty<?>, Object> propertyMap = new HashMap<>();
public NPC(World world, NPCType type, PacketLocation location) { public NPC(World world, NPCType type, PacketLocation location) {
this.worldName = world.getName(); this.worldName = world.getName();
this.type = type; this.type = type;
this.location = location; this.location = location;
entity = new PacketEntity(type.getType(), location); entity = new PacketEntity(this, type.getType(), location);
} }
public void setType(NPCType type) { public void setType(NPCType type) {
_hideAll(); _hideAll();
this.type = type; 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(); _showAll();
} }
@ -100,20 +98,20 @@ public class NPC {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T getProperty(NPCPropertyKey<T> key) { public <T> T getProperty(NPCProperty<T> key) {
return (T) propertyMap.get(key); return hasProperty(key) ? (T) propertyMap.get(key) : key.getDefaultValue();
} }
public boolean hasProperty(NPCPropertyKey<?> key) { public boolean hasProperty(NPCProperty<?> key) {
return propertyMap.containsKey(key); return propertyMap.containsKey(key);
} }
public <T> void setProperty(NPCPropertyKey<T> key, T value) { public <T> void setProperty(NPCProperty<T> key, T value) {
propertyMap.put(key, value); if (value.equals(key.getDefaultValue())) removeProperty(key);
key.update(this, value); else propertyMap.put(key, value);
} }
public void removeProperty(NPCPropertyKey<?> key) { public void removeProperty(NPCProperty<?> key) {
propertyMap.remove(key); propertyMap.remove(key);
} }
} }

@ -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<T> {
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<String, NPCProperty<?>> BY_NAME = new HashMap<>();
public static NPCProperty<?> getByName(String name) {
return BY_NAME.get(name.toUpperCase());
}
public static NPCProperty<Boolean> SKIN_LAYERS = new NPCProperty<>("skin_layers", true);
public static NPCProperty<NPCSkin> SKIN = new NPCProperty<>("skin");
}

@ -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<T> {
private final UpdateCallback<T> updateCallback;
public NPCPropertyKey() {
this(null);
}
public NPCPropertyKey(UpdateCallback<T> updateCallback) {
this.updateCallback = updateCallback;
}
public void update(NPC npc, T value) {
if (updateCallback != null) updateCallback.onUpdate(npc, value);
}
@FunctionalInterface
public interface UpdateCallback<T> {
void onUpdate(NPC npc, T value);
}
public static NPCPropertyKey<NPCSkin> 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();
});
}

@ -1,4 +1,43 @@
package lol.pyr.znpcsplus.npc; 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 { public class NPCType {
private final static ImmutableList<NPCType> npcTypes;
public static List<NPCType> values() {
return npcTypes;
}
private final EntityType type;
private final Set<NPCProperty<?>> allowedProperties;
public NPCType(EntityType type, NPCProperty<?>... allowedProperties) {
this.type = type;
this.allowedProperties = Set.of(allowedProperties);
}
public EntityType getType() {
return type;
}
public Set<NPCProperty<?>> getAllowedProperties() {
return allowedProperties;
}
static {
ImmutableList.Builder<NPCType> 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();
}
} }

@ -2,8 +2,8 @@ package lol.pyr.znpcsplus.packets;
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.data.EntityData;
import lol.pyr.znpcsplus.entity.PacketEntity; import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.entity.PacketPlayer;
import lol.pyr.znpcsplus.util.LazyLoader; import lol.pyr.znpcsplus.util.LazyLoader;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -11,14 +11,15 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public interface PacketFactory { public interface PacketFactory {
void spawnPlayer(Player player, PacketPlayer entity); void spawnPlayer(Player player, PacketEntity entity);
void spawnEntity(Player player, PacketEntity entity); void spawnEntity(Player player, PacketEntity entity);
void destroyEntity(Player player, PacketEntity entity); void destroyEntity(Player player, PacketEntity entity);
void teleportEntity(Player player, PacketEntity entity); void teleportEntity(Player player, PacketEntity entity);
void addTabPlayer(Player player, PacketPlayer entity); void addTabPlayer(Player player, PacketEntity entity);
void removeTabPlayer(Player player, PacketPlayer entity); void removeTabPlayer(Player player, PacketEntity entity);
void createTeam(Player player, PacketPlayer entity); void createTeam(Player player, PacketEntity entity);
void removeTeam(Player player, PacketPlayer entity); void removeTeam(Player player, PacketEntity entity);
void sendMetadata(Player player, PacketEntity entity, EntityData... data);
PacketFactory factory = get(); PacketFactory factory = get();

@ -2,9 +2,10 @@ package lol.pyr.znpcsplus.packets;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.player.GameMode; 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.WrapperPlayServerPlayerInfoRemove;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoUpdate; 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 net.kyori.adventure.text.Component;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -12,17 +13,17 @@ import java.util.EnumSet;
public class V1_19Factory extends V1_14Factory { public class V1_19Factory extends V1_14Factory {
@Override @Override
public void addTabPlayer(Player player, PacketPlayer entity) { public void addTabPlayer(Player player, PacketEntity entity) {
if (entity.getType() != EntityTypes.PLAYER) return; if (entity.getType() != EntityTypes.PLAYER) return;
WrapperPlayServerPlayerInfoUpdate.PlayerInfo info = new WrapperPlayServerPlayerInfoUpdate.PlayerInfo( WrapperPlayServerPlayerInfoUpdate.PlayerInfo info = new WrapperPlayServerPlayerInfoUpdate.PlayerInfo(
entity.getGameProfile(), false, 1, GameMode.CREATIVE, skinned(entity, new UserProfile(entity.getUuid(), Integer.toString(entity.getEntityId()))), false,
Component.empty(), null); 1, GameMode.CREATIVE, Component.empty(), null);
sendPacket(player, new WrapperPlayServerPlayerInfoUpdate(EnumSet.of(WrapperPlayServerPlayerInfoUpdate.Action.ADD_PLAYER, sendPacket(player, new WrapperPlayServerPlayerInfoUpdate(EnumSet.of(WrapperPlayServerPlayerInfoUpdate.Action.ADD_PLAYER,
WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_LISTED), info, info)); WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_LISTED), info, info));
} }
@Override @Override
public void removeTabPlayer(Player player, PacketPlayer entity) { public void removeTabPlayer(Player player, PacketEntity entity) {
if (entity.getType() != EntityTypes.PLAYER) return; if (entity.getType() != EntityTypes.PLAYER) return;
sendPacket(player, new WrapperPlayServerPlayerInfoRemove(entity.getUuid())); sendPacket(player, new WrapperPlayServerPlayerInfoRemove(entity.getUuid()));
} }

@ -1,17 +1,23 @@
package lol.pyr.znpcsplus.packets; package lol.pyr.znpcsplus.packets;
import com.github.retrooper.packetevents.PacketEvents; 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.EntityType;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion; import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode; 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.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.PacketWrapper; import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.*; import com.github.retrooper.packetevents.wrapper.play.server.*;
import io.github.znetworkw.znpcservers.npc.NPCSkin;
import lol.pyr.znpcsplus.ZNPCsPlus; import lol.pyr.znpcsplus.ZNPCsPlus;
import lol.pyr.znpcsplus.entity.PacketEntity; import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.entity.PacketLocation; 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.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -21,12 +27,14 @@ import java.util.Optional;
public class V1_8Factory implements PacketFactory { public class V1_8Factory implements PacketFactory {
@Override @Override
public void spawnPlayer(Player player, PacketPlayer entity) { public void spawnPlayer(Player player, PacketEntity entity) {
NPC owner = entity.getOwner();
addTabPlayer(player, entity); addTabPlayer(player, entity);
createTeam(player, entity); createTeam(player, entity);
PacketLocation location = entity.getLocation(); PacketLocation location = entity.getLocation();
sendPacket(player, new WrapperPlayServerSpawnPlayer(entity.getEntityId(), sendPacket(player, new WrapperPlayServerSpawnPlayer(entity.getEntityId(),
entity.getUuid(), location.toVector3d(), location.getYaw(), location.getPitch(), List.of())); 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); ZNPCsPlus.SCHEDULER.scheduleSyncDelayedTask(() -> removeTabPlayer(player, entity), 60);
} }
@ -45,7 +53,7 @@ public class V1_8Factory implements PacketFactory {
@Override @Override
public void destroyEntity(Player player, PacketEntity entity) { public void destroyEntity(Player player, PacketEntity entity) {
sendPacket(player, new WrapperPlayServerDestroyEntities(entity.getEntityId())); sendPacket(player, new WrapperPlayServerDestroyEntities(entity.getEntityId()));
if (entity.getType() == EntityTypes.PLAYER) removeTeam(player, (PacketPlayer) entity); if (entity.getType() == EntityTypes.PLAYER) removeTeam(player, entity);
} }
@Override @Override
@ -56,22 +64,23 @@ public class V1_8Factory implements PacketFactory {
} }
@Override @Override
public void addTabPlayer(Player player, PacketPlayer entity) { public void addTabPlayer(Player player, PacketEntity entity) {
if (entity.getType() != EntityTypes.PLAYER) return; if (entity.getType() != EntityTypes.PLAYER) return;
sendPacket(player, new WrapperPlayServerPlayerInfo( 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 @Override
public void removeTabPlayer(Player player, PacketPlayer entity) { public void removeTabPlayer(Player player, PacketEntity entity) {
if (entity.getType() != EntityTypes.PLAYER) return; if (entity.getType() != EntityTypes.PLAYER) return;
sendPacket(player, new WrapperPlayServerPlayerInfo( sendPacket(player, new WrapperPlayServerPlayerInfo(
WrapperPlayServerPlayerInfo.Action.REMOVE_PLAYER, new WrapperPlayServerPlayerInfo.PlayerData(null, WrapperPlayServerPlayerInfo.Action.REMOVE_PLAYER, new WrapperPlayServerPlayerInfo.PlayerData(null,
entity.getGameProfile(), null, -1))); new UserProfile(entity.getUuid(), null), null, -1)));
} }
@Override @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( sendPacket(player, new WrapperPlayServerTeams("npc_team_" + entity.getEntityId(), WrapperPlayServerTeams.TeamMode.CREATE, new WrapperPlayServerTeams.ScoreBoardTeamInfo(
Component.empty(), Component.empty(), Component.empty(), Component.empty(), Component.empty(), Component.empty(),
WrapperPlayServerTeams.NameTagVisibility.NEVER, WrapperPlayServerTeams.NameTagVisibility.NEVER,
@ -83,11 +92,24 @@ public class V1_8Factory implements PacketFactory {
} }
@Override @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)); 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) { protected void sendPacket(Player player, PacketWrapper<?> packet) {
PacketEvents.getAPI().getPlayerManager().sendPacket(player, 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;
}
} }