From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar Date: Tue, 22 Nov 2016 00:40:42 -0500 Subject: [PATCH] Fix client rendering skulls from same user See: https://github.com/PaperMC/Paper/issues/1304 Changes the UUID sent to client to be based on either the texture payload, or random. This allows the client to render multiple skull textures from the same user, for when different skins were used when skull was made. diff --git a/src/main/java/net/minecraft/network/FriendlyByteBuf.java b/src/main/java/net/minecraft/network/FriendlyByteBuf.java index 70631b3fe080320dfea0d1a4deb23e87448da250..9bffc37939586bcca0ae3d1c4aa3b0b96ad2b20d 100644 --- a/src/main/java/net/minecraft/network/FriendlyByteBuf.java +++ b/src/main/java/net/minecraft/network/FriendlyByteBuf.java @@ -579,9 +579,18 @@ public class FriendlyByteBuf extends ByteBuf { if (item.canBeDepleted() || item.shouldOverrideMultiplayerNbt()) { // Spigot start - filter stack = stack.copy(); - CraftItemStack.setItemMeta(stack, CraftItemStack.getItemMeta(stack)); + // CraftItemStack.setItemMeta(stack, CraftItemStack.getItemMeta(stack)); // Paper - This is no longer needed due to NBT being supported // Spigot end nbttagcompound = stack.getTag(); + // Paper start + if (nbttagcompound != null && nbttagcompound.contains("SkullOwner", 10)) { + CompoundTag owner = nbttagcompound.getCompound("SkullOwner"); + if (owner.hasUUID("Id")) { + nbttagcompound.putUUID("SkullOwnerOrig", owner.getUUID("Id")); + net.minecraft.world.level.block.entity.SkullBlockEntity.sanitizeUUID(owner); + } + } + // Paper end } this.writeNbt(nbttagcompound); @@ -601,7 +610,16 @@ public class FriendlyByteBuf extends ByteBuf { itemstack.setTag(this.readNbt()); // CraftBukkit start if (itemstack.getTag() != null) { - CraftItemStack.setItemMeta(itemstack, CraftItemStack.getItemMeta(itemstack)); + // Paper start - Fix skulls of same owner - restore orig ID since we changed it on send to client + if (itemstack.tag.contains("SkullOwnerOrig")) { + CompoundTag owner = itemstack.tag.getCompound("SkullOwner"); + if (itemstack.tag.contains("SkullOwnerOrig")) { + owner.tags.put("Id", itemstack.tag.tags.get("SkullOwnerOrig")); + itemstack.tag.remove("SkullOwnerOrig"); + } + } + // Paper end + // CraftItemStack.setItemMeta(itemstack, CraftItemStack.getItemMeta(itemstack)); // Paper - This is no longer needed due to NBT being supported } // CraftBukkit end return itemstack; diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java index cc2f53fba1e5f6b6d4d31081ddaca1ace70abf99..56cc2169077fed1fe820d08dc14b3add63289add 100644 --- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java +++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java @@ -151,6 +151,7 @@ public class ClientboundLevelChunkPacketData { static ClientboundLevelChunkPacketData.BlockEntityInfo create(BlockEntity blockEntity) { CompoundTag compoundTag = blockEntity.getUpdateTag(); BlockPos blockPos = blockEntity.getBlockPos(); + if (blockEntity instanceof net.minecraft.world.level.block.entity.SkullBlockEntity) { net.minecraft.world.level.block.entity.SkullBlockEntity.sanitizeTileEntityUUID(compoundTag); } // Paper int i = SectionPos.sectionRelative(blockPos.getX()) << 4 | SectionPos.sectionRelative(blockPos.getZ()); return new ClientboundLevelChunkPacketData.BlockEntityInfo(i, blockPos.getY(), blockEntity.getType(), compoundTag.isEmpty() ? null : compoundTag); } diff --git a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java index 0c7e29b589ab106013d979a20edc415b4b32a677..170f051d820ee1add1b61a20dbd1f18f758717dc 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java @@ -11,6 +11,7 @@ import javax.annotation.Nullable; import net.minecraft.Util; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.server.Services; @@ -94,9 +95,37 @@ public class SkullBlockEntity extends BlockEntity { @Override public ClientboundBlockEntityDataPacket getUpdatePacket() { - return ClientboundBlockEntityDataPacket.create(this); + return ClientboundBlockEntityDataPacket.create(this, e -> sanitizeTileEntityUUID(e.getUpdateTag())); // Paper } + // Paper start + public static CompoundTag sanitizeTileEntityUUID(CompoundTag cmp) { + CompoundTag owner = cmp.getCompound("Owner"); + if (!owner.isEmpty()) { + sanitizeUUID(owner); + } + return cmp; + } + + public static void sanitizeUUID(CompoundTag owner) { + CompoundTag properties = owner.getCompound("Properties"); + ListTag list = null; + if (!properties.isEmpty()) { + list = properties.getList("textures", 10); + } + + if (list != null && !list.isEmpty()) { + String textures = ((CompoundTag)list.get(0)).getString("Value"); + if (textures != null && textures.length() > 3) { + UUID uuid = UUID.nameUUIDFromBytes(textures.getBytes()); + owner.putUUID("Id", uuid); + return; + } + } + owner.putUUID("Id", UUID.randomUUID()); + } + // Paper end + @Override public CompoundTag getUpdateTag() { return this.saveWithoutMetadata();