Skip to content

Instantly share code, notes, and snippets.

@DanielTheDev
Last active February 21, 2024 21:53
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save DanielTheDev/96862d0f79d24d8df029648ddc45c2c0 to your computer and use it in GitHub Desktop.
Save DanielTheDev/96862d0f79d24d8df029648ddc45c2c0 to your computer and use it in GitHub Desktop.
Advanced NPC Util [1.19] (Packets)
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import com.mojang.datafixers.util.Pair;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import net.minecraft.EnumChatFormat;
import net.minecraft.core.BlockPosition;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketDataSerializer;
import net.minecraft.network.chat.IChatBaseComponent;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.*;
import net.minecraft.network.syncher.DataWatcher;
import net.minecraft.network.syncher.DataWatcherObject;
import net.minecraft.network.syncher.DataWatcherRegistry;
import net.minecraft.network.syncher.DataWatcherSerializer;
import net.minecraft.world.EnumHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityPose;
import net.minecraft.world.entity.EntityTypes;
import net.minecraft.world.entity.EnumItemSlot;
import net.minecraft.world.entity.animal.EntityParrot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.EnumGamemode;
import net.minecraft.world.scores.Scoreboard;
import net.minecraft.world.scores.ScoreboardTeam;
import net.minecraft.world.scores.ScoreboardTeamBase;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R1.CraftServer;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftParrot;
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_19_R1.util.CraftChatMessage;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.Plugin;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
public class NPC {
private static AtomicInteger atomicInteger;
private final int entityID;
private final Location location;
private GameProfile profile;
private MetaData metadata = new MetaData();
static {
try {
Field field = Entity.class.getDeclaredField("c");
field.setAccessible(true);
atomicInteger = (AtomicInteger) field.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
public NPC(UUID uuid, Location location, String displayName) {
this.entityID = atomicInteger.incrementAndGet();
this.profile = new GameProfile(uuid, displayName);
this.location = location;
}
public NPC(Location location, String displayName) {
this(UUID.randomUUID(), location, displayName);
}
public void spawnNPC(Collection<? extends Player> receivers) {
receivers.forEach(this::spawnNPC);
}
public void spawnNPC(Player receiver) {
this.addToTabList(receiver);
this.sendPacket(receiver, this.getEntitySpawnPacket());
this.updateMetadata(receiver);
}
public void destroyNPC(Collection<? extends Player> receivers) {
receivers.forEach(this::destroyNPC);
}
public void destroyNPC(Player receiver) {
this.sendPacket(receiver, this.getPlayerInfoPacket(PlayerInfo.REMOVE_PLAYER));
this.sendPacket(receiver, this.getEntityDestroyPacket());
}
public void reloadNPC(Collection<? extends Player> receivers) {
receivers.forEach(this::reloadNPC);
}
public void reloadNPC(Player receiver) {
this.destroyNPC(receiver);
this.spawnNPC(receiver);
}
public void teleportNPC(Collection<? extends Player> receivers, Location location, boolean onGround) {
receivers.forEach(receiver -> this.teleportNPC(receiver, location, onGround));
}
public void teleportNPC(Player receiver, Location location, boolean onGround) {
this.location.setX(location.getX());
this.location.setY(location.getY());
this.location.setZ(location.getZ());
this.location.setPitch(location.getPitch());
this.location.setYaw(location.getYaw());
this.rotateHead(receiver, location.getPitch(), location.getYaw(), true);
this.sendPacket(receiver, this.getEntityTeleportPacket(onGround));
}
public void updateMetadata(Collection<? extends Player> receivers) {
receivers.forEach(this::updateMetadata);
}
public void updateMetadata(Player receiver) {
this.sendPacket(receiver, this.getEntityMetadataPacket());
}
public void updateGameMode(Collection<? extends Player> receivers) {
receivers.forEach(this::updateGameMode);
}
public void updateGameMode(Player receiver) {
this.sendPacket(receiver, this.getPlayerInfoPacket(PlayerInfo.UPDATE_GAME_MODE));
}
public void setPing(Collection<? extends Player> receivers, Ping ping) {
receivers.forEach(receiver -> this.setPing(receiver, ping));
}
public void setPing(Player receiver, Ping ping) {
this.sendPacket(receiver, this.getUpdatePlayerInfoPacket(PlayerInfo.UPDATE_LATENCY, ping));
}
public void setGameMode(Collection<? extends Player> receivers, GameMode gameMode) {
receivers.forEach(receiver -> this.setGameMode(receiver, gameMode));
}
public void setGameMode(Player receiver, GameMode gameMode) {
this.sendPacket(receiver, this.getUpdatePlayerInfoPacket(PlayerInfo.UPDATE_GAME_MODE, gameMode));
}
public void setTabListName(Collection<? extends Player> receivers, String displayName) {
receivers.forEach(receiver -> this.setTabListName(receiver, displayName));
}
public void setTabListName(Player receiver, String displayName) {
this.sendPacket(receiver, this.getUpdatePlayerInfoPacket(PlayerInfo.UPDATE_DISPLAY_NAME, displayName));
}
public void removeFromTabList(Collection<? extends Player> receivers) {
receivers.forEach(this::removeFromTabList);
}
public void removeFromTabList(Player receiver) {
this.sendPacket(receiver, this.getPlayerInfoPacket(PlayerInfo.REMOVE_PLAYER));
}
public void addToTabList(Collection<? extends Player> receivers) {
receivers.forEach(this::addToTabList);
}
public void addToTabList(Player receiver) {
this.sendPacket(receiver, this.getPlayerInfoPacket(PlayerInfo.ADD_PLAYER));
}
public void playAnimation(Collection<? extends Player> receivers, Animation animation) {
receivers.forEach(receiver -> this.playAnimation(receiver, animation));
}
public void playAnimation(Player receiver, Animation animation) {
this.sendPacket(receiver, this.getEntityAnimationPacket(animation));
}
public void lookAtPlayer(Collection<? extends Player> receivers, Player target) {
receivers.forEach(receiver -> this.lookAtPlayer(receiver, target));
}
public void lookAtPlayer(Player receiver, Player target) {
this.lookAtPoint(receiver, target.getEyeLocation());
}
public void lookAtPoint(Collection<? extends Player> receivers, Location location) {
receivers.forEach(receiver -> this.lookAtPoint(receiver, location));
}
public void lookAtPoint(Player receiver, Location location) {
Location eyeLocation = this.getEyeLocation();
float yaw = (float) Math.toDegrees(Math.atan2(location.getZ() - eyeLocation.getZ(), location.getX() - eyeLocation.getX())) - 90;
yaw = (float) (yaw + Math.ceil(-yaw / 360) * 360);
float deltaXZ = (float) Math.sqrt(Math.pow(eyeLocation.getX() - location.getX(), 2) + Math.pow(eyeLocation.getZ() - location.getZ(), 2));
float pitch = (float) Math.toDegrees(Math.atan2(deltaXZ, location.getY() - eyeLocation.getY())) - 90;
pitch = (float) (pitch + Math.ceil(-pitch / 360) * 360);
this.rotateHead(receiver, pitch, yaw, true);
}
public void rotateHead(Collection<? extends Player> receivers, float pitch, float yaw, boolean body) {
receivers.forEach(receiver -> this.rotateHead(receiver, pitch, yaw, body));
}
public void rotateHead(Player receiver, float pitch, float yaw, boolean body) {
this.location.setPitch(pitch);
this.location.setYaw(yaw);
System.out.println(yaw);
if(body) this.sendPacket(receiver, this.getEntityLookPacket());
this.sendPacket(receiver, this.getEntityHeadRotatePacket());
}
public void setEquipment(Collection<? extends Player> receivers, ItemSlot slot, org.bukkit.inventory.ItemStack itemStack) {
receivers.forEach(receiver -> this.setEquipment(receiver, slot, itemStack));
}
public void setEquipment(Player receiver, ItemSlot slot, org.bukkit.inventory.ItemStack itemStack) {
this.sendPacket(receiver, this.getEntityEquipmentPacket(slot.getNMSItemSlot(), CraftItemStack.asNMSCopy(itemStack)));
}
public void setPassenger(Collection<? extends Player> receivers, int... entityIDs) {
receivers.forEach(receiver -> this.setPassenger(receiver, entityIDs));
}
public void setPassenger(Player receiver, int... entityIDs) {
this.sendPacket(receiver, getEntityAttachPacket(entityIDs));
}
public void setLeash(Player receiver, org.bukkit.entity.Entity entity) {
this.sendPacket(receiver, getAttachEntityPacket(entity));
}
public void setLeash(Collection<? extends Player> receivers, org.bukkit.entity.Entity entity) {
receivers.forEach(p->this.setLeash(p, entity));
}
public void moveRelative(Player receiver, double relX, double relY, double relZ, boolean onGround) {
this.sendPacket(receiver, getEntityMovePacket(relX, relY, relZ, onGround));
}
public void moveRelative(Collection<? extends Player> receivers, double relX, double relY, double relZ, boolean onGround) {
receivers.forEach(p->this.moveRelative(p, relX, relY, relZ, onGround));
}
public BukkitCompletable<NPC> setSkinByUsername(Plugin plugin, String username) {
return BukkitCompletable.supplyASync(plugin, ()->{
this.setSkin(NPC.SkinTextures.getByUsername(plugin, username).getSync());
return NPC.this;
});
}
public BukkitCompletable<NPC> setSkinByUUID(Plugin plugin, UUID uuid) {
return BukkitCompletable.supplyASync(plugin, ()->{
this.setSkin(NPC.SkinTextures.getByUUID(plugin, uuid).getSync());
return NPC.this;
});
}
private void sendPacket(Player receiver, Packet<?> packet) {
((CraftPlayer) (receiver)).getHandle().b.a(packet);
}
public void setTeamFeatures(Player receiver, TeamFeatures teamFeatures) {
ScoreboardTeam team = new ScoreboardTeam(new Scoreboard(), this.profile.getName());
team.a(teamFeatures.nameTagVisible() ? ScoreboardTeamBase.EnumNameTagVisibility.a : ScoreboardTeamBase.EnumNameTagVisibility.b);
team.a(teamFeatures.glowColor().getNMSColor());
team.a(teamFeatures.collision() ? ScoreboardTeamBase.EnumTeamPush.a : ScoreboardTeamBase.EnumTeamPush.b);
PacketPlayOutScoreboardTeam createPacket = PacketPlayOutScoreboardTeam.a(team, true);
PacketPlayOutScoreboardTeam joinPacket = PacketPlayOutScoreboardTeam.a(team, this.profile.getName(), PacketPlayOutScoreboardTeam.a.a);
this.sendPacket(receiver, createPacket);
this.sendPacket(receiver, joinPacket);
}
public NBTTagCompound createParrot(Consumer<Parrot> callback, World world) {
EntityParrot entityParrot = new EntityParrot(EntityTypes.ao, ((CraftWorld) world).getHandle());
CraftParrot parrot = new CraftParrot((CraftServer) Bukkit.getServer(), entityParrot);
callback.accept(parrot);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
entityParrot.d(nbtTagCompound);
return nbtTagCompound;
}
public void setParrotLeftShoulder(Consumer<Parrot> callback, World world) {
this.metadata.setLeftShoulder(this.createParrot(callback, world));
}
public void setParrotRightShoulder(Consumer<Parrot> callback, World world) {
this.metadata.setRightShoulder(this.createParrot(callback, world));
}
public int getEntityID() {
return entityID;
}
public GameProfile getProfile() {
return profile;
}
public MetaData getMetadata() {
return metadata;
}
public Location getLocation() {
return location;
}
public Location getEyeLocation() {
return this.location.clone().add(0, EntityTypes.bn.m().b * 0.85F, 0);
}
public MetaData getMetaData() {
return this.metadata;
}
public void setMetaData(MetaData metaData) {
this.metadata = metaData;
}
public void setSkin(SkinTextures skinTextures) {
this.profile.getProperties().put("textures", new Property("textures", skinTextures.getTexture(), skinTextures.getSignature()));
}
public void setDisplayName(String displayName) {
GameProfile swapProfile = new GameProfile(this.profile.getId(), displayName);
swapProfile.getProperties().putAll(this.profile.getProperties());
this.profile = swapProfile;
}
public void registerListener(NPCListener listener) {
if (EventManager.isInitialized()) {
EventManager.INSTANCE.listenNPC(this, listener);
}
}
public void unregisterListener() {
if (EventManager.isInitialized()) {
EventManager.INSTANCE.unlistenNPC(this);
}
}
private PacketPlayOutMount getEntityAttachPacket(int[] entityIDs) {
return this.createDataSerializer(data -> {
data.d(this.entityID);
data.a(entityIDs);
return new PacketPlayOutMount(data);
});
}
private PacketPlayOutEntity.PacketPlayOutEntityLook getEntityLookPacket() {
return new PacketPlayOutEntity.PacketPlayOutEntityLook(this.entityID, (byte) ((int) (this.location.getYaw() * 256.0F / 360.0F)), (byte) ((int) (this.location.getPitch() * 256.0F / 360.0F)), true);
}
private PacketPlayOutEntityHeadRotation getEntityHeadRotatePacket() {
return this.createDataSerializer(data -> {
data.d(this.entityID);
data.writeByte((byte) ((int) (this.location.getYaw() * 256.0F / 360.0F)));
return new PacketPlayOutEntityHeadRotation(data);
});
}
private PacketPlayOutEntityTeleport getEntityTeleportPacket(boolean onGround) {
return this.createDataSerializer(data -> {
data.d(this.entityID);
data.writeDouble(this.location.getX());
data.writeDouble(this.location.getY());
data.writeDouble(this.location.getZ());
data.writeByte((byte) ((int) (this.location.getYaw() * 256.0F / 360.0F)));
data.writeByte((byte) ((int) (this.location.getPitch() * 256.0F / 360.0F)));
data.writeBoolean(onGround);
return new PacketPlayOutEntityTeleport(data);
});
}
private PacketPlayOutEntity.PacketPlayOutRelEntityMove getEntityMovePacket(double x, double y, double z, boolean onGround) {
return new PacketPlayOutEntity.PacketPlayOutRelEntityMove(this.entityID, (short)(x * 4096), (short)(y * 4096), (short)(z * 4096), onGround);
}
private PacketPlayOutAttachEntity getAttachEntityPacket(org.bukkit.entity.Entity entity) {
return createDataSerializer(data -> {
data.writeInt(entity.getEntityId());
data.writeInt(this.entityID);
return new PacketPlayOutAttachEntity(data);
});
}
private PacketPlayOutEntityEquipment getEntityEquipmentPacket(EnumItemSlot slot, ItemStack itemStack) {
return new PacketPlayOutEntityEquipment(this.entityID, Arrays.asList(new Pair<>(slot, itemStack)));
}
private PacketPlayOutAnimation getEntityAnimationPacket(Animation animation) {
return this.createDataSerializer((data) -> {
data.d(this.entityID);
data.writeByte((byte) animation.getType());
return new PacketPlayOutAnimation(data);
});
}
private PacketPlayOutEntityDestroy getEntityDestroyPacket() {
return new PacketPlayOutEntityDestroy(this.entityID);
}
private PacketPlayOutEntityMetadata getEntityMetadataPacket() {
return this.createDataSerializer((data) -> {
data.d(this.entityID);
DataWatcher.a(this.metadata.getList(), data);
return new PacketPlayOutEntityMetadata(data);
});
}
private PacketPlayOutNamedEntitySpawn getEntitySpawnPacket() {
return this.createDataSerializer((data) -> {
data.d(this.entityID);
data.a(this.profile.getId());
data.writeDouble(this.location.getX());
data.writeDouble(this.location.getY());
data.writeDouble(this.location.getZ());
data.writeByte((byte) ((int) (this.location.getYaw() * 256.0F / 360.0F)));
data.writeByte((byte) ((int) (this.location.getPitch() * 256.0F / 360.0F)));
return new PacketPlayOutNamedEntitySpawn(data);
});
}
private PacketPlayOutPlayerInfo getUpdatePlayerInfoPacket(PlayerInfo playerInfo, Object obj) {
return this.createDataSerializer((data) -> {
PacketPlayOutPlayerInfo.EnumPlayerInfoAction action = playerInfo.getNMSAction();
PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData;
net.minecraft.world.entity.player.ProfilePublicKey.a playerPublicKey = null;
if (playerInfo == PlayerInfo.UPDATE_LATENCY) {
playerInfoData = new PacketPlayOutPlayerInfo.PlayerInfoData(this.profile, ((Ping) obj).getMilliseconds(), null, null, playerPublicKey);
} else if (playerInfo == PlayerInfo.UPDATE_GAME_MODE) {
playerInfoData = new PacketPlayOutPlayerInfo.PlayerInfoData(this.profile, 0, ((GameMode) obj).getNMSGameMode(), null, playerPublicKey);
} else if (playerInfo == PlayerInfo.UPDATE_DISPLAY_NAME) {
playerInfoData = new PacketPlayOutPlayerInfo.PlayerInfoData(this.profile, 0, null, CraftChatMessage.fromString(((String) obj))[0], playerPublicKey);
} else {
throw new NullPointerException();
}
List<PacketPlayOutPlayerInfo.PlayerInfoData> list = Arrays.asList(playerInfoData);
Method method = playerInfo.getNMSAction().getDeclaringClass().getDeclaredMethod("a", PacketDataSerializer.class, PacketPlayOutPlayerInfo.PlayerInfoData.class);
method.setAccessible(true);
data.a(playerInfo.getNMSAction());
data.a(list, (PacketDataSerializer.b<PacketPlayOutPlayerInfo.PlayerInfoData>) (a, b) -> this.unsafe(() -> method.invoke(action, a, b)));
return new PacketPlayOutPlayerInfo(data);
});
}
private PacketPlayOutPlayerInfo getPlayerInfoPacket(PlayerInfo playerInfo) {
return this.createDataSerializer((data) -> {
PacketPlayOutPlayerInfo.EnumPlayerInfoAction action = playerInfo.getNMSAction();
net.minecraft.world.entity.player.ProfilePublicKey.a playerPublicKey = null;
PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = new PacketPlayOutPlayerInfo.PlayerInfoData(this.profile, Ping.FIVE_BARS.getMilliseconds(), GameMode.CREATIVE.getNMSGameMode(), CraftChatMessage.fromString(this.getProfile().getName())[0], playerPublicKey);
List<PacketPlayOutPlayerInfo.PlayerInfoData> list = Arrays.asList(playerInfoData);
data.a(playerInfo.getNMSAction());
Method method = playerInfo.getNMSAction().getDeclaringClass().getDeclaredMethod("a", PacketDataSerializer.class, PacketPlayOutPlayerInfo.PlayerInfoData.class);
method.setAccessible(true);
data.a(list, (PacketDataSerializer.b<PacketPlayOutPlayerInfo.PlayerInfoData>) (a, b) -> this.unsafe(() -> method.invoke(action, a, b)));
return new PacketPlayOutPlayerInfo(data);
});
}
public static void initEventHandler(Plugin plugin) {
EventManager.init(plugin);
}
public enum EntityState implements EnumUtil.Maskable<EntityState> {
DEFAULT(0x00),
ON_FIRE(0x01),
@Deprecated CROUCHING(0x02),
@Deprecated UNUSED(0x04),
SPRINTING(0x08),
SWIMMING(0x10),
INVISIBLE(0x20),
GLOWING(0x40),
FLYING(0x80);
private final int mask;
EntityState(int mask) {
this.mask = mask;
}
public int getMask() {
return mask;
}
}
public enum SkinStatus implements EnumUtil.Maskable<SkinStatus> {
CAPE_ENABLED(0x01),
JACKET_ENABLED(0x02),
LEFT_SLEEVE_ENABLED(0x04),
RIGHT_SLEEVE_ENABLED(0x08),
LEFT_PANTS_LEG_ENABLED(0x10),
RIGHT_PANTS_LEG_ENABLED(0x20),
HAT_ENABLED(0x40),
@Deprecated UNUSED(0x80);
private static final SkinStatus[] ALL = {CAPE_ENABLED, JACKET_ENABLED, LEFT_SLEEVE_ENABLED, RIGHT_SLEEVE_ENABLED, LEFT_PANTS_LEG_ENABLED, RIGHT_PANTS_LEG_ENABLED, HAT_ENABLED};
private final int mask;
SkinStatus(int mask) {
this.mask = mask;
}
public int getMask() {
return mask;
}
}
public enum Pose implements EnumUtil.Identifiable<EntityPose> {
STANDING(EntityPose.a),
FALL_FLYING(EntityPose.b),
SLEEPING(EntityPose.c),
SWIMMING(EntityPose.d),
SPIN_ATTACK(EntityPose.e),
CROUCHING(EntityPose.f),
LONG_JUMPING(EntityPose.g),
DYING(EntityPose.h),
CROAKING(EntityPose.i),
ROARING(EntityPose.j),
SNIFFING(EntityPose.k),
EMERGING(EntityPose.l),
DIGGING(EntityPose.m);
private final EntityPose nmsPose;
Pose(EntityPose nmsPose) {
this.nmsPose = nmsPose;
}
public EntityPose getID() {
return nmsPose;
}
}
public enum HandStatus implements EnumUtil.Maskable<HandStatus> {
MAIN_HAND(0x00),
HAND_ACTIVE(0x01),
OFF_HAND(0x02),
RIPTIDE_SPIN_ATTACK(0x04);
private final int mask;
HandStatus(int mask) {
this.mask = mask;
}
public int getMask() {
return mask;
}
}
public enum Hand implements EnumUtil.BiIdentifiable<EnumHand, Integer> {
OFF_HAND(EnumHand.b, 1),
MAIN_HAND(EnumHand.a, 0);
private final EnumHand id;
private final int type;
Hand(EnumHand id, int type) {
this.id = id;
this.type = type;
}
public Integer getSecondID() {
return type;
}
public EnumHand getID() {
return id;
}
}
public enum InteractType implements EnumUtil.Identifiable<String> {
RIGHT_CLICK("INTERACT"),
LEFT_CLICK("ATTACK"),
RIGHT_CLICK_AT("INTERACT_AT");
private final String id;
InteractType(String id) {
this.id = id;
}
public String getID() {
return id;
}
}
public enum PlayerInfo {
ADD_PLAYER(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a),
UPDATE_GAME_MODE(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.b),
UPDATE_LATENCY(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.c),
UPDATE_DISPLAY_NAME(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.d),
REMOVE_PLAYER(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.e);
private final PacketPlayOutPlayerInfo.EnumPlayerInfoAction nmsAction;
PlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction nmsAction) {
this.nmsAction = nmsAction;
}
public PacketPlayOutPlayerInfo.EnumPlayerInfoAction getNMSAction() {
return nmsAction;
}
}
public enum Ping {
NO_CONNECTION(-1),
ONE_BAR(1000),
TWO_BARS(999),
THREE_BARS(599),
FOUR_BARS(299),
FIVE_BARS(149);
private final int milliseconds;
Ping(int milliseconds) {
this.milliseconds = milliseconds;
}
public int getMilliseconds() {
return milliseconds;
}
}
public enum ItemSlot {
MAIN_HAND(EnumItemSlot.a),
OFF_HAND(EnumItemSlot.b),
BOOTS(EnumItemSlot.c),
LEGGINGS(EnumItemSlot.d),
CHESTPLATE(EnumItemSlot.e),
HELMET(EnumItemSlot.f);
private final EnumItemSlot nmsItemSlot;
ItemSlot(EnumItemSlot nmsItemSlot) {
this.nmsItemSlot = nmsItemSlot;
}
public EnumItemSlot getNMSItemSlot() {
return nmsItemSlot;
}
}
public enum GlowColor {
BLACK(EnumChatFormat.a),
DARK_BLUE(EnumChatFormat.b),
DARK_GREEN(EnumChatFormat.c),
DARK_AQUA(EnumChatFormat.d),
DARK_RED(EnumChatFormat.e),
DARK_PURPLE(EnumChatFormat.f),
GOLD(EnumChatFormat.g),
GRAY(EnumChatFormat.h),
DARK_GRAY(EnumChatFormat.i),
BLUE(EnumChatFormat.j),
GREEN(EnumChatFormat.k),
AQUA(EnumChatFormat.l),
RED(EnumChatFormat.m),
LIGHT_PURPLE(EnumChatFormat.n),
YELLOW(EnumChatFormat.o),
WHITE(EnumChatFormat.p),
NONE(EnumChatFormat.v);
private final EnumChatFormat nmsColor;
GlowColor(EnumChatFormat nmsColor) {
this.nmsColor = nmsColor;
}
public EnumChatFormat getNMSColor() {
return nmsColor;
}
}
public enum GameMode {
SURVIVAL(EnumGamemode.a),
CREATIVE(EnumGamemode.b),
ADVENTURE(EnumGamemode.c),
SPECTATOR(EnumGamemode.d);
private final EnumGamemode nmsGameMode;
GameMode(EnumGamemode nmsGameMode) {
this.nmsGameMode = nmsGameMode;
}
public EnumGamemode getNMSGameMode() {
return nmsGameMode;
}
}
public enum Animation {
SWING_MAIN_HAND(0),
TAKE_DAMAGE(1),
LEAVE_BED(2),
SWING_OFFHAND(3),
CRITICAL_EFFECT(4),
MAGIC_CRITICAL_EFFECT(5);
private final int type;
Animation(int type) {
this.type = type;
}
public int getType() {
return type;
}
}
public class MetaData {
//Entity metadata
private final DataWatcher.Item<Byte> entityState = a(0, (byte) EnumUtil.createMask(EntityState.DEFAULT));
private final DataWatcher.Item<Integer> airTicks = a(1, 300);
private final DataWatcher.Item<Optional<IChatBaseComponent>> customName = a(2, Optional.empty(), DataWatcherRegistry.f);
private final DataWatcher.Item<Boolean> customNameVisible = a(3, false);
private final DataWatcher.Item<Boolean> silent = a(4, false);
private final DataWatcher.Item<Boolean> noGravity = a(5, false);
private final DataWatcher.Item<EntityPose> pose = a(6, Pose.STANDING.getID());
private final DataWatcher.Item<Integer> frozenTicks = a(7, 0); //shaking at tick 140
//LivingEntity metadata
private final DataWatcher.Item<Byte> handStatus = a(8, (byte) EnumUtil.createMask(HandStatus.MAIN_HAND));
private final DataWatcher.Item<Float> health = a(9, 1.0F);
private final DataWatcher.Item<Integer> potionEffectColor = a(10, 0);
private final DataWatcher.Item<Boolean> isPotionEffectAmbient = a(11, false);
private final DataWatcher.Item<Integer> arrowsInEntity = a(12, 0);
private final DataWatcher.Item<Integer> beeStingers = a(13, 0);
private final DataWatcher.Item<Optional<BlockPosition>> sleepingBedLocation = a(14, Optional.empty(), DataWatcherRegistry.m);
//Player metadata
private final DataWatcher.Item<Float> additionalHearts = a(15, 0.0F);
private final DataWatcher.Item<Integer> score = a(16, 0);
private final DataWatcher.Item<Byte> skinStatus = a(17, (byte) EnumUtil.createMask(SkinStatus.ALL));
private final DataWatcher.Item<Byte> hand = a(18, (byte) ((int) Hand.MAIN_HAND.getSecondID()));
private final DataWatcher.Item<NBTTagCompound> leftShoulder = a(19, new NBTTagCompound());
private final DataWatcher.Item<NBTTagCompound> rightShoulder = a(20, new NBTTagCompound());
private final List<DataWatcher.Item<?>> list;
public MetaData() {
this.list = new ArrayList<>(Arrays.asList(
this.entityState,
this.airTicks,
this.customName,
this.customNameVisible,
this.silent,
this.noGravity,
this.pose,
this.frozenTicks,
this.handStatus,
this.health,
this.potionEffectColor,
this.isPotionEffectAmbient,
this.arrowsInEntity,
this.beeStingers,
this.sleepingBedLocation,
this.additionalHearts,
this.score,
this.skinStatus,
this.hand,
this.leftShoulder,
this.rightShoulder));
}
public List<EntityState> getEntityState() {
return EnumUtil.fromMask(entityState.b(), EntityState.class);
}
public Integer getAirTicks() {
return airTicks.b();
}
public Optional<IChatBaseComponent> getCustomName() {
return customName.b();
}
public Boolean isCustomNameVisible() {
return customNameVisible.b();
}
public Boolean isSilent() {
return silent.b();
}
public Boolean hasNoGravity() {
return noGravity.b();
}
public Pose getPose() {
return EnumUtil.getByID(this.pose.b(), Pose.class);
}
public Integer getFrozenTicks() {
return frozenTicks.b();
}
public List<HandStatus> getHandStatus() {
return EnumUtil.fromMask(handStatus.b(), HandStatus.class);
}
public Float getHealth() {
return health.b();
}
public Integer getPotionEffectColor() {
return potionEffectColor.b();
}
public Boolean isPotionEffectAmbient() {
return isPotionEffectAmbient.b();
}
public Integer getArrowsInEntity() {
return arrowsInEntity.b();
}
public Integer getBeeStingers() {
return beeStingers.b();
}
public Optional<BlockPosition> getSleepingBedLocation() {
return sleepingBedLocation.b();
}
public Float getAdditionalHearts() {
return additionalHearts.b();
}
public Integer getScore() {
return score.b();
}
public List<SkinStatus> getSkinStatus() {
return EnumUtil.fromMask(skinStatus.b(), SkinStatus.class);
}
public Hand getHand() {
return EnumUtil.getBySecondID((int) hand.b(), Hand.class);
}
public NBTTagCompound getLeftShoulder() {
return leftShoulder.b();
}
public NBTTagCompound getRightShoulder() {
return rightShoulder.b();
}
public void setEntityState(EntityState... entityState) {
this.entityState.a((byte) EnumUtil.createMask(entityState));
}
public void setAirTicks(Integer airTicks) {
this.airTicks.a(airTicks);
}
public void setCustomName(String customName) {
this.customName.a(Optional.ofNullable(IChatBaseComponent.a(customName)));
}
public void setCustomNameVisible(Boolean customNameVisible) {
this.customNameVisible.a(customNameVisible);
}
public void setSilent(Boolean silent) {
this.silent.a(silent);
}
public void setNoGravity(Boolean gravity) {
this.noGravity.a(gravity);
}
public void setPose(Pose pose) {
this.pose.a(pose.getID());
}
public void setFrozenTicks(Integer frozenTicks) {
this.frozenTicks.a(frozenTicks);
}
public void setShaking(boolean shaking) {
this.setFrozenTicks(shaking ? 140 : 0);
}
public void setHandStatus(HandStatus handStatus) {
this.handStatus.a((byte) EnumUtil.createMask(handStatus));
}
public void setHealth(Float health) {
this.health.a(health);
}
public void setPotionEffectColor(Integer potionEffectColor) {
this.potionEffectColor.a(potionEffectColor);
}
public void setIsPotionEffectAmbient(Boolean isPotionEffectAmbient) {
this.isPotionEffectAmbient.a(isPotionEffectAmbient);
}
public void setArrowsInEntity(Integer arrowsInEntity) {
this.arrowsInEntity.a(arrowsInEntity);
}
public void setBeeStingers(Integer beeStingers) {
this.beeStingers.a(beeStingers);
}
public void setSleepingBedLocation(BlockPosition sleepingBedLocation) {
this.sleepingBedLocation.a(Optional.ofNullable(sleepingBedLocation));
}
public void setAdditionalHearts(Float additionalHearts) {
this.additionalHearts.a(additionalHearts);
}
public void setScore(Integer score) {
this.score.a(score);
}
public void setSkinStatus(SkinStatus... skinStatus) {
this.skinStatus.a((byte) EnumUtil.createMask(skinStatus));
}
public void setHand(Hand hand) {
this.hand.a((byte) ((int) hand.getSecondID()));
}
public void setLeftShoulder(NBTTagCompound leftShoulder) {
this.leftShoulder.a(leftShoulder);
}
public void setRightShoulder(NBTTagCompound rightShoulder) {
this.rightShoulder.a(rightShoulder);
}
public List<DataWatcher.Item<?>> getList() {
return list;
}
private static <T> DataWatcher.Item<T> a(int index, T value) {
DataWatcherSerializer<?> serializer = null;
if (value instanceof Byte) {
serializer = DataWatcherRegistry.a;
} else if (value instanceof Float) {
serializer = DataWatcherRegistry.c;
} else if (value instanceof Integer) {
serializer = DataWatcherRegistry.b;
} else if (value instanceof String) {
serializer = DataWatcherRegistry.d;
} else if (value instanceof Boolean) {
serializer = DataWatcherRegistry.i;
} else if (value instanceof NBTTagCompound) {
serializer = DataWatcherRegistry.q;
} else if (value instanceof BlockPosition) {
serializer = DataWatcherRegistry.m;
} else if (value instanceof IChatBaseComponent) {
serializer = DataWatcherRegistry.e;
} else if (value instanceof EntityPose) {
serializer = DataWatcherRegistry.t;
}
return a(index, value, (DataWatcherSerializer<T>) serializer);
}
private static <T> DataWatcher.Item<T> a(int index, T value, DataWatcherSerializer<T> serializer) {
return new DataWatcher.Item<T>(new DataWatcherObject<T>(index, serializer), value);
}
}
public static class EnumUtil {
private interface Maskable<M> {
int getMask();
}
private interface Identifiable<I> {
I getID();
}
private interface BiIdentifiable<I, J> extends Identifiable<I> {
J getSecondID();
}
@SafeVarargs
private static <M> int createMask(Maskable<M>... maskables) {
int mask = 0;
for (Maskable m : maskables) {
mask |= m.getMask();
}
return mask;
}
private static <M extends Maskable<M>> List<M> fromMask(int mask, Class<M> enumClass) {
List<M> list = new ArrayList<M>();
for (M maskable : enumClass.getEnumConstants()) {
if ((maskable.getMask() & mask) != 0) {
list.add(maskable);
}
}
return list;
}
private static <I, M extends Identifiable<I>> M getByID(I id, Class<M> enumClass) {
for (M identifiable : enumClass.getEnumConstants()) {
if (id == identifiable.getID()) {
return identifiable;
}
}
return null;
}
private static <I, J, M extends BiIdentifiable<I, J>> M getBySecondID(J id, Class<M> enumClass) {
for (M identifiable : enumClass.getEnumConstants()) {
if (id == identifiable.getID()) {
return identifiable;
}
}
return null;
}
}
public static class SkinTextures {
private static final String TEXTURE_URL = "https://sessionserver.mojang.com/session/minecraft/profile/%s?unsigned=false";
private static final String UUID_URL = "https://api.mojang.com/profiles/minecraft";
private final String texture;
private final String signature;
public SkinTextures(String textures, String signature) {
this.texture = textures;
this.signature = signature;
}
public String getTexture() {
return texture;
}
public String getSignature() {
return signature;
}
public static BukkitCompletable<SkinTextures> getByUsername(Plugin plugin, String username) {
return BukkitCompletable.supplyASync(plugin, ()->{
JSONArray array = new JSONArray();
array.add(username);
UUID uuid = null;
HttpRequest request = HttpRequest.newBuilder(new URI(UUID_URL))
.setHeader("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(array.toString()))
.timeout(Duration.ofSeconds(5))
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
JSONArray uuidArray = (JSONArray) new JSONParser().parse(response.body());
if (uuidArray.size() > 0) {
String uuidStr = (String) ((JSONObject) uuidArray.get(0)).get("id");
uuid = UUID.fromString(uuidStr.replaceAll("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
}
}
if (uuid == null) throw new NullPointerException("uuid is null");
return getByUUID(plugin, uuid).getSync();
});
}
public static BukkitCompletable<SkinTextures> getByUUID(Plugin plugin, UUID uuid) {
return BukkitCompletable.supplyASync(plugin, ()->{
SkinTextures result = null;
HttpRequest request = HttpRequest.newBuilder(new URI(String.format(TEXTURE_URL, uuid.toString().replace("-", ""))))
.timeout(Duration.ofSeconds(5))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
JSONArray properties = (JSONArray) ((JSONObject) new JSONParser().parse(response.body())).get("properties");
for (int t = 0; t < properties.size(); t++) {
JSONObject obj = (JSONObject) properties.get(t);
if (obj.containsKey("name") && obj.get("name").equals("textures")) {
result = new SkinTextures((String) obj.get("value"), (String) obj.get("signature"));
}
}
}
return result;
});
}
}
public static class BukkitCompletable<T> {
private final Plugin plugin;
private final UnsafeSupplier<T> runnable;
private Consumer<Throwable> errorHandler;
private Consumer<T> callbackHandler;
private Runnable emptyCallbackHandler;
private BukkitCompletable(Plugin plugin, UnsafeSupplier<T> runnable) {
this.plugin = plugin;
this.runnable = runnable;
}
public static <T> BukkitCompletable<T> supplyASync(Plugin plugin, UnsafeSupplier<T> runnable) {
return new BukkitCompletable<T>(plugin, runnable);
}
public BukkitCompletable<T> onFinish(Consumer<T> callbackHandler) {
this.callbackHandler = callbackHandler;
return this;
}
public BukkitCompletable<T> onEmptyFinish(Runnable emptyCallbackHandler) {
this.emptyCallbackHandler = emptyCallbackHandler;
return this;
}
public BukkitCompletable<T> onException(Consumer<Throwable> errorHandler) {
this.errorHandler = errorHandler;
return this;
}
public void getSafe() {
this.get(true);
}
public void getUnsafe() {
this.get(false);
}
public T getSync() throws Exception {
return runnable.get();
}
private void get(boolean safe) {
async(plugin, ()->{
try {
T t = this.runnable.get();
if(!(this.callbackHandler == null && this.emptyCallbackHandler == null)) {
if(safe) {
sync(plugin, () -> {
if (callbackHandler != null) this.callbackHandler.accept(t);
if (emptyCallbackHandler != null) this.emptyCallbackHandler.run();
});
} else {
if(callbackHandler != null) this.callbackHandler.accept(t);
if(emptyCallbackHandler != null) this.emptyCallbackHandler.run();
}
}
} catch (Throwable e) {
if(this.errorHandler != null) {
if(safe) sync(plugin, ()->this.errorHandler.accept(e));
else this.errorHandler.accept(e);
}
}
});
}
}
private static class EventManager implements Listener {
private static final String CHANNEL_NAME = "npc_manager";
private static EventManager INSTANCE;
private final Plugin plugin;
private final Map<Integer, NPCListener> listenerMap = new HashMap<>();
private EventManager(Plugin plugin) {
this.plugin = plugin;
Bukkit.getPluginManager().registerEvents(this, plugin);
Bukkit.getOnlinePlayers().forEach(this::unregisterPlayer);
Bukkit.getOnlinePlayers().forEach(this::registerPlayer);
}
private void listenNPC(NPC npc, NPCListener listener) {
if (listenerMap.containsKey(npc.getEntityID()))
throw new UnsupportedOperationException("cannot register same npc twice");
this.listenerMap.put(npc.getEntityID(), listener);
}
private void unlistenNPC(NPC npc) {
if (!listenerMap.containsKey(npc.getEntityID())) throw new NullPointerException("listener does not exist");
this.listenerMap.remove(npc.getEntityID());
}
private void unregisterPlayer(Player player) {
ChannelPipeline pipeline = ((CraftPlayer) player).getHandle().b.b.m.pipeline();
if(pipeline.names().contains(CHANNEL_NAME)) {
pipeline.remove(CHANNEL_NAME);
}
}
private void registerPlayer(Player player) {
ChannelPipeline pipeline = ((CraftPlayer) player).getHandle().b.b.m.pipeline();
if(!pipeline.names().contains(CHANNEL_NAME)) {
pipeline.addBefore("packet_handler", CHANNEL_NAME, new PlayerInboundHandlerAdapter(player));
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerJoinEvent(PlayerJoinEvent e) {
this.registerPlayer(e.getPlayer());
}
public static boolean isInitialized() {
return INSTANCE != null;
}
public static void init(Plugin plugin) {
if(INSTANCE != null) INSTANCE.listenerMap.clear();
INSTANCE = new EventManager(plugin);
}
private class PlayerInboundHandlerAdapter extends ChannelInboundHandlerAdapter {
private final Player player;
public PlayerInboundHandlerAdapter(Player player) {
this.player = player;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
super.channelRead(ctx, msg);
try {
if (msg instanceof PacketPlayInUseEntity packet) {
Field entityIdField = packet.getClass().getDeclaredField("a");
entityIdField.setAccessible(true);
int entityId = (int) entityIdField.get(packet);
final NPCListener listener = listenerMap.getOrDefault(entityId, null);
if (listener != null) {
Field typeField = packet.getClass().getDeclaredField("b");
typeField.setAccessible(true);
Object type = typeField.get(packet);
Method typeMethod = type.getClass().getDeclaredMethod("a");
typeMethod.setAccessible(true);
InteractType interactType = EnumUtil.getByID(((Enum) typeMethod.invoke(type)).name(), InteractType.class);
Hand hand = Hand.MAIN_HAND;
if (interactType != InteractType.RIGHT_CLICK_AT) {
if (interactType == InteractType.RIGHT_CLICK) {
Field handField = type.getClass().getDeclaredField("a");
handField.setAccessible(true);
hand = EnumUtil.getByID((EnumHand) handField.get(type), Hand.class);
}
boolean sneaking = packet.b();
final NPCInteractEvent event = new NPCInteractEvent(this.player, interactType, hand, sneaking);
Bukkit.getScheduler().runTask(plugin, () -> listener.accept(event));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
;
}
}
}
public record TeamFeatures(boolean nameTagVisible, boolean collision, GlowColor glowColor) {}
public record NPCInteractEvent(Player player, InteractType interactType, Hand hand, boolean sneaking) {
}
public static void sync(Plugin plugin, Runnable runnable) {
Bukkit.getScheduler().runTask(plugin, runnable);
}
public static void async(Plugin plugin, Runnable runnable) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable);
}
public static void sleep(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {}
}
private static void unsafe(UnsafeRunnable run) {
try {
run.run();
} catch (Exception e) {
e.printStackTrace();
}
}
private static <T> T createDataSerializer(UnsafeFunction<PacketDataSerializer, T> callback) {
PacketDataSerializer data = new PacketDataSerializer(Unpooled.buffer());
T result = null;
try {
result = callback.apply(data);
} catch (Exception e) {
e.printStackTrace();
} finally {
data.release();
}
return result;
}
@FunctionalInterface
private interface UnsafeSupplier<T> {
T get() throws Exception;
}
@FunctionalInterface
private interface UnsafeRunnable {
void run() throws Exception;
}
@FunctionalInterface
private interface UnsafeFunction<K, T> {
T apply(K k) throws Exception;
}
@FunctionalInterface
public interface NPCListener extends Consumer<NPCInteractEvent> {
}
}
@DanielTheDev
Copy link
Author

DanielTheDev commented Aug 17, 2022 via email

@Thentoxd
Copy link

Hey! I've got the dependencies working just fine. However there appears to be loads of errors:

image

image

image

image

Any help with these would be highly appreciated :)

@DanielTheDev
Copy link
Author

DanielTheDev commented Aug 18, 2022 via email

@DanielTheDev
Copy link
Author

DanielTheDev commented Aug 18, 2022 via email

@Thentoxd
Copy link

Amazing! That all worked, thanks so much!

@DanielTheDev
Copy link
Author

DanielTheDev commented Aug 18, 2022 via email

@Thentoxd
Copy link

Hi, is there any method implemented to allow this npc to walk to a set location using pathfinding or anything else?

@DanielTheDev
Copy link
Author

DanielTheDev commented Aug 23, 2022 via email

@vlladislav45
Copy link

@DanielTheDev are you still support and maintain this project? Because there are new changes in 1.19.3. I would like to know if there will be created a new version on it?

@DanielTheDev
Copy link
Author

No, there won't be a new version since 1.20 will be released this month. And if there is no demand of this utility (which is the case nowadays), I will not take time to update it.

No, there won't be a new version since 1.20 will be released this month.
And if there is no demand of this utility (which is the case nowadays), I will not take time to update it.

@ZeTioZ
Copy link

ZeTioZ commented Jan 14, 2023

Hi, tried to update for the 1.19.3 by changing PacketPlayOutPlayerInfo to ClientboundPlayerInfoUpdatePacket (should be the new name for the updated class). But can't make it work. They seem to have changed some things about that class.

@DanielTheDev
Copy link
Author

DanielTheDev commented Jan 14, 2023

Hi, tried to update for the 1.19.3 by changing PacketPlayOutPlayerInfo to ClientboundPlayerInfoUpdatePacket (should be the new name for the updated class). But can't make it work. They seem to have changed some things about that class.

Just use these methods to write the 'data' object in the createDataSerialized in the two packetInfo methods.

data.writeEnumSet(this.actions, ClientboundPlayerInfoUpdatePacket.a.class);
data.writeCollection(this.entries, (packetdataserializer1, clientboundplayerinfoupdatepacket_b) -> {
	packetdataserializer1.writeUUID(clientboundplayerinfoupdatepacket_b.profileId());
	Iterator iterator = this.actions.iterator();
	while (iterator.hasNext()) {
		ClientboundPlayerInfoUpdatePacket.a clientboundplayerinfoupdatepacket_a = (ClientboundPlayerInfoUpdatePacket.a) iterator.next();
		clientboundplayerinfoupdatepacket_a.writer.write(packetdataserializer1, clientboundplayerinfoupdatepacket_b);
	}

});

But remember to modify the data methods to replace the variables with the one created in the methods from the util.
And leave out any redundant method callings (if needed). For instance, you can replace the for loop because you only have one entry which is the NPC's.

@ZeTioZ
Copy link

ZeTioZ commented Jan 14, 2023

Thanks, gonna try it out :D

@ZeTioZ
Copy link

ZeTioZ commented Jan 30, 2023

Hi, sorry to bother you again, but I can't get this method to get back the metadata packet to work... if you could give it a look that would be lovely (talking about getEntityMetadataPacket() method)

@DanielTheDev
Copy link
Author

Hi, sorry to bother you again, but I can't get this method to get back the metadata packet to work... if you could give it a look that would be lovely (talking about getEntityMetadataPacket() method)

Sure, give me an hour to make it work. I will get back to you.

@DanielTheDev
Copy link
Author

private PacketPlayOutEntityMetadata getEntityMetadataPacket() {
    return this.createDataSerializer((data) -> {
        data.d(this.entityID);
        Iterator var2 = this.metadata.getList().iterator();
        while(var2.hasNext()) {
            DataWatcher.b<?> var3 = (DataWatcher.b)var2.next();
            var3.a(data);
        }
        data.writeByte(255);
        return new PacketPlayOutEntityMetadata(data);
    });
}

This should be working correctly, assuming that no DataWatchRegitry or MetaData items has changed.

@ZeTioZ
Copy link

ZeTioZ commented Jan 30, 2023

private PacketPlayOutEntityMetadata getEntityMetadataPacket() {
    return this.createDataSerializer((data) -> {
        data.d(this.entityID);
        Iterator var2 = this.metadata.getList().iterator();
        while(var2.hasNext()) {
            DataWatcher.b<?> var3 = (DataWatcher.b)var2.next();
            var3.a(data);
        }
        data.writeByte(255);
        return new PacketPlayOutEntityMetadata(data);
    });
}

This should be working correctly, assuming that no DataWatchRegitry or MetaData items has changed.

Thanks for the reply, looks like it can't cast the Item object to "b"

class net.minecraft.network.syncher.DataWatcher$Item cannot be cast to class net.minecraft.network.syncher.DataWatcher$b

Gonna check if I find out how to fix it, I'll post the solution if I find one ^^

EDIT: Fixed it by using "Item" instead of "b" but the NPC doesn't seem to spawn, here is the modified code I got from updating on my own the other parts as well https://pastebin.com/d1JG7cpN

EDIT 2: I think that I don't entirely understand the code, do you have any documentation to understand a bit how you managed to make the other versions of your lib? I'll maybe just need to read and understand more about packets and its serializers.

@Kinqdos
Copy link

Kinqdos commented Feb 20, 2023

First of all, thank you for your awesome work!

I think I found a little typo in line 293. It should be EntityTypes.ap.

@DanielTheDev
Copy link
Author

First of all, thank you for your awesome work!

I think I found a little typo in line 293. It should be EntityTypes.ap.

Thank you very much. I appreciate it.
Also, thanks for notifying me, I will look into it.

@ZeTioZ
Copy link

ZeTioZ commented Feb 22, 2023

Hi, sorry to ask for it, but could you make the update to 1.19.3. I can't get it working properly, I have no errors with what I did to update but it doesn't spawn the npc :'( (and I need this because the server is going to be updated to 1.19.3)

Here is what I got when updated: https://pastebin.com/CxMdYPYh (not working)

@Thentoxd
Copy link

Hello - I'm not sure I understand how getting an offline player's skin works. Any way you can teach me?

@DanielTheDev
Copy link
Author

Hello - I'm not sure I understand how getting an offline player's skin works. Any way you can teach me?

We can discuss this if you like. You can add me on discord danielthedev

@Thentoxd
Copy link

Friend request sent

Hello - I'm not sure I understand how getting an offline player's skin works. Any way you can teach me?

We can discuss this if you like. You can add me on discord danielthedev

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment