diff --git a/patches/server/Add-PlayerShearBlockEvent.patch b/patches/server/Add-PlayerShearBlockEvent.patch index b52fc498a0..c7ce627503 100644 --- a/patches/server/Add-PlayerShearBlockEvent.patch +++ b/patches/server/Add-PlayerShearBlockEvent.patch @@ -50,7 +50,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), new java.util.ArrayList<>()); + event.getDrops().add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(new ItemStack(Items.PUMPKIN_SEEDS, 4))); + if (!event.callEvent()) { -+ return InteractionResult.PASS; ++ return ItemInteractionResult.PASS; + } + // Paper end - Add PlayerShearBlockEvent Direction direction = hit.getDirection(); diff --git a/patches/server/Add-Raw-Byte-Entity-Serialization.patch b/patches/server/Add-Raw-Byte-Entity-Serialization.patch index 688ab2ee40..848fc3eea0 100644 --- a/patches/server/Add-Raw-Byte-Entity-Serialization.patch +++ b/patches/server/Add-Raw-Byte-Entity-Serialization.patch @@ -54,15 +54,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -0,0 +0,0 @@ public final class CraftMagicNumbers implements UnsafeValues { - return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.of(compound)); + return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.parse(MinecraftServer.getServer().registryAccess(), compound).orElseThrow()); } +- private byte[] serializeNbtToBytes(CompoundTag compound) { + @Override + public byte[] serializeEntity(org.bukkit.entity.Entity entity) { + Preconditions.checkNotNull(entity, "null cannot be serialized"); + Preconditions.checkArgument(entity instanceof org.bukkit.craftbukkit.entity.CraftEntity, "only CraftEntities can be serialized"); + -+ CompoundTag compound = new CompoundTag(); ++ net.minecraft.nbt.CompoundTag compound = new net.minecraft.nbt.CompoundTag(); + ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().serializeEntity(compound); + return serializeNbtToBytes(compound); + } @@ -72,9 +73,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + Preconditions.checkNotNull(data, "null cannot be deserialized"); + Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing"); + -+ CompoundTag compound = deserializeNbtFromBytes(data); ++ net.minecraft.nbt.CompoundTag compound = deserializeNbtFromBytes(data); + int dataVersion = compound.getInt("DataVersion"); -+ compound = (CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ENTITY, new Dynamic<>(NbtOps.INSTANCE, compound), dataVersion, this.getDataVersion()).getValue(); ++ compound = (net.minecraft.nbt.CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ENTITY, new Dynamic<>(NbtOps.INSTANCE, compound), dataVersion, this.getDataVersion()).getValue(); + if (!preserveUUID) { + // Generate a new UUID so we don't have to worry about deserializing the same entity twice + compound.remove("UUID"); @@ -83,6 +84,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + .orElseThrow(() -> new IllegalArgumentException("An ID was not found for the data. Did you downgrade?")).getBukkitEntity(); + } + - private byte[] serializeNbtToBytes(CompoundTag compound) { ++ private byte[] serializeNbtToBytes(net.minecraft.nbt.CompoundTag compound) { compound.putInt("DataVersion", getDataVersion()); java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream(); + try { diff --git a/patches/server/Add-Raw-Byte-ItemStack-Serialization.patch b/patches/server/Add-Raw-Byte-ItemStack-Serialization.patch index 1da0e69865..42dd267b50 100644 --- a/patches/server/Add-Raw-Byte-ItemStack-Serialization.patch +++ b/patches/server/Add-Raw-Byte-ItemStack-Serialization.patch @@ -19,7 +19,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + Preconditions.checkNotNull(item, "null cannot be serialized"); + Preconditions.checkArgument(item.getType() != Material.AIR, "air cannot be serialized"); + -+ return serializeNbtToBytes((item instanceof CraftItemStack ? ((CraftItemStack) item).handle : CraftItemStack.asNMSCopy(item)).save(new CompoundTag())); ++ return serializeNbtToBytes((net.minecraft.nbt.CompoundTag) (item instanceof CraftItemStack ? ((CraftItemStack) item).handle : CraftItemStack.asNMSCopy(item)).save(MinecraftServer.getServer().registryAccess())); + } + + @Override @@ -27,10 +27,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + Preconditions.checkNotNull(data, "null cannot be deserialized"); + Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing"); + -+ CompoundTag compound = deserializeNbtFromBytes(data); ++ net.minecraft.nbt.CompoundTag compound = deserializeNbtFromBytes(data); + final int dataVersion = compound.getInt("DataVersion"); -+ compound = (CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, compound), dataVersion, this.getDataVersion()).getValue(); -+ return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.of(compound)); ++ compound = (net.minecraft.nbt.CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, compound), dataVersion, this.getDataVersion()).getValue(); ++ return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.parse(MinecraftServer.getServer().registryAccess(), compound).orElseThrow()); + } + + private byte[] serializeNbtToBytes(CompoundTag compound) { @@ -47,8 +47,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return outputStream.toByteArray(); + } + -+ private CompoundTag deserializeNbtFromBytes(byte[] data) { -+ CompoundTag compound; ++ private net.minecraft.nbt.CompoundTag deserializeNbtFromBytes(byte[] data) { ++ net.minecraft.nbt.CompoundTag compound; + try { + compound = net.minecraft.nbt.NbtIo.readCompressed( + new java.io.ByteArrayInputStream(data), net.minecraft.nbt.NbtAccounter.unlimitedHeap() diff --git a/patches/server/Cache-map-ids-on-item-frames.patch b/patches/server/Cache-map-ids-on-item-frames.patch index 1abe765e44..2b661b917d 100644 --- a/patches/server/Cache-map-ids-on-item-frames.patch +++ b/patches/server/Cache-map-ids-on-item-frames.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable - MapId mapid = (MapId) itemstack.get(DataComponents.MAP_ID); -+ Integer integer = entityitemframe.cachedMapId; // Paper - Perf: Cache map ids on item frames ++ MapId mapid = entityitemframe.cachedMapId; // Paper - Perf: Cache map ids on item frames MapItemSavedData worldmap = MapItem.getSavedData(mapid, this.level); if (worldmap != null) { @@ -25,7 +25,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public static final int NUM_ROTATIONS = 8; public float dropChance; public boolean fixed; -+ public Integer cachedMapId; // Paper - Perf: Cache map ids on item frames ++ public @Nullable MapId cachedMapId; // Paper - Perf: Cache map ids on item frames public ItemFrame(EntityType<? extends ItemFrame> type, Level world) { super(type, world); @@ -33,7 +33,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } private void onItemChanged(ItemStack stack) { -+ this.cachedMapId = MapItem.getMapId(stack); // Paper - Perf: Cache map ids on item frames ++ this.cachedMapId = stack.getComponents().get(net.minecraft.core.component.DataComponents.MAP_ID); // Paper - Perf: Cache map ids on item frames if (!stack.isEmpty() && stack.getFrame() != this) { stack.setEntityRepresentation(this); } diff --git a/patches/server/Expose-protocol-version.patch b/patches/server/Expose-protocol-version.patch index 4f55ae6f04..d60caf0797 100644 --- a/patches/server/Expose-protocol-version.patch +++ b/patches/server/Expose-protocol-version.patch @@ -10,7 +10,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -0,0 +0,0 @@ public final class CraftMagicNumbers implements UnsafeValues { public io.papermc.paper.inventory.ItemRarity getItemStackRarity(org.bukkit.inventory.ItemStack itemStack) { - return io.papermc.paper.inventory.ItemRarity.values()[getItem(itemStack.getType()).getRarity(CraftItemStack.asNMSCopy(itemStack)).ordinal()]; + return io.papermc.paper.inventory.ItemRarity.values()[itemStack.getRarity().ordinal()]; } + + @Override diff --git a/patches/server/Fix-UnsafeValues-loadAdvancement.patch b/patches/server/Fix-UnsafeValues-loadAdvancement.patch index 33f1c9429d..a357c26bbf 100644 --- a/patches/server/Fix-UnsafeValues-loadAdvancement.patch +++ b/patches/server/Fix-UnsafeValues-loadAdvancement.patch @@ -23,7 +23,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + MinecraftServer.getServer().getAdvancements().advancements = mapBuilder.build(); + final net.minecraft.advancements.AdvancementTree tree = MinecraftServer.getServer().getAdvancements().tree(); -+ tree.addAll(List.of(holder)); ++ tree.addAll(java.util.List.of(holder)); + + // recalculate advancement position + final net.minecraft.advancements.AdvancementNode node = tree.get(minecraftkey); diff --git a/patches/server/Item-Rarity-API.patch b/patches/server/Item-Rarity-API.patch index db24dc99f6..f66b378adf 100644 --- a/patches/server/Item-Rarity-API.patch +++ b/patches/server/Item-Rarity-API.patch @@ -21,12 +21,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (item == null) { + throw new IllegalArgumentException(material + " is not an item, and rarity does not apply to blocks"); + } -+ return io.papermc.paper.inventory.ItemRarity.values()[item.rarity.ordinal()]; ++ return io.papermc.paper.inventory.ItemRarity.values()[item.components().getOrDefault(net.minecraft.core.component.DataComponents.RARITY, net.minecraft.world.item.Rarity.COMMON).ordinal()]; + } + + @Override + public io.papermc.paper.inventory.ItemRarity getItemStackRarity(org.bukkit.inventory.ItemStack itemStack) { -+ return io.papermc.paper.inventory.ItemRarity.values()[getItem(itemStack.getType()).getRarity(CraftItemStack.asNMSCopy(itemStack)).ordinal()]; ++ return io.papermc.paper.inventory.ItemRarity.values()[itemStack.getRarity().ordinal()]; + } // Paper end diff --git a/patches/server/ItemStack-Tooltip-API.patch b/patches/server/ItemStack-Tooltip-API.patch index a57e9e936d..37c29b717e 100644 --- a/patches/server/ItemStack-Tooltip-API.patch +++ b/patches/server/ItemStack-Tooltip-API.patch @@ -14,13 +14,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper end + // Paper start - expose itemstack tooltip lines + @Override -+ public List<net.kyori.adventure.text.Component> computeTooltipLines(final ItemStack itemStack, final io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, final org.bukkit.entity.Player player) { ++ public java.util.List<net.kyori.adventure.text.Component> computeTooltipLines(final ItemStack itemStack, final io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, final org.bukkit.entity.Player player) { + Preconditions.checkArgument(tooltipContext != null, "tooltipContext cannot be null"); + net.minecraft.world.item.TooltipFlag.Default flag = tooltipContext.isAdvanced() ? net.minecraft.world.item.TooltipFlag.ADVANCED : net.minecraft.world.item.TooltipFlag.NORMAL; + if (tooltipContext.isCreative()) { + flag = flag.asCreative(); + } -+ final List<net.minecraft.network.chat.Component> lines = CraftItemStack.asNMSCopy(itemStack).getTooltipLines(player == null ? null : ((org.bukkit.craftbukkit.entity.CraftPlayer) player).getHandle(), flag); ++ final java.util.List<net.minecraft.network.chat.Component> lines = CraftItemStack.asNMSCopy(itemStack).getTooltipLines(player == null ? null : ((org.bukkit.craftbukkit.entity.CraftPlayer) player).getHandle(), flag); + return lines.stream().map(io.papermc.paper.adventure.PaperAdventure::asAdventure).toList(); + } + // Paper end - expose itemstack tooltip lines diff --git a/patches/server/ItemStack-repair-check-API.patch b/patches/server/ItemStack-repair-check-API.patch index fb1bb5e948..a9785c3161 100644 --- a/patches/server/ItemStack-repair-check-API.patch +++ b/patches/server/ItemStack-repair-check-API.patch @@ -9,7 +9,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -0,0 +0,0 @@ public final class CraftMagicNumbers implements UnsafeValues { - return io.papermc.paper.inventory.ItemRarity.values()[getItem(itemStack.getType()).getRarity(CraftItemStack.asNMSCopy(itemStack)).ordinal()]; + return io.papermc.paper.inventory.ItemRarity.values()[itemStack.getRarity().ordinal()]; } + @Override diff --git a/patches/server/LootTable-API-and-replenishable-lootables.patch b/patches/server/LootTable-API-and-replenishable-lootables.patch index 68de2a8aea..50780be420 100644 --- a/patches/server/LootTable-API-and-replenishable-lootables.patch +++ b/patches/server/LootTable-API-and-replenishable-lootables.patch @@ -673,9 +673,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Copied from super with changes, always check the original method + this.lootableData.loadNbt(nbt); // Paper + if (nbt.contains("LootTable", 8)) { -+ this.setLootTable(ResourceLocation.tryParse(nbt.getString("LootTable"))); -+ try { org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.lootTable); } catch (IllegalArgumentException ex) { this.lootTable = null; } // Paper - validate -+ this.setLootTableSeed(nbt.getLong("LootTableSeed")); ++ final var loc = new net.minecraft.resources.ResourceLocation(nbt.getString("LootTable")); ++ this.setLootTable(ResourceKey.create(net.minecraft.core.registries.Registries.LOOT_TABLE, loc)); ++ try { org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.lootTable.location()); } catch (IllegalArgumentException ex) { this.lootTable = null; } // Paper - validate ++ if (nbt.contains("LootTableSeed", 4)) { ++ this.setLootTableSeed(nbt.getLong("LootTableSeed")); ++ } else { ++ this.setLootTableSeed(0L); ++ } + return false; // Paper - always load the items, table may still remain + } else { + return false; @@ -694,11 +699,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Copied from super with changes, always check the original method + net.minecraft.world.level.Level level = this.getLevel(); + BlockPos blockPos = this.getBlockPos(); -+ ResourceLocation resourceLocation = this.getLootTable(); -+ if (this.lootableData.shouldReplenish(player) && level != null) { // Paper -+ net.minecraft.world.level.storage.loot.LootTable lootTable = level.getServer().getLootData().getLootTable(resourceLocation); ++ ResourceKey<LootTable> resourceKey = this.getLootTable(); ++ if (this.lootableData.shouldReplenish(player) && resourceKey != null && level != null && level.getServer() != null) { // Paper ++ net.minecraft.world.level.storage.loot.LootTable lootTable = level.getServer().reloadableRegistries().getLootTable(resourceKey); + if (player instanceof net.minecraft.server.level.ServerPlayer) { -+ net.minecraft.advancements.CriteriaTriggers.GENERATE_LOOT.trigger((net.minecraft.server.level.ServerPlayer)player, resourceLocation); ++ net.minecraft.advancements.CriteriaTriggers.GENERATE_LOOT.trigger((net.minecraft.server.level.ServerPlayer)player, resourceKey); + } + + this.lootableData.processRefill(player); // Paper diff --git a/patches/server/MC-Utils.patch b/patches/server/MC-Utils.patch index f21ab41545..cae05842d3 100644 --- a/patches/server/MC-Utils.patch +++ b/patches/server/MC-Utils.patch @@ -6171,12 +6171,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public @Nullable ChunkAccess getAvailableChunkNow() { + // TODO can we just getStatusFuture(EMPTY)? + for (ChunkStatus curr = ChunkStatus.FULL, next = curr.getParent(); curr != next; curr = next, next = next.getParent()) { -+ CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = this.getFutureIfPresentUnchecked(curr); -+ Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = future.getNow(null); -+ if (either == null || either.left().isEmpty()) { ++ CompletableFuture<ChunkResult<ChunkAccess>> future = this.getFutureIfPresentUnchecked(curr); ++ ChunkResult<ChunkAccess> either = future.getNow(null); ++ if (either == null || either.isSuccess()) { + continue; + } -+ return either.left().get(); ++ return either.orElseThrow(IllegalStateException::new); + } + return null; + } @@ -6214,11 +6214,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // Paper start -+ public ChunkStatus getChunkHolderStatus() { ++ public @Nullable ChunkStatus getChunkHolderStatus() { + for (ChunkStatus curr = ChunkStatus.FULL, next = curr.getParent(); curr != next; curr = next, next = next.getParent()) { -+ CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = this.getFutureIfPresentUnchecked(curr); -+ Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = future.getNow(null); -+ if (either == null || !either.left().isPresent()) { ++ CompletableFuture<ChunkResult<ChunkAccess>> future = this.getFutureIfPresentUnchecked(curr); ++ ChunkResult<ChunkAccess> either = future.getNow(null); ++ if (either == null || !either.isSuccess()) { + continue; + } + return curr; @@ -6291,8 +6291,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.tickingChunkFuture = chunkStorage.prepareTickingChunk(this); this.scheduleFullChunkPromotion(chunkStorage, this.tickingChunkFuture, executor, FullChunkStatus.BLOCK_TICKING); + // Paper start - cache ticking ready status -+ this.tickingChunkFuture.thenAccept(either -> { -+ either.ifLeft(chunk -> { ++ this.tickingChunkFuture.thenAccept(chunkResult -> { ++ chunkResult.ifSuccess(chunk -> { + // note: Here is a very good place to add callbacks to logic waiting on this. + ChunkHolder.this.isTickingReady = true; + io.papermc.paper.chunk.system.ChunkSystem.onChunkTicking(chunk, this); @@ -6306,7 +6306,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); + // Paper start + if (this.isTickingReady) { -+ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().left().get(), this); // Paper ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().orElseThrow(IllegalStateException::new), this); // Paper + } + // Paper end + this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isTickingReady = false; // Paper - cache chunk ticking stage diff --git a/patches/server/Only-tick-item-frames-if-players-can-see-it.patch b/patches/server/Only-tick-item-frames-if-players-can-see-it.patch index 4d5169d57a..60e5b70e6d 100644 --- a/patches/server/Only-tick-item-frames-if-players-can-see-it.patch +++ b/patches/server/Only-tick-item-frames-if-players-can-see-it.patch @@ -14,7 +14,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 Entity entity = this.entity; - if (entity instanceof ItemFrame entityitemframe) { -+ if (!this.trackedPlayers.isEmpty() && entity instanceof ItemFrame) { // Paper - Perf: Only tick item frames if players can see it ++ if (!this.trackedPlayers.isEmpty() && entity instanceof ItemFrame entityitemframe) { // Paper - Perf: Only tick item frames if players can see it if (true || this.tickCount % 10 == 0) { // CraftBukkit - Moved below, should always enter this block ItemStack itemstack = entityitemframe.getItem();