From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Cryptite Date: Mon, 3 Oct 2022 08:17:50 -0500 Subject: [PATCH] Equipment Packet Caching diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEquipmentPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEquipmentPacket.java index 5a8f850b447fc3a4bd0eb0c505bbdfc8be7115e8..34d74735b7a7d258c6bd14bb7e5406934a208a31 100644 --- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEquipmentPacket.java +++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEquipmentPacket.java @@ -18,6 +18,15 @@ public class ClientboundSetEquipmentPacket implements Packet> equipmentList, net.minecraft.world.entity.LivingEntity entity, String tag) { + this.entity = id; + slots = new java.util.ArrayList<>(equipmentList.size()); + for (Pair pair : equipmentList) { + EquipmentSlot slot = pair.getFirst(); + slots.add(Pair.of(slot, entity.getOrCreateCachedEquipmentItem(tag, slot, pair.getSecond()))); + } + } + public ClientboundSetEquipmentPacket(FriendlyByteBuf buf) { this.entity = buf.readVarInt(); EquipmentSlot[] equipmentSlots = EquipmentSlot.values(); diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java index d9481017e36f607c6dee8ab833a36ac700267a9f..48830e44dcae2a5263dbae65506c5cb29e1ea2a7 100644 --- a/src/main/java/net/minecraft/server/level/ServerEntity.java +++ b/src/main/java/net/minecraft/server/level/ServerEntity.java @@ -3,12 +3,8 @@ package net.minecraft.server.level; import com.google.common.collect.Lists; import com.mojang.datafixers.util.Pair; import com.mojang.logging.LogUtils; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.Set; + +import java.util.*; import java.util.function.Consumer; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundAddMobPacket; @@ -310,27 +306,8 @@ public class ServerEntity { consumer.accept(new ClientboundSetEntityMotionPacket(this.entity.getId(), this.ap)); } - if (this.entity instanceof LivingEntity) { - List> list = Lists.newArrayList(); - EquipmentSlot[] aenumitemslot = EquipmentSlot.values(); - int i = aenumitemslot.length; - - for (int j = 0; j < i; ++j) { - EquipmentSlot enumitemslot = aenumitemslot[j]; - ItemStack itemstack = ((LivingEntity) this.entity).getItemBySlot(enumitemslot); - - if (!itemstack.isEmpty()) { - // Paper start - prevent oversized data - final ItemStack sanitized = LivingEntity.sanitizeItemStack(itemstack.copy(), false); - list.add(Pair.of(enumitemslot, ((LivingEntity) this.entity).stripMeta(sanitized, false))); // Paper - remove unnecessary item meta - // Paper end - } - } - - if (!list.isEmpty()) { - consumer.accept(new ClientboundSetEquipmentPacket(this.entity.getId(), list)); - } - ((LivingEntity) this.entity).detectEquipmentUpdates(); // CraftBukkit - SPIGOT-3789: sync again immediately after sending + if (this.entity instanceof LivingEntity livingEntity) { + livingEntity.sendEquipment(entityplayer); // Slice } // CraftBukkit start - Fix for nonsensical head yaw diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index 44612616560c087ca80bd10c2077e955f5ce7c85..505d5de63dec642974ac8fda477450164b87caf6 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -6,14 +6,8 @@ import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Either; import com.mojang.logging.LogUtils; import com.mojang.serialization.DataResult; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.OptionalInt; -import java.util.Random; -import java.util.UUID; + +import java.util.*; import javax.annotation.Nullable; import net.minecraft.BlockUtil; import net.minecraft.ChatFormatting; @@ -2447,4 +2441,19 @@ public class ServerPlayer extends Player { // CraftBukkit end public final int getViewDistance() { throw new UnsupportedOperationException("Use PlayerChunkLoader"); } // Paper - placeholder + + // Slice + public net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket setCachedEquipment(String tag, java.util.Map equipment) { + List> pairs = new ArrayList<>(equipment.size()); + for (java.util.Map.Entry entry : equipment.entrySet()) { + com.mojang.datafixers.util.Pair pair = com.mojang.datafixers.util.Pair.of(net.minecraft.world.entity.EquipmentSlot.byName(entry.getKey().name()), + CraftItemStack.asNMSCopy(entry.getValue())); + pairs.add(pair); + } + + net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket packet = new net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket(getId(), pairs); + cachedEquipmentMap.put(tag, packet); + return packet; + } + // Slice end } diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java index 9002ace5beb17b5a8b7efd0e83de17f2dbfc054a..6b504b854ccd9f0d63baf4cff4b1f279335b7dde 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -262,6 +262,8 @@ public abstract class LivingEntity extends Entity { public boolean bukkitPickUpLoot; public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event + private final com.google.common.collect.Table equipmentPacketCache = com.google.common.collect.HashBasedTable.create(); // Slice + public java.util.Map cachedEquipmentMap = new java.util.HashMap<>(); // Slice @Override public float getBukkitYaw() { @@ -3002,6 +3004,7 @@ public abstract class LivingEntity extends Entity { if (map != null) { this.handleHandSwap(map); if (!map.isEmpty()) { + cachedEquipmentMap.clear(); // Slice - Must invalidate cached equipment map if we have changes this.handleEquipmentChanges(map); } } @@ -3090,7 +3093,25 @@ public abstract class LivingEntity extends Entity { } }); - ((ServerLevel) this.level).getChunkSource().broadcast(this, new ClientboundSetEquipmentPacket(this.getId(), list)); + + // Slice start + net.minecraft.server.level.ChunkMap.TrackedEntity entityTracker = ((ServerLevel) this.level).getChunkSource().chunkMap.entityMap.get(getId()); + if (entityTracker != null) { + ClientboundSetEquipmentPacket packet = new ClientboundSetEquipmentPacket(this.getId(), list); + for (net.minecraft.server.network.ServerPlayerConnection playerConnection : entityTracker.seenBy) { + ServerPlayer player = playerConnection.getPlayer(); + org.bukkit.event.player.PlayerReceiveEquipmentEvent event = new org.bukkit.event.player.PlayerReceiveEquipmentEvent(player.getBukkitEntity(), getBukkitEntity()); + level.getCraftServer().getPluginManager().callEvent(event); + + String tag = event.getTag(); + if (tag != null) { + playerConnection.send(new ClientboundSetEquipmentPacket(this.getId(), list, this, tag)); + } else { + playerConnection.send(packet); + } + } + } + // Slice end } // Paper start - hide unnecessary item meta @@ -4320,6 +4341,26 @@ public abstract class LivingEntity extends Entity { this.setDeltaMovement((double) ((float) packet.getXd() / 8000.0F), (double) ((float) packet.getYd() / 8000.0F), (double) ((float) packet.getZd() / 8000.0F)); } + // Slice start + public ItemStack getOrCreateCachedEquipmentItem(String tag, EquipmentSlot slot, ItemStack itemStack) { + return equipmentPacketCache.row(tag).computeIfAbsent(itemStack, i -> { + String name = slot.name(); + + //How neat is this. + if (name.equals("MAINHAND")) { + name = "HAND"; + } else if (name.equals("OFFHAND")) { + name = "OFF_HAND"; + } + + org.bukkit.event.entity.EntityEquipmentItemLookup event = new org.bukkit.event.entity.EntityEquipmentItemLookup(getBukkitEntity(), tag, org.bukkit.inventory.EquipmentSlot.valueOf(name), CraftItemStack.asBukkitCopy(i)); + this.level.getCraftServer().getPluginManager().callEvent(event); + org.bukkit.inventory.ItemStack eventItem = event.getItemStack(); + return CraftItemStack.asNMSCopy(eventItem); + }); + } + // Slice end + // CraftBukkit start - decompile error public static record Fallsounds(SoundEvent small, SoundEvent big) { @@ -4342,4 +4383,54 @@ public abstract class LivingEntity extends Entity { */ // CraftBukkit end } + + // Slice start + public void sendEquipment(ServerPlayer p) { + org.bukkit.event.player.PlayerReceiveEquipmentEvent event = new org.bukkit.event.player.PlayerReceiveEquipmentEvent(p.getBukkitEntity(), getBukkitEntity()); + level.getCraftServer().getPluginManager().callEvent(event); + + boolean sendEquipment = !event.isCancelled(); + String tag = event.getTag(); + if (sendEquipment && this instanceof ServerPlayer player && tag != null) { + ClientboundSetEquipmentPacket equipmentPacket = player.cachedEquipmentMap.get(tag); + if (equipmentPacket != null) { + //Event says use a tag, and our tag exists; so we simply used our entire cached packet + p.connection.send(equipmentPacket); + sendEquipment = false; + } + } + + if (sendEquipment) { + EquipmentSlot[] equipmentSlots = EquipmentSlot.values(); + List> list = new ArrayList<>(equipmentSlots.length); + + for (EquipmentSlot enumitemslot : equipmentSlots) { + ItemStack itemstack = getItemBySlot(enumitemslot); + + if (!itemstack.isEmpty()) { + // Paper start - prevent oversized data + final ItemStack sanitized = LivingEntity.sanitizeItemStack(itemstack.copy(), false); + ItemStack strippedItem = stripMeta(sanitized, false); + + if (tag != null) { + strippedItem = getOrCreateCachedEquipmentItem(tag, enumitemslot, strippedItem); + } + + list.add(Pair.of(enumitemslot, strippedItem)); // Paper - remove unnecessary item meta + // Paper end + } + } + + if (!list.isEmpty()) { + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(getId(), list); + if (tag != null) { + cachedEquipmentMap.put(tag, equipmentPacket); + } + p.connection.send(equipmentPacket); + } + + detectEquipmentUpdates(); // CraftBukkit - SPIGOT-3789: sync again immediately after sending + } + } + // Slice end } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java index c022751e3b45469cc0ad6732e2d6ff08918bafa4..04708105c6264bfacd0cc20a25178f7a62ebd78e 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -920,4 +920,13 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { throw new IllegalArgumentException(entityCategory + " is an unrecognized entity category"); } // Paper end + + // Slice start + @Override + public void sendEquipment(Player p) { + if (entity instanceof net.minecraft.world.entity.LivingEntity livingEntity) { + livingEntity.sendEquipment(((CraftPlayer) p).getHandle()); + } + } + // Slice end }