diff --git a/src/main/java/net/dries007/tfc/api/ITreeGenerator.java b/src/main/java/net/dries007/tfc/api/ITreeGenerator.java index 82fc55654e..d535ebc81e 100644 --- a/src/main/java/net/dries007/tfc/api/ITreeGenerator.java +++ b/src/main/java/net/dries007/tfc/api/ITreeGenerator.java @@ -8,18 +8,71 @@ import java.util.Random; +import net.minecraft.block.Block; import net.minecraft.block.BlockSapling; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; import net.minecraft.util.Rotation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -import net.minecraft.world.gen.structure.template.PlacementSettings; -import net.minecraft.world.gen.structure.template.TemplateManager; +import net.minecraft.world.gen.structure.StructureBoundingBox; +import net.minecraft.world.gen.structure.template.*; import net.dries007.tfc.api.types.Tree; +import net.dries007.tfc.objects.blocks.wood.BlockLeavesTFC; public interface ITreeGenerator { + /** + * This is a copy of the method included in the Template class, with some key differences. + * This will ignore TEs / Entities, and does less checks for bad usage, since it will only be used for tree worldgen + * It will do an additional check that the block is replaceable; important for tree growth; as to not replace other blocks + * + * @param worldIn the world + * @param pos the position + * @param template the template + * @param placementIn the placement settings + */ + static void addStructureToWorld(World worldIn, BlockPos pos, Template template, PlacementSettings placementIn) + { + int flags = 2; + ITemplateProcessor templateProcessor = new BlockRotationProcessor(pos, placementIn); + StructureBoundingBox structureboundingbox = placementIn.getBoundingBox(); + + for (Template.BlockInfo template$blockinfo : template.blocks) + { + BlockPos blockpos = Template.transformedBlockPos(placementIn, template$blockinfo.pos).add(pos); + Template.BlockInfo template$blockinfo1 = templateProcessor.processBlock(worldIn, blockpos, template$blockinfo); + + if (template$blockinfo1 != null) + { + Block block1 = template$blockinfo1.blockState.getBlock(); + + if ((!placementIn.getIgnoreStructureBlock() || block1 != Blocks.STRUCTURE_BLOCK) && (structureboundingbox == null || structureboundingbox.isVecInside(blockpos))) + { + IBlockState iblockstate = template$blockinfo1.blockState.withMirror(placementIn.getMirror()); + IBlockState iblockstate1 = iblockstate.withRotation(placementIn.getRotation()); + + if (worldIn.getBlockState(blockpos).getMaterial().isReplaceable() || worldIn.getBlockState(blockpos).getBlock() instanceof BlockLeavesTFC) + worldIn.setBlockState(blockpos, iblockstate1, flags); + + } + } + } + + for (Template.BlockInfo template$blockinfo2 : template.blocks) + { + BlockPos blockpos1 = Template.transformedBlockPos(placementIn, template$blockinfo2.pos).add(pos); + + if (structureboundingbox == null || structureboundingbox.isVecInside(blockpos1)) + { + worldIn.notifyNeighborsRespectDebug(blockpos1, template$blockinfo2.blockState.getBlock(), false); + } + + } + } + /** * Called to generate a tree. Each Tree must have one of these. Used for world gen and sapling growth * @@ -32,27 +85,34 @@ public interface ITreeGenerator void generateTree(TemplateManager manager, World world, BlockPos pos, Tree tree, Random rand); /** + * This only sets the properties used by ITreeGenerator.addStructureToWorld * @return A default set of placement settings for tree generation */ static PlacementSettings getDefaultSettings() { - return new PlacementSettings() - .setIgnoreEntities(true) - .setIgnoreStructureBlock(false); + return new PlacementSettings().setIgnoreStructureBlock(false); } /** + * This only sets the properties used by ITreeGenerator.addStructureToWorld * @param rand For generating random settings * @return A set of placement settings with random rotation */ static PlacementSettings getRandomSettings(Random rand) { - return getDefaultSettings() - .setRotation(Rotation.values()[rand.nextInt(Rotation.values().length)]); + return getDefaultSettings().setRotation(Rotation.values()[rand.nextInt(Rotation.values().length)]); } - static boolean checkGenerationConditions(World world, BlockPos pos, Tree treeType) + /** + * Checks if a tree can be generated. This implementation checks height, radius, and light level + * + * @param world The world + * @param pos The pos of the tree + * @param treeType The tree type (for checking if the tree can generate) + * @return true if the tree can generate. + */ + default boolean canGenerateTree(World world, BlockPos pos, Tree treeType) { // Check if ground is flat enough final int radius = treeType.maxGrowthRadius; @@ -79,24 +139,10 @@ static boolean checkGenerationConditions(World world, BlockPos pos, Tree treeTyp // Check the position for liquids, etc. if (world.getBlockState(pos).getMaterial().isLiquid() || !world.getBlockState(pos).getMaterial().isReplaceable()) - if (!(world.getBlockState(pos) instanceof BlockSapling)) + if (!(world.getBlockState(pos).getBlock() instanceof BlockSapling)) return false; // Check if there is sufficient light level return world.getLightFromNeighbors(pos) >= 7; } - - /** - * Checks if a tree can be generated. This implementation checks height, radius, and light level - * Suggested use is to use within your implementation of generateTree() - * - * @param world The world - * @param pos The pos of the tree - * @param treeType The tree type (for checking if the tree can generate) - * @return true if the tree can generate. - */ - default boolean canGenerateTree(World world, BlockPos pos, Tree treeType) - { - return checkGenerationConditions(world, pos, treeType); - } } diff --git a/src/main/java/net/dries007/tfc/api/types/Rock.java b/src/main/java/net/dries007/tfc/api/types/Rock.java index 9b25397f12..e4fdc2ab89 100644 --- a/src/main/java/net/dries007/tfc/api/types/Rock.java +++ b/src/main/java/net/dries007/tfc/api/types/Rock.java @@ -14,6 +14,8 @@ import net.minecraft.util.ResourceLocation; import net.minecraftforge.registries.IForgeRegistryEntry; +import static net.dries007.tfc.api.types.Rock.FallingBlockType.*; + /** * todo: document API */ @@ -79,31 +81,42 @@ public RockCategory getRockCategory() public enum Type { - RAW(Material.ROCK, false, false), - SMOOTH(Material.ROCK, false, false), - COBBLE(Material.ROCK, true, false), - BRICKS(Material.ROCK, false, false), - SAND(Material.SAND, true, false), - GRAVEL(Material.SAND, true, false), - DIRT(Material.GROUND, false, false), - GRASS(Material.GRASS, false, true), - DRY_GRASS(Material.GRASS, false, true), - CLAY(Material.GRASS, false, false), - CLAY_GRASS(Material.GRASS, false, true), - FARMLAND(Material.GROUND, false, false), - PATH(Material.GROUND, false, false); + RAW(Material.ROCK, NO_FALL, false), // Todo: add collapsing when broken + SMOOTH(Material.ROCK, NO_FALL, false), + COBBLE(Material.ROCK, FALL_HORIZONTAL, false), + BRICKS(Material.ROCK, NO_FALL, false), + SAND(Material.SAND, FALL_HORIZONTAL, false), + GRAVEL(Material.SAND, FALL_HORIZONTAL, false), + DIRT(Material.GROUND, FALL_HORIZONTAL, false), + GRASS(Material.GRASS, FALL_HORIZONTAL, true), + DRY_GRASS(Material.GRASS, FALL_HORIZONTAL, true), + CLAY(Material.GRASS, FALL_VERTICAL, false), + CLAY_GRASS(Material.GRASS, FALL_VERTICAL, true), + FARMLAND(Material.GROUND, FALL_VERTICAL, false), + PATH(Material.GROUND, FALL_VERTICAL, false); public final Material material; - public final boolean isAffectedByGravity; public final boolean isGrass; - Type(Material material, boolean isAffectedByGravity, boolean isGrass) + private final FallingBlockType gravType; + + Type(Material material, FallingBlockType gravType, boolean isGrass) { this.material = material; - this.isAffectedByGravity = isAffectedByGravity; + this.gravType = gravType; this.isGrass = isGrass; } + public boolean canFall() + { + return gravType != NO_FALL; + } + + public boolean canFallHorizontal() + { + return gravType == FALL_HORIZONTAL; + } + public Type getNonGrassVersion() { if (!isGrass) return this; @@ -132,4 +145,11 @@ public Type getGrassVersion(Type spreader) throw new IllegalArgumentException("You cannot get grass from rock types."); } } + + protected enum FallingBlockType + { + NO_FALL, + FALL_VERTICAL, + FALL_HORIZONTAL + } } diff --git a/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockFarmlandTFC.java b/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockFarmlandTFC.java index 217fc3c4a9..a8a0698381 100644 --- a/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockFarmlandTFC.java +++ b/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockFarmlandTFC.java @@ -7,6 +7,8 @@ import java.util.Random; +import javax.annotation.ParametersAreNonnullByDefault; + import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.properties.PropertyInteger; @@ -26,9 +28,13 @@ import net.minecraft.world.World; import net.minecraftforge.common.IPlantable; +import mcp.MethodsReturnNonnullByDefault; import net.dries007.tfc.api.types.Rock; +import net.dries007.tfc.util.IFallingBlock; -public class BlockFarmlandTFC extends BlockRockVariant +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public class BlockFarmlandTFC extends BlockRockVariantFallable { public static final int MAX_MOISTURE = 15; public static final PropertyInteger MOISTURE = PropertyInteger.create("moisture", 0, MAX_MOISTURE); @@ -50,8 +56,8 @@ public class BlockFarmlandTFC extends BlockRockVariant 0xff8f8f8f, 0xff878787, }; - protected static final AxisAlignedBB FARMLAND_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.9375D, 1.0D); - protected static final AxisAlignedBB FLIPPED_AABB = new AxisAlignedBB(0.0D, 0.9375D, 0.0D, 1.0D, 1.0D, 1.0D); + private static final AxisAlignedBB FARMLAND_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.9375D, 1.0D); + private static final AxisAlignedBB FLIPPED_AABB = new AxisAlignedBB(0.0D, 0.9375D, 0.0D, 1.0D, 1.0D, 1.0D); public BlockFarmlandTFC(Rock.Type type, Rock rock) { diff --git a/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockPathTFC.java b/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockPathTFC.java index 1c1bd991ed..323a7e0f6d 100644 --- a/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockPathTFC.java +++ b/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockPathTFC.java @@ -7,6 +7,8 @@ import java.util.Random; +import javax.annotation.ParametersAreNonnullByDefault; + import net.minecraft.block.state.BlockFaceShape; import net.minecraft.block.state.IBlockState; import net.minecraft.item.Item; @@ -15,11 +17,14 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; +import mcp.MethodsReturnNonnullByDefault; import net.dries007.tfc.api.types.Rock; -public class BlockPathTFC extends BlockRockVariant +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public class BlockPathTFC extends BlockRockVariantFallable { - protected static final AxisAlignedBB GRASS_PATH_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.9375D, 1.0D); + private static final AxisAlignedBB GRASS_PATH_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.9375D, 1.0D); public BlockPathTFC(Rock.Type type, Rock rock) { diff --git a/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockRaw.java b/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockRaw.java new file mode 100644 index 0000000000..d013e887f7 --- /dev/null +++ b/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockRaw.java @@ -0,0 +1,26 @@ +/* + * Work under Copyright. Licensed under the EUPL. + * See the project README.md and LICENSE.txt for more information. + * + */ + +package net.dries007.tfc.objects.blocks.stone; + +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault; +import net.dries007.tfc.api.types.Rock; +import net.dries007.tfc.util.ICollapsableBlock; + +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public class BlockRockRaw extends BlockRockVariant implements ICollapsableBlock +{ + + public BlockRockRaw(Rock.Type type, Rock rock) + { + super(type, rock); + } + + //todo: add collapsable mechanics +} diff --git a/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockVariant.java b/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockVariant.java index 6bf5bc89ef..f82e121646 100644 --- a/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockVariant.java +++ b/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockVariant.java @@ -5,10 +5,8 @@ package net.dries007.tfc.objects.blocks.stone; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; +import java.util.*; +import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; import net.minecraft.block.*; @@ -27,6 +25,7 @@ import net.minecraftforge.fml.relauncher.SideOnly; import mcp.MethodsReturnNonnullByDefault; +import net.dries007.tfc.TerraFirmaCraft; import net.dries007.tfc.api.types.Rock; import net.dries007.tfc.objects.blocks.BlocksTFC; import net.dries007.tfc.objects.entity.EntityFallingBlockTFC; @@ -37,7 +36,7 @@ @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault -public class BlockRockVariant extends Block implements IFallingBlock +public class BlockRockVariant extends Block { private static final Map> TABLE = new HashMap<>(); @@ -50,6 +49,8 @@ public static BlockRockVariant create(Rock rock, Rock.Type type) { switch (type) { + case RAW: + return new BlockRockRaw(type, rock); case FARMLAND: return new BlockFarmlandTFC(type, rock); case PATH: @@ -58,6 +59,12 @@ public static BlockRockVariant create(Rock rock, Rock.Type type) case DRY_GRASS: case CLAY_GRASS: return new BlockRockVariantConnected(type, rock); + case SAND: + case DIRT: + case CLAY: + case GRAVEL: + case COBBLE: + return new BlockRockVariantFallable(type, rock); default: return new BlockRockVariant(type, rock); } @@ -125,12 +132,6 @@ public BlockRockVariant getVariant(Rock.Type t) return TABLE.get(rock).get(t); } - @Override - public boolean shouldFall(IBlockState state, World world, BlockPos pos) - { - return type.isAffectedByGravity && IFallingBlock.super.shouldFall(state, world, pos); - } - @Override @SideOnly(Side.CLIENT) @SuppressWarnings("deprecation") @@ -180,63 +181,13 @@ public void randomTick(World world, BlockPos pos, IBlockState state, Random rand super.randomTick(world, pos, state, rand); } - @Override - public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random rand) - { - super.updateTick(worldIn, pos, state, rand); - if (worldIn.isRemote) return; - if (shouldFall(state, worldIn, pos)) - { - if (!BlockFalling.fallInstantly && worldIn.isAreaLoaded(pos.add(-32, -32, -32), pos.add(32, 32, 32))) - { - worldIn.spawnEntity(new EntityFallingBlockTFC(worldIn, pos, this, worldIn.getBlockState(pos))); - } - else - { - worldIn.setBlockToAir(pos); - pos = pos.add(0, -1, 0); - while (canFallThrough(worldIn.getBlockState(pos)) && pos.getY() > 0) - pos = pos.add(0, -1, 0); - if (pos.getY() > 0) worldIn.setBlockState(pos.up(), state); // Includes Forge's fix for data loss. - } - } - } - - @SideOnly(Side.CLIENT) - public void randomDisplayTick(IBlockState stateIn, World worldIn, BlockPos pos, Random rand) - { - if (!this.type.isAffectedByGravity) return; - if (rand.nextInt(16) != 0) return; - if (shouldFall(stateIn, worldIn, pos)) - { - double d0 = (double) ((float) pos.getX() + rand.nextFloat()); - double d1 = (double) pos.getY() - 0.05D; - double d2 = (double) ((float) pos.getZ() + rand.nextFloat()); - worldIn.spawnParticle(EnumParticleTypes.FALLING_DUST, d0, d1, d2, 0.0D, 0.0D, 0.0D, Block.getStateId(stateIn)); - } - } - - // IDK what the alternative is supposed to be, so I'm gonna continue using this. - @SuppressWarnings("deprecation") - @Override - public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos) - { - super.neighborChanged(state, worldIn, pos, blockIn, fromPos); - if (shouldFall(state, worldIn, pos)) worldIn.scheduleUpdate(pos, this, tickRate(worldIn)); - } - + // This only affects things that tick constantly AFAIK, not random ticks. @Override public int tickRate(World worldIn) { return 1; // todo: tickrate in vanilla is 2, in tfc1710 it's 10 } - @Override - public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state) - { - if (shouldFall(state, worldIn, pos)) worldIn.scheduleUpdate(pos, this, tickRate(worldIn)); - } - @Override public Item getItemDropped(IBlockState state, Random rand, int fortune) { diff --git a/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockVariantConnected.java b/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockVariantConnected.java index 3dd002d59d..95ee23091e 100644 --- a/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockVariantConnected.java +++ b/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockVariantConnected.java @@ -5,6 +5,8 @@ package net.dries007.tfc.objects.blocks.stone; +import javax.annotation.ParametersAreNonnullByDefault; + import net.minecraft.block.properties.PropertyBool; import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; @@ -12,10 +14,14 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; +import mcp.MethodsReturnNonnullByDefault; import net.dries007.tfc.api.types.Rock; import net.dries007.tfc.objects.blocks.BlocksTFC; +import net.dries007.tfc.util.IFallingBlock; -public class BlockRockVariantConnected extends BlockRockVariant +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public class BlockRockVariantConnected extends BlockRockVariantFallable { // Used for connected textures only. public static final PropertyBool NORTH = PropertyBool.create("north"); diff --git a/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockVariantFallable.java b/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockVariantFallable.java new file mode 100644 index 0000000000..ece9c1f73d --- /dev/null +++ b/src/main/java/net/dries007/tfc/objects/blocks/stone/BlockRockVariantFallable.java @@ -0,0 +1,100 @@ +/* + * Work under Copyright. Licensed under the EUPL. + * See the project README.md and LICENSE.txt for more information. + * + */ + +package net.dries007.tfc.objects.blocks.stone; + +import java.util.Arrays; +import java.util.Random; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import mcp.MethodsReturnNonnullByDefault; +import net.dries007.tfc.TerraFirmaCraft; +import net.dries007.tfc.api.types.Rock; +import net.dries007.tfc.util.IFallingBlock; + +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public class BlockRockVariantFallable extends BlockRockVariant implements IFallingBlock +{ + public BlockRockVariantFallable(Rock.Type type, Rock rock) + { + super(type, rock); + } + + @SideOnly(Side.CLIENT) + @Override + public void randomDisplayTick(IBlockState stateIn, World worldIn, BlockPos pos, Random rand) + { + if (!this.type.canFall()) return; + if (rand.nextInt(16) != 0) return; + if (shouldFall(worldIn, pos)) + { + double d0 = (double) ((float) pos.getX() + rand.nextFloat()); + double d1 = (double) pos.getY() - 0.05D; + double d2 = (double) ((float) pos.getZ() + rand.nextFloat()); + worldIn.spawnParticle(EnumParticleTypes.FALLING_DUST, d0, d1, d2, 0.0D, 0.0D, 0.0D, Block.getStateId(stateIn)); + } + } + + // IDK what the alternative is supposed to be, so I'm gonna continue using this. + @SuppressWarnings("deprecation") + @Override + public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos) + { + super.neighborChanged(state, worldIn, pos, blockIn, fromPos); + checkFalling(worldIn, pos, state); + } + + @Override + public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state) + { + super.onBlockAdded(worldIn, pos, state); + checkFalling(worldIn, pos, state); + } + + // What is the position that the block will fall at? + @Nullable + @Override + public BlockPos getFallablePos(World world, BlockPos pos) + { + for(EnumFacing f : EnumFacing.HORIZONTALS) + TerraFirmaCraft.getLog().info("Can it fall: "+f+"? "+shouldFall(world, pos.offset(f))); + if(type.canFall() && shouldFall(world, pos)) + return pos; + if(type.canFallHorizontal()) + { + // Check if supported + EnumFacing[] faces = Arrays.stream(EnumFacing.HORIZONTALS) + .filter(x -> world.getBlockState(pos.offset(x)).isOpaqueCube()) + .toArray(EnumFacing[]::new); + if(faces.length >= 2) + { + TerraFirmaCraft.getLog().info("Defeated by the supported blocks"); + return null; + } + + // Check if it can fall + faces = Arrays.stream(EnumFacing.HORIZONTALS) + .filter(x -> shouldFall(world, pos.offset(x))) + .toArray(EnumFacing[]::new); + + if(faces.length >= 1) + return pos.offset(faces[(int)(Math.random() * faces.length)]); + } + return null; + } +} diff --git a/src/main/java/net/dries007/tfc/util/ICollapsableBlock.java b/src/main/java/net/dries007/tfc/util/ICollapsableBlock.java new file mode 100644 index 0000000000..f19334f178 --- /dev/null +++ b/src/main/java/net/dries007/tfc/util/ICollapsableBlock.java @@ -0,0 +1,12 @@ +/* + * Work under Copyright. Licensed under the EUPL. + * See the project README.md and LICENSE.txt for more information. + * + */ + +package net.dries007.tfc.util; + +// For raw stone, because it collapses +public interface ICollapsableBlock +{ +} diff --git a/src/main/java/net/dries007/tfc/util/IFallingBlock.java b/src/main/java/net/dries007/tfc/util/IFallingBlock.java index 0ea5eed685..69fafadcb9 100644 --- a/src/main/java/net/dries007/tfc/util/IFallingBlock.java +++ b/src/main/java/net/dries007/tfc/util/IFallingBlock.java @@ -5,6 +5,7 @@ package net.dries007.tfc.util; +import java.util.Arrays; import javax.annotation.Nullable; import com.google.common.collect.ImmutableList; @@ -12,20 +13,54 @@ import net.minecraft.block.state.IBlockState; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fluids.BlockFluidBase; +import net.dries007.tfc.TerraFirmaCraft; +import net.dries007.tfc.objects.entity.EntityFallingBlockTFC; + public interface IFallingBlock { default boolean canFallThrough(IBlockState state) { - return BlockFalling.canFallThrough(state) || state.getBlock() instanceof BlockFluidBase; + return state.getMaterial().isReplaceable(); } - default boolean shouldFall(IBlockState state, World world, BlockPos pos) + // Can the block fall at a particular position; ignore horizontal falling + default boolean shouldFall(World world, BlockPos pos) + { + return canFallThrough(world.getBlockState(pos.down())); + } + + // Get the position that the block will fall from (allows for horizontal falling) + @Nullable + BlockPos getFallablePos(World world, BlockPos pos); + + default void checkFalling(World worldIn, BlockPos pos, IBlockState state) { - return canFallThrough(world.getBlockState(pos.add(0, -1, 0))); + BlockPos pos1 = getFallablePos(worldIn, pos); + if (pos1 != null) + { + if (!BlockFalling.fallInstantly && worldIn.isAreaLoaded(pos.add(-32, -32, -32), pos.add(32, 32, 32))) + { + if(!pos1.equals(pos)) + { + worldIn.setBlockToAir(pos); + worldIn.setBlockState(pos1, state); + } + worldIn.spawnEntity(new EntityFallingBlockTFC(worldIn, pos1, this, worldIn.getBlockState(pos1))); + } + else + { + worldIn.setBlockToAir(pos); + pos1 = pos1.down(); + while (canFallThrough(worldIn.getBlockState(pos1)) && pos1.getY() > 0) + pos1 = pos1.down(); + if (pos1.getY() > 0) worldIn.setBlockState(pos1.up(), state); // Includes Forge's fix for data loss. + } + } } default Iterable getDropsFromFall(World world, BlockPos pos, IBlockState state, @Nullable NBTTagCompound teData, int fallTime, float fallDistance) diff --git a/src/main/java/net/dries007/tfc/world/classic/worldgen/WorldGenTrees.java b/src/main/java/net/dries007/tfc/world/classic/worldgen/WorldGenTrees.java index f83b529b54..325eb412f9 100644 --- a/src/main/java/net/dries007/tfc/world/classic/worldgen/WorldGenTrees.java +++ b/src/main/java/net/dries007/tfc/world/classic/worldgen/WorldGenTrees.java @@ -41,55 +41,6 @@ public class WorldGenTrees implements IWorldGenerator private static final ITreeGenerator GEN_BUSHES = new TreeGenBushes(); - /** - * This is a copy of the method included in the Template class, with some key differences. - * This will ignore TEs / Entities, and does less checks for bad usage, since it will only be used for tree worldgen - * It will do an additional check that the block is replaceable; important for tree growth; as to not replace other blocks - * - * @param worldIn the world - * @param pos the position - * @param template the template - * @param placementIn the placement settings - */ - public static void addStructureToWorld(World worldIn, BlockPos pos, Template template, PlacementSettings placementIn) - { - int flags = 2; - ITemplateProcessor templateProcessor = new BlockRotationProcessor(pos, placementIn); - StructureBoundingBox structureboundingbox = placementIn.getBoundingBox(); - - for (Template.BlockInfo template$blockinfo : template.blocks) - { - BlockPos blockpos = Template.transformedBlockPos(placementIn, template$blockinfo.pos).add(pos); - Template.BlockInfo template$blockinfo1 = templateProcessor.processBlock(worldIn, blockpos, template$blockinfo); - - if (template$blockinfo1 != null) - { - Block block1 = template$blockinfo1.blockState.getBlock(); - - if ((!placementIn.getIgnoreStructureBlock() || block1 != Blocks.STRUCTURE_BLOCK) && (structureboundingbox == null || structureboundingbox.isVecInside(blockpos))) - { - IBlockState iblockstate = template$blockinfo1.blockState.withMirror(placementIn.getMirror()); - IBlockState iblockstate1 = iblockstate.withRotation(placementIn.getRotation()); - - if (worldIn.getBlockState(blockpos).getMaterial().isReplaceable() || worldIn.getBlockState(blockpos).getBlock() instanceof BlockLeavesTFC) - worldIn.setBlockState(blockpos, iblockstate1, flags); - - } - } - } - - for (Template.BlockInfo template$blockinfo2 : template.blocks) - { - BlockPos blockpos1 = Template.transformedBlockPos(placementIn, template$blockinfo2.pos).add(pos); - - if (structureboundingbox == null || structureboundingbox.isVecInside(blockpos1)) - { - worldIn.notifyNeighborsRespectDebug(blockpos1, template$blockinfo2.blockState.getBlock(), false); - } - - } - } - private Tree getTree(List trees, float density, Random random) { if (trees.size() == 1 || random.nextFloat() < 0.8f - density * 0.4f) diff --git a/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenAcacia.java b/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenAcacia.java index ee7235fb30..adbe7a55b9 100644 --- a/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenAcacia.java +++ b/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenAcacia.java @@ -27,7 +27,6 @@ import net.dries007.tfc.api.types.Tree; import net.dries007.tfc.objects.blocks.wood.BlockLeavesTFC; import net.dries007.tfc.objects.blocks.wood.BlockLogTFC; -import net.dries007.tfc.world.classic.worldgen.WorldGenTrees; import static net.dries007.tfc.objects.blocks.wood.BlockLogTFC.PLACED; import static net.minecraft.block.BlockLog.LOG_AXIS; @@ -97,7 +96,7 @@ private void placeBranch(TemplateManager manager, World world, BlockPos pos, Str BlockPos size = structureBase.getSize(); pos = pos.add(-size.getX() / 2, 0, -size.getZ() / 2); - WorldGenTrees.addStructureToWorld(world, pos, structureBase, settings); + ITreeGenerator.addStructureToWorld(world, pos, structureBase, settings); } private void placeLog(World world, BlockPos pos, boolean useBark) diff --git a/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenKapok.java b/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenKapok.java index cf34d36840..00cbe8140c 100644 --- a/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenKapok.java +++ b/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenKapok.java @@ -26,7 +26,6 @@ import net.dries007.tfc.objects.blocks.BlocksTFC; import net.dries007.tfc.objects.blocks.wood.BlockLeavesTFC; import net.dries007.tfc.objects.blocks.wood.BlockLogTFC; -import net.dries007.tfc.world.classic.worldgen.WorldGenTrees; import static net.dries007.tfc.objects.blocks.wood.BlockLogTFC.PLACED; import static net.minecraft.block.BlockLog.LOG_AXIS; @@ -93,7 +92,7 @@ public boolean canGenerateTree(World world, BlockPos pos, Tree treeType) return false; } - return ITreeGenerator.checkGenerationConditions(world, pos, treeType); + return ITreeGenerator.super.canGenerateTree(world, pos, treeType); } private void placeBranch(TemplateManager manager, World world, BlockPos pos, String name) @@ -109,7 +108,7 @@ private void placeBranch(TemplateManager manager, World world, BlockPos pos, Str BlockPos size = structureBase.getSize(); pos = pos.add(-size.getX() / 2, 0, -size.getZ() / 2); - WorldGenTrees.addStructureToWorld(world, pos, structureBase, settings); + ITreeGenerator.addStructureToWorld(world, pos, structureBase, settings); } private void placeTrunk(World world, BlockPos pos) diff --git a/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenNormal.java b/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenNormal.java index 2328c47f4a..82f61c8dbb 100644 --- a/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenNormal.java +++ b/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenNormal.java @@ -21,7 +21,6 @@ import net.dries007.tfc.api.ITreeGenerator; import net.dries007.tfc.api.types.Tree; import net.dries007.tfc.objects.blocks.wood.BlockLogTFC; -import net.dries007.tfc.world.classic.worldgen.WorldGenTrees; import static net.dries007.tfc.objects.blocks.wood.BlockLogTFC.PLACED; @@ -66,10 +65,10 @@ public void generateTree(TemplateManager manager, World world, BlockPos pos, Tre BlockPos size = structureBase.getSize(); pos = pos.add(-size.getX() / 2, height, -size.getZ() / 2); - WorldGenTrees.addStructureToWorld(world, pos, structureBase, settingsFull); + ITreeGenerator.addStructureToWorld(world, pos, structureBase, settingsFull); if (structureOverlay != null) { - WorldGenTrees.addStructureToWorld(world, pos, structureOverlay, settingsWeak); + ITreeGenerator.addStructureToWorld(world, pos, structureOverlay, settingsWeak); } final IBlockState log = BlockLogTFC.get(tree).getDefaultState().withProperty(PLACED, false); diff --git a/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenSequoia.java b/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenSequoia.java index 2897a50192..d24633d1ff 100644 --- a/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenSequoia.java +++ b/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenSequoia.java @@ -23,7 +23,6 @@ import net.dries007.tfc.objects.blocks.BlocksTFC; import net.dries007.tfc.objects.blocks.wood.BlockLeavesTFC; import net.dries007.tfc.objects.blocks.wood.BlockLogTFC; -import net.dries007.tfc.world.classic.worldgen.WorldGenTrees; import static net.dries007.tfc.objects.blocks.wood.BlockLogTFC.PLACED; @@ -78,7 +77,7 @@ public boolean canGenerateTree(World world, BlockPos pos, Tree treeType) return false; } - return ITreeGenerator.checkGenerationConditions(world, pos, treeType); + return ITreeGenerator.super.canGenerateTree(world, pos, treeType); } private int placeLayer(TemplateManager manager, World world, BlockPos pos, String name) @@ -94,7 +93,7 @@ private int placeLayer(TemplateManager manager, World world, BlockPos pos, Strin BlockPos size = structureBase.getSize(); pos = pos.add(-size.getX() / 2, 0, -size.getZ() / 2); - WorldGenTrees.addStructureToWorld(world, pos, structureBase, settings); + ITreeGenerator.addStructureToWorld(world, pos, structureBase, settings); return size.getY(); } diff --git a/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenVariants.java b/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenVariants.java index 9a115ae295..eab319ee6a 100644 --- a/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenVariants.java +++ b/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenVariants.java @@ -20,7 +20,6 @@ import net.dries007.tfc.TerraFirmaCraft; import net.dries007.tfc.api.ITreeGenerator; import net.dries007.tfc.api.types.Tree; -import net.dries007.tfc.world.classic.worldgen.WorldGenTrees; public class TreeGenVariants implements ITreeGenerator { @@ -70,6 +69,6 @@ public void generateTree(TemplateManager manager, World world, BlockPos pos, Tre BlockPos size = structureBase.getSize().rotate(settings2.getRotation()); // Begin rotation things pos = pos.add(-size.getX() / 2, 0, -size.getZ() / 2); - WorldGenTrees.addStructureToWorld(world, pos, structureBase, settings2); + ITreeGenerator.addStructureToWorld(world, pos, structureBase, settings2); } } diff --git a/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenWillow.java b/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenWillow.java index 82fa310777..39bbe53c50 100644 --- a/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenWillow.java +++ b/src/main/java/net/dries007/tfc/world/classic/worldgen/trees/TreeGenWillow.java @@ -22,7 +22,6 @@ import net.dries007.tfc.api.types.Tree; import net.dries007.tfc.objects.blocks.wood.BlockLeavesTFC; import net.dries007.tfc.objects.blocks.wood.BlockLogTFC; -import net.dries007.tfc.world.classic.worldgen.WorldGenTrees; import static net.dries007.tfc.objects.blocks.wood.BlockLogTFC.PLACED; import static net.minecraft.block.BlockLog.LOG_AXIS; @@ -96,8 +95,8 @@ private void createLeafGroup(World world, BlockPos pos) BlockPos size = structureBase.getSize(); pos = pos.add(-size.getX() / 2, -size.getY() / 2, -size.getZ() / 2); - WorldGenTrees.addStructureToWorld(world, pos, structureBase, settingsFull); - WorldGenTrees.addStructureToWorld(world, pos, structureOverlay, settingsWeak); + ITreeGenerator.addStructureToWorld(world, pos, structureBase, settingsFull); + ITreeGenerator.addStructureToWorld(world, pos, structureOverlay, settingsWeak); } private void tryPlaceLog(World world, BlockPos pos, Tree tree, BlockLog.EnumAxis axis)