diff --git a/patches/minecraft/net/minecraft/block/Block.java.patch b/patches/minecraft/net/minecraft/block/Block.java.patch index 493340132..102f4415c 100644 --- a/patches/minecraft/net/minecraft/block/Block.java.patch +++ b/patches/minecraft/net/minecraft/block/Block.java.patch @@ -116,9 +116,12 @@ } public final void func_149697_b(World p_149697_1_, int p_149697_2_, int p_149697_3_, int p_149697_4_, int p_149697_5_, int p_149697_6_) -@@ -624,18 +652,14 @@ +@@ -622,20 +650,16 @@ + + public void func_149690_a(World p_149690_1_, int p_149690_2_, int p_149690_3_, int p_149690_4_, int p_149690_5_, float p_149690_6_, int p_149690_7_) { - if (!p_149690_1_.field_72995_K) +- if (!p_149690_1_.field_72995_K) ++ if (!p_149690_1_.field_72995_K && !p_149690_1_.restoringBlockSnapshots) // do not drop items while restoring blockstates, prevents item dupe { - int j1 = this.func_149679_a(p_149690_7_, p_149690_1_.field_73012_v); + ArrayList items = getDrops(p_149690_1_, p_149690_2_, p_149690_3_, p_149690_4_, p_149690_5_, p_149690_7_); @@ -139,9 +142,12 @@ } } } -@@ -645,6 +669,11 @@ +@@ -643,8 +667,13 @@ + + protected void func_149642_a(World p_149642_1_, int p_149642_2_, int p_149642_3_, int p_149642_4_, ItemStack p_149642_5_) { - if (!p_149642_1_.field_72995_K && p_149642_1_.func_82736_K().func_82766_b("doTileDrops")) +- if (!p_149642_1_.field_72995_K && p_149642_1_.func_82736_K().func_82766_b("doTileDrops")) ++ if (!p_149642_1_.field_72995_K && p_149642_1_.func_82736_K().func_82766_b("doTileDrops") && !p_149642_1_.restoringBlockSnapshots) // do not drop items while restoring blockstates, prevents item dupe { + if (captureDrops.get()) + { diff --git a/patches/minecraft/net/minecraft/item/ItemLilyPad.java.patch b/patches/minecraft/net/minecraft/item/ItemLilyPad.java.patch new file mode 100644 index 000000000..1196c91da --- /dev/null +++ b/patches/minecraft/net/minecraft/item/ItemLilyPad.java.patch @@ -0,0 +1,17 @@ +--- ../src-base/minecraft/net/minecraft/item/ItemLilyPad.java ++++ ../src-work/minecraft/net/minecraft/item/ItemLilyPad.java +@@ -46,7 +46,14 @@ + + if (p_77659_2_.func_147439_a(i, j, k).func_149688_o() == Material.field_151586_h && p_77659_2_.func_72805_g(i, j, k) == 0 && p_77659_2_.func_147437_c(i, j + 1, k)) + { ++ // special case for handling block placement with water lilies ++ net.minecraftforge.common.util.BlockSnapshot blocksnapshot = net.minecraftforge.common.util.BlockSnapshot.getBlockSnapshot(p_77659_2_, i, j + 1, k); + p_77659_2_.func_147449_b(i, j + 1, k, Blocks.field_150392_bi); ++ if (net.minecraftforge.event.ForgeEventFactory.onPlayerBlockPlace(p_77659_3_, blocksnapshot, net.minecraftforge.common.util.ForgeDirection.UP).isCanceled()) ++ { ++ blocksnapshot.restore(true, false); ++ return p_77659_1_; ++ } + + if (!p_77659_3_.field_71075_bZ.field_75098_d) + { diff --git a/patches/minecraft/net/minecraft/item/ItemStack.java.patch b/patches/minecraft/net/minecraft/item/ItemStack.java.patch index 10f06c8c7..f0d3176e3 100644 --- a/patches/minecraft/net/minecraft/item/ItemStack.java.patch +++ b/patches/minecraft/net/minecraft/item/ItemStack.java.patch @@ -8,7 +8,15 @@ public final class ItemStack { -@@ -182,7 +183,7 @@ +@@ -124,6 +125,7 @@ + + public boolean func_77943_a(EntityPlayer p_77943_1_, World p_77943_2_, int p_77943_3_, int p_77943_4_, int p_77943_5_, int p_77943_6_, float p_77943_7_, float p_77943_8_, float p_77943_9_) + { ++ if (!p_77943_2_.field_72995_K) return net.minecraftforge.common.ForgeHooks.onPlaceItemIntoWorld(this, p_77943_1_, p_77943_2_, p_77943_3_, p_77943_4_, p_77943_5_, p_77943_6_, p_77943_7_, p_77943_8_, p_77943_9_); + boolean flag = this.func_77973_b().func_77648_a(this, p_77943_1_, p_77943_2_, p_77943_3_, p_77943_4_, p_77943_5_, p_77943_6_, p_77943_7_, p_77943_8_, p_77943_9_); + + if (flag) +@@ -182,7 +184,7 @@ public int func_77976_d() { @@ -17,7 +25,7 @@ } public boolean func_77985_e() -@@ -192,7 +193,7 @@ +@@ -192,7 +194,7 @@ public boolean func_77984_f() { @@ -26,7 +34,7 @@ } public boolean func_77981_g() -@@ -202,32 +203,27 @@ +@@ -202,32 +204,27 @@ public boolean func_77951_h() { @@ -64,7 +72,7 @@ } public boolean func_96631_a(int p_96631_1_, Random p_96631_2_) -@@ -259,8 +255,8 @@ +@@ -259,8 +256,8 @@ } } @@ -75,7 +83,7 @@ } } -@@ -319,7 +315,7 @@ +@@ -319,7 +316,7 @@ public boolean func_150998_b(Block p_150998_1_) { @@ -84,7 +92,7 @@ } public boolean func_111282_a(EntityPlayer p_111282_1_, EntityLivingBase p_111282_2_) -@@ -626,16 +622,24 @@ +@@ -626,16 +623,24 @@ { arraylist.add("Durability: " + (this.func_77958_k() - this.func_77952_i()) + " / " + this.func_77958_k()); } @@ -110,7 +118,7 @@ public EnumRarity func_77953_t() { return this.func_77973_b().func_77613_e(this); -@@ -737,7 +741,7 @@ +@@ -737,7 +742,7 @@ } else { diff --git a/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.java.patch b/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.java.patch index 311ad8a72..cc1d23ada 100644 --- a/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.java.patch +++ b/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.java.patch @@ -103,7 +103,15 @@ { return; } -@@ -500,7 +532,11 @@ +@@ -487,6 +519,7 @@ + WorldServer worldserver = this.field_147367_d.func_71218_a(this.field_147369_b.field_71093_bK); + ItemStack itemstack = this.field_147369_b.field_71071_by.func_70448_g(); + boolean flag = false; ++ boolean placeResult = true; + int i = p_147346_1_.func_149576_c(); + int j = p_147346_1_.func_149571_d(); + int k = p_147346_1_.func_149570_e(); +@@ -500,7 +533,11 @@ return; } @@ -116,7 +124,7 @@ } else if (p_147346_1_.func_149571_d() >= this.field_147367_d.func_71207_Z() - 1 && (p_147346_1_.func_149568_f() == 1 || p_147346_1_.func_149571_d() >= this.field_147367_d.func_71207_Z())) { -@@ -511,7 +547,9 @@ +@@ -511,9 +548,15 @@ } else { @@ -125,9 +133,25 @@ + dist *= dist; + if (this.field_147380_r && this.field_147369_b.func_70092_e((double)i + 0.5D, (double)j + 0.5D, (double)k + 0.5D) < dist && !this.field_147367_d.func_96290_a(worldserver, i, j, k, this.field_147369_b)) { - this.field_147369_b.field_71134_c.func_73078_a(this.field_147369_b, worldserver, itemstack, i, j, k, l, p_147346_1_.func_149573_h(), p_147346_1_.func_149569_i(), p_147346_1_.func_149575_j()); +- this.field_147369_b.field_71134_c.func_73078_a(this.field_147369_b, worldserver, itemstack, i, j, k, l, p_147346_1_.func_149573_h(), p_147346_1_.func_149569_i(), p_147346_1_.func_149575_j()); ++ // record block place result so we can update client itemstack size if place event was cancelled. ++ if (!this.field_147369_b.field_71134_c.func_73078_a(this.field_147369_b, worldserver, itemstack, i, j, k, l, p_147346_1_.func_149573_h(), p_147346_1_.func_149569_i(), p_147346_1_.func_149575_j())) ++ { ++ placeResult = false; ++ } } -@@ -677,6 +715,8 @@ + + flag = true; +@@ -572,7 +615,7 @@ + this.field_147369_b.field_71070_bA.func_75142_b(); + this.field_147369_b.field_71137_h = false; + +- if (!ItemStack.func_77989_b(this.field_147369_b.field_71071_by.func_70448_g(), p_147346_1_.func_149574_g())) ++ if (!ItemStack.func_77989_b(this.field_147369_b.field_71071_by.func_70448_g(), p_147346_1_.func_149574_g()) || !placeResult) // force client itemstack update if place event was cancelled + { + this.func_147359_a(new S2FPacketSetSlot(this.field_147369_b.field_71070_bA.field_75152_c, slot.field_75222_d, this.field_147369_b.field_71071_by.func_70448_g())); + } +@@ -677,6 +720,8 @@ else { ChatComponentTranslation chatcomponenttranslation1 = new ChatComponentTranslation("chat.type.text", new Object[] {this.field_147369_b.func_145748_c_(), s}); @@ -136,7 +160,7 @@ this.field_147367_d.func_71203_ab().func_148544_a(chatcomponenttranslation1, false); } -@@ -812,7 +852,7 @@ +@@ -812,7 +857,7 @@ return; } diff --git a/patches/minecraft/net/minecraft/world/World.java.patch b/patches/minecraft/net/minecraft/world/World.java.patch index 622f6d918..5643a8c8c 100644 --- a/patches/minecraft/net/minecraft/world/World.java.patch +++ b/patches/minecraft/net/minecraft/world/World.java.patch @@ -36,7 +36,13 @@ public boolean field_72999_e; public List field_72996_f = new ArrayList(); protected List field_72997_g = new ArrayList(); -@@ -97,6 +124,11 @@ +@@ -94,9 +121,17 @@ + private boolean field_147481_N; + int[] field_72994_J; + private static final String __OBFID = "CL_00000140"; ++ public boolean restoringBlockSnapshots = false; ++ public boolean captureBlockSnapshots = false; ++ public ArrayList capturedBlockSnapshots = new ArrayList(); public BiomeGenBase func_72807_a(final int p_72807_1_, final int p_72807_2_) { @@ -48,7 +54,7 @@ if (this.func_72899_e(p_72807_1_, 0, p_72807_2_)) { Chunk chunk = this.func_72938_d(p_72807_1_, p_72807_2_); -@@ -143,7 +175,13 @@ +@@ -143,7 +178,13 @@ this.field_72984_F = p_i45368_5_; this.field_72986_A = new WorldInfo(p_i45368_4_, p_i45368_2_); this.field_73011_w = p_i45368_3_; @@ -63,7 +69,7 @@ VillageCollection villagecollection = (VillageCollection)this.field_72988_C.func_75742_a(VillageCollection.class, "villages"); if (villagecollection == null) -@@ -157,7 +195,10 @@ +@@ -157,7 +198,10 @@ this.field_72982_D.func_82566_a(this); } @@ -75,7 +81,7 @@ this.field_73020_y = this.func_72970_h(); this.func_72966_v(); this.func_72947_a(); -@@ -172,7 +213,7 @@ +@@ -172,7 +216,7 @@ this.field_72994_J = new int[32768]; this.field_73019_z = p_i45369_1_; this.field_72984_F = p_i45369_5_; @@ -84,7 +90,7 @@ this.field_72986_A = p_i45369_1_.func_75757_d(); if (p_i45369_4_ != null) -@@ -200,6 +241,15 @@ +@@ -200,6 +244,15 @@ this.field_73011_w.func_76558_a(this); this.field_73020_y = this.func_72970_h(); @@ -100,7 +106,7 @@ if (!this.field_72986_A.func_76070_v()) { try -@@ -225,12 +275,12 @@ +@@ -225,12 +278,12 @@ this.field_72986_A.func_76091_d(true); } @@ -115,7 +121,7 @@ } else { -@@ -242,6 +292,20 @@ +@@ -242,6 +295,20 @@ this.func_72947_a(); } @@ -136,7 +142,7 @@ protected abstract IChunkProvider func_72970_h(); protected void func_72963_a(WorldSettings p_72963_1_) -@@ -295,7 +359,8 @@ +@@ -295,7 +362,8 @@ public boolean func_147437_c(int p_147437_1_, int p_147437_2_, int p_147437_3_) { @@ -146,7 +152,82 @@ } public boolean func_72899_e(int p_72899_1_, int p_72899_2_, int p_72899_3_) -@@ -927,7 +992,7 @@ +@@ -367,33 +435,33 @@ + { + Chunk chunk = this.func_72964_e(p_147465_1_ >> 4, p_147465_3_ >> 4); + Block block1 = null; ++ net.minecraftforge.common.util.BlockSnapshot blockSnapshot = null; + + if ((p_147465_6_ & 1) != 0) + { + block1 = chunk.func_150810_a(p_147465_1_ & 15, p_147465_2_, p_147465_3_ & 15); ++ if (this.captureBlockSnapshots && block1 != null && !this.field_72995_K) ++ { ++ blockSnapshot = net.minecraftforge.common.util.BlockSnapshot.getBlockSnapshot(this, p_147465_1_, p_147465_2_, p_147465_3_, p_147465_6_); ++ this.capturedBlockSnapshots.add(blockSnapshot); ++ } + } + + boolean flag = chunk.func_150807_a(p_147465_1_ & 15, p_147465_2_, p_147465_3_ & 15, p_147465_4_, p_147465_5_); ++ ++ if (!flag && this.captureBlockSnapshots && block1 != null && !this.field_72995_K) ++ { ++ this.capturedBlockSnapshots.remove(blockSnapshot); ++ } ++ + this.field_72984_F.func_76320_a("checkLight"); + this.func_147451_t(p_147465_1_, p_147465_2_, p_147465_3_); + this.field_72984_F.func_76319_b(); + +- if (flag) ++ if (flag && !this.captureBlockSnapshots) // Don't notify clients or update physics while capturing blockstates + { +- if ((p_147465_6_ & 2) != 0 && (!this.field_72995_K || (p_147465_6_ & 4) == 0) && chunk.func_150802_k()) +- { +- this.func_147471_g(p_147465_1_, p_147465_2_, p_147465_3_); +- } +- +- if (!this.field_72995_K && (p_147465_6_ & 1) != 0) +- { +- this.func_147444_c(p_147465_1_, p_147465_2_, p_147465_3_, block1); +- +- if (p_147465_4_.func_149740_M()) +- { +- this.func_147453_f(p_147465_1_, p_147465_2_, p_147465_3_, p_147465_4_); +- } +- } ++ // Modularize client and physic updates ++ this.markAndNotifyBlock(p_147465_1_, p_147465_2_, p_147465_3_, chunk, block1, p_147465_4_, p_147465_6_); + } + + return flag; +@@ -405,6 +473,25 @@ + } + } + ++ // Split off from original setBlock(int p_147465_1_, int p_147465_2_, int p_147465_3_, Block p_147465_4_, int p_147465_5_, int p_147465_6_) method in order to directly send client and physic updates ++ public void markAndNotifyBlock(int x, int y, int z, Chunk chunk, Block oldBlock, Block newBlock, int flag) ++ { ++ if ((flag & 2) != 0 && (chunk == null || chunk.func_150802_k())) ++ { ++ this.func_147471_g(x, y, z); ++ } ++ ++ if (!this.field_72995_K && (flag & 1) != 0) ++ { ++ this.func_147444_c(x, y, z, oldBlock); ++ ++ if (newBlock.func_149740_M()) ++ { ++ this.func_147453_f(x, y, z, newBlock); ++ } ++ } ++ } ++ + public int func_72805_g(int p_72805_1_, int p_72805_2_, int p_72805_3_) + { + if (p_72805_1_ >= -30000000 && p_72805_3_ >= -30000000 && p_72805_1_ < 30000000 && p_72805_3_ < 30000000) +@@ -927,7 +1014,7 @@ public boolean func_72935_r() { @@ -155,7 +236,7 @@ } public MovingObjectPosition func_72933_a(Vec3 p_72933_1_, Vec3 p_72933_2_) -@@ -1158,6 +1223,12 @@ +@@ -1158,6 +1245,12 @@ public void func_72956_a(Entity p_72956_1_, String p_72956_2_, float p_72956_3_, float p_72956_4_) { @@ -168,7 +249,7 @@ for (int i = 0; i < this.field_73021_x.size(); ++i) { ((IWorldAccess)this.field_73021_x.get(i)).func_72704_a(p_72956_2_, p_72956_1_.field_70165_t, p_72956_1_.field_70163_u - (double)p_72956_1_.field_70129_M, p_72956_1_.field_70161_v, p_72956_3_, p_72956_4_); -@@ -1166,6 +1237,12 @@ +@@ -1166,6 +1259,12 @@ public void func_85173_a(EntityPlayer p_85173_1_, String p_85173_2_, float p_85173_3_, float p_85173_4_) { @@ -181,7 +262,17 @@ for (int i = 0; i < this.field_73021_x.size(); ++i) { ((IWorldAccess)this.field_73021_x.get(i)).func_85102_a(p_85173_1_, p_85173_2_, p_85173_1_.field_70165_t, p_85173_1_.field_70163_u - (double)p_85173_1_.field_70129_M, p_85173_1_.field_70161_v, p_85173_3_, p_85173_4_); -@@ -1227,6 +1304,7 @@ +@@ -1206,6 +1305,9 @@ + + public boolean func_72838_d(Entity p_72838_1_) + { ++ // do not drop any items while restoring blocksnapshots. Prevents dupes ++ if (!this.field_72995_K && (p_72838_1_ == null || (p_72838_1_ instanceof net.minecraft.entity.item.EntityItem && this.restoringBlockSnapshots))) return false; ++ + int i = MathHelper.func_76128_c(p_72838_1_.field_70165_t / 16.0D); + int j = MathHelper.func_76128_c(p_72838_1_.field_70161_v / 16.0D); + boolean flag = p_72838_1_.field_98038_p; +@@ -1227,6 +1329,7 @@ this.field_73010_i.add(entityplayer); this.func_72854_c(); } @@ -189,7 +280,7 @@ this.func_72964_e(i, j).func_76612_a(p_72838_1_); this.field_72996_f.add(p_72838_1_); -@@ -1398,6 +1476,20 @@ +@@ -1398,6 +1501,20 @@ public int func_72967_a(float p_72967_1_) { @@ -210,7 +301,7 @@ float f1 = this.func_72826_c(p_72967_1_); float f2 = 1.0F - (MathHelper.func_76134_b(f1 * (float)Math.PI * 2.0F) * 2.0F + 0.5F); -@@ -1414,11 +1506,9 @@ +@@ -1414,11 +1531,9 @@ f2 = 1.0F - f2; f2 = (float)((double)f2 * (1.0D - (double)(this.func_72867_j(p_72967_1_) * 5.0F) / 16.0D)); f2 = (float)((double)f2 * (1.0D - (double)(this.func_72819_i(p_72967_1_) * 5.0F) / 16.0D)); @@ -223,7 +314,7 @@ public void func_72848_b(IWorldAccess p_72848_1_) { this.field_73021_x.remove(p_72848_1_); -@@ -1427,6 +1517,12 @@ +@@ -1427,6 +1542,12 @@ @SideOnly(Side.CLIENT) public float func_72971_b(float p_72971_1_) { @@ -236,7 +327,7 @@ float f1 = this.func_72826_c(p_72971_1_); float f2 = 1.0F - (MathHelper.func_76134_b(f1 * (float)Math.PI * 2.0F) * 2.0F + 0.2F); -@@ -1449,6 +1545,12 @@ +@@ -1449,6 +1570,12 @@ @SideOnly(Side.CLIENT) public Vec3 func_72833_a(Entity p_72833_1_, float p_72833_2_) { @@ -249,7 +340,7 @@ float f1 = this.func_72826_c(p_72833_2_); float f2 = MathHelper.func_76134_b(f1 * (float)Math.PI * 2.0F) * 2.0F + 0.5F; -@@ -1465,9 +1567,7 @@ +@@ -1465,9 +1592,7 @@ int i = MathHelper.func_76128_c(p_72833_1_.field_70165_t); int j = MathHelper.func_76128_c(p_72833_1_.field_70163_u); int k = MathHelper.func_76128_c(p_72833_1_.field_70161_v); @@ -260,7 +351,7 @@ float f4 = (float)(l >> 16 & 255) / 255.0F; float f5 = (float)(l >> 8 & 255) / 255.0F; float f6 = (float)(l & 255) / 255.0F; -@@ -1529,6 +1629,11 @@ +@@ -1529,6 +1654,11 @@ public float func_130001_d() { @@ -272,7 +363,7 @@ return WorldProvider.field_111203_a[this.field_73011_w.func_76559_b(this.field_72986_A.func_76073_f())]; } -@@ -1541,6 +1646,12 @@ +@@ -1541,6 +1671,12 @@ @SideOnly(Side.CLIENT) public Vec3 func_72824_f(float p_72824_1_) { @@ -285,7 +376,7 @@ float f1 = this.func_72826_c(p_72824_1_); float f2 = MathHelper.func_76134_b(f1 * (float)Math.PI * 2.0F) * 2.0F + 0.5F; -@@ -1602,6 +1713,8 @@ +@@ -1602,6 +1738,8 @@ public int func_72825_h(int p_72825_1_, int p_72825_2_) { Chunk chunk = this.func_72938_d(p_72825_1_, p_72825_2_); @@ -294,7 +385,7 @@ int k = chunk.func_76625_h() + 15; p_72825_1_ &= 15; -@@ -1609,7 +1722,7 @@ +@@ -1609,7 +1747,7 @@ { Block block = chunk.func_150810_a(p_72825_1_, k, p_72825_2_); @@ -303,7 +394,7 @@ { return k + 1; } -@@ -1621,7 +1734,13 @@ +@@ -1621,7 +1759,13 @@ @SideOnly(Side.CLIENT) public float func_72880_h(float p_72880_1_) { @@ -318,7 +409,7 @@ float f2 = 1.0F - (MathHelper.func_76134_b(f1 * (float)Math.PI * 2.0F) * 2.0F + 0.25F); if (f2 < 0.0F) -@@ -1675,7 +1794,15 @@ +@@ -1675,7 +1819,15 @@ entity.func_85029_a(crashreportcategory); } @@ -335,7 +426,7 @@ } if (entity.field_70128_L) -@@ -1737,7 +1864,16 @@ +@@ -1737,7 +1889,16 @@ crashreport = CrashReport.func_85055_a(throwable1, "Ticking entity"); crashreportcategory = crashreport.func_85058_a("Entity being ticked"); entity.func_85029_a(crashreportcategory); @@ -353,7 +444,7 @@ } } -@@ -1780,7 +1916,16 @@ +@@ -1780,7 +1941,16 @@ crashreport = CrashReport.func_85055_a(throwable, "Ticking block entity"); crashreportcategory = crashreport.func_85058_a("Block entity being ticked"); tileentity.func_145828_a(crashreportcategory); @@ -371,7 +462,7 @@ } } -@@ -1794,7 +1939,7 @@ +@@ -1794,7 +1964,7 @@ if (chunk != null) { @@ -380,7 +471,7 @@ } } } -@@ -1802,6 +1947,10 @@ +@@ -1802,6 +1972,10 @@ if (!this.field_147483_b.isEmpty()) { @@ -391,7 +482,7 @@ this.field_147482_g.removeAll(this.field_147483_b); this.field_147483_b.clear(); } -@@ -1822,18 +1971,18 @@ +@@ -1822,18 +1996,18 @@ { this.field_147482_g.add(tileentity1); } @@ -414,7 +505,7 @@ } } -@@ -1846,14 +1995,11 @@ +@@ -1846,14 +2020,11 @@ public void func_147448_a(Collection p_147448_1_) { @@ -432,7 +523,7 @@ } public void func_72870_g(Entity p_72870_1_) -@@ -1865,10 +2011,19 @@ +@@ -1865,10 +2036,19 @@ { int i = MathHelper.func_76128_c(p_72866_1_.field_70165_t); int j = MathHelper.func_76128_c(p_72866_1_.field_70161_v); @@ -454,7 +545,7 @@ p_72866_1_.field_70142_S = p_72866_1_.field_70165_t; p_72866_1_.field_70137_T = p_72866_1_.field_70163_u; p_72866_1_.field_70136_U = p_72866_1_.field_70161_v; -@@ -2086,6 +2241,10 @@ +@@ -2086,6 +2266,10 @@ { return true; } @@ -465,7 +556,7 @@ } } } -@@ -2378,13 +2537,15 @@ +@@ -2378,13 +2562,15 @@ public void func_147455_a(int p_147455_1_, int p_147455_2_, int p_147455_3_, TileEntity p_147455_4_) { @@ -485,7 +576,7 @@ Iterator iterator = this.field_147484_a.iterator(); while (iterator.hasNext()) -@@ -2403,40 +2564,22 @@ +@@ -2403,40 +2589,22 @@ else { this.field_147482_g.add(p_147455_4_); @@ -536,7 +627,7 @@ } public void func_147457_a(TileEntity p_147457_1_) -@@ -2453,8 +2596,7 @@ +@@ -2453,8 +2621,7 @@ public static boolean func_147466_a(IBlockAccess p_147466_0_, int p_147466_1_, int p_147466_2_, int p_147466_3_) { Block block = p_147466_0_.func_147439_a(p_147466_1_, p_147466_2_, p_147466_3_); @@ -546,7 +637,7 @@ } public boolean func_147445_c(int p_147445_1_, int p_147445_2_, int p_147445_3_, boolean p_147445_4_) -@@ -2466,7 +2608,7 @@ +@@ -2466,7 +2633,7 @@ if (chunk != null && !chunk.func_76621_g()) { Block block = this.func_147439_a(p_147445_1_, p_147445_2_, p_147445_3_); @@ -555,7 +646,7 @@ } else { -@@ -2491,8 +2633,7 @@ +@@ -2491,8 +2658,7 @@ public void func_72891_a(boolean p_72891_1_, boolean p_72891_2_) { @@ -565,7 +656,7 @@ } public void func_72835_b() -@@ -2502,6 +2643,11 @@ +@@ -2502,6 +2668,11 @@ private void func_72947_a() { @@ -577,7 +668,7 @@ if (this.field_72986_A.func_76059_o()) { this.field_73004_o = 1.0F; -@@ -2515,6 +2661,11 @@ +@@ -2515,6 +2686,11 @@ protected void func_72979_l() { @@ -589,7 +680,7 @@ if (!this.field_73011_w.field_76576_e) { if (!this.field_72995_K) -@@ -2599,6 +2750,7 @@ +@@ -2599,6 +2775,7 @@ { this.field_72993_I.clear(); this.field_72984_F.func_76320_a("buildList"); @@ -597,7 +688,7 @@ int i; EntityPlayer entityplayer; int j; -@@ -2693,6 +2845,11 @@ +@@ -2693,6 +2870,11 @@ public boolean func_72834_c(int p_72834_1_, int p_72834_2_, int p_72834_3_, boolean p_72834_4_) { @@ -609,7 +700,7 @@ BiomeGenBase biomegenbase = this.func_72807_a(p_72834_1_, p_72834_3_); float f = biomegenbase.func_150564_a(p_72834_1_, p_72834_2_, p_72834_3_); -@@ -2748,6 +2905,11 @@ +@@ -2748,6 +2930,11 @@ public boolean func_147478_e(int p_147478_1_, int p_147478_2_, int p_147478_3_, boolean p_147478_4_) { @@ -621,7 +712,7 @@ BiomeGenBase biomegenbase = this.func_72807_a(p_147478_1_, p_147478_3_); float f = biomegenbase.func_150564_a(p_147478_1_, p_147478_2_, p_147478_3_); -@@ -2797,10 +2959,11 @@ +@@ -2797,10 +2984,11 @@ else { Block block = this.func_147439_a(p_98179_1_, p_98179_2_, p_98179_3_); @@ -636,7 +727,7 @@ { i1 = 1; } -@@ -2900,7 +3063,7 @@ +@@ -2900,7 +3088,7 @@ int j4 = i2 + Facing.field_71586_b[i4]; int k4 = j2 + Facing.field_71587_c[i4]; int l4 = k2 + Facing.field_71585_d[i4]; @@ -645,7 +736,7 @@ i3 = this.func_72972_b(p_147463_1_, j4, k4, l4); if (i3 == l2 - i5 && i1 < this.field_72994_J.length) -@@ -2998,10 +3161,10 @@ +@@ -2998,10 +3186,10 @@ public List func_94576_a(Entity p_94576_1_, AxisAlignedBB p_94576_2_, IEntitySelector p_94576_3_) { ArrayList arraylist = new ArrayList(); @@ -660,7 +751,7 @@ for (int i1 = i; i1 <= j; ++i1) { -@@ -3024,10 +3187,10 @@ +@@ -3024,10 +3212,10 @@ public List func_82733_a(Class p_82733_1_, AxisAlignedBB p_82733_2_, IEntitySelector p_82733_3_) { @@ -675,7 +766,7 @@ ArrayList arraylist = new ArrayList(); for (int i1 = i; i1 <= j; ++i1) -@@ -3104,11 +3267,14 @@ +@@ -3104,11 +3292,14 @@ public void func_72868_a(List p_72868_1_) { @@ -693,7 +784,7 @@ } } -@@ -3121,7 +3287,7 @@ +@@ -3121,7 +3312,7 @@ { Block block1 = this.func_147439_a(p_147472_2_, p_147472_3_, p_147472_4_); AxisAlignedBB axisalignedbb = p_147472_5_ ? null : p_147472_1_.func_149668_a(this, p_147472_2_, p_147472_3_, p_147472_4_); @@ -702,7 +793,7 @@ } public PathEntity func_72865_a(Entity p_72865_1_, Entity p_72865_2_, float p_72865_3_, boolean p_72865_4_, boolean p_72865_5_, boolean p_72865_6_, boolean p_72865_7_) -@@ -3226,7 +3392,8 @@ +@@ -3226,7 +3417,8 @@ public int func_72878_l(int p_72878_1_, int p_72878_2_, int p_72878_3_, int p_72878_4_) { @@ -712,7 +803,7 @@ } public boolean func_72864_z(int p_72864_1_, int p_72864_2_, int p_72864_3_) -@@ -3374,7 +3541,7 @@ +@@ -3374,7 +3566,7 @@ public long func_72905_C() { @@ -721,7 +812,7 @@ } public long func_82737_E() -@@ -3384,22 +3551,22 @@ +@@ -3384,22 +3576,22 @@ public long func_72820_D() { @@ -748,7 +839,7 @@ } @SideOnly(Side.CLIENT) -@@ -3419,12 +3586,20 @@ +@@ -3419,12 +3611,20 @@ if (!this.field_72996_f.contains(p_72897_1_)) { @@ -770,7 +861,7 @@ return true; } -@@ -3514,8 +3689,7 @@ +@@ -3514,8 +3714,7 @@ public boolean func_72958_C(int p_72958_1_, int p_72958_2_, int p_72958_3_) { @@ -780,7 +871,7 @@ } public void func_72823_a(String p_72823_1_, WorldSavedData p_72823_2_) -@@ -3569,12 +3743,12 @@ +@@ -3569,12 +3768,12 @@ public int func_72800_K() { @@ -795,7 +886,7 @@ } public Random func_72843_D(int p_72843_1_, int p_72843_2_, int p_72843_3_) -@@ -3598,7 +3772,7 @@ +@@ -3598,7 +3797,7 @@ @SideOnly(Side.CLIENT) public double func_72919_O() { @@ -804,7 +895,7 @@ } public CrashReportCategory func_72914_a(CrashReport p_72914_1_) -@@ -3663,25 +3837,24 @@ +@@ -3663,25 +3862,24 @@ public void func_147453_f(int p_147453_1_, int p_147453_2_, int p_147453_3_, Block p_147453_4_) { @@ -843,7 +934,7 @@ } } } -@@ -3722,4 +3895,110 @@ +@@ -3722,4 +3920,110 @@ iworldaccess.func_147584_b(); } } diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index 71214251a..6b8891367 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -16,15 +16,19 @@ import net.minecraft.init.Items; import net.minecraft.inventory.Container; import net.minecraft.inventory.ContainerRepair; import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; import net.minecraft.item.ItemArmor; import net.minecraft.item.ItemAxe; +import net.minecraft.item.ItemBucket; import net.minecraft.item.ItemPickaxe; import net.minecraft.item.ItemSpade; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemSword; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.NetHandlerPlayServer; import net.minecraft.network.Packet; import net.minecraft.network.play.server.S23PacketBlockChange; +import net.minecraft.stats.StatList; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityNote; import net.minecraft.util.AxisAlignedBB; @@ -37,6 +41,7 @@ import net.minecraft.util.WeightedRandom; import net.minecraft.world.World; import net.minecraft.world.WorldSettings.GameType; import net.minecraftforge.event.AnvilUpdateEvent; +import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.event.ServerChatEvent; import net.minecraftforge.event.entity.item.ItemTossEvent; import net.minecraftforge.event.entity.living.LivingAttackEvent; @@ -430,6 +435,100 @@ public class ForgeHooks return event; } + public static boolean onPlaceItemIntoWorld(ItemStack itemstack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ) + { + // handle all placement events here + int meta = itemstack.getItemDamage(); + int size = itemstack.stackSize; + NBTTagCompound nbt = null; + if (itemstack.getTagCompound() != null) + { + nbt = (NBTTagCompound)itemstack.getTagCompound().copy(); + } + + if (!(itemstack.getItem() instanceof ItemBucket)) // if not bucket + { + world.captureBlockSnapshots = true; + } + + boolean flag = itemstack.getItem().onItemUse(itemstack, player, world, x, y, z, side, hitX, hitY, hitZ); + world.captureBlockSnapshots = false; + + if (flag) + { + // save new item data + int newMeta = itemstack.getItemDamage(); + int newSize = itemstack.stackSize; + NBTTagCompound newNBT = null; + if (itemstack.getTagCompound() != null) + { + newNBT = (NBTTagCompound)itemstack.getTagCompound().copy(); + } + net.minecraftforge.event.world.BlockEvent.PlaceEvent placeEvent = null; + List blockSnapshots = (List) world.capturedBlockSnapshots.clone(); + world.capturedBlockSnapshots.clear(); + + // make sure to set pre-placement item data for event + itemstack.setItemDamage(meta); + itemstack.stackSize = size; + if (nbt != null) + { + itemstack.setTagCompound(nbt); + } + if (blockSnapshots.size() > 1) + { + placeEvent = ForgeEventFactory.onPlayerMultiBlockPlace(player, blockSnapshots, net.minecraftforge.common.util.ForgeDirection.getOrientation(side)); + } + else if (blockSnapshots.size() == 1) + { + placeEvent = ForgeEventFactory.onPlayerBlockPlace(player, blockSnapshots.get(0), net.minecraftforge.common.util.ForgeDirection.getOrientation(side)); + } + + if (placeEvent != null && (placeEvent.isCanceled())) + { + flag = false; // cancel placement + // revert back all captured blocks + for (net.minecraftforge.common.util.BlockSnapshot blocksnapshot : blockSnapshots) + { + world.restoringBlockSnapshots = true; + blocksnapshot.restore(true, false); + world.restoringBlockSnapshots = false; + } + } + else + { + // Change the stack to its new content + itemstack.setItemDamage(newMeta); + itemstack.stackSize = newSize; + if (nbt != null) + { + itemstack.setTagCompound(newNBT); + } + + for (net.minecraftforge.common.util.BlockSnapshot blocksnapshot : blockSnapshots) + { + int blockX = blocksnapshot.x; + int blockY = blocksnapshot.y; + int blockZ = blocksnapshot.z; + int metadata = world.getBlockMetadata(blockX, blockY, blockZ); + int updateFlag = blocksnapshot.flag; + Block oldBlock = blocksnapshot.replacedBlock; + Block newBlock = world.getBlock(blockX, blockY, blockZ); + if (newBlock != null && !(newBlock.hasTileEntity(metadata))) // Containers get placed automatically + { + newBlock.onBlockAdded(world, blockX, blockY, blockZ); + } + + world.markAndNotifyBlock(blockX, blockY, blockZ, null, oldBlock, newBlock, updateFlag); + } + player.addStat(StatList.objectUseStats[Item.getIdFromItem(itemstack.getItem())], 1); + } + } + world.capturedBlockSnapshots.clear(); + + return flag; + } + public static boolean onAnvilChange(ContainerRepair container, ItemStack left, ItemStack right, IInventory outputSlot, String name, int baseCost) { AnvilUpdateEvent e = new AnvilUpdateEvent(left, right, name, baseCost); diff --git a/src/main/java/net/minecraftforge/common/util/BlockSnapshot.java b/src/main/java/net/minecraftforge/common/util/BlockSnapshot.java new file mode 100644 index 000000000..91f76062e --- /dev/null +++ b/src/main/java/net/minecraftforge/common/util/BlockSnapshot.java @@ -0,0 +1,312 @@ +package net.minecraftforge.common.util; + + +import java.io.Serializable; + +import net.minecraft.block.Block; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.DimensionManager; +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.common.registry.GameRegistry.UniqueIdentifier; + +/** + * Represents a captured snapshot of a block which will not change + * automatically. + *

+ * Unlike Block, which only one object can exist per coordinate, BlockSnapshot + * can exist multiple times for any given Block. + */ +@SuppressWarnings("serial") +public class BlockSnapshot implements Serializable +{ + private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("forge.debugBlockSnapshot", "false")); + + public final int x; + public final int y; + public final int z; + public final int dimId; + public transient Block replacedBlock; + public final int meta; + public int flag; + private final NBTTagCompound nbt; + public transient World world; + public final UniqueIdentifier blockIdentifier; + + public BlockSnapshot(World world, int x, int y, int z, Block block, int meta) + { + this.world = world; + this.dimId = world.provider.dimensionId; + this.x = x; + this.y = y; + this.z = z; + this.replacedBlock = block; + this.blockIdentifier = GameRegistry.findUniqueIdentifierFor(block); + this.meta = meta; + this.flag = 3; + TileEntity te = world.getTileEntity(x, y, z); + if (te != null) + { + nbt = new NBTTagCompound(); + te.writeToNBT(nbt); + } + else nbt = null; + if (DEBUG) + { + System.out.printf("Created BlockSnapshot - [World: %s ][Location: %d,%d,%d ][Block: %s ][Meta: %d ]", world.getWorldInfo().getWorldName(), x, y, z, block, meta); + } + } + + public BlockSnapshot(World world, int x, int y, int z, Block block, int meta, NBTTagCompound nbt) + { + this.world = world; + this.dimId = world.provider.dimensionId; + this.x = x; + this.y = y; + this.z = z; + this.replacedBlock = block; + this.blockIdentifier = GameRegistry.findUniqueIdentifierFor(block); + this.meta = meta; + this.flag = 3; + this.nbt = nbt; + if (DEBUG) + { + System.out.printf("Created BlockSnapshot - [World: %s ][Location: %d,%d,%d ][Block: %s ][Meta: %d ]", world.getWorldInfo().getWorldName(), x, y, z, block, meta); + } + } + + public BlockSnapshot(World world, int x, int y, int z, Block block, int meta, int flag) + { + this(world, x, y, z, block, meta); + this.flag = flag; + } + + /** + * Raw constructor designed for serialization usages. + */ + public BlockSnapshot(int dimension, int x, int y, int z, String modid, String blockName, int meta, int flag, NBTTagCompound nbt) + { + this.dimId = dimension; + this.x = x; + this.y = y; + this.z = z; + this.meta = meta; + this.flag = flag; + this.blockIdentifier = new UniqueIdentifier(modid + ":" + blockName); + this.nbt = nbt; + } + + public static BlockSnapshot getBlockSnapshot(World world, int x, int y, int z) + { + return new BlockSnapshot(world, x, y, z, world.getBlock(x, y, z), world.getBlockMetadata(x, y,z)); + } + + public static BlockSnapshot getBlockSnapshot(World world, int x, int y, int z, int flag) + { + return new BlockSnapshot(world, x, y, z, world.getBlock(x, y, z), world.getBlockMetadata(x, y,z), flag); + } + + public static BlockSnapshot readFromNBT(NBTTagCompound tag) + { + NBTTagCompound nbt = tag.getBoolean("hasTE") ? null : tag.getCompoundTag("tileEntity"); + + return new BlockSnapshot( + tag.getInteger("dimension"), + tag.getInteger("posX"), + tag.getInteger("posY"), + tag.getInteger("posZ"), + tag.getString("blockMod"), + tag.getString("blockName"), + tag.getInteger("metadata"), + tag.getInteger("flag"), + nbt); + } + + public Block getCurrentBlock() + { + return world.getBlock(x, y, z); + } + + public World getWorld() + { + if (this.world == null) + { + this.world = DimensionManager.getWorld(dimId); + } + return this.world; + } + + public Block getReplacedBlock() + { + if (this.replacedBlock == null) + { + this.replacedBlock = GameRegistry.findBlock(this.blockIdentifier.modId, this.blockIdentifier.name); + } + return this.replacedBlock; + } + + public TileEntity getTileEntity() + { + if (nbt != null) + return TileEntity.createAndLoadEntity(nbt); + else return null; + } + + public boolean restore() + { + return restore(false); + } + + public boolean restore(boolean force) + { + return restore(force, true); + } + + public boolean restore(boolean force, boolean applyPhysics) + { + if (getCurrentBlock() != getReplacedBlock() || world.getBlockMetadata(x & 15, y, z & 15) != meta) + { + if (force) + { + world.setBlock(x, y, z, getReplacedBlock(), meta, applyPhysics ? 3 : 2); + } + else + { + return false; + } + } + + world.setBlockMetadataWithNotify(x, y, z, meta, applyPhysics ? 3 : 2); + world.markBlockForUpdate(x, y, z); + TileEntity te = null; + if (nbt != null) + { + te = world.getTileEntity(x, y, z); + if (te != null) + { + te.readFromNBT(nbt); + } + } + + if (DEBUG) + { + System.out.printf("Restored BlockSnapshot with data [World: %s ][Location: %d,%d,%d ][Meta: %d ][Block: %s ][TileEntity: %s ][force: %s ][applyPhysics: %s]", world.getWorldInfo().getWorldName(), x, y, z, meta, getReplacedBlock(), te, force, applyPhysics); + } + return true; + } + + public boolean restoreToLocation(World world, int x, int y, int z, boolean force, boolean applyPhysics) + { + if (getCurrentBlock() != getReplacedBlock() || world.getBlockMetadata(x & 15, y, z & 15) != meta) + { + if (force) + { + world.setBlock(x, y, z, getReplacedBlock(), meta, applyPhysics ? 3 : 2); + } + else + { + return false; + } + } + + world.setBlockMetadataWithNotify(x, y, z, meta, applyPhysics ? 3 : 2); + world.markBlockForUpdate(x, y, z); + TileEntity te = null; + if (nbt != null) + { + te = world.getTileEntity(x, y, z); + if (te != null) + { + te.readFromNBT(nbt); + } + } + + if (DEBUG) + { + System.out.printf("Restored BlockSnapshot with data [World: %s ][Location: %d,%d,%d ][Meta: %d ][Block: %s ][TileEntity: %s ][force: %s ][applyPhysics: %s]", world.getWorldInfo().getWorldName(), x, y, z, meta, getReplacedBlock(), te, force, applyPhysics); + } + return true; + } + + public void writeToNBT(NBTTagCompound compound) + { + compound.setString("blockMod", blockIdentifier.modId); + compound.setString("blockName", blockIdentifier.name); + compound.setInteger("posX", x); + compound.setInteger("posY", y); + compound.setInteger("posZ", z); + compound.setInteger("flag", flag); + compound.setInteger("dimension", dimId); + compound.setInteger("metadata", meta); + + compound.setBoolean("hasTE", nbt != null); + + if (nbt != null) + { + compound.setTag("tileEntity", nbt); + } + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final BlockSnapshot other = (BlockSnapshot) obj; + if (this.x != other.x) + { + return false; + } + if (this.y != other.y) + { + return false; + } + if (this.z != other.z) + { + return false; + } + if (this.meta != other.meta) + { + return false; + } + if (this.dimId != other.dimId) + { + return false; + } + if (this.nbt != other.nbt && (this.nbt == null || !this.nbt.equals(other.nbt))) + { + return false; + } + if (this.world != other.world && (this.world == null || !this.world.equals(other.world))) + { + return false; + } + if (this.blockIdentifier != other.blockIdentifier && (this.blockIdentifier == null || !this.blockIdentifier.equals(other.blockIdentifier))) + { + return false; + } + return true; + } + + @Override + public int hashCode() + { + int hash = 7; + hash = 73 * hash + this.x; + hash = 73 * hash + this.y; + hash = 73 * hash + this.z; + hash = 73 * hash + this.meta; + hash = 73 * hash + this.dimId; + hash = 73 * hash + (this.nbt != null ? this.nbt.hashCode() : 0); + hash = 73 * hash + (this.world != null ? this.world.hashCode() : 0); + hash = 73 * hash + (this.blockIdentifier != null ? this.blockIdentifier.hashCode() : 0); + return hash; + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java index 7916413c3..aec4cd9a0 100644 --- a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java +++ b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java @@ -14,6 +14,7 @@ import net.minecraft.entity.effect.EntityLightningBolt; import net.minecraft.entity.monster.EntityZombie; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import net.minecraft.world.WorldServer; @@ -21,6 +22,8 @@ import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.storage.IPlayerFileData; import net.minecraft.world.storage.SaveHandler; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.BlockSnapshot; +import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.event.entity.EntityStruckByLightningEvent; import net.minecraftforge.event.entity.living.LivingPackSizeEvent; import net.minecraftforge.event.entity.living.LivingSpawnEvent; @@ -33,10 +36,31 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; import net.minecraftforge.event.entity.player.PlayerUseItemEvent; import net.minecraftforge.event.world.BlockEvent; +import net.minecraftforge.event.world.BlockEvent.MultiPlaceEvent; +import net.minecraftforge.event.world.BlockEvent.PlaceEvent; import net.minecraftforge.event.world.WorldEvent; public class ForgeEventFactory { + + public static MultiPlaceEvent onPlayerMultiBlockPlace(EntityPlayer player, List blockSnapshots, ForgeDirection direction) + { + Block placedAgainst = blockSnapshots.get(0).world.getBlock(blockSnapshots.get(0).x + direction.getOpposite().offsetX, blockSnapshots.get(0).y + direction.getOpposite().offsetY, blockSnapshots.get(0).z + direction.getOpposite().offsetZ); + + MultiPlaceEvent event = new MultiPlaceEvent(blockSnapshots, placedAgainst, player); + MinecraftForge.EVENT_BUS.post(event); + return event; + } + + public static PlaceEvent onPlayerBlockPlace(EntityPlayer player, BlockSnapshot blockSnapshot, ForgeDirection direction) + { + Block placedAgainst = blockSnapshot.world.getBlock(blockSnapshot.x + direction.getOpposite().offsetX, blockSnapshot.y + direction.getOpposite().offsetY, blockSnapshot.z + direction.getOpposite().offsetZ); + + PlaceEvent event = new PlaceEvent(blockSnapshot, placedAgainst, player); + MinecraftForge.EVENT_BUS.post(event); + return event; + } + public static boolean doPlayerHarvestCheck(EntityPlayer player, Block block, boolean success) { PlayerEvent.HarvestCheck event = new PlayerEvent.HarvestCheck(player, block, success); diff --git a/src/main/java/net/minecraftforge/event/world/BlockEvent.java b/src/main/java/net/minecraftforge/event/world/BlockEvent.java index 40c3b3ec8..5033edfdf 100644 --- a/src/main/java/net/minecraftforge/event/world/BlockEvent.java +++ b/src/main/java/net/minecraftforge/event/world/BlockEvent.java @@ -1,17 +1,24 @@ package net.minecraftforge.event.world; import java.util.ArrayList; +import java.util.List; + +import com.google.common.collect.ImmutableList; import cpw.mods.fml.common.eventhandler.Cancelable; import cpw.mods.fml.common.eventhandler.Event; import net.minecraft.block.Block; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.common.util.BlockSnapshot; public class BlockEvent extends Event { + private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("forge.debugBlockEvent", "false")); + public final int x; public final int y; public final int z; @@ -111,4 +118,63 @@ public class BlockEvent extends Event { this.exp = exp; } } + + /** + * Called when a block is placed by a player. + * + * If a Block Place event is cancelled, the block will not be placed. + */ + @Cancelable + public static class PlaceEvent extends BlockEvent { + + public final EntityPlayer player; + public final ItemStack itemInHand; + public final BlockSnapshot blockSnapshot; + public final Block placedBlock; + public final Block placedAgainst; + + public PlaceEvent(BlockSnapshot blockSnapshot, Block placedAgainst, EntityPlayer player) { + super(blockSnapshot.x, blockSnapshot.y, blockSnapshot.z, blockSnapshot.world, blockSnapshot.getCurrentBlock(), blockSnapshot.meta); + this.player = player; + this.itemInHand = player.getCurrentEquippedItem(); + this.blockSnapshot = blockSnapshot; + this.placedBlock = blockSnapshot.getCurrentBlock(); + this.placedAgainst = placedAgainst; + if (DEBUG) + { + System.out.printf("Created PlaceEvent - [PlacedBlock: %s ][PlacedAgainst: %s ][ItemStack: %s ][Player: %s ]\n", placedBlock, placedAgainst, player.getCurrentEquippedItem(), player); + } + } + } + + /** + * Fired when a single block placement action of a player triggers the + * creation of multiple blocks(e.g. placing a bed block). The block returned + * by {@link #block} and its related methods is the block where + * the placed block would exist if the placement only affected a single + * block. + */ + @Cancelable + public static class MultiPlaceEvent extends PlaceEvent { + private final List blockSnapshots; + + public MultiPlaceEvent(List blockSnapshots, Block placedAgainst, EntityPlayer player) { + super(blockSnapshots.get(0), placedAgainst, player); + this.blockSnapshots = ImmutableList.copyOf(blockSnapshots); + if (DEBUG) + { + System.out.printf("Created MultiPlaceEvent - [PlacedAgainst: %s ][ItemInHand: %s ][Player: %s ]\n", placedAgainst, this.itemInHand, player); + } + } + + /** + * Gets a list of blocksnapshots for all blocks which were replaced by the + * placement of the new blocks. Most of these blocks will just be of type AIR. + * + * @return immutable list of replaced BlockSnapshots + */ + public List getReplacedBlockSnapshots() { + return blockSnapshots; + } + } }