diff --git a/core/src/main/java/com/rexcantor64/triton/packetinterceptor/protocollib/EntitiesPacketHandler.java b/core/src/main/java/com/rexcantor64/triton/packetinterceptor/protocollib/EntitiesPacketHandler.java index bd9f2f2c..6711c3a2 100644 --- a/core/src/main/java/com/rexcantor64/triton/packetinterceptor/protocollib/EntitiesPacketHandler.java +++ b/core/src/main/java/com/rexcantor64/triton/packetinterceptor/protocollib/EntitiesPacketHandler.java @@ -5,7 +5,14 @@ import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.utility.MinecraftVersion; -import com.comphenix.protocol.wrappers.*; +import com.comphenix.protocol.wrappers.Converters; +import com.comphenix.protocol.wrappers.EnumWrappers; +import com.comphenix.protocol.wrappers.PlayerInfoData; +import com.comphenix.protocol.wrappers.WrappedChatComponent; +import com.comphenix.protocol.wrappers.WrappedDataValue; +import com.comphenix.protocol.wrappers.WrappedDataWatcher; +import com.comphenix.protocol.wrappers.WrappedGameProfile; +import com.comphenix.protocol.wrappers.WrappedWatchableObject; import com.rexcantor64.triton.Triton; import com.rexcantor64.triton.api.wrappers.EntityType; import com.rexcantor64.triton.player.LanguagePlayer; @@ -24,7 +31,15 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; @@ -86,9 +101,22 @@ private void handleSpawnEntity(PacketEvent packet, SpigotLanguagePlayer language return; } if (entityType == EntityType.PLAYER) { - // Ignore human entities since they're handled separately - // This packet should never spawn one either way - return; + if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) { // 1.20.2 + // Ignore human entities since they're handled separately + // This packet should never spawn one either way + return; + } + // TODO For now, it is only possible to translate NPCs that are saved server side + // Fetch entity object using main thread, otherwise we'll get concurrency issues + Triton.asSpigot() + .callSync(() -> packet.getPacket().getEntityModifier(packet).readSafely(0)) + .ifPresent(entity -> addEntity( + languagePlayer.getPlayersMap(), + packet.getPlayer().getWorld(), + entity.getEntityId(), + entity + ) + ); } // Add entity to cache @@ -159,6 +187,7 @@ private void handleSpawnEntityLiving(PacketEvent packet, SpigotLanguagePlayer la * translation is enabled for human entities. * Due to the complexity of translating human entities, it is only possible to translate * those stored server side by the server itself. + * This packet was removed in MC 1.20.2 * * @param packet ProtocolLib's packet event. * @param languagePlayer The language player this packet is being sent to. @@ -619,7 +648,13 @@ private void refreshHumanEntities(@NotNull SpigotLanguagePlayer languagePlayer, val packetAdd = getPlayerInfoAddPacket(humanEntity); // Spawn the entity again - val packetSpawn = createPacket(PacketType.Play.Server.NAMED_ENTITY_SPAWN); + PacketContainer packetSpawn; + if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) { // 1.20.2 + packetSpawn = createPacket(PacketType.Play.Server.SPAWN_ENTITY); + } else { + // noinspection deprecation + packetSpawn = createPacket(PacketType.Play.Server.NAMED_ENTITY_SPAWN); + } packetSpawn.getIntegers().writeSafely(0, humanEntity.getEntityId()); packetSpawn.getUUIDs().writeSafely(0, humanEntity.getUniqueId()); if (getMcVersion() < 9) { @@ -638,7 +673,18 @@ private void refreshHumanEntities(@NotNull SpigotLanguagePlayer languagePlayer, packetSpawn.getBytes() .writeSafely(0, (byte) (int) (humanEntity.getLocation().getYaw() * 256.0F / 360.0F)) .writeSafely(1, (byte) (int) (humanEntity.getLocation().getPitch() * 256.0F / 360.0F)); - packetSpawn.getDataWatcherModifier().writeSafely(0, WrappedDataWatcher.getEntityWatcher(humanEntity)); + if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) { // 1.20.2 + packetSpawn.getBytes().writeSafely(2, (byte) 0); + val velocity = humanEntity.getVelocity(); + packetSpawn.getIntegers() + .writeSafely(1, (int) (Math.max(-3.9d, Math.min(3.9d, velocity.getX())) * 8000.0d)) + .writeSafely(2, (int) (Math.max(-3.9d, Math.min(3.9d, velocity.getY())) * 8000.0d)) + .writeSafely(3, (int) (Math.max(-3.9d, Math.min(3.9d, velocity.getZ())) * 8000.0d)) + .writeSafely(4, 0); // "entity data" + packetSpawn.getEntityTypeModifier().writeSafely(0, org.bukkit.entity.EntityType.PLAYER); + } else { + packetSpawn.getDataWatcherModifier().writeSafely(0, WrappedDataWatcher.getEntityWatcher(humanEntity)); + } // Even though this is sent in the spawn packet, we still need to send it again for some reason val packetLook = createPacket(PacketType.Play.Server.ENTITY_HEAD_ROTATION);