diff --git a/src/main/java/xiamomc/morph/backends/server/renderer/network/DisplayParameters.java b/src/main/java/xiamomc/morph/backends/server/renderer/network/DisplayParameters.java index 66d0c045..dd45c622 100644 --- a/src/main/java/xiamomc/morph/backends/server/renderer/network/DisplayParameters.java +++ b/src/main/java/xiamomc/morph/backends/server/renderer/network/DisplayParameters.java @@ -27,11 +27,14 @@ public GameProfile getProfile() private final EntityType entityType; private final SingleWatcher singleWatcher; private final GameProfile gameProfile; - private boolean dontRandomProfileUUID; + private boolean dontRandomProfileUUID = false; + private boolean includeMeta = true; - public void setDontRandomProfileUUID() + public DisplayParameters setDontRandomProfileUUID() { dontRandomProfileUUID = true; + + return this; } public boolean dontRandomProfileUUID() @@ -39,6 +42,18 @@ public boolean dontRandomProfileUUID() return dontRandomProfileUUID; } + public DisplayParameters setDontIncludeMeta() + { + includeMeta = false; + + return this; + } + + public boolean includeMeta() + { + return includeMeta; + } + public DisplayParameters(EntityType bindingType, SingleWatcher watcher, GameProfile profile) { this.entityType = bindingType; diff --git a/src/main/java/xiamomc/morph/backends/server/renderer/network/PacketFactory.java b/src/main/java/xiamomc/morph/backends/server/renderer/network/PacketFactory.java index a98b4d3a..1e06a94b 100644 --- a/src/main/java/xiamomc/morph/backends/server/renderer/network/PacketFactory.java +++ b/src/main/java/xiamomc/morph/backends/server/renderer/network/PacketFactory.java @@ -107,8 +107,11 @@ public List buildSpawnPackets(Player player, DisplayParameters ProtocolEquipment.toPairs(player.getEquipment())); packets.add(PacketContainer.fromPacket(equipmentPacket)); - var watcher = parameters.getWatcher(); - packets.add(buildFullMetaPacket(player, watcher)); + if (parameters.includeMeta()) + { + var watcher = parameters.getWatcher(); + packets.add(buildFullMetaPacket(player, watcher)); + } if (player.getVehicle() != null) { diff --git a/src/main/java/xiamomc/morph/backends/server/renderer/network/ProtocolEquipment.java b/src/main/java/xiamomc/morph/backends/server/renderer/network/ProtocolEquipment.java index 41e62a72..278f8276 100644 --- a/src/main/java/xiamomc/morph/backends/server/renderer/network/ProtocolEquipment.java +++ b/src/main/java/xiamomc/morph/backends/server/renderer/network/ProtocolEquipment.java @@ -5,6 +5,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.entity.EquipmentSlot; import org.bukkit.inventory.EntityEquipment; +import xiamomc.morph.misc.DisguiseEquipment; public class ProtocolEquipment { @@ -13,9 +14,7 @@ public static ObjectArrayList> toPairs(EntityEqui var list = new ObjectArrayList>(); for (org.bukkit.inventory.EquipmentSlot bukkitSlot : org.bukkit.inventory.EquipmentSlot.values()) - { list.add(toEquipmentPair(equipment, bukkitSlot)); - } return list; } diff --git a/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/EquipmentPacketListener.java b/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/EquipmentPacketListener.java index 314889d4..fbca5372 100644 --- a/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/EquipmentPacketListener.java +++ b/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/EquipmentPacketListener.java @@ -4,21 +4,27 @@ import com.comphenix.protocol.events.ListeningWhitelist; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.injector.GamePhase; -import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; import org.bukkit.entity.Player; -import xiamomc.morph.MorphPlugin; import xiamomc.morph.backends.server.renderer.network.PacketFactory; import xiamomc.morph.backends.server.renderer.network.registries.EntryIndex; import xiamomc.morph.backends.server.renderer.network.registries.RenderRegistry; import xiamomc.morph.utilities.NmsUtils; import xiamomc.pluginbase.Annotations.Resolved; +import java.util.Map; + public class EquipmentPacketListener extends ProtocolListener { @Resolved(shouldSolveImmediately = true) private RenderRegistry registry; + public EquipmentPacketListener() + { + registry.onUnRegister(this, alreadyFake::remove); + } + @Override public String getIdentifier() { @@ -40,6 +46,8 @@ public void onPacketSending(PacketEvent event) onEquipmentPacket((ClientboundSetEquipmentPacket) event.getPacket().getHandle(), event); } + private final Map alreadyFake = new Object2ObjectOpenHashMap<>(); + private void onEquipmentPacket(ClientboundSetEquipmentPacket packet, PacketEvent event) { if (event.getPacket().getMeta(PacketFactory.MORPH_PACKET_METAKEY).isPresent()) @@ -47,6 +55,13 @@ private void onEquipmentPacket(ClientboundSetEquipmentPacket packet, PacketEvent //获取此包的来源实体 var sourceNmsEntity = NmsUtils.getNmsLevel(event.getPlayer().getWorld()).getEntity(packet.getEntity()); + if (sourceNmsEntity == null) + { + logger.warn("A packet from a player that doesn't exist in its world?!"); + logger.warn("Packet: " + event.getPacketType()); + return; + } + if (!(sourceNmsEntity.getBukkitEntity() instanceof Player sourcePlayer)) return; var watcher = registry.getWatcher(sourcePlayer.getUniqueId()); @@ -55,9 +70,21 @@ private void onEquipmentPacket(ClientboundSetEquipmentPacket packet, PacketEvent return; if (!watcher.getOrDefault(EntryIndex.DISPLAY_FAKE_EQUIPMENT, false)) + { + alreadyFake.remove(sourcePlayer); return; + } + + if (alreadyFake.getOrDefault(sourcePlayer, false)) + { + //如果已经在显示伪装物品,那么只取消此包 + event.setCancelled(true); + return; + } event.setPacket(getFactory().getEquipmentPacket(sourcePlayer, watcher)); + + alreadyFake.put(sourcePlayer, true); } @Override diff --git a/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/MetaPacketListener.java b/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/MetaPacketListener.java index e87a0e61..093532f6 100644 --- a/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/MetaPacketListener.java +++ b/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/MetaPacketListener.java @@ -42,6 +42,13 @@ private void onMetaPacket(ClientboundSetEntityDataPacket packet, PacketEvent pac { //获取此包的来源实体 var sourceNmsEntity = NmsUtils.getNmsLevel(packetEvent.getPlayer().getWorld()).getEntity(packet.id()); + if (sourceNmsEntity == null) + { + logger.warn("A packet from a player that doesn't exist in its world?!"); + logger.warn("Packet: " + packetEvent.getPacketType()); + return; + } + if (!(sourceNmsEntity.getBukkitEntity() instanceof Player sourcePlayer)) return; var watcher = registry.getWatcher(sourcePlayer.getUniqueId()); diff --git a/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/PlayerLookPacketListener.java b/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/PlayerLookPacketListener.java index c89f65d9..3d8e5dd7 100644 --- a/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/PlayerLookPacketListener.java +++ b/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/PlayerLookPacketListener.java @@ -55,6 +55,10 @@ else if (packetType == PacketType.Play.Server.ENTITY_TELEPORT) var cast = (ClientboundTeleportEntityPacket)packet.getHandle(); onTeleport(cast, event); } + else + { + logger.error("Invalid packet type: " + packetType); + } } @Resolved(shouldSolveImmediately = true) private RenderRegistry registry; @@ -63,6 +67,13 @@ private void onTeleport(ClientboundTeleportEntityPacket packet, PacketEvent even { //获取此包的来源实体 var sourceNmsEntity = NmsUtils.getNmsLevel(event.getPlayer().getWorld()).getEntity(packet.getId()); + if (sourceNmsEntity == null) + { + logger.warn("A packet from a player that doesn't exist in its world?!"); + logger.warn("Packet: " + event.getPacketType()); + return; + } + if (!(sourceNmsEntity.getBukkitEntity() instanceof Player sourcePlayer)) return; var watcher = registry.getWatcher(sourcePlayer.getUniqueId()); @@ -73,6 +84,9 @@ private void onTeleport(ClientboundTeleportEntityPacket packet, PacketEvent even var isDragon = watcher.getEntityType() == EntityType.ENDER_DRAGON; var isPhantom = watcher.getEntityType() == EntityType.PHANTOM; + if (!isDragon && !isPhantom) + return; + var yaw = packet.getyRot(); var pitch = packet.getxRot(); @@ -94,22 +108,23 @@ private void onHeadRotation(ClientboundRotateHeadPacket packet, PacketEvent even { //获取此包的来源实体 var sourceNmsEntity = packet.getEntity(NmsUtils.getNmsLevel(event.getPlayer().getWorld())); + if (sourceNmsEntity == null) + { + logger.warn("A packet from a player that doesn't exist in its world?!"); + logger.warn("Packet: " + event.getPacketType()); + return; + } + if (!(sourceNmsEntity.getBukkitEntity() instanceof Player sourcePlayer)) return; var watcher = registry.getWatcher(sourcePlayer.getUniqueId()); - if (watcher == null) + if (watcher == null || watcher.getEntityType() != EntityType.ENDER_DRAGON) return; - var headYaw = packet.getYHeadRot(); - - if (watcher.getEntityType() == EntityType.ENDER_DRAGON) - { - var finalYaw = ((sourcePlayer.getYaw() + 180f) / 360f) * 256f; - headYaw = (byte)finalYaw; - } + var newHeadYaw = (byte)(((sourcePlayer.getYaw() + 180f) / 360f) * 256f); - var newPacket = new ClientboundRotateHeadPacket(sourceNmsEntity, headYaw); + var newPacket = new ClientboundRotateHeadPacket(sourceNmsEntity, newHeadYaw); var finalPacket = PacketContainer.fromPacket(newPacket); finalPacket.setMeta(PacketFactory.MORPH_PACKET_METAKEY, true); @@ -120,6 +135,13 @@ private void onLookPacket(ClientboundMoveEntityPacket packet, PacketEvent event) { //获取此包的来源实体 var sourceNmsEntity = packet.getEntity(NmsUtils.getNmsLevel(event.getPlayer().getWorld())); + if (sourceNmsEntity == null) + { + logger.warn("A packet from a player that doesn't exist in its world?!"); + logger.warn("Packet: " + event.getPacketType()); + return; + } + if (!(sourceNmsEntity.getBukkitEntity() instanceof Player sourcePlayer)) return; var watcher = registry.getWatcher(sourcePlayer.getUniqueId()); @@ -130,6 +152,9 @@ private void onLookPacket(ClientboundMoveEntityPacket packet, PacketEvent event) var isDragon = watcher.getEntityType() == EntityType.ENDER_DRAGON; var isPhantom = watcher.getEntityType() == EntityType.PHANTOM; + if (!isDragon && !isPhantom) + return; + var yaw = packet.getyRot(); var pitch = packet.getxRot(); @@ -144,7 +169,9 @@ private void onLookPacket(ClientboundMoveEntityPacket packet, PacketEvent event) ClientboundMoveEntityPacket newPacket; - if (event.getPacketType() == PacketType.Play.Server.ENTITY_LOOK) + var packetType = event.getPacketType(); + + if (packetType == PacketType.Play.Server.ENTITY_LOOK) { newPacket = new ClientboundMoveEntityPacket.Rot( sourcePlayer.getEntityId(), @@ -152,7 +179,7 @@ private void onLookPacket(ClientboundMoveEntityPacket packet, PacketEvent event) packet.isOnGround() ); } - else if (event.getPacketType() == PacketType.Play.Server.REL_ENTITY_MOVE) + else if (packetType == PacketType.Play.Server.REL_ENTITY_MOVE) { newPacket = new ClientboundMoveEntityPacket.Pos( sourcePlayer.getEntityId(), @@ -160,7 +187,7 @@ else if (event.getPacketType() == PacketType.Play.Server.REL_ENTITY_MOVE) packet.isOnGround() ); } - else if (event.getPacketType() == PacketType.Play.Server.REL_ENTITY_MOVE_LOOK) + else if (packetType == PacketType.Play.Server.REL_ENTITY_MOVE_LOOK) { newPacket = new ClientboundMoveEntityPacket.PosRot( sourcePlayer.getEntityId(), @@ -171,7 +198,8 @@ else if (event.getPacketType() == PacketType.Play.Server.REL_ENTITY_MOVE_LOOK) } else { - throw new IllegalArgumentException("Unknown type " + event.getPacketType()); + logger.error("Unknown ClientboundMoveEntityPacket: " + packetType); + return; } var finalPacket = PacketContainer.fromPacket(newPacket); diff --git a/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/SpawnPacketHandler.java b/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/SpawnPacketHandler.java index f11bec9b..f1b291b3 100644 --- a/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/SpawnPacketHandler.java +++ b/src/main/java/xiamomc/morph/backends/server/renderer/network/listeners/SpawnPacketHandler.java @@ -73,19 +73,19 @@ private void unDisguiseForPlayer(@Nullable Player player) var gameProfile = ((CraftPlayer) player).getProfile(); var watcher = new PlayerWatcher(player); - var parameters = new DisplayParameters(org.bukkit.entity.EntityType.PLAYER, watcher, gameProfile); - parameters.setDontRandomProfileUUID(); + var parameters = new DisplayParameters(org.bukkit.entity.EntityType.PLAYER, watcher, gameProfile) + .setDontRandomProfileUUID(); + var spawnPackets = getFactory().buildSpawnPackets(player, parameters); var removePacket = new ClientboundRemoveEntitiesPacket(player.getEntityId()); var rmPacketContainer = PacketContainer.fromPacket(removePacket); - affectedPlayers.forEach(p -> protocolManager.sendServerPacket(p, rmPacketContainer)); affectedPlayers.forEach(p -> { + protocolManager.sendServerPacket(p, rmPacketContainer); + for (PacketContainer packet : spawnPackets) - { protocolManager.sendServerPacket(p, packet); - } }); } @@ -95,7 +95,7 @@ private void refreshStateForPlayer(@Nullable Player player) var watcher = registry.getWatcher(player.getUniqueId()); if (watcher == null) - throw new NullDependencyException("Null RegistryParameters for a existing player?!"); + throw new NullDependencyException("Null Watcher for a existing player?!"); refreshStateForPlayer(player, new DisplayParameters(watcher.getEntityType(), watcher, watcher.get(EntryIndex.PROFILE))); } @@ -143,15 +143,14 @@ private void refreshStateForPlayer(@Nullable Player player, @NotNull DisplayPara gameProfile = Objects.requireNonNullElseGet(cachedProfile, () -> new GameProfile(UUID.randomUUID(), disguiseName)); } - var parametersFinal = new DisplayParameters(displayType, watcher, gameProfile); + var parametersFinal = new DisplayParameters(displayType, watcher, gameProfile).setDontIncludeMeta(); var spawnPackets = getFactory().buildSpawnPackets(player, parametersFinal); - affectedPlayers.forEach(p -> protocolManager.sendServerPacket(p, packetRemoveContainer)); - - spawnPackets.forEach(packet -> + affectedPlayers.forEach(p -> { - for (var visiblePlayer : affectedPlayers) - protocolManager.sendServerPacket(visiblePlayer, packet); + protocolManager.sendServerPacket(p, packetRemoveContainer); + + spawnPackets.forEach(packet -> protocolManager.sendServerPacket(p, packet)); }); } diff --git a/src/main/java/xiamomc/morph/misc/DisguiseEquipment.java b/src/main/java/xiamomc/morph/misc/DisguiseEquipment.java index 957c8132..d292b150 100644 --- a/src/main/java/xiamomc/morph/misc/DisguiseEquipment.java +++ b/src/main/java/xiamomc/morph/misc/DisguiseEquipment.java @@ -1,5 +1,6 @@ package xiamomc.morph.misc; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.apache.commons.lang3.NotImplementedException; import org.bukkit.entity.Entity; import org.bukkit.inventory.EntityEquipment; @@ -11,11 +12,22 @@ import xiamomc.morph.utilities.ItemUtils; import java.util.Arrays; +import java.util.Map; public class DisguiseEquipment implements EntityEquipment { private final ItemStack[] itemStacks = new ItemStack[EquipmentSlot.values().length]; + private final Map dirtyStacks = new Object2ObjectOpenHashMap<>(); + + public Map getDirty() + { + var map = new Object2ObjectOpenHashMap<>(dirtyStacks); + dirtyStacks.clear(); + + return map; + } + @Override public void setItem(@NotNull EquipmentSlot slot, @Nullable ItemStack item) { @@ -49,7 +61,7 @@ public void setHandItems(@Nullable ItemStack... stacks) * @return An {@link ItemStack} */ @Override - public @Nullable ItemStack getItem(@NotNull EquipmentSlot slot) + public @NotNull ItemStack getItem(@NotNull EquipmentSlot slot) { return allowNull ? itemStacks[slot.ordinal()] : DisguiseUtils.itemOrAir(itemStacks[slot.ordinal()]); }