Files
OldSliceMC/patches/server/0025-Equipment-Packet-Caching.patch
2022-10-06 08:41:11 -05:00

265 lines
13 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cryptite <cryptite@gmail.com>
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<ClientGamePacketLis
this.slots = equipmentList;
}
+ public ClientboundSetEquipmentPacket(int id, List<Pair<EquipmentSlot, ItemStack>> equipmentList, net.minecraft.world.entity.LivingEntity entity, String tag) {
+ this.entity = id;
+ slots = new java.util.ArrayList<>(equipmentList.size());
+ for (Pair<EquipmentSlot, ItemStack> 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<Pair<EquipmentSlot, ItemStack>> 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<org.bukkit.inventory.EquipmentSlot, org.bukkit.inventory.ItemStack> equipment) {
+ List<com.mojang.datafixers.util.Pair<net.minecraft.world.entity.EquipmentSlot, net.minecraft.world.item.ItemStack>> pairs = new ArrayList<>(equipment.size());
+ for (java.util.Map.Entry<org.bukkit.inventory.EquipmentSlot, org.bukkit.inventory.ItemStack> entry : equipment.entrySet()) {
+ com.mojang.datafixers.util.Pair<net.minecraft.world.entity.EquipmentSlot, net.minecraft.world.item.ItemStack> 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<String, ItemStack, ItemStack> equipmentPacketCache = com.google.common.collect.HashBasedTable.create(); // Slice
+ public java.util.Map<String, net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket> 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<Pair<EquipmentSlot, ItemStack>> 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
}