Entity Head Rotation not working for fake player NPCs on Minecraft 1.21.10
Environment
- Minecraft Version: Paper 1.21.10
- PacketEvents Version: 2.10.1
- Problem: Rotation packets are sent successfully but NPCs don't rotate visually
Description
I'm developing a Spigot/Paper plugin that creates fake player NPCs using PacketEvents. The NPCs spawn correctly with skins and are fully visible, but when I try to make them rotate their head to look at nearby players, the rotation packets are sent without errors but the NPCs don't rotate visually in-game.
What Works ✅
- NPC spawning (using
WrapperPlayServerPlayerInfoUpdate + WrapperPlayServerSpawnEntity)
- Player skins display correctly
- Entity metadata (skin layers, colors)
- Distance detection and angle calculations
- Packet creation and sending (no errors in logs)
What Doesn't Work ❌
- Visual rotation of the NPC's head/body
- All rotation-related packets seem to have no effect on the client
Implementation Details
How I spawn NPCs (this works perfectly)
public void sendSpawnPackets(Player player, int entityID, Location location, Pose entityPose) {
// STEP 1: PlayerInfo with skin
List<WrapperPlayServerPlayerInfoUpdate.PlayerInfo> playerInfoList = new ArrayList<>();
UserProfile userProfile = new UserProfile(npcUUID, npcName);
// Add skin texture
userProfile.getTextureProperties().add(
new TextureProperty("textures", skinValue, skinSignature)
);
WrapperPlayServerPlayerInfoUpdate.PlayerInfo playerInfo =
new WrapperPlayServerPlayerInfoUpdate.PlayerInfo(
userProfile,
false, // listed
0, // ping
GameMode.SURVIVAL,
null, // displayName
null // chatSession
);
playerInfoList.add(playerInfo);
// Send PlayerInfo
WrapperPlayServerPlayerInfoUpdate playerInfoPacket =
new WrapperPlayServerPlayerInfoUpdate(
WrapperPlayServerPlayerInfoUpdate.Action.ADD_PLAYER,
playerInfoList
);
PacketEvents.getAPI().getPlayerManager().sendPacket(player, playerInfoPacket);
// STEP 2: Spawn entity
WrapperPlayServerSpawnEntity spawnPacket = new WrapperPlayServerSpawnEntity(
entityID,
Optional.of(npcUUID),
EntityTypes.PLAYER,
new Vector3d(location.getX(), location.getY(), location.getZ()),
location.getPitch(),
location.getYaw(),
location.getYaw(), // headYaw
0, // data
Optional.of(new Vector3d(0, 0, 0)) // velocity
);
PacketEvents.getAPI().getPlayerManager().sendPacket(player, spawnPacket);
// STEP 3: Metadata for skin layers
EntityData skinLayers = new EntityData(
16, // index for displayed skin parts
EntityDataTypes.BYTE,
(byte) 127 // all layers enabled
);
WrapperPlayServerEntityMetadata metadataPacket =
new WrapperPlayServerEntityMetadata(entityID, List.of(skinLayers));
PacketEvents.getAPI().getPlayerManager().sendPacket(player, metadataPacket);
}
How I try to rotate the NPC (this doesn't work)
I run this every 2 ticks (synchronously on main thread) for NPCs within 6 blocks of players:
public static void sendHeadRotate(Player player, int entityID, Location npcLocation) {
if (player == null || !player.isOnline() || npcLocation == null) return;
// Calculate direction toward the player
Location newLoc = npcLocation.clone()
.setDirection(player.getLocation().clone().subtract(npcLocation).toVector());
// Try TELEPORT with same position but new rotation
WrapperPlayServerEntityTeleport teleportPacket = new WrapperPlayServerEntityTeleport(
entityID,
new Vector3d(npcLocation.getX(), npcLocation.getY(), npcLocation.getZ()),
newLoc.getYaw(),
newLoc.getPitch(),
false // onGround
);
PacketEvents.getAPI().getPlayerManager().sendPacket(player, teleportPacket);
// Also send head rotation
WrapperPlayServerEntityHeadLook headLookPacket =
new WrapperPlayServerEntityHeadLook(entityID, newLoc.getYaw());
PacketEvents.getAPI().getPlayerManager().sendPacket(player, headLookPacket);
}
Packet creation helpers:
public static WrapperPlayServerEntityTeleport createTeleport(int entityID, Location location) {
return new WrapperPlayServerEntityTeleport(
entityID,
new Vector3d(location.getX(), location.getY(), location.getZ()),
location.getYaw(),
location.getPitch(),
false // onGround
);
}
public static WrapperPlayServerEntityHeadLook createHeadRotation(int entityID, float yaw) {
// PacketEvents handles conversion automatically (degrees → protocol format)
return new WrapperPlayServerEntityHeadLook(entityID, yaw);
}
public static WrapperPlayServerEntityRotation createRotation(int entityID, float yaw, float pitch) {
return new WrapperPlayServerEntityRotation(entityID, yaw, pitch, true);
}
What I've Tried
- EntityRotation + EntityHeadLook packets → No visual effect
- EntityHeadLook only → No visual effect
- EntityTeleport with rotation + EntityHeadLook → No visual effect
- Async vs sync execution → No difference
- Different angle formats → PacketEvents documentation confirms float degrees are correct
Debug Results
With extensive logging, I confirmed:
- ✅ Packets are created successfully
- ✅ Packets are sent without exceptions
- ✅ Yaw/pitch calculations are correct (e.g., yaw changes from 213° to 214°)
- ✅ Distance detection works (only sending to players < 6 blocks away)
- ❌ NPCs don't rotate visually at all
Questions
-
Do rotation packets work for fake entities (client-side only) in Minecraft 1.21.10?
- My NPCs are created purely client-side with spawn packets (no server-side entity)
- Could this be why rotation packets have no effect?
-
Is there a specific packet sequence required?
- Should I send PlayerInfo again before rotation?
- Do I need to update metadata along with rotation?
-
Is this a known limitation in PacketEvents 2.10.1 or Minecraft 1.21.10?
- Did the protocol change regarding fake entity rotation?
-
Alternative approaches?
- Should I despawn and respawn the NPC with new rotation instead?
- Is there a metadata field for rotation I'm missing?
Expected Behavior
The NPC should visually rotate its head/body to face nearby players, similar to how real player entities look at each other.
Actual Behavior
The NPC remains frozen in its initial spawn rotation, even though rotation packets are being sent successfully every 2 ticks.
Any help or insights would be greatly appreciated! Is this a known issue, or am I missing something in my implementation?
Entity Head Rotation not working for fake player NPCs on Minecraft 1.21.10
Environment
Description
I'm developing a Spigot/Paper plugin that creates fake player NPCs using PacketEvents. The NPCs spawn correctly with skins and are fully visible, but when I try to make them rotate their head to look at nearby players, the rotation packets are sent without errors but the NPCs don't rotate visually in-game.
What Works ✅
WrapperPlayServerPlayerInfoUpdate+WrapperPlayServerSpawnEntity)What Doesn't Work ❌
Implementation Details
How I spawn NPCs (this works perfectly)
How I try to rotate the NPC (this doesn't work)
I run this every 2 ticks (synchronously on main thread) for NPCs within 6 blocks of players:
Packet creation helpers:
What I've Tried
Debug Results
With extensive logging, I confirmed:
Questions
Do rotation packets work for fake entities (client-side only) in Minecraft 1.21.10?
Is there a specific packet sequence required?
Is this a known limitation in PacketEvents 2.10.1 or Minecraft 1.21.10?
Alternative approaches?
Expected Behavior
The NPC should visually rotate its head/body to face nearby players, similar to how real player entities look at each other.
Actual Behavior
The NPC remains frozen in its initial spawn rotation, even though rotation packets are being sent successfully every 2 ticks.
Any help or insights would be greatly appreciated! Is this a known issue, or am I missing something in my implementation?