Send an extra headrotation packet since spigot resets head rotation now, make some protocollib methods async, bump avoid-water costs by one block

This commit is contained in:
fullwall 2023-07-08 21:36:04 +08:00
parent 5b5811cfea
commit c0be235538
11 changed files with 134 additions and 89 deletions

View File

@ -1,18 +1,26 @@
package net.citizensnpcs;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Play.Server;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.ListenerOptions;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
@ -28,11 +36,16 @@ import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.comphenix.protocol.wrappers.WrappedSignedProperty;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.NPCAddTraitEvent;
import net.citizensnpcs.api.event.NPCDespawnEvent;
import net.citizensnpcs.api.event.NPCEvent;
import net.citizensnpcs.api.event.NPCSpawnEvent;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.trait.MobType;
import net.citizensnpcs.api.util.Messaging;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.trait.MirrorTrait;
@ -40,10 +53,12 @@ import net.citizensnpcs.trait.RotationTrait;
import net.citizensnpcs.trait.RotationTrait.PacketRotationSession;
import net.citizensnpcs.util.NMS;
public class ProtocolLibListener {
public class ProtocolLibListener implements Listener {
private final Class<?> flagsClass;
private final ProtocolManager manager;
private final Map<UUID, MirrorTrait> mirrorTraits = Maps.newConcurrentMap();
private final Citizens plugin;
private final Map<Integer, RotationTrait> rotationTraits = Maps.newConcurrentMap();
public ProtocolLibListener(Citizens plugin) {
this.plugin = plugin;
@ -51,6 +66,7 @@ public class ProtocolLibListener {
flagsClass = MinecraftReflection.getMinecraftClass("RelativeMovement", "world.entity.RelativeMovement",
"EnumPlayerTeleportFlags", "PacketPlayOutPosition$EnumPlayerTeleportFlags",
"network.protocol.game.PacketPlayOutPosition$EnumPlayerTeleportFlags");
Bukkit.getPluginManager().registerEvents(this, plugin);
manager.addPacketListener(new PacketAdapter(plugin, ListenerPriority.HIGHEST, Server.ENTITY_METADATA) {
@Override
public void onPacketSending(PacketEvent event) {
@ -98,12 +114,14 @@ public class ProtocolLibListener {
}
}
});
manager.addPacketListener(new PacketAdapter(plugin, ListenerPriority.HIGHEST, Server.PLAYER_INFO) {
manager.addPacketListener(new PacketAdapter(plugin, ListenerPriority.HIGHEST, Arrays.asList(Server.PLAYER_INFO),
ListenerOptions.ASYNC) {
@Override
public void onPacketSending(PacketEvent event) {
int version = manager.getProtocolVersion(event.getPlayer());
if (version >= 761) {
NMS.onPlayerInfoAdd(event.getPlayer(), event.getPacket().getHandle());
NMS.onPlayerInfoAdd(event.getPlayer(), event.getPacket().getHandle(),
uuid -> mirrorTraits.get(uuid));
return;
}
List<PlayerInfoData> list = event.getPacket().getPlayerInfoDataLists().readSafely(0);
@ -114,10 +132,7 @@ public class ProtocolLibListener {
PlayerInfoData npcInfo = list.get(i);
if (npcInfo == null)
continue;
NPC npc = CitizensAPI.getNPCRegistry().getByUniqueIdGlobal(npcInfo.getProfile().getUUID());
if (npc == null || !npc.isSpawned())
continue;
MirrorTrait trait = npc.getTraitNullable(MirrorTrait.class);
MirrorTrait trait = mirrorTraits.get(npcInfo.getProfile().getUUID());
if (trait == null || !trait.isMirroring(event.getPlayer())) {
continue;
}
@ -148,46 +163,45 @@ public class ProtocolLibListener {
}
}
});
manager.addPacketListener(
new PacketAdapter(plugin, ListenerPriority.MONITOR, Server.ENTITY_HEAD_ROTATION, Server.ENTITY_LOOK) {
@Override
public void onPacketSending(PacketEvent event) {
NPC npc = getNPCFromPacket(event);
if (npc == null)
return;
manager.addPacketListener(new PacketAdapter(
plugin, ListenerPriority.MONITOR, Arrays.asList(Server.ENTITY_HEAD_ROTATION, Server.ENTITY_LOOK,
Server.REL_ENTITY_MOVE_LOOK, Server.ENTITY_MOVE_LOOK, Server.POSITION, Server.ENTITY_TELEPORT),
ListenerOptions.ASYNC) {
@Override
public void onPacketSending(PacketEvent event) {
RotationTrait trait = rotationTraits.get(event.getPacket().getIntegers().readSafely(0));
if (trait == null)
return;
RotationTrait trait = npc.getTraitNullable(RotationTrait.class);
if (trait == null)
return;
PacketRotationSession session = trait.getPacketSession(event.getPlayer());
if (session == null || !session.isActive())
return;
PacketRotationSession session = trait.getPacketSession(event.getPlayer());
if (session == null || !session.isActive())
return;
PacketContainer packet = event.getPacket();
PacketType type = event.getPacketType();
if (type == Server.ENTITY_HEAD_ROTATION) {
packet.getBytes().write(0, degToByte(session.getHeadYaw()));
} else if (type == Server.ENTITY_LOOK) {
packet.getBytes().write(0, degToByte(session.getBodyYaw()));
packet.getBytes().write(1, degToByte(session.getPitch()));
} else if (type == Server.ENTITY_MOVE_LOOK || type == Server.REL_ENTITY_MOVE_LOOK) {
packet.getBytes().write(0, degToByte(session.getBodyYaw()));
packet.getBytes().write(1, degToByte(session.getPitch()));
} else if (type == Server.POSITION) {
StructureModifier<Set<PlayerTeleportFlag>> flagsModifier = packet
.getSets(EnumWrappers.getGenericConverter(flagsClass, PlayerTeleportFlag.class));
Set<PlayerTeleportFlag> rel = flagsModifier.read(0);
rel.remove(PlayerTeleportFlag.ZYAW);
rel.remove(PlayerTeleportFlag.ZPITCH);
flagsModifier.write(0, rel);
packet.getFloat().write(0, session.getBodyYaw());
packet.getFloat().write(1, session.getPitch());
}
PacketContainer packet = event.getPacket();
PacketType type = event.getPacketType();
if (type == Server.ENTITY_HEAD_ROTATION) {
packet.getBytes().write(0, degToByte(session.getHeadYaw()));
} else if (type == Server.ENTITY_LOOK) {
packet.getBytes().write(0, degToByte(session.getBodyYaw()));
packet.getBytes().write(1, degToByte(session.getPitch()));
} else if (type == Server.ENTITY_MOVE_LOOK || type == Server.REL_ENTITY_MOVE_LOOK) {
packet.getBytes().write(0, degToByte(session.getBodyYaw()));
packet.getBytes().write(1, degToByte(session.getPitch()));
} else if (type == Server.POSITION) {
StructureModifier<Set<PlayerTeleportFlag>> flagsModifier = packet
.getSets(EnumWrappers.getGenericConverter(flagsClass, PlayerTeleportFlag.class));
Set<PlayerTeleportFlag> rel = flagsModifier.read(0);
rel.remove(PlayerTeleportFlag.ZYAW);
rel.remove(PlayerTeleportFlag.ZPITCH);
flagsModifier.write(0, rel);
packet.getFloat().write(0, session.getBodyYaw());
packet.getFloat().write(1, session.getPitch());
}
session.onPacketOverwritten();
}
});
session.onPacketOverwritten();
Messaging.log("OVERWRITTEN " + type + " " + packet.getHandle());
}
});
}
@ -214,6 +228,36 @@ public class ProtocolLibListener {
return entity instanceof NPCHolder ? ((NPCHolder) entity).getNPC() : null;
}
@EventHandler(ignoreCancelled = true)
public void onNPCDespawn(NPCDespawnEvent event) {
rotationTraits.remove(event.getNPC().getEntity().getEntityId());
mirrorTraits.remove(event.getNPC().getEntity().getUniqueId());
}
@EventHandler(ignoreCancelled = true)
public void onNPCSpawn(NPCSpawnEvent event) {
onSpawn(event);
}
private void onSpawn(NPCEvent event) {
if (event.getNPC().hasTrait(RotationTrait.class)) {
rotationTraits.put(event.getNPC().getEntity().getEntityId(),
event.getNPC().getTraitNullable(RotationTrait.class));
}
if (event.getNPC().hasTrait(MirrorTrait.class)
&& event.getNPC().getOrAddTrait(MobType.class).getType() == EntityType.PLAYER) {
mirrorTraits.put(event.getNPC().getEntity().getUniqueId(),
event.getNPC().getTraitNullable(MirrorTrait.class));
}
}
@EventHandler(ignoreCancelled = true)
public void onTraitAdd(NPCAddTraitEvent event) {
if (!event.getNPC().isSpawned())
return;
onSpawn(event);
}
public enum PlayerTeleportFlag {
X,
Y,

View File

@ -158,10 +158,10 @@ public class AStarNavigationStrategy extends AbstractPathStrategy {
@Override
public float getCost(BlockSource source, PathPoint point) {
Vector pos = point.getVector();
Material above = source.getMaterialAt(pos.setY(pos.getY() + 1));
Material above = source.getMaterialAt(pos.getBlockX(), pos.getBlockY() + 1, pos.getBlockZ());
return params.avoidWater() && (MinecraftBlockExaminer.isLiquid(above)
|| MinecraftBlockExaminer.isLiquidOrInLiquid(pos.toLocation(source.getWorld()).getBlock()))
? 1F
? 2F
: 0F;
}

View File

@ -11,9 +11,9 @@ import net.citizensnpcs.api.trait.TraitName;
@TraitName("mirrortrait")
public class MirrorTrait extends Trait {
@Persist
private boolean enabled;
private volatile boolean enabled;
@Persist
private boolean mirrorName;
private volatile boolean mirrorName;
public MirrorTrait() {
super("mirrortrait");

View File

@ -18,6 +18,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.persistence.Persistable;
import net.citizensnpcs.api.trait.Trait;
@ -32,7 +33,7 @@ public class RotationTrait extends Trait {
private final RotationParams globalParameters = new RotationParams();
private final RotationSession globalSession = new RotationSession(globalParameters);
private final List<PacketRotationSession> packetSessions = Lists.newArrayList();
private final Map<UUID, PacketRotationSession> packetSessionsByUUID = Maps.newHashMap();
private final Map<UUID, PacketRotationSession> packetSessionsByUUID = Maps.newConcurrentMap();
public RotationTrait() {
super("rotationtrait");
@ -104,6 +105,9 @@ public class RotationTrait extends Trait {
public void run() {
if (!npc.isSpawned())
return;
if (npc.data().get(NPC.Metadata.RESET_PITCH_ON_TICK, false)) {
NMS.setPitch(npc.getEntity(), 0);
}
Set<PacketRotationSession> ran = Sets.newHashSet();
for (Iterator<PacketRotationSession> itr = Iterables.concat(packetSessions, packetSessionsByUUID.values())
@ -146,9 +150,9 @@ public class RotationTrait extends Trait {
}
public static class PacketRotationSession {
private boolean ended;
private volatile boolean ended;
private final RotationSession session;
private PacketRotationTriple triple;
private volatile PacketRotationTriple triple;
public PacketRotationSession(RotationSession session) {
this.session = session;
@ -201,9 +205,9 @@ public class RotationTrait extends Trait {
}
private static class PacketRotationTriple extends EntityRotation {
private float lastBodyYaw;
private float lastHeadYaw;
private float lastPitch;
private volatile float lastBodyYaw;
private volatile float lastHeadYaw;
private volatile float lastPitch;
public PacketRotationTriple(Entity entity) {
super(entity);

View File

@ -410,7 +410,8 @@ public class LinearWaypointProvider implements EnumerableWaypointProvider {
if (showingMarkers) {
markers.createMarker(element, element.getLocation().clone());
}
Messaging.sendTr(player, Messages.LINEAR_WAYPOINT_EDITOR_ADDED_WAYPOINT, formatLoc(at), idx);
Messaging.sendTr(player, Messages.LINEAR_WAYPOINT_EDITOR_ADDED_WAYPOINT, formatLoc(at),
waypoints.size());
} else if (waypoints.size() > 0 && !event.getPlayer().isSneaking()) {
event.setCancelled(true);

View File

@ -7,7 +7,9 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@ -57,6 +59,7 @@ import net.citizensnpcs.npc.ai.MCNavigationStrategy.MCNavigator;
import net.citizensnpcs.npc.ai.MCTargetStrategy.TargetNavigator;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.npc.skin.SkinnableEntity;
import net.citizensnpcs.trait.MirrorTrait;
import net.citizensnpcs.trait.PacketNPC;
import net.citizensnpcs.trait.versioned.CamelTrait.CamelPose;
import net.citizensnpcs.trait.versioned.SnifferTrait.SnifferState;
@ -640,8 +643,8 @@ public class NMS {
BRIDGE.mount(entity, passenger);
}
public static void onPlayerInfoAdd(Player player, Object source) {
BRIDGE.onPlayerInfoAdd(player, source);
public static void onPlayerInfoAdd(Player player, Object source, Function<UUID, MirrorTrait> mirrorTraits) {
BRIDGE.onPlayerInfoAdd(player, source, mirrorTraits);
}
public static InventoryView openAnvilInventory(Player player, Inventory inventory, String title) {

View File

@ -2,6 +2,8 @@ package net.citizensnpcs.util;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.function.Function;
import org.bukkit.Location;
import org.bukkit.Sound;
@ -40,6 +42,7 @@ import net.citizensnpcs.api.util.EntityDim;
import net.citizensnpcs.npc.ai.MCNavigationStrategy.MCNavigator;
import net.citizensnpcs.npc.ai.MCTargetStrategy.TargetNavigator;
import net.citizensnpcs.npc.skin.SkinnableEntity;
import net.citizensnpcs.trait.MirrorTrait;
import net.citizensnpcs.trait.versioned.CamelTrait.CamelPose;
import net.citizensnpcs.trait.versioned.SnifferTrait.SnifferState;
import net.citizensnpcs.util.EntityPacketTracker.PacketAggregator;
@ -134,7 +137,7 @@ public interface NMSBridge {
public void mount(Entity entity, Entity passenger);
public default void onPlayerInfoAdd(Player player, Object source) {
public default void onPlayerInfoAdd(Player player, Object source, Function<UUID, MirrorTrait> mirrorTraits) {
}
public InventoryView openAnvilInventory(Player player, Inventory anvil, String title);

View File

@ -15,7 +15,9 @@ import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@ -54,7 +56,6 @@ import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.scoreboard.Team;
import org.bukkit.util.Vector;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@ -705,12 +706,7 @@ public class NMSImpl implements NMSBridge {
Entity handle = getHandle(entity);
if (handle == null || handle.passengers == null)
return Lists.newArrayList();
return Lists.transform(handle.passengers, new Function<Entity, org.bukkit.entity.Entity>() {
@Override
public org.bukkit.entity.Entity apply(Entity input) {
return input.getBukkitEntity();
}
});
return Lists.transform(handle.passengers, input -> input.getBukkitEntity());
}
@Override
@ -777,7 +773,7 @@ public class NMSImpl implements NMSBridge {
}));
Node last = list.size() > 0 ? list.get(list.size() - 1) : null;
final Path path = new Path(list, last != null ? new BlockPos(last.x, last.y, last.z) : null, true);
return getTargetNavigator(entity, params, (input) -> {
return getTargetNavigator(entity, params, input -> {
return input.moveTo(path, params.speed());
});
}
@ -1177,7 +1173,7 @@ public class NMSImpl implements NMSBridge {
}
@Override
public void onPlayerInfoAdd(Player player, Object raw) {
public void onPlayerInfoAdd(Player player, Object raw, Function<UUID, MirrorTrait> mirrorTraits) {
ClientboundPlayerInfoUpdatePacket packet = (ClientboundPlayerInfoUpdatePacket) raw;
List<ClientboundPlayerInfoUpdatePacket.Entry> list = Lists.newArrayList(packet.entries());
boolean changed = false;
@ -1185,9 +1181,10 @@ public class NMSImpl implements NMSBridge {
ClientboundPlayerInfoUpdatePacket.Entry npcInfo = list.get(i);
if (npcInfo == null)
continue;
NPC npc = CitizensAPI.getNPCRegistry().getByUniqueIdGlobal(npcInfo.profileId());
if (npc == null || !npc.isSpawned())
MirrorTrait trait = mirrorTraits.apply(npcInfo.profileId());
if (trait == null || !trait.isMirroring(player)) {
continue;
}
if (Setting.DISABLE_TABLIST.asBoolean() != npcInfo.listed()) {
list.set(i,
new ClientboundPlayerInfoUpdatePacket.Entry(npcInfo.profileId(), npcInfo.profile(),
@ -1196,10 +1193,6 @@ public class NMSImpl implements NMSBridge {
npcInfo.chatSession()));
changed = true;
}
MirrorTrait trait = npc.getTraitNullable(MirrorTrait.class);
if (trait == null || !trait.isMirroring(player)) {
continue;
}
GameProfile playerProfile = NMS.getProfile(player);
if (trait.mirrorName()) {
list.set(i,

View File

@ -56,9 +56,9 @@ public class HorseSkeletonController extends MobEntityController {
public static class EntityHorseSkeletonNPC extends SkeletonHorse implements NPCHolder {
private double baseMovementSpeed;
private final CitizensNPC npc;
private boolean riding;
public EntityHorseSkeletonNPC(EntityType<? extends SkeletonHorse> types, Level level) {
this(types, level, null);
}

View File

@ -18,6 +18,7 @@ import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
import net.minecraft.network.protocol.game.ClientboundAnimatePacket;
import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ChunkMap.TrackedEntity;
import net.minecraft.server.level.ServerEntity;
@ -69,6 +70,8 @@ public class CitizensEntityTracker extends ChunkMap.TrackedEntity {
return;
}
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
NMSImpl.sendPacket(entityplayer.getBukkitEntity(),
new ClientboundRotateHeadPacket(tracker, (byte) (tracker.getYHeadRot() * 256.0F / 360.0F)));
NMSImpl.sendPacket(entityplayer.getBukkitEntity(), new ClientboundAnimatePacket(tracker, 0));
NMS.sendTabListRemove(entityplayer.getBukkitEntity(), (Player) tracker.getBukkitEntity());
}, Setting.TABLIST_REMOVE_PACKET_DELAY.asTicks());

View File

@ -14,7 +14,9 @@ import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@ -53,7 +55,6 @@ import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.scoreboard.Team;
import org.bukkit.util.Vector;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@ -704,12 +705,7 @@ public class NMSImpl implements NMSBridge {
Entity handle = getHandle(entity);
if (handle == null || handle.passengers == null)
return Lists.newArrayList();
return Lists.transform(handle.passengers, new Function<Entity, org.bukkit.entity.Entity>() {
@Override
public org.bukkit.entity.Entity apply(Entity input) {
return input.getBukkitEntity();
}
});
return Lists.transform(handle.passengers, input -> input.getBukkitEntity());
}
@Override
@ -1176,7 +1172,7 @@ public class NMSImpl implements NMSBridge {
}
@Override
public void onPlayerInfoAdd(Player player, Object raw) {
public void onPlayerInfoAdd(Player player, Object raw, Function<UUID, MirrorTrait> mirrorTraits) {
ClientboundPlayerInfoUpdatePacket packet = (ClientboundPlayerInfoUpdatePacket) raw;
List<ClientboundPlayerInfoUpdatePacket.Entry> list = Lists.newArrayList(packet.entries());
boolean changed = false;
@ -1184,9 +1180,11 @@ public class NMSImpl implements NMSBridge {
ClientboundPlayerInfoUpdatePacket.Entry npcInfo = list.get(i);
if (npcInfo == null)
continue;
NPC npc = CitizensAPI.getNPCRegistry().getByUniqueIdGlobal(npcInfo.profileId());
if (npc == null || !npc.isSpawned())
MirrorTrait trait = mirrorTraits.apply(npcInfo.profileId());
if (trait == null || !trait.isMirroring(player)) {
continue;
}
if (Setting.DISABLE_TABLIST.asBoolean() != npcInfo.listed()) {
list.set(i,
new ClientboundPlayerInfoUpdatePacket.Entry(npcInfo.profileId(), npcInfo.profile(),
@ -1195,10 +1193,6 @@ public class NMSImpl implements NMSBridge {
npcInfo.chatSession()));
changed = true;
}
MirrorTrait trait = npc.getTraitNullable(MirrorTrait.class);
if (trait == null || !trait.isMirroring(player)) {
continue;
}
GameProfile playerProfile = NMS.getProfile(player);
if (trait.mirrorName()) {
list.set(i,