Search in sources :

Example 1 with Cell

use of com.ferreusveritas.dynamictrees.util.SimpleVoxmap.Cell in project DynamicTrees by DynamicTreesTeam.

the class FeatureGenHugeMushroom method generate.

@Override
public boolean generate(World world, BlockPos rootPos, Species species, Biome biome, Random random, int radius, SafeChunkBounds safeBounds) {
    BlockPos genPos = rootPos.up();
    int height = getMushroomHeight(world, rootPos, biome, random, radius, safeBounds);
    IBlockState soilState = world.getBlockState(rootPos);
    if (species.isAcceptableSoilForWorldgen(world, rootPos, soilState)) {
        Block mushroomBlock = this.mushroomType;
        if (mushroomBlock == null) {
            mushroomBlock = random.nextBoolean() ? Blocks.BROWN_MUSHROOM_BLOCK : Blocks.RED_MUSHROOM_BLOCK;
        }
        SimpleVoxmap capMap = getCapForHeight(mushroomBlock, height);
        // Determine the cap position(top block of mushroom cap)
        BlockPos capPos = genPos.up(height - 1);
        // Get a bounding box for the entire cap
        BlockBounds capBounds = capMap.getBounds().move(capPos);
        if (safeBounds.inBounds(capBounds, true)) {
            // Check if there's room for a mushroom cap and stem
            for (MutableBlockPos mutPos : Iterables.concat(BlockPos.getAllInBoxMutable(BlockPos.ORIGIN.down(capMap.getLenY()), BlockPos.ORIGIN.down(height - 1)), capMap.getAllNonZero())) {
                // System.out.println(mutPos);
                BlockPos dPos = mutPos.add(capPos);
                IBlockState state = world.getBlockState(dPos);
                if (!state.getBlock().canBeReplacedByLeaves(state, world, dPos) || !state.getBlock().isReplaceable(world, dPos)) {
                    return false;
                }
            }
            // Construct the mushroom cap from the voxel map
            for (Cell cell : capMap.getAllNonZeroCells()) {
                BlockHugeMushroom.EnumType mushroomType = BlockHugeMushroom.EnumType.byMetadata(cell.getValue());
                world.setBlockState(capPos.add(cell.getPos()), mushroomBlock.getDefaultState().withProperty(BlockHugeMushroom.VARIANT, mushroomType));
            }
            // Construct the stem
            int stemLen = height - capMap.getLenY();
            IBlockState stemBlock = mushroomBlock.getDefaultState().withProperty(BlockHugeMushroom.VARIANT, BlockHugeMushroom.EnumType.STEM);
            for (int y = 0; y < stemLen; y++) {
                world.setBlockState(genPos.up(y), stemBlock);
            }
            return true;
        }
    }
    return false;
}
Also used : IBlockState(net.minecraft.block.state.IBlockState) Block(net.minecraft.block.Block) BlockHugeMushroom(net.minecraft.block.BlockHugeMushroom) BlockPos(net.minecraft.util.math.BlockPos) MutableBlockPos(net.minecraft.util.math.BlockPos.MutableBlockPos) SimpleVoxmap(com.ferreusveritas.dynamictrees.util.SimpleVoxmap) BlockBounds(com.ferreusveritas.dynamictrees.util.BlockBounds) MutableBlockPos(net.minecraft.util.math.BlockPos.MutableBlockPos) Cell(com.ferreusveritas.dynamictrees.util.SimpleVoxmap.Cell)

Example 2 with Cell

use of com.ferreusveritas.dynamictrees.util.SimpleVoxmap.Cell in project DynamicTrees by DynamicTreesTeam.

the class FeatureGenMound method preGeneration.

/**
 * Used to create a 5x4x5 rounded mound that is one block higher than the ground surface. This is meant to replicate
 * the appearance of a root hill and gives generated surface roots a better appearance.
 *
 * @param world      The world
 * @param rootPos    The position of the rooty dirt
 * @param safeBounds A safebounds structure for preventing runaway cascading generation
 * @return The modified position of the rooty dirt that is one block higher
 */
@Override
public BlockPos preGeneration(World world, BlockPos rootPos, Species species, int radius, EnumFacing facing, SafeChunkBounds safeBounds, JoCode joCode) {
    if (radius >= moundCutoffRadius && safeBounds != SafeChunkBounds.ANY) {
        // worldgen test
        IBlockState initialDirtState = world.getBlockState(rootPos);
        IBlockState initialUnderState = world.getBlockState(rootPos.down());
        if (initialUnderState.getMaterial() == Material.AIR || (initialUnderState.getMaterial() != Material.GROUND && initialUnderState.getMaterial() != Material.ROCK)) {
            Biome biome = world.getBiome(rootPos);
            initialUnderState = biome.fillerBlock;
        }
        rootPos = rootPos.up();
        for (Cell cell : moundMap.getAllNonZeroCells()) {
            IBlockState placeState = cell.getValue() == 1 ? initialDirtState : initialUnderState;
            world.setBlockState(rootPos.add(cell.getPos()), placeState);
        }
    }
    return rootPos;
}
Also used : IBlockState(net.minecraft.block.state.IBlockState) Biome(net.minecraft.world.biome.Biome) Cell(com.ferreusveritas.dynamictrees.util.SimpleVoxmap.Cell)

Example 3 with Cell

use of com.ferreusveritas.dynamictrees.util.SimpleVoxmap.Cell in project DynamicTrees by DynamicTreesTeam.

the class JoCode method cleanupFrankentree.

/**
 * Attempt to clean up fused trees that have multiple root blocks by simply destroying them both messily
 */
protected void cleanupFrankentree(World world, BlockPos treePos, IBlockState treeState, List<BlockPos> endPoints, SafeChunkBounds safeBounds) {
    Set<BlockPos> blocksToDestroy = new HashSet<>();
    BlockBranch branch = TreeHelper.getBranch(treeState);
    MapSignal signal = new MapSignal(new NodeCollector(blocksToDestroy));
    signal.destroyLoopedNodes = false;
    signal.trackVisited = true;
    branch.analyse(treeState, world, treePos, null, signal);
    BlockBranch.destroyMode = EnumDestroyMode.IGNORE;
    for (BlockPos pos : blocksToDestroy) {
        if (safeBounds.inBounds(pos, false)) {
            IBlockState branchState = world.getBlockState(pos);
            Optional<BlockBranch> branchBlock = TreeHelper.getBranchOpt(branchState);
            if (branchBlock.isPresent()) {
                int radius = branchBlock.get().getRadius(branchState);
                TreeFamily family = branchBlock.get().getFamily();
                Species species = family.getCommonSpecies();
                if (family.getPrimaryThickness() == radius) {
                    ILeavesProperties leavesProperties = species.getLeavesProperties();
                    if (leavesProperties != LeavesProperties.NULLPROPERTIES) {
                        SimpleVoxmap leafCluster = leavesProperties.getCellKit().getLeafCluster();
                        if (leafCluster != LeafClusters.NULLMAP) {
                            for (Cell cell : leafCluster.getAllNonZeroCells()) {
                                BlockPos delPos = pos.add(cell.getPos());
                                if (safeBounds.inBounds(delPos, false)) {
                                    IBlockState leavesState = world.getBlockState(delPos);
                                    if (TreeHelper.isLeaves(leavesState)) {
                                        BlockDynamicLeaves leavesBlock = (BlockDynamicLeaves) leavesState.getBlock();
                                        if (leavesProperties.getTree() == leavesBlock.getProperties(leavesState).getTree()) {
                                            world.setBlockState(delPos, ModBlocks.blockStates.air, 2);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                world.setBlockState(pos, ModBlocks.blockStates.air, 2);
            }
        }
    }
    BlockBranch.destroyMode = EnumDestroyMode.HARVEST;
// Now wreck out all surrounding leaves.  Let them grow back naturally.
/*if(!endPoints.isEmpty()) {
			BlockBounds bounds = new BlockBounds(endPoints);
			bounds.expand(3);
			for(BlockPos pos : bounds.iterate()) {
				if(safeBounds.inBounds(pos, false)) {
					if(TreeHelper.isLeaves(world.getBlockState(pos))) {
						world.setBlockState(pos, ModBlocks.blockStates.air, 2);
					}
				}
			}
		}*/
}
Also used : IBlockState(net.minecraft.block.state.IBlockState) SimpleVoxmap(com.ferreusveritas.dynamictrees.util.SimpleVoxmap) BlockDynamicLeaves(com.ferreusveritas.dynamictrees.blocks.BlockDynamicLeaves) BlockBranch(com.ferreusveritas.dynamictrees.blocks.BlockBranch) NodeCollector(com.ferreusveritas.dynamictrees.systems.nodemappers.NodeCollector) ILeavesProperties(com.ferreusveritas.dynamictrees.api.treedata.ILeavesProperties) TreeFamily(com.ferreusveritas.dynamictrees.trees.TreeFamily) MutableBlockPos(net.minecraft.util.math.BlockPos.MutableBlockPos) BlockPos(net.minecraft.util.math.BlockPos) Species(com.ferreusveritas.dynamictrees.trees.Species) Cell(com.ferreusveritas.dynamictrees.util.SimpleVoxmap.Cell) MapSignal(com.ferreusveritas.dynamictrees.api.network.MapSignal)

Example 4 with Cell

use of com.ferreusveritas.dynamictrees.util.SimpleVoxmap.Cell in project DynamicTrees by DynamicTreesTeam.

the class JoCode method generate.

/**
 * Generate a tree from a JoCode instruction list.
 *
 * @param world   The world
 * @param seed    The seed used to create the tree
 * @param rootPos The position of what will become the rootydirt block
 * @param biome   The biome of the coordinates.
 * @param facing  Direction of tree
 * @param radius  Constraint radius
 */
public void generate(World world, Species species, BlockPos rootPosIn, Biome biome, EnumFacing facing, int radius, SafeChunkBounds safeBounds) {
    boolean worldGen = safeBounds != SafeChunkBounds.ANY;
    // A Tree generation boundary radius is at least 2 and at most 8
    radius = MathHelper.clamp(radius, 2, 8);
    setFacing(facing);
    BlockPos rootPos = species.preGeneration(world, rootPosIn, radius, facing, safeBounds, this);
    if (rootPos != BlockPos.ORIGIN) {
        // Save the initial state of the dirt in case this fails
        IBlockState initialDirtState = world.getBlockState(rootPos);
        // Set to unfertilized rooty dirt
        species.placeRootyDirtBlock(world, rootPos, 0);
        // Make the tree branch structure
        generateFork(world, species, 0, rootPos, false);
        // Establish a position for the bottom block of the trunk
        BlockPos treePos = rootPos.up();
        // Fix branch thicknesses and map out leaf locations
        IBlockState treeState = world.getBlockState(treePos);
        BlockBranch branch = TreeHelper.getBranch(treeState);
        if (branch != null) {
            // If a branch exists then the growth was successful
            ILeavesProperties leavesProperties = species.getLeavesProperties();
            SimpleVoxmap leafMap = new SimpleVoxmap(radius * 2 + 1, species.getWorldGenLeafMapHeight(), radius * 2 + 1).setMapAndCenter(treePos, new BlockPos(radius, 0, radius));
            // This is responsible for thickening the branches
            INodeInspector inflator = species.getNodeInflator(leafMap);
            // This is responsible for gathering a list of branch end points
            NodeFindEnds endFinder = new NodeFindEnds();
            // The inflator signal will "paint" a temporary voxmap of all of the leaves and branches.
            MapSignal signal = new MapSignal(inflator, endFinder);
            // During worldgen we will not destroy looped nodes
            signal.destroyLoopedNodes = careful;
            branch.analyse(treeState, world, treePos, EnumFacing.DOWN, signal);
            if (signal.found || signal.overflow) {
                // Something went terribly wrong.
                DynamicTrees.log.debug("Non-viable branch network detected during world generation @ " + treePos);
                DynamicTrees.log.debug("Species: " + species);
                DynamicTrees.log.debug("Radius: " + radius);
                DynamicTrees.log.debug("JoCode: " + this);
                // Completely blow away any improperly defined network nodes
                cleanupFrankentree(world, treePos, treeState, endFinder.getEnds(), safeBounds);
                // Now that everything is clear we may as well regenerate the tree that screwed everything up.
                if (!secondChanceRegen) {
                    secondChanceRegen = true;
                    generate(world, species, rootPosIn, biome, facing, radius, safeBounds);
                }
                secondChanceRegen = false;
                return;
            }
            List<BlockPos> endPoints = endFinder.getEnds();
            // Use the voxmap to precompute leaf smothering so we don't have to age it as many times.
            smother(leafMap, leavesProperties);
            // Place Growing Leaves Blocks from voxmap
            for (Cell cell : leafMap.getAllNonZeroCells((byte) 0x0F)) {
                // Iterate through all of the cells that are leaves(not air or branches)
                MutableBlockPos cellPos = cell.getPos();
                if (safeBounds.inBounds(cellPos, false)) {
                    IBlockState testBlockState = world.getBlockState(cellPos);
                    Block testBlock = testBlockState.getBlock();
                    if (testBlock.isReplaceable(world, cellPos)) {
                        // Flag 16 to prevent observers from causing cascading lag
                        world.setBlockState(cellPos, leavesProperties.getDynamicLeavesState(cell.getValue()), worldGen ? 16 : 2);
                    }
                } else {
                    leafMap.setVoxel(cellPos, (byte) 0);
                }
            }
            // Shrink the leafMap down by the safeBounds object so that the aging process won't look for neighbors outside of the bounds.
            for (Cell cell : leafMap.getAllNonZeroCells()) {
                MutableBlockPos cellPos = cell.getPos();
                if (!safeBounds.inBounds(cellPos, true)) {
                    leafMap.setVoxel(cellPos, (byte) 0);
                }
            }
            // Age volume for 3 cycles using a leafmap
            TreeHelper.ageVolume(world, leafMap, species.getWorldGenAgeIterations(), safeBounds);
            // Rot the unsupported branches
            if (species.handleRot(world, endPoints, rootPos, treePos, 0, safeBounds)) {
                // The entire tree rotted away before it had a chance
                return;
            }
            // Allow for special decorations by the tree itself
            species.postGeneration(world, rootPos, biome, radius, endPoints, safeBounds, initialDirtState);
            MinecraftForge.EVENT_BUS.post(new SpeciesPostGenerationEvent(world, species, rootPos, endPoints, safeBounds, initialDirtState));
            // Add snow to parts of the tree in chunks where snow was already placed
            addSnow(leafMap, world, rootPos, biome);
        } else {
            // The growth failed.. turn the soil back to what it was
            world.setBlockState(rootPos, initialDirtState, careful ? 3 : 2);
        }
    }
}
Also used : INodeInspector(com.ferreusveritas.dynamictrees.api.network.INodeInspector) NodeFindEnds(com.ferreusveritas.dynamictrees.systems.nodemappers.NodeFindEnds) IBlockState(net.minecraft.block.state.IBlockState) SpeciesPostGenerationEvent(com.ferreusveritas.dynamictrees.event.SpeciesPostGenerationEvent) SimpleVoxmap(com.ferreusveritas.dynamictrees.util.SimpleVoxmap) BlockBranch(com.ferreusveritas.dynamictrees.blocks.BlockBranch) ILeavesProperties(com.ferreusveritas.dynamictrees.api.treedata.ILeavesProperties) Block(net.minecraft.block.Block) MutableBlockPos(net.minecraft.util.math.BlockPos.MutableBlockPos) BlockPos(net.minecraft.util.math.BlockPos) Cell(com.ferreusveritas.dynamictrees.util.SimpleVoxmap.Cell) MutableBlockPos(net.minecraft.util.math.BlockPos.MutableBlockPos) MapSignal(com.ferreusveritas.dynamictrees.api.network.MapSignal)

Example 5 with Cell

use of com.ferreusveritas.dynamictrees.util.SimpleVoxmap.Cell in project DynamicTrees by DynamicTreesTeam.

the class BlockBranch method destroyLeaves.

/**
 * Attempt to destroy all of the leaves on the branch while leaving the other leaves unharmed.
 *
 * @param world           The world
 * @param cutPos          The position of the block that was initially destroyed
 * @param species         The species of the tree that is being modified
 * @param endPoints       The absolute positions of the branch endpoints
 * @param destroyedLeaves A map for collecting the positions and blockstates for all of the leaves blocks that will
 *                        be destroyed.
 * @param drops           A list for collecting the ItemStacks and their positions relative to the cut position
 */
protected void destroyLeaves(World world, BlockPos cutPos, Species species, List<BlockPos> endPoints, Map<BlockPos, IBlockState> destroyedLeaves, List<BlockItemStack> drops) {
    if (!world.isRemote && !endPoints.isEmpty()) {
        // Make a bounding volume that holds all of the endpoints and expand the volume by 3 blocks for the leaves radius
        BlockBounds bounds = new BlockBounds(endPoints).expand(3);
        // Create a voxmap to store the leaf destruction map
        SimpleVoxmap vmap = new SimpleVoxmap(bounds);
        // For each of the endpoints add a 7x7 destruction volume around it
        for (BlockPos endPos : endPoints) {
            for (BlockPos leafPos : BlockPos.getAllInBoxMutable(endPos.add(-3, -3, -3), endPos.add(3, 3, 3))) {
                // Flag this position for destruction
                vmap.setVoxel(leafPos, (byte) 1);
            }
            // We know that the endpoint does not have a leaves block in it because it was a branch
            vmap.setVoxel(endPos, (byte) 0);
        }
        TreeFamily family = species.getFamily();
        BlockBranch familyBranch = family.getDynamicBranch();
        int primaryThickness = (int) family.getPrimaryThickness();
        // Expand the volume yet again by 3 blocks in all directions and search for other non-destroyed endpoints
        for (MutableBlockPos findPos : bounds.expand(3).iterate()) {
            IBlockState findState = world.getBlockState(findPos);
            if (familyBranch.getRadius(findState) == primaryThickness) {
                // Search for endpoints of the same tree family
                Iterable<MutableBlockPos> leaves = species.getLeavesProperties().getCellKit().getLeafCluster().getAllNonZero();
                for (MutableBlockPos leafpos : leaves) {
                    vmap.setVoxel(findPos.getX() + leafpos.getX(), findPos.getY() + leafpos.getY(), findPos.getZ() + leafpos.getZ(), (byte) 0);
                }
            }
        }
        ArrayList<ItemStack> dropList = new ArrayList<ItemStack>();
        // Destroy all family compatible leaves
        for (Cell cell : vmap.getAllNonZeroCells()) {
            MutableBlockPos pos = cell.getPos();
            IBlockState state = world.getBlockState(pos);
            if (species.isCompatibleLeaves(world, pos, state)) {
                dropList.clear();
                species.getTreeHarvestDrops(world, pos, dropList, world.rand);
                // We are storing this so it must be immutable
                BlockPos imPos = pos.toImmutable();
                BlockPos relPos = imPos.subtract(cutPos);
                // Covertly destroy the leaves on the server side
                world.setBlockState(imPos, ModBlocks.blockStates.air, 0);
                destroyedLeaves.put(relPos, state);
                dropList.forEach(i -> drops.add(new BlockItemStack(i, relPos)));
            }
        }
    }
}
Also used : IBlockState(net.minecraft.block.state.IBlockState) SimpleVoxmap(com.ferreusveritas.dynamictrees.util.SimpleVoxmap) TreeFamily(com.ferreusveritas.dynamictrees.trees.TreeFamily) MutableBlockPos(net.minecraft.util.math.BlockPos.MutableBlockPos) BlockPos(net.minecraft.util.math.BlockPos) ItemStack(net.minecraft.item.ItemStack) BlockBounds(com.ferreusveritas.dynamictrees.util.BlockBounds) MutableBlockPos(net.minecraft.util.math.BlockPos.MutableBlockPos) Cell(com.ferreusveritas.dynamictrees.util.SimpleVoxmap.Cell)

Aggregations

Cell (com.ferreusveritas.dynamictrees.util.SimpleVoxmap.Cell)5 IBlockState (net.minecraft.block.state.IBlockState)5 SimpleVoxmap (com.ferreusveritas.dynamictrees.util.SimpleVoxmap)4 BlockPos (net.minecraft.util.math.BlockPos)4 MutableBlockPos (net.minecraft.util.math.BlockPos.MutableBlockPos)4 MapSignal (com.ferreusveritas.dynamictrees.api.network.MapSignal)2 ILeavesProperties (com.ferreusveritas.dynamictrees.api.treedata.ILeavesProperties)2 BlockBranch (com.ferreusveritas.dynamictrees.blocks.BlockBranch)2 TreeFamily (com.ferreusveritas.dynamictrees.trees.TreeFamily)2 BlockBounds (com.ferreusveritas.dynamictrees.util.BlockBounds)2 Block (net.minecraft.block.Block)2 INodeInspector (com.ferreusveritas.dynamictrees.api.network.INodeInspector)1 BlockDynamicLeaves (com.ferreusveritas.dynamictrees.blocks.BlockDynamicLeaves)1 SpeciesPostGenerationEvent (com.ferreusveritas.dynamictrees.event.SpeciesPostGenerationEvent)1 NodeCollector (com.ferreusveritas.dynamictrees.systems.nodemappers.NodeCollector)1 NodeFindEnds (com.ferreusveritas.dynamictrees.systems.nodemappers.NodeFindEnds)1 Species (com.ferreusveritas.dynamictrees.trees.Species)1 BlockHugeMushroom (net.minecraft.block.BlockHugeMushroom)1 ItemStack (net.minecraft.item.ItemStack)1 Biome (net.minecraft.world.biome.Biome)1