This commit is contained in:
Pyrbu 2023-04-24 19:10:55 +01:00
parent a98e75df2f
commit 8cf4f25c5a
13 changed files with 156 additions and 27 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, (values, ex) -> { private static final SkinFunction DO_APPLY_SKIN = (sender, npc, skin) -> NPCSkin.forName(skin, (value, signature, 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(values)); npc.changeSkin(NPCSkin.forValues(value, signature));
Configuration.MESSAGES.sendMessage(sender, ConfigurationValue.GET_SKIN); Configuration.MESSAGES.sendMessage(sender, ConfigurationValue.GET_SKIN);
}); });

@ -9,14 +9,13 @@ public class NPCSkin {
private final String texture; private final String texture;
private final String signature; private final String signature;
protected NPCSkin(String... values) { protected NPCSkin(String texture, String signature) {
if (values.length < 1) throw new IllegalArgumentException("Invalid arguments for NPC skin constructor"); this.texture = texture;
this.texture = values[0]; this.signature = signature;
this.signature = values[1];
} }
public static NPCSkin forValues(String... values) { public static NPCSkin forValues(String... values) {
return new NPCSkin((values.length > 0) ? values : new String[0]); return new NPCSkin(values[0], (values.length > 1) ? values[1] : null);
} }
public static void forName(String skin, SkinFetcherResult skinFetcherResult) { public static void forName(String skin, SkinFetcherResult skinFetcherResult) {

@ -667,5 +667,8 @@ public final class Reflections {
public static final ReflectionLazyLoader<AtomicInteger> ATOMIC_ENTITY_ID_FIELD = new FieldReflection(new ReflectionBuilder(ReflectionPackage.ENTITY) public static final ReflectionLazyLoader<AtomicInteger> ATOMIC_ENTITY_ID_FIELD = new FieldReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withClassName(ENTITY_CLASS) .withClassName(ENTITY_CLASS)
.withFieldName("entityCount") .withFieldName("entityCount")
.withFieldName("d")
.withFieldName("c")
.withExpectResult(AtomicInteger.class)
.setStrict(Utils.versionNewer(14))).staticValueLoader(AtomicInteger.class); .setStrict(Utils.versionNewer(14))).staticValueLoader(AtomicInteger.class);
} }

@ -18,26 +18,35 @@ public class FieldReflection extends ReflectionLazyLoader<Field> {
} }
protected Field load() throws NoSuchFieldException { protected Field load() throws NoSuchFieldException {
for (Class<?> clazz : this.reflectionClasses) { if (fieldName != null && fieldName.length() > 0) for (Class<?> clazz : this.reflectionClasses) {
Field field = load(clazz); Field field = loadByName(clazz);
if (field != null) return field;
}
if (expectType != null) for (Class<?> clazz : this.reflectionClasses) {
Field field = loadByType(clazz);
if (field != null) return field; if (field != null) return field;
} }
return null; return null;
} }
private Field load(Class<?> clazz) { private Field loadByName(Class<?> clazz) {
if (expectType != null) for (Field field : clazz.getDeclaredFields()) if (field.getType() == expectType) {
field.setAccessible(true);
return field;
}
try { try {
Field field = clazz.getDeclaredField(fieldName); Field field = clazz.getDeclaredField(fieldName);
if (expectType != null && !field.getType().equals(expectType)) return null;
field.setAccessible(true); field.setAccessible(true);
return field; return field;
} catch (NoSuchFieldException ignored) {} } catch (NoSuchFieldException ignored) {}
return null; return null;
} }
private Field loadByType(Class<?> clazz) {
for (Field field : clazz.getDeclaredFields()) if (field.getType() == expectType) {
field.setAccessible(true);
return field;
}
return null;
}
@Override @Override
protected void printDebugInfo(Consumer<String> logger) { protected void printDebugInfo(Consumer<String> logger) {
logger.accept("Field Name: " + fieldName); logger.accept("Field Name: " + fieldName);

@ -46,11 +46,11 @@ public class SkinFetcher {
}); });
completableFuture.whenComplete((response, throwable) -> { completableFuture.whenComplete((response, throwable) -> {
if (completableFuture.isCompletedExceptionally()) { if (completableFuture.isCompletedExceptionally()) {
skinFetcherResult.onDone(null, throwable); skinFetcherResult.onDone(null, 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(new String[]{properties.get("value").getAsString(), properties.get("signature").getAsString()}, null); skinFetcherResult.onDone(properties.get("value").getAsString(), properties.get("signature").getAsString(), null);
} }
}); });
return completableFuture; return completableFuture;

@ -1,5 +1,5 @@
package io.github.znetworkw.znpcservers.skin; package io.github.znetworkw.znpcservers.skin;
public interface SkinFetcherResult { public interface SkinFetcherResult {
void onDone(String[] paramArrayOfString, Throwable paramThrowable); void onDone(String value, String signature, Throwable paramThrowable);
} }

@ -6,14 +6,18 @@ import lol.pyr.znpcsplus.packets.PacketFactory;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.Set; import java.util.Set;
import java.util.UUID;
public class PacketEntity { public class PacketEntity {
private final int entityId; private final int entityId;
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(EntityType type, PacketLocation location) {
this.entityId = EntityIDProvider.reserve(); this.entityId = EntityIDProvider.reserve();
this.uuid = UUID.randomUUID();
this.type = type; this.type = type;
this.location = location; this.location = location;
} }
@ -26,6 +30,10 @@ public class PacketEntity {
return location; return location;
} }
public UUID getUuid() {
return uuid;
}
public EntityType getType() { public EntityType getType() {
return type; return type;
} }

@ -2,11 +2,15 @@ package lol.pyr.znpcsplus.npc;
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.properties.NPCProperty;
import lol.pyr.znpcsplus.properties.NPCPropertyKey;
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;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
public class NPC { public class NPC {
@ -16,6 +20,8 @@ public class NPC {
private PacketLocation location; private PacketLocation location;
private NPCType type; private NPCType type;
private final Map<NPCPropertyKey, NPCProperty> 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;
@ -83,4 +89,12 @@ public class NPC {
public boolean isShown(Player player) { public boolean isShown(Player player) {
return viewers.contains(player); return viewers.contains(player);
} }
public NPCProperty getProperty(NPCPropertyKey key) {
return propertyMap.get(key);
}
public boolean hasProperty(NPCPropertyKey key) {
return propertyMap.containsKey(key);
}
} }

@ -16,6 +16,8 @@ public interface PacketFactory {
void teleportEntity(Player player, PacketEntity entity); void teleportEntity(Player player, PacketEntity entity);
void addTabPlayer(Player player, PacketEntity entity); void addTabPlayer(Player player, PacketEntity entity);
void removeTabPlayer(Player player, PacketEntity entity); void removeTabPlayer(Player player, PacketEntity entity);
void createTeam(Player player, PacketEntity entity);
void removeTeam(Player player, PacketEntity entity);
PacketFactory factory = get(); PacketFactory factory = get();
@ -35,6 +37,8 @@ public interface PacketFactory {
private static Map<ServerVersion, LazyLoader<? extends PacketFactory>> buildFactoryMap() { private static Map<ServerVersion, LazyLoader<? extends PacketFactory>> buildFactoryMap() {
HashMap<ServerVersion, LazyLoader<? extends PacketFactory>> map = new HashMap<>(); HashMap<ServerVersion, LazyLoader<? extends PacketFactory>> map = new HashMap<>();
map.put(ServerVersion.V_1_8, LazyLoader.of(V1_8Factory::new)); map.put(ServerVersion.V_1_8, LazyLoader.of(V1_8Factory::new));
map.put(ServerVersion.V_1_14, LazyLoader.of(V1_14Factory::new));
map.put(ServerVersion.V_1_19, LazyLoader.of(V1_19Factory::new));
return map; return map;
} }
} }

@ -0,0 +1,17 @@
package lol.pyr.znpcsplus.packets;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.entity.PacketLocation;
import org.bukkit.entity.Player;
import java.util.Optional;
public class V1_14Factory extends V1_8Factory {
@Override
public void spawnEntity(Player player, PacketEntity entity) {
PacketLocation location = entity.getLocation();
sendPacket(player, new WrapperPlayServerSpawnEntity(entity.getEntityId(), Optional.of(entity.getUuid()), entity.getType(),
location.toVector3d(), location.getPitch(), location.getYaw(), location.getYaw(), 0, Optional.empty()));
}
}

@ -0,0 +1,30 @@
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.PacketEntity;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import java.util.EnumSet;
public class V1_19Factory extends V1_14Factory {
@Override
public void addTabPlayer(Player player, PacketEntity entity) {
if (entity.getType() != EntityTypes.PLAYER) return;
WrapperPlayServerPlayerInfoUpdate.PlayerInfo info = new WrapperPlayServerPlayerInfoUpdate.PlayerInfo(
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, PacketEntity entity) {
if (entity.getType() != EntityTypes.PLAYER) return;
sendPacket(player, new WrapperPlayServerPlayerInfoRemove(entity.getUuid()));
}
}

@ -2,24 +2,32 @@ package lol.pyr.znpcsplus.packets;
import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.PacketEvents;
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.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.UserProfile; 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.play.server.*; import com.github.retrooper.packetevents.wrapper.play.server.*;
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 net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
public class V1_8Factory implements PacketFactory { public class V1_8Factory implements PacketFactory {
@Override @Override
public void spawnPlayer(Player player, PacketEntity entity) { public void spawnPlayer(Player player, PacketEntity entity) {
addTabPlayer(player, entity); addTabPlayer(player, entity);
PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerSpawnPlayer()); createTeam(player, entity);
// TODO PacketLocation location = entity.getLocation();
sendPacket(player, new WrapperPlayServerSpawnPlayer(entity.getEntityId(),
entity.getUuid(), location.toVector3d(), location.getYaw(), location.getPitch(), List.of()));
ZNPCsPlus.SCHEDULER.scheduleSyncDelayedTask(() -> removeTabPlayer(player, entity), 60);
} }
@Override @Override
@ -27,32 +35,62 @@ public class V1_8Factory implements PacketFactory {
PacketLocation location = entity.getLocation(); PacketLocation location = entity.getLocation();
EntityType type = entity.getType(); EntityType type = entity.getType();
ClientVersion clientVersion = PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(); ClientVersion clientVersion = PacketEvents.getAPI().getServerManager().getVersion().toClientVersion();
PacketEvents.getAPI().getPlayerManager().sendPacket(player, type.getLegacyId(clientVersion) == -1 ? sendPacket(player, type.getLegacyId(clientVersion) == -1 ?
new WrapperPlayServerSpawnLivingEntity(entity.getEntityId(), new UUID(0, 0), type, location.toVector3d(), new WrapperPlayServerSpawnLivingEntity(entity.getEntityId(), entity.getUuid(), type, location.toVector3d(),
location.getYaw(), location.getPitch(), location.getPitch(), new Vector3d(), List.of()) : location.getYaw(), location.getPitch(), location.getPitch(), new Vector3d(), List.of()) :
new WrapperPlayServerSpawnEntity(entity.getEntityId(), Optional.empty(), entity.getType(), location.toVector3d(), new WrapperPlayServerSpawnEntity(entity.getEntityId(), Optional.of(entity.getUuid()), entity.getType(), location.toVector3d(),
location.getPitch(), location.getYaw(), location.getYaw(), 0, Optional.empty())); location.getPitch(), location.getYaw(), location.getYaw(), 0, Optional.empty()));
} }
@Override @Override
public void destroyEntity(Player player, PacketEntity entity) { public void destroyEntity(Player player, PacketEntity entity) {
PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerDestroyEntities(entity.getEntityId())); sendPacket(player, new WrapperPlayServerDestroyEntities(entity.getEntityId()));
if (entity.getType() == EntityTypes.PLAYER) removeTeam(player, entity);
} }
@Override @Override
public void teleportEntity(Player player, PacketEntity entity) { public void teleportEntity(Player player, PacketEntity entity) {
PacketLocation location = entity.getLocation(); PacketLocation location = entity.getLocation();
PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityTeleport(entity.getEntityId(), sendPacket(player, new WrapperPlayServerEntityTeleport(entity.getEntityId(),
location.toVector3d(), location.getYaw(), location.getPitch(), true)); location.toVector3d(), location.getYaw(), location.getPitch(), true));
} }
@Override @Override
public void addTabPlayer(Player player, PacketEntity 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(""),
new UserProfile(entity.getUuid(), Integer.toString(entity.getEntityId())), GameMode.CREATIVE, 1)));
} }
@Override @Override
public void removeTabPlayer(Player player, PacketEntity entity) { public void removeTabPlayer(Player player, PacketEntity entity) {
new WrapperPlayServerPlayerInfo(WrapperPlayServerPlayerInfo.Action.REMOVE_PLAYER, new WrapperPlayServerPlayerInfo.PlayerData(null, new UserProfile(gameProfile.getId(), gameProfile.getName()), null, 1)) if (entity.getType() != EntityTypes.PLAYER) return;
sendPacket(player, new WrapperPlayServerPlayerInfo(
WrapperPlayServerPlayerInfo.Action.REMOVE_PLAYER, new WrapperPlayServerPlayerInfo.PlayerData(null,
new UserProfile(entity.getUuid(), null), null, -1)));
}
@Override
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,
WrapperPlayServerTeams.CollisionRule.NEVER,
NamedTextColor.WHITE,
WrapperPlayServerTeams.OptionData.NONE
)));
sendPacket(player, new WrapperPlayServerTeams("npc_team_" + entity.getEntityId(), WrapperPlayServerTeams.TeamMode.ADD_ENTITIES, (WrapperPlayServerTeams.ScoreBoardTeamInfo) null, Integer.toString(entity.getEntityId())));
}
@Override
public void removeTeam(Player player, PacketEntity entity) {
sendPacket(player, new WrapperPlayServerTeams("npc_team_" + entity.getEntityId(), WrapperPlayServerTeams.TeamMode.REMOVE, (WrapperPlayServerTeams.ScoreBoardTeamInfo) null));
}
protected void sendPacket(Player player, PacketWrapper<?> packet) {
PacketEvents.getAPI().getPlayerManager().sendPacket(player, packet);
} }
} }

@ -0,0 +1,7 @@
package lol.pyr.znpcsplus.properties;
public class NPCPropertyKey<T> {
public NPCPropertyKey() {}
public static NPCPropertyKey<>
}