From 65fc767a7afdb5b6a33194ddcf92f198b650e6af Mon Sep 17 00:00:00 2001 From: JustRed23 Date: Sun, 12 Nov 2023 17:24:17 +0100 Subject: [PATCH 1/2] Incorrect comment spacing --- .../net/minecraft/world/item/trading/MerchantOffer.java.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/minecraft/net/minecraft/world/item/trading/MerchantOffer.java.patch b/patches/minecraft/net/minecraft/world/item/trading/MerchantOffer.java.patch index 8823f1a558..0f7affc9da 100644 --- a/patches/minecraft/net/minecraft/world/item/trading/MerchantOffer.java.patch +++ b/patches/minecraft/net/minecraft/world/item/trading/MerchantOffer.java.patch @@ -27,7 +27,7 @@ + this(itemstack, itemstack1, itemstack2, uses, maxUses, experience, priceMultiplier, demand); + this.bukkitHandle = bukkit; + } -+// CraftBukkit end ++ // CraftBukkit end public MerchantOffer(CompoundTag p_45351_) { this.baseCostA = ItemStack.of(p_45351_.getCompound("buy")); From 7c70ea6a643dbb258eff8335d3db0fe68e1576de Mon Sep 17 00:00:00 2001 From: JustRed23 Date: Sun, 12 Nov 2023 18:22:39 +0100 Subject: [PATCH 2/2] Finish item patches!! --- docs/README.md | 2 +- .../minecraft/world/item/ItemStack.java.patch | 390 +++++++++++++++++- .../net/minecraftforge/common/ForgeHooks.java | 2 +- 3 files changed, 371 insertions(+), 23 deletions(-) diff --git a/docs/README.md b/docs/README.md index fdc56e92d1..1a243d39ef 100644 --- a/docs/README.md +++ b/docs/README.md @@ -14,7 +14,7 @@ that enables the use of Bukkit plugins on Forge servers. Ketting is still in development and is not ready for production use. ### PATCHES DONE -Bukkit: 209 / 530 +Bukkit: 251 / 530
CraftBukkit: 0 / 685 diff --git a/patches/minecraft/net/minecraft/world/item/ItemStack.java.patch b/patches/minecraft/net/minecraft/world/item/ItemStack.java.patch index bf6472d050..0158b19159 100644 --- a/patches/minecraft/net/minecraft/world/item/ItemStack.java.patch +++ b/patches/minecraft/net/minecraft/world/item/ItemStack.java.patch @@ -1,7 +1,71 @@ --- a/net/minecraft/world/item/ItemStack.java +++ b/net/minecraft/world/item/ItemStack.java -@@ -76,12 +_,16 @@ +@@ -6,6 +_,7 @@ + import com.mojang.brigadier.exceptions.CommandSyntaxException; + import com.mojang.logging.LogUtils; + import com.mojang.serialization.Codec; ++import com.mojang.serialization.Dynamic; + import com.mojang.serialization.codecs.RecordCodecBuilder; + import java.text.DecimalFormat; + import java.text.DecimalFormatSymbols; +@@ -24,14 +_,12 @@ + import net.minecraft.Util; + import net.minecraft.advancements.CriteriaTriggers; + import net.minecraft.commands.arguments.blocks.BlockStateParser; +-import net.minecraft.core.BlockPos; +-import net.minecraft.core.Holder; +-import net.minecraft.core.HolderSet; +-import net.minecraft.core.Registry; ++import net.minecraft.core.*; + import net.minecraft.core.registries.BuiltInRegistries; + import net.minecraft.core.registries.Registries; + import net.minecraft.nbt.CompoundTag; + import net.minecraft.nbt.ListTag; ++import net.minecraft.nbt.NbtOps; + import net.minecraft.nbt.Tag; + import net.minecraft.network.chat.CommonComponents; + import net.minecraft.network.chat.Component; +@@ -39,12 +_,17 @@ + import net.minecraft.network.chat.HoverEvent; + import net.minecraft.network.chat.MutableComponent; + import net.minecraft.network.chat.Style; ++import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; + import net.minecraft.resources.ResourceLocation; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ServerLevel; + import net.minecraft.server.level.ServerPlayer; + import net.minecraft.sounds.SoundEvent; ++import net.minecraft.sounds.SoundSource; + import net.minecraft.stats.Stats; + import net.minecraft.tags.TagKey; + import net.minecraft.util.RandomSource; ++import net.minecraft.util.datafix.fixes.References; + import net.minecraft.world.InteractionHand; + import net.minecraft.world.InteractionResult; + import net.minecraft.world.InteractionResultHolder; +@@ -71,17 +_,36 @@ + import net.minecraft.world.item.enchantment.Enchantments; + import net.minecraft.world.level.ItemLike; + import net.minecraft.world.level.Level; +-import net.minecraft.world.level.block.Block; ++import net.minecraft.world.level.block.*; ++import net.minecraft.world.level.block.entity.BlockEntity; ++import net.minecraft.world.level.block.entity.JukeboxBlockEntity; ++import net.minecraft.world.level.block.entity.SignBlockEntity; ++import net.minecraft.world.level.block.entity.SkullBlockEntity; + import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.pattern.BlockInWorld; ++import net.minecraft.world.level.gameevent.GameEvent; ++import org.bukkit.Location; ++import org.bukkit.TreeType; ++import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock; ++import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockState; ++import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; ++import org.bukkit.craftbukkit.v1_20_R2.util.CraftLocation; ++import org.bukkit.craftbukkit.v1_20_R2.util.CraftMagicNumbers; ++import org.bukkit.event.block.BlockFertilizeEvent; ++import org.bukkit.event.player.PlayerItemDamageEvent; ++import org.bukkit.event.world.StructureGrowEvent; import org.slf4j.Logger; -public final class ItemStack { @@ -12,21 +76,31 @@ })).apply(p_258963_, ItemStack::new); }); + @org.jetbrains.annotations.Nullable -+ private final net.minecraft.core.Holder.Reference delegate; ++ private net.minecraft.core.Holder.Reference delegate; + private CompoundTag capNBT; + private static final Logger LOGGER = LogUtils.getLogger(); public static final ItemStack EMPTY = new ItemStack((Void)null); public static final DecimalFormat ATTRIBUTE_MODIFIER_FORMAT = Util.make(new DecimalFormat("#.##"), (p_41704_) -> { -@@ -137,28 +_,40 @@ - this(p_220155_.value(), p_220156_); +@@ -106,7 +_,7 @@ + /** @deprecated */ + @Deprecated + @Nullable +- private final Item item; ++ private Item item; + @Nullable + private CompoundTag tag; + @Nullable +@@ -138,30 +_,63 @@ } -- public ItemStack(ItemLike p_41601_, int p_41602_) { + public ItemStack(ItemLike p_41601_, int p_41602_) { - this.item = p_41601_.asItem(); - this.count = p_41602_; - if (this.item.canBeDepleted()) { -+ public ItemStack(ItemLike p_41601_, int p_41602_) { this(p_41601_, p_41602_, (CompoundTag) null); } ++ this(p_41601_, p_41602_, (CompoundTag) null); ++ } ++ + public ItemStack(ItemLike p_41604_, int p_41605_, @Nullable CompoundTag p_41606_) { + super(ItemStack.class, true); + this.capNBT = p_41606_; @@ -43,27 +117,55 @@ private ItemStack(@Nullable Void p_282703_) { + super(ItemStack.class, true); this.item = null; +- } +- +- private ItemStack(CompoundTag p_41608_) { +- this.item = BuiltInRegistries.ITEM.get(new ResourceLocation(p_41608_.getString("id"))); +- this.count = p_41608_.getByte("Count"); +- if (p_41608_.contains("tag", 10)) { +- this.tag = p_41608_.getCompound("tag"); + this.delegate = null; - } - - private ItemStack(CompoundTag p_41608_) { -+ super(ItemStack.class, true); -+ this.capNBT = p_41608_.contains("ForgeCaps") ? p_41608_.getCompound("ForgeCaps") : null; ++ } ++ ++ // Called to run this stack through the data converter to handle older storage methods and serialized items ++ public void convertStack(int version) { ++ if (0 < version && version < CraftMagicNumbers.INSTANCE.getDataVersion()) { ++ CompoundTag savedStack = new CompoundTag(); ++ this.save(savedStack); ++ savedStack = (CompoundTag) MinecraftServer.getServer().fixerUpper.update(References.ITEM_STACK, new Dynamic(NbtOps.INSTANCE, savedStack), version, CraftMagicNumbers.INSTANCE.getDataVersion()).getValue(); ++ this.load(savedStack); ++ } ++ } ++ ++ // CraftBukkit - break into own method ++ private void load(CompoundTag tag) { ++ this.capNBT = tag.contains("ForgeCaps") ? tag.getCompound("ForgeCaps") : null; + Item rawItem = - this.item = BuiltInRegistries.ITEM.get(new ResourceLocation(p_41608_.getString("id"))); ++ this.item = BuiltInRegistries.ITEM.get(new ResourceLocation(tag.getString("id"))); + this.delegate = net.minecraftforge.registries.ForgeRegistries.ITEMS.getDelegateOrThrow(rawItem); - this.count = p_41608_.getByte("Count"); - if (p_41608_.contains("tag", 10)) { - this.tag = p_41608_.getCompound("tag"); ++ this.count = tag.getByte("Count"); ++ if (tag.contains("tag", 10)) { ++ // CraftBukkit start - make defensive copy as this data may be coming from the save thread ++ this.tag = tag.getCompound("tag").copy(); ++ // CraftBukkit end this.getItem().verifyTagAfterLoad(this.tag); } -+ this.forgeInit(); - if (this.getItem().canBeDepleted()) { ++ this.forgeInit(); ++ + if (this.getItem().isDamageable(this)) { this.setDamageValue(this.getDamageValue()); } ++ } + ++ private ItemStack(CompoundTag p_41608_) { ++ super(ItemStack.class, true); ++ this.load(p_41608_); ++ // CraftBukkit end + } + public static ItemStack of(CompoundTag p_41713_) { @@ -174,7 +_,7 @@ } @@ -94,19 +196,202 @@ + return onItemUse(p_41662_, (c) -> getItem().onItemUseFirst(this, p_41662_)); + } + -+ private InteractionResult onItemUse(UseOnContext p_41662_, java.util.function.Function callback) { ++ public InteractionResult onItemUse(UseOnContext p_41662_, java.util.function.Function callback) { Player player = p_41662_.getPlayer(); BlockPos blockpos = p_41662_.getClickedPos(); BlockInWorld blockinworld = new BlockInWorld(p_41662_.getLevel(), blockpos, false); -@@ -238,7 +_,7 @@ +@@ -238,10 +_,189 @@ return InteractionResult.PASS; } else { Item item = this.getItem(); - InteractionResult interactionresult = item.useOn(p_41662_); -+ InteractionResult interactionresult = callback.apply(p_41662_); ++ // CraftBukkit start - handle all block place event logic here ++ CompoundTag oldData = this.getTagClone(); ++ int oldCount = this.getCount(); ++ ServerLevel world = (ServerLevel) p_41662_.getLevel(); ++ ++ if (!(item instanceof BucketItem || item instanceof SolidBucketItem)) { // if not bucket ++ world.captureBlockStates = true; ++ // special case bonemeal ++ if (item == Items.BONE_MEAL) { ++ world.captureTreeGeneration = true; ++ } ++ } ++ ++ InteractionResult interactionresult; ++ try { ++ interactionresult = callback.apply(p_41662_); ++ } finally { ++ world.captureBlockStates = false; ++ } ++ CompoundTag newData = this.getTagClone(); ++ int newCount = this.getCount(); ++ this.setCount(oldCount); ++ this.setTagClone(oldData); ++ if (interactionresult.consumesAction() && world.captureTreeGeneration && world.capturedBlockStates.size() > 0) { ++ world.captureTreeGeneration = false; ++ Location location = CraftLocation.toBukkit(blockpos, world.getWorld()); ++ TreeType treeType = SaplingBlock.treeType; ++ SaplingBlock.treeType = null; ++ List blocks = new java.util.ArrayList<>(world.capturedBlockStates.values()); ++ world.capturedBlockStates.clear(); ++ StructureGrowEvent structureEvent = null; ++ if (treeType != null) { ++ boolean isBonemeal = getItem() == Items.BONE_MEAL; ++ structureEvent = new StructureGrowEvent(location, treeType, isBonemeal, (org.bukkit.entity.Player) player.getBukkitEntity(), blocks); ++ org.bukkit.Bukkit.getPluginManager().callEvent(structureEvent); ++ } ++ ++ BlockFertilizeEvent fertilizeEvent = new BlockFertilizeEvent(CraftBlock.at(world, blockpos), (org.bukkit.entity.Player) player.getBukkitEntity(), blocks); ++ fertilizeEvent.setCancelled(structureEvent != null && structureEvent.isCancelled()); ++ org.bukkit.Bukkit.getPluginManager().callEvent(fertilizeEvent); ++ ++ if (!fertilizeEvent.isCancelled()) { ++ // Change the stack to its new contents if it hasn't been tampered with. ++ if (this.getCount() == oldCount && Objects.equals(this.tag, oldData)) { ++ this.setTag(newData); ++ this.setCount(newCount); ++ } ++ for (CraftBlockState blockstate : blocks) { ++ world.setBlock(blockstate.getPosition(),blockstate.getHandle(), blockstate.getFlag()); // SPIGOT-7248 - manual update to avoid physics where appropriate ++ } ++ player.awardStat(Stats.ITEM_USED.get(item)); // SPIGOT-7236 - award stat ++ } ++ ++ SignItem.openSign = null; // SPIGOT-6758 - Reset on early return ++ return interactionresult; ++ } ++ world.captureTreeGeneration = false; ++ if (player != null && interactionresult.shouldAwardStats()) { - player.awardStat(Stats.ITEM_USED.get(item)); +- player.awardStat(Stats.ITEM_USED.get(item)); ++ InteractionHand enumhand = p_41662_.getHand(); ++ org.bukkit.event.block.BlockPlaceEvent placeEvent = null; ++ List blocks = new java.util.ArrayList<>(world.capturedBlockStates.values()); ++ world.capturedBlockStates.clear(); ++ if (blocks.size() > 1) { ++ placeEvent = org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callBlockMultiPlaceEvent(world, player, enumhand, blocks, blockpos.getX(), blockpos.getY(), blockpos.getZ()); ++ } else if (blocks.size() == 1) { ++ placeEvent = org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callBlockPlaceEvent(world, player, enumhand, blocks.get(0), blockpos.getX(), blockpos.getY(), blockpos.getZ()); ++ } ++ ++ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) { ++ interactionresult = InteractionResult.FAIL; ++ // PAIL: Remove this when MC-99075 fixed ++ placeEvent.getPlayer().updateInventory(); ++ // revert back all captured blocks ++ world.preventPoiUpdated = true; // CraftBukkit - SPIGOT-5710 ++ for (org.bukkit.block.BlockState blockstate : blocks) { ++ blockstate.update(true, false); ++ } ++ world.preventPoiUpdated = false; ++ ++ // Brute force all possible updates ++ BlockPos placedPos = ((CraftBlock) placeEvent.getBlock()).getPosition(); ++ for (Direction dir : Direction.values()) { ++ ((ServerPlayer) player).connection.send(new ClientboundBlockUpdatePacket(world, placedPos.relative(dir))); ++ } ++ SignItem.openSign = null; // SPIGOT-6758 - Reset on early return ++ } else { ++ // Change the stack to its new contents if it hasn't been tampered with. ++ if (this.getCount() == oldCount && Objects.equals(this.tag, oldData)) { ++ this.setTag(newData); ++ this.setCount(newCount); ++ } ++ ++ for (Map.Entry e : world.capturedTileEntities.entrySet()) { ++ world.setBlockEntity(e.getValue()); ++ } ++ ++ for (org.bukkit.block.BlockState blockstate : blocks) { ++ int updateFlag = ((CraftBlockState) blockstate).getFlag(); ++ BlockState oldBlock = ((CraftBlockState) blockstate).getHandle(); ++ BlockPos newblockposition = ((CraftBlockState) blockstate).getPosition(); ++ BlockState block = world.getBlockState(newblockposition); ++ ++ if (!(block.getBlock() instanceof BaseEntityBlock)) { // Containers get placed automatically ++ block.getBlock().onPlace(block, world, newblockposition, oldBlock, true); ++ } ++ ++ world.markAndNotifyBlock(newblockposition, null, oldBlock, block, updateFlag, 512); // send null chunk as chunk.k() returns false by this point ++ } ++ ++ // Special case juke boxes as they update their tile entity. Copied from ItemRecord. ++ // PAIL: checkme on updates. ++ if (this.item instanceof RecordItem) { ++ BlockEntity tileentity = world.getBlockEntity(blockpos); ++ ++ if (tileentity instanceof JukeboxBlockEntity jukebox) { ++ // There can only be one ++ ItemStack record = this.copy(); ++ if (!record.isEmpty()) { ++ record.setCount(1); ++ } ++ ++ jukebox.setFirstItem(record); ++ world.gameEvent(GameEvent.BLOCK_CHANGE, blockpos, GameEvent.Context.of(player, world.getBlockState(blockpos))); ++ } ++ ++ this.shrink(1); ++ player.awardStat(Stats.PLAY_RECORD); ++ } ++ ++ if (this.item == Items.WITHER_SKELETON_SKULL) { // Special case skulls to allow wither spawns to be cancelled ++ BlockPos bp = blockpos; ++ if (!world.getBlockState(blockpos).canBeReplaced()) { ++ if (!world.getBlockState(blockpos).isSolid()) { ++ bp = null; ++ } else { ++ bp = bp.relative(p_41662_.getClickedFace()); ++ } ++ } ++ if (bp != null) { ++ BlockEntity te = world.getBlockEntity(bp); ++ if (te instanceof SkullBlockEntity) { ++ WitherSkullBlock.checkSpawn(world, bp, (SkullBlockEntity) te); ++ } ++ } ++ } ++ ++ // SPIGOT-4678 ++ if (this.item instanceof SignItem && SignItem.openSign != null) { ++ try { ++ if (world.getBlockEntity(SignItem.openSign) instanceof SignBlockEntity tileentitysign) { ++ if (world.getBlockState(SignItem.openSign).getBlock() instanceof SignBlock blocksign) { ++ blocksign.openTextEdit(player, tileentitysign, true, org.bukkit.event.player.PlayerSignOpenEvent.Cause.PLACE); // Craftbukkit ++ } ++ } ++ } finally { ++ SignItem.openSign = null; ++ } ++ } ++ ++ // SPIGOT-7315: Moved from BlockBed#setPlacedBy ++ if (placeEvent != null && this.item instanceof BedItem) { ++ BlockPos position = ((CraftBlock) placeEvent.getBlock()).getPosition(); ++ BlockState blockData = world.getBlockState(position); ++ ++ if (blockData.getBlock() instanceof BedBlock) { ++ world.blockUpdated(position, Blocks.AIR); ++ blockData.updateNeighbourShapes(world, position, 3); ++ } ++ } ++ ++ // SPIGOT-1288 - play sound stripped from ItemBlock ++ if (this.item instanceof BlockItem) { ++ SoundType soundeffecttype = ((BlockItem) this.item).getBlock().defaultBlockState().getSoundType(); // TODO: not strictly correct, however currently only affects decorated pots ++ world.playSound(player, blockpos, soundeffecttype.getPlaceSound(), SoundSource.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F); ++ } ++ ++ player.awardStat(Stats.ITEM_USED.get(item)); ++ } } ++ world.capturedTileEntities.clear(); ++ world.capturedBlockStates.clear(); ++ // CraftBukkit end + + return interactionresult; + } @@ -267,11 +_,15 @@ p_41740_.put("tag", this.tag.copy()); } @@ -157,7 +442,29 @@ } public boolean hurt(int p_220158_, RandomSource p_220159_, @Nullable ServerPlayer p_220160_) { -@@ -336,6 +_,7 @@ +@@ -318,6 +_,21 @@ + } + + p_220158_ -= j; ++ // CraftBukkit start ++ if (p_220160_ != null) { ++ PlayerItemDamageEvent event = new PlayerItemDamageEvent(p_220160_.getBukkitEntity(), CraftItemStack.asCraftMirror(this), p_220158_); ++ event.getPlayer().getServer().getPluginManager().callEvent(event); ++ ++ if (p_220158_ != event.getDamage() || event.isCancelled()) { ++ event.getPlayer().updateInventory(); ++ } ++ if (event.isCancelled()) { ++ return false; ++ } ++ ++ p_220158_ = event.getDamage(); ++ } ++ // CraftBukkit end + if (p_220158_ <= 0) { + return false; + } +@@ -336,9 +_,16 @@ public void hurtAndBreak(int p_41623_, T p_41624_, Consumer p_41625_) { if (!p_41624_.level().isClientSide && (!(p_41624_ instanceof Player) || !((Player)p_41624_).getAbilities().instabuild)) { if (this.isDamageableItem()) { @@ -165,6 +472,15 @@ if (this.hurt(p_41623_, p_41624_.getRandom(), p_41624_ instanceof ServerPlayer ? (ServerPlayer)p_41624_ : null)) { p_41625_.accept(p_41624_); Item item = this.getItem(); ++ // CraftBukkit start - Check for item breaking ++ if (this.count == 1 && p_41624_ instanceof Player) { ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callPlayerItemBreakEvent((Player) p_41624_, this); ++ } ++ // CraftBukkit end ++ + this.shrink(1); + if (p_41624_ instanceof Player) { + ((Player)p_41624_).awardStat(Stats.ITEM_BROKEN.get(item)); @@ -388,7 +_,7 @@ } @@ -192,6 +508,24 @@ } } +@@ -488,6 +_,17 @@ + return this.tag; + } + ++ // CraftBukkit start ++ @Nullable ++ private CompoundTag getTagClone() { ++ return this.tag == null ? null : this.tag.copy(); ++ } ++ ++ private void setTagClone(@Nullable CompoundTag nbtttagcompound) { ++ this.setTag(nbtttagcompound == null ? null : nbtttagcompound.copy()); ++ } ++ // CraftBukkit end ++ + public CompoundTag getOrCreateTag() { + if (this.tag == null) { + this.setTag(new CompoundTag()); @@ -527,7 +_,7 @@ public void setTag(@Nullable CompoundTag p_41752_) { @@ -239,6 +573,20 @@ return multimap; } +@@ -885,6 +_,13 @@ + listtag.add(compoundtag); + } + ++ // CraftBukkit start ++ @Deprecated ++ public void setItem(Item item) { ++ this.item = item; ++ } ++ // CraftBukkit end ++ + public Component getDisplayName() { + MutableComponent mutablecomponent = Component.empty().append(this.getHoverName()); + if (this.hasCustomHoverName()) { @@ -893,7 +_,7 @@ MutableComponent mutablecomponent1 = ComponentUtils.wrapInSquareBrackets(mutablecomponent); diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index a3a99c33fc..98895fb665 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -510,7 +510,7 @@ public static InteractionResult onPlaceItemIntoWorld(@NotNull UseOnContext conte level.captureBlockSnapshots = true; ItemStack copy = itemstack.copy(); - InteractionResult ret = itemstack.getItem().useOn(context); + InteractionResult ret = itemstack.onItemUse(context, (c) -> itemstack.getItem().useOn(context)); //Ketting - make sure that craftbukkit knows that we fired this event if (itemstack.isEmpty()) ForgeEventFactory.onPlayerDestroyItem(player, copy, context.getHand());