Commits

md_5 authored 91cae6efbf0
SPIGOT-4387: Durability looping from cancelled BlockPlaceEvent
No tags

nms-patches/ItemStack.patch

Modified
78 78
79 79 @@ -98,7 +138,7 @@
80 80 return this.h ? Items.AIR : this.item;
81 81 }
82 82
83 83 - public EnumInteractionResult placeItem(ItemActionContext itemactioncontext) {
84 84 + public EnumInteractionResult placeItem(ItemActionContext itemactioncontext, EnumHand enumhand) { // CraftBukkit - add hand
85 85 EntityHuman entityhuman = itemactioncontext.getEntity();
86 86 BlockPosition blockposition = itemactioncontext.getClickPosition();
87 87 ShapeDetectorBlock shapedetectorblock = new ShapeDetectorBlock(itemactioncontext.getWorld(), blockposition, false);
88 -@@ -106,12 +146,142 @@
88 +@@ -106,12 +146,147 @@
89 89 if (entityhuman != null && !entityhuman.abilities.mayBuild && !this.b(itemactioncontext.getWorld().F(), shapedetectorblock)) {
90 90 return EnumInteractionResult.PASS;
91 91 } else {
92 92 + // CraftBukkit start - handle all block place event logic here
93 ++ NBTTagCompound oldData = this.getTagClone();
93 94 + int oldCount = this.getCount();
94 95 + World world = itemactioncontext.getWorld();
95 96 +
96 97 + if (!(this.getItem() instanceof ItemBucket)) { // if not bucket
97 98 + world.captureBlockStates = true;
98 99 + // special case bonemeal
99 100 + if (this.getItem() == Items.BONE_MEAL) {
100 101 + world.captureTreeGeneration = true;
101 102 + }
102 103 + }
103 104 Item item = this.getItem();
104 105 EnumInteractionResult enuminteractionresult = item.a(itemactioncontext);
106 ++ NBTTagCompound newData = this.getTagClone();
105 107 + int newCount = this.getCount();
106 108 + this.setCount(oldCount);
109 ++ this.setTagClone(oldData);
107 110 + world.captureBlockStates = false;
108 111 + if (enuminteractionresult == EnumInteractionResult.SUCCESS && world.captureTreeGeneration && world.capturedBlockStates.size() > 0) {
109 112 + world.captureTreeGeneration = false;
110 113 + Location location = new Location(world.getWorld(), blockposition.getX(), blockposition.getY(), blockposition.getZ());
111 114 + TreeType treeType = BlockSapling.treeType;
112 115 + BlockSapling.treeType = null;
113 116 + List<BlockState> blocks = (List<BlockState>) world.capturedBlockStates.clone();
114 117 + world.capturedBlockStates.clear();
115 118 + StructureGrowEvent structureEvent = null;
116 119 + if (treeType != null) {
117 120 + boolean isBonemeal = getItem() == Items.BONE_MEAL;
118 121 + structureEvent = new StructureGrowEvent(location, treeType, isBonemeal, (Player) entityhuman.getBukkitEntity(), blocks);
119 122 + org.bukkit.Bukkit.getPluginManager().callEvent(structureEvent);
120 123 + }
121 124 +
122 125 + BlockFertilizeEvent fertilizeEvent = new BlockFertilizeEvent(CraftBlock.at(world, blockposition), (Player) entityhuman.getBukkitEntity(), blocks);
123 126 + fertilizeEvent.setCancelled(structureEvent != null && structureEvent.isCancelled());
124 127 + org.bukkit.Bukkit.getPluginManager().callEvent(fertilizeEvent);
125 128 +
126 129 + if (!fertilizeEvent.isCancelled()) {
127 130 + // Change the stack to its new contents if it hasn't been tampered with.
128 -+ if (this.getCount() == oldCount) {
131 ++ if (this.getCount() == oldCount && Objects.equals(this.tag, oldData)) {
132 ++ this.setTag(newData);
129 133 + this.setCount(newCount);
130 134 + }
131 135 + for (BlockState blockstate : blocks) {
132 136 + blockstate.update(true);
133 137 + }
134 138 + }
135 139 +
136 140 + return enuminteractionresult;
137 141 + }
138 142 + world.captureTreeGeneration = false;
157 161 + blockstate.update(true, false);
158 162 + }
159 163 +
160 164 + // Brute force all possible updates
161 165 + BlockPosition placedPos = ((CraftBlock) placeEvent.getBlock()).getPosition();
162 166 + for (EnumDirection dir : EnumDirection.values()) {
163 167 + ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutBlockChange(world, placedPos.shift(dir)));
164 168 + }
165 169 + } else {
166 170 + // Change the stack to its new contents if it hasn't been tampered with.
167 -+ if (this.getCount() == oldCount) {
171 ++ if (this.getCount() == oldCount && Objects.equals(this.tag, oldData)) {
172 ++ this.setTag(newData);
168 173 + this.setCount(newCount);
169 174 + }
170 175 +
171 176 + for (Map.Entry<BlockPosition, TileEntity> e : world.capturedTileEntities.entrySet()) {
172 177 + world.setTileEntity(e.getKey(), e.getValue());
173 178 + }
174 179 +
175 180 + for (BlockState blockstate : blocks) {
176 181 + int x = blockstate.getX();
177 182 + int y = blockstate.getY();
222 227 +
223 228 + entityhuman.b(StatisticList.ITEM_USED.b(item));
224 229 + }
225 230 }
226 231 + world.capturedTileEntities.clear();
227 232 + world.capturedBlockStates.clear();
228 233 + // CraftBukkit end
229 234
230 235 return enuminteractionresult;
231 236 }
232 -@@ -135,7 +305,7 @@
237 +@@ -135,7 +310,7 @@
233 238 nbttagcompound.setString("id", minecraftkey == null ? "minecraft:air" : minecraftkey.toString());
234 239 nbttagcompound.setByte("Count", (byte) this.count);
235 240 if (this.tag != null) {
236 241 - nbttagcompound.set("tag", this.tag);
237 242 + nbttagcompound.set("tag", this.tag.clone()); // CraftBukkit - make defensive copy, data is going to another thread
238 243 }
239 244
240 245 return nbttagcompound;
241 -@@ -213,6 +383,11 @@
246 +@@ -213,6 +388,11 @@
242 247 if (this.isDamaged(i, entityliving.getRandom(), entityliving instanceof EntityPlayer ? (EntityPlayer) entityliving : null)) {
243 248 entityliving.c(this);
244 249 Item item = this.getItem();
245 250 + // CraftBukkit start - Check for item breaking
246 251 + if (this.count == 1 && entityliving instanceof EntityHuman) {
247 252 + org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent((EntityHuman) entityliving, this);
248 253 + }
249 254 + // CraftBukkit end
250 255
251 256 this.subtract(1);
252 257 if (entityliving instanceof EntityHuman) {
253 -@@ -480,6 +655,14 @@
258 +@@ -336,6 +516,17 @@
259 + return this.tag;
260 + }
261 +
262 ++ // CraftBukkit start
263 ++ @Nullable
264 ++ private NBTTagCompound getTagClone() {
265 ++ return this.tag == null ? null : this.tag.clone();
266 ++ }
267 ++
268 ++ private void setTagClone(@Nullable NBTTagCompound nbtttagcompound) {
269 ++ this.setTag(nbtttagcompound == null ? null : nbtttagcompound.clone());
270 ++ }
271 ++ // CraftBukkit end
272 ++
273 + public NBTTagCompound getOrCreateTag() {
274 + if (this.tag == null) {
275 + this.setTag(new NBTTagCompound());
276 +@@ -480,6 +671,14 @@
254 277 }
255 278
256 279 public void setRepairCost(int i) {
257 280 + // CraftBukkit start - remove RepairCost tag when 0 (SPIGOT-3945)
258 281 + if (i == 0) {
259 282 + if (this.hasTag()) {
260 283 + this.tag.remove("RepairCost");
261 284 + }
262 285 + return;
263 286 + }
264 287 + // CraftBukkit end
265 288 this.getOrCreateTag().setInt("RepairCost", i);
266 289 }
267 290
268 -@@ -522,6 +705,13 @@
291 +@@ -522,6 +721,13 @@
269 292 nbttaglist.add((NBTBase) nbttagcompound);
270 293 }
271 294
272 295 + // CraftBukkit start
273 296 + @Deprecated
274 297 + public void setItem(Item item) {
275 298 + this.item = item;
276 299 + }
277 300 + // CraftBukkit end
278 301 +

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut