From 0e65f20f22e8cc0d61ca85bb23c646cda40a9bfd Mon Sep 17 00:00:00 2001 From: Richard Freimer Date: Wed, 20 Nov 2019 22:19:34 -0500 Subject: [PATCH] Add hooks to make it easier to add custom TNT blocks (#6290) --- .../net/minecraft/block/FireBlock.java.patch | 28 ++-- .../net/minecraft/block/TNTBlock.java.patch | 67 +++++++++ .../IDispenseItemBehavior.java.patch | 14 +- .../common/extensions/IForgeBlock.java | 11 ++ .../common/extensions/IForgeBlockState.java | 13 ++ .../resources/META-INF/accesstransformer.cfg | 1 + .../debug/block/CustomTNTTest.java | 134 ++++++++++++++++++ src/test/resources/META-INF/mods.toml | 2 + .../custom_tnt_test/blockstates/test_tnt.json | 5 + .../custom_tnt_test/models/item/test_tnt.json | 3 + 10 files changed, 269 insertions(+), 9 deletions(-) create mode 100644 patches/minecraft/net/minecraft/block/TNTBlock.java.patch create mode 100644 src/test/java/net/minecraftforge/debug/block/CustomTNTTest.java create mode 100644 src/test/resources/assets/custom_tnt_test/blockstates/test_tnt.json create mode 100644 src/test/resources/assets/custom_tnt_test/models/item/test_tnt.json diff --git a/patches/minecraft/net/minecraft/block/FireBlock.java.patch b/patches/minecraft/net/minecraft/block/FireBlock.java.patch index ef818687f4..accd9795b8 100644 --- a/patches/minecraft/net/minecraft/block/FireBlock.java.patch +++ b/patches/minecraft/net/minecraft/block/FireBlock.java.patch @@ -83,7 +83,19 @@ if (p_176536_4_.nextInt(p_176536_3_) < i) { BlockState blockstate = p_176536_1_.func_180495_p(p_176536_2_); if (p_176536_4_.nextInt(p_176536_5_ + 10) < 5 && !p_176536_1_.func_175727_C(p_176536_2_)) { -@@ -199,7 +203,7 @@ +@@ -188,18 +192,14 @@ + p_176536_1_.func_217377_a(p_176536_2_, false); + } + +- Block block = blockstate.func_177230_c(); +- if (block instanceof TNTBlock) { +- TNTBlock tntblock = (TNTBlock)block; +- TNTBlock.func_196534_a(p_176536_1_, p_176536_2_); +- } ++ blockstate.catchFire(p_176536_1_, p_176536_2_, face, null); + } + + } private boolean func_196447_a(IBlockReader p_196447_1_, BlockPos p_196447_2_) { for(Direction direction : Direction.values()) { @@ -92,7 +104,7 @@ return true; } } -@@ -215,13 +219,14 @@ +@@ -215,13 +215,14 @@ for(Direction direction : Direction.values()) { BlockState blockstate = p_176538_1_.func_180495_p(p_176538_2_.func_177972_a(direction)); @@ -108,7 +120,7 @@ public boolean func_196446_i(BlockState p_196446_1_) { return this.func_220275_r(p_196446_1_) > 0; } -@@ -246,8 +251,8 @@ +@@ -246,8 +247,8 @@ BlockPos blockpos = p_180655_3_.func_177977_b(); BlockState blockstate = p_180655_2_.func_180495_p(blockpos); @@ -119,7 +131,7 @@ for(int j = 0; j < 2; ++j) { double d3 = (double)p_180655_3_.func_177958_n() + p_180655_4_.nextDouble() * (double)0.1F; double d8 = (double)p_180655_3_.func_177956_o() + p_180655_4_.nextDouble(); -@@ -256,7 +261,7 @@ +@@ -256,7 +257,7 @@ } } @@ -128,7 +140,7 @@ for(int k = 0; k < 2; ++k) { double d4 = (double)(p_180655_3_.func_177958_n() + 1) - p_180655_4_.nextDouble() * (double)0.1F; double d9 = (double)p_180655_3_.func_177956_o() + p_180655_4_.nextDouble(); -@@ -265,7 +270,7 @@ +@@ -265,7 +266,7 @@ } } @@ -137,7 +149,7 @@ for(int l = 0; l < 2; ++l) { double d5 = (double)p_180655_3_.func_177958_n() + p_180655_4_.nextDouble(); double d10 = (double)p_180655_3_.func_177956_o() + p_180655_4_.nextDouble(); -@@ -274,7 +279,7 @@ +@@ -274,7 +275,7 @@ } } @@ -146,7 +158,7 @@ for(int i1 = 0; i1 < 2; ++i1) { double d6 = (double)p_180655_3_.func_177958_n() + p_180655_4_.nextDouble(); double d11 = (double)p_180655_3_.func_177956_o() + p_180655_4_.nextDouble(); -@@ -283,7 +288,7 @@ +@@ -283,7 +284,7 @@ } } @@ -155,7 +167,7 @@ for(int j1 = 0; j1 < 2; ++j1) { double d7 = (double)p_180655_3_.func_177958_n() + p_180655_4_.nextDouble(); double d12 = (double)(p_180655_3_.func_177956_o() + 1) - p_180655_4_.nextDouble() * (double)0.1F; -@@ -311,10 +316,23 @@ +@@ -311,10 +312,23 @@ } public void func_180686_a(Block p_180686_1_, int p_180686_2_, int p_180686_3_) { diff --git a/patches/minecraft/net/minecraft/block/TNTBlock.java.patch b/patches/minecraft/net/minecraft/block/TNTBlock.java.patch new file mode 100644 index 0000000000..9a263980b4 --- /dev/null +++ b/patches/minecraft/net/minecraft/block/TNTBlock.java.patch @@ -0,0 +1,67 @@ +--- a/net/minecraft/block/TNTBlock.java ++++ b/net/minecraft/block/TNTBlock.java +@@ -28,10 +28,14 @@ + this.func_180632_j(this.func_176223_P().func_206870_a(field_212569_a, Boolean.valueOf(false))); + } + ++ public void catchFire(BlockState state, World world, BlockPos pos, @Nullable net.minecraft.util.Direction face, @Nullable LivingEntity igniter) { ++ func_196535_a(world, pos, igniter); ++ } ++ + public void func_220082_b(BlockState p_220082_1_, World p_220082_2_, BlockPos p_220082_3_, BlockState p_220082_4_, boolean p_220082_5_) { + if (p_220082_4_.func_177230_c() != p_220082_1_.func_177230_c()) { + if (p_220082_2_.func_175640_z(p_220082_3_)) { +- func_196534_a(p_220082_2_, p_220082_3_); ++ catchFire(p_220082_1_, p_220082_2_, p_220082_3_, null, null); + p_220082_2_.func_217377_a(p_220082_3_, false); + } + +@@ -40,7 +44,7 @@ + + public void func_220069_a(BlockState p_220069_1_, World p_220069_2_, BlockPos p_220069_3_, Block p_220069_4_, BlockPos p_220069_5_, boolean p_220069_6_) { + if (p_220069_2_.func_175640_z(p_220069_3_)) { +- func_196534_a(p_220069_2_, p_220069_3_); ++ catchFire(p_220069_1_, p_220069_2_, p_220069_3_, null, null); + p_220069_2_.func_217377_a(p_220069_3_, false); + } + +@@ -48,7 +52,7 @@ + + public void func_176208_a(World p_176208_1_, BlockPos p_176208_2_, BlockState p_176208_3_, PlayerEntity p_176208_4_) { + if (!p_176208_1_.func_201670_d() && !p_176208_4_.func_184812_l_() && p_176208_3_.func_177229_b(field_212569_a)) { +- func_196534_a(p_176208_1_, p_176208_2_); ++ catchFire(p_176208_3_, p_176208_1_, p_176208_2_, null, null); + } + + super.func_176208_a(p_176208_1_, p_176208_2_, p_176208_3_, p_176208_4_); +@@ -62,10 +66,12 @@ + } + } + ++ @Deprecated //Forge: Prefer using IForgeBlock#catchFire + public static void func_196534_a(World p_196534_0_, BlockPos p_196534_1_) { + func_196535_a(p_196534_0_, p_196534_1_, (LivingEntity)null); + } + ++ @Deprecated //Forge: Prefer using IForgeBlock#catchFire + private static void func_196535_a(World p_196535_0_, BlockPos p_196535_1_, @Nullable LivingEntity p_196535_2_) { + if (!p_196535_0_.field_72995_K) { + TNTEntity tntentity = new TNTEntity(p_196535_0_, (double)((float)p_196535_1_.func_177958_n() + 0.5F), (double)p_196535_1_.func_177956_o(), (double)((float)p_196535_1_.func_177952_p() + 0.5F), p_196535_2_); +@@ -80,7 +86,7 @@ + if (item != Items.field_151033_d && item != Items.field_151059_bz) { + return super.func_220051_a(p_220051_1_, p_220051_2_, p_220051_3_, p_220051_4_, p_220051_5_, p_220051_6_); + } else { +- func_196535_a(p_220051_2_, p_220051_3_, p_220051_4_); ++ catchFire(p_220051_1_, p_220051_2_, p_220051_3_, p_220051_6_.func_216354_b(), p_220051_4_); + p_220051_2_.func_180501_a(p_220051_3_, Blocks.field_150350_a.func_176223_P(), 11); + if (item == Items.field_151033_d) { + itemstack.func_222118_a(1, p_220051_4_, (p_220287_1_) -> { +@@ -100,7 +106,7 @@ + Entity entity = abstractarrowentity.func_212360_k(); + if (abstractarrowentity.func_70027_ad()) { + BlockPos blockpos = p_220066_3_.func_216350_a(); +- func_196535_a(p_220066_1_, blockpos, entity instanceof LivingEntity ? (LivingEntity)entity : null); ++ catchFire(p_220066_2_, p_220066_1_, blockpos, null, entity instanceof LivingEntity ? (LivingEntity)entity : null); + p_220066_1_.func_217377_a(blockpos, false); + } + } diff --git a/patches/minecraft/net/minecraft/dispenser/IDispenseItemBehavior.java.patch b/patches/minecraft/net/minecraft/dispenser/IDispenseItemBehavior.java.patch index 46d4b146a6..0fa8480c8d 100644 --- a/patches/minecraft/net/minecraft/dispenser/IDispenseItemBehavior.java.patch +++ b/patches/minecraft/net/minecraft/dispenser/IDispenseItemBehavior.java.patch @@ -1,6 +1,18 @@ --- a/net/minecraft/dispenser/IDispenseItemBehavior.java +++ b/net/minecraft/dispenser/IDispenseItemBehavior.java -@@ -370,15 +370,23 @@ +@@ -270,8 +270,9 @@ + world.func_175656_a(blockpos, Blocks.field_150480_ab.func_176223_P()); + } else if (FlintAndSteelItem.func_219997_a(blockstate)) { + world.func_175656_a(blockpos, blockstate.func_206870_a(BlockStateProperties.field_208190_q, Boolean.valueOf(true))); +- } else if (blockstate.func_177230_c() instanceof TNTBlock) { +- TNTBlock.func_196534_a(world, blockpos); ++ } else if (blockstate.isFlammable(world, blockpos, p_82487_1_.func_189992_e().func_177229_b(DispenserBlock.field_176441_a).func_176734_d())) { ++ blockstate.catchFire(world, blockpos, p_82487_1_.func_189992_e().func_177229_b(DispenserBlock.field_176441_a).func_176734_d(), null); ++ if (blockstate.func_177230_c() instanceof TNTBlock) + world.func_217377_a(blockpos, false); + } else { + this.field_218407_b = false; +@@ -370,15 +371,23 @@ } DispenserBlock.func_199774_a(Items.field_151097_aZ.func_199767_j(), new OptionalDispenseBehavior() { diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java b/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java index e3bbeae999..110e5ac752 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java @@ -923,6 +923,17 @@ public interface IForgeBlock return state.getFlammability(world, pos, face) > 0; } + /** + * If the block is flammable, this is called when it gets lit on fire. + * + * @param state The current state + * @param world The current world + * @param pos Block position in world + * @param face The face that the fire is coming from + * @param igniter The entity that lit the fire + */ + default void catchFire(BlockState state, World world, BlockPos pos, @Nullable Direction face, @Nullable LivingEntity igniter) {} + /** * Called when fire is updating on a neighbor block. * The higher the number returned, the faster fire will spread around this block. diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java b/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java index 3cb151969b..56ab58eeb4 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java @@ -771,6 +771,19 @@ public interface IForgeBlockState return getBlockState().getBlock().isFlammable(getBlockState(), world, pos, face); } + /** + * If the block is flammable, this is called when it gets lit on fire. + * + * @param world The current world + * @param pos Block position in world + * @param face The face that the fire is coming from + * @param igniter The entity that lit the fire + */ + default void catchFire(World world, BlockPos pos, @Nullable Direction face, @Nullable LivingEntity igniter) + { + getBlockState().getBlock().catchFire(getBlockState(), world, pos, face, igniter); + } + /** * Called when fire is updating on a neighbor block. * The higher the number returned, the faster fire will spread around this block. diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 0b9ca66113..953d6151e8 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -99,6 +99,7 @@ public net.minecraft.entity.ai.brain.memory.MemoryModuleType (Ljava/util/O public net.minecraft.entity.ai.brain.schedule.Activity (Ljava/lang/String;)V public net.minecraft.entity.ai.brain.sensor.SensorType (Ljava/util/function/Supplier;)V public net.minecraft.entity.item.ExperienceOrbEntity field_70530_e # xpValue +protected net.minecraft.entity.item.TNTEntity func_70515_d()V # explode - make it easier to extend TNTEntity with custom explosion logic public net.minecraft.entity.merchant.villager.VillagerProfession (Ljava/lang/String;Lnet/minecraft/village/PointOfInterestType;Lcom/google/common/collect/ImmutableSet;Lcom/google/common/collect/ImmutableSet;)V protected net.minecraft.entity.monster.AbstractSkeletonEntity func_190727_o()Lnet/minecraft/util/SoundEvent; # getStepSound - make AbstractSkeletonEntity implementable protected net.minecraft.entity.monster.SkeletonEntity func_190727_o()Lnet/minecraft/util/SoundEvent; # getStepSound - make AbstractSkeletonEntity implementable diff --git a/src/test/java/net/minecraftforge/debug/block/CustomTNTTest.java b/src/test/java/net/minecraftforge/debug/block/CustomTNTTest.java new file mode 100644 index 0000000000..9749b7a5db --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/block/CustomTNTTest.java @@ -0,0 +1,134 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.debug.block; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.TNTBlock; +import net.minecraft.entity.EntityClassification; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.item.TNTEntity; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.network.IPacket; +import net.minecraft.util.Direction; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvents; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.Explosion; +import net.minecraft.world.World; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.RegistryObject; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.fml.network.NetworkHooks; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; + +@Mod(CustomTNTTest.MODID) +@Mod.EventBusSubscriber(modid = CustomTNTTest.MODID, bus = Bus.MOD) +public class CustomTNTTest { + + static final String MODID = "custom_tnt_test"; + static final String BLOCK_ID = "test_tnt"; + + private static final DeferredRegister BLOCKS = new DeferredRegister<>(ForgeRegistries.BLOCKS, MODID); + private static final DeferredRegister ITEMS = new DeferredRegister<>(ForgeRegistries.ITEMS, MODID); + private static final DeferredRegister> ENTITIES = new DeferredRegister<>(ForgeRegistries.ENTITIES, MODID); + + public static final RegistryObject CUSTOM_TNT = BLOCKS.register(BLOCK_ID, () -> new CustomTNTBlock(Block.Properties.from(Blocks.TNT))); + public static final RegistryObject> CUSTOM_TNT_ENTITY = ENTITIES.register(BLOCK_ID, () -> EntityType.Builder + .create((EntityType.IFactory) CustomTNTEntity::new, EntityClassification.MISC) + .build(BLOCK_ID)); + + static { + ITEMS.register(BLOCK_ID, () -> new BlockItem(CUSTOM_TNT.get(), new Item.Properties())); + } + + public CustomTNTTest() { + IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); + BLOCKS.register(modBus); + ITEMS.register(modBus); + ENTITIES.register(modBus); + } + + public static class CustomTNTBlock extends TNTBlock { + + public CustomTNTBlock(Properties properties) { + super(properties); + } + + @Override + public void onExplosionDestroy(World world, BlockPos pos, Explosion explosion) { + if (!world.isRemote) { + TNTEntity tnt = new CustomTNTEntity(world, (float) pos.getX() + 0.5F, pos.getY(), (float) pos.getZ() + 0.5F, explosion.getExplosivePlacedBy()); + tnt.setFuse((short) (world.rand.nextInt(tnt.getFuse() / 4) + tnt.getFuse() / 8)); + world.addEntity(tnt); + } + } + + @Override + public void catchFire(BlockState state, World world, BlockPos pos, @Nullable Direction face, @Nullable LivingEntity igniter) { + if (!world.isRemote) { + TNTEntity tnt = new CustomTNTEntity(world, pos.getX() + 0.5F, pos.getY(), pos.getZ() + 0.5F, igniter); + world.addEntity(tnt); + world.playSound(null, tnt.posX, tnt.posY, tnt.posZ, SoundEvents.ENTITY_TNT_PRIMED, SoundCategory.BLOCKS, 1.0F, 1.0F); + } + } + } + + /** + * Custom TNT Entity that has a fuse of a quarter length, and four times the explosion strength + */ + public static class CustomTNTEntity extends TNTEntity { + + public CustomTNTEntity(EntityType type, World world) { + super(type, world); + setFuse(getFuse() / 4); + } + + public CustomTNTEntity(World world, double x, double y, double z, @Nullable LivingEntity placer) { + super(world, x, y, z, placer); + setFuse(getFuse() / 4); + } + + @Nonnull + @Override + public EntityType getType() { + return CUSTOM_TNT_ENTITY.get(); + } + + @Override + protected void explode() { + this.world.createExplosion(this, this.posX, this.posY, this.posZ, 16.0F, Explosion.Mode.BREAK); + } + + @Nonnull + @Override + public IPacket createSpawnPacket() { + return NetworkHooks.getEntitySpawningPacket(this); + } + } +} \ No newline at end of file diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index d74f85d9ce..2e7e6fe52a 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -57,3 +57,5 @@ loaderVersion="[28,)" modId="player_xp_event_test" [[mods]] modId="forgeblockstatesloader" +[[mods]] + modId="custom_tnt_test" \ No newline at end of file diff --git a/src/test/resources/assets/custom_tnt_test/blockstates/test_tnt.json b/src/test/resources/assets/custom_tnt_test/blockstates/test_tnt.json new file mode 100644 index 0000000000..c6eafdc1b7 --- /dev/null +++ b/src/test/resources/assets/custom_tnt_test/blockstates/test_tnt.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "block/tnt" } + } +} \ No newline at end of file diff --git a/src/test/resources/assets/custom_tnt_test/models/item/test_tnt.json b/src/test/resources/assets/custom_tnt_test/models/item/test_tnt.json new file mode 100644 index 0000000000..794c83bb98 --- /dev/null +++ b/src/test/resources/assets/custom_tnt_test/models/item/test_tnt.json @@ -0,0 +1,3 @@ +{ + "parent": "block/tnt" +} \ No newline at end of file