Search in sources :

Example 6 with SimpleVoxmap

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

the class NodeInflator method returnRun.

@Override
public boolean returnRun(IBlockState blockState, World world, BlockPos pos, EnumFacing fromDir) {
    // Calculate Branch Thickness based on neighboring branches
    BlockBranch branch = TreeHelper.getBranch(blockState);
    if (branch != null) {
        // Start by accumulating the branch we just came from
        float areaAccum = radius * radius;
        boolean isTwig = true;
        for (EnumFacing dir : EnumFacing.VALUES) {
            if (!dir.equals(fromDir)) {
                // Don't count where the signal originated from
                BlockPos dPos = pos.offset(dir);
                if (dPos.equals(last)) {
                    // or the branch we just came back from
                    // on the return journey if the block we just came from is a branch we are obviously not the endpoint(twig)
                    isTwig = false;
                    continue;
                }
                IBlockState deltaBlockState = world.getBlockState(dPos);
                ITreePart treepart = TreeHelper.getTreePart(deltaBlockState);
                if (branch.isSameTree(treepart)) {
                    int branchRadius = treepart.getRadius(deltaBlockState);
                    areaAccum += branchRadius * branchRadius;
                }
            }
        }
        if (isTwig) {
            // Handle leaves here
            if (leafMap != null) {
                // 16(bit 5) is code for a twig
                leafMap.setVoxel(pos, (byte) 16);
                SimpleVoxmap leafCluster = species.getLeavesProperties().getCellKit().getLeafCluster();
                leafMap.blitMax(pos, leafCluster);
            }
        } else {
            // The new branch should be the square root of all of the sums of the areas of the branches coming into it.
            radius = (float) Math.sqrt(areaAccum) + (species.getTapering() * species.getWorldGenTaperingFactor());
            // Ensure the branch is never inflated past it's species maximum
            int maxRadius = species.maxBranchRadius();
            if (radius > maxRadius) {
                radius = maxRadius;
            }
            // Ensure non-twig branches are at least radius 2
            float secondaryThickness = species.getFamily().getSecondaryThickness();
            if (radius < secondaryThickness) {
                radius = secondaryThickness;
            }
            branch.setRadius(world, pos, (int) Math.floor(radius), null);
            if (leafMap != null) {
                // 32(bit 6) is code for a branch
                leafMap.setVoxel(pos, (byte) 32);
            }
        }
        last = pos;
    }
    return false;
}
Also used : ITreePart(com.ferreusveritas.dynamictrees.api.treedata.ITreePart) IBlockState(net.minecraft.block.state.IBlockState) EnumFacing(net.minecraft.util.EnumFacing) BlockPos(net.minecraft.util.math.BlockPos) SimpleVoxmap(com.ferreusveritas.dynamictrees.util.SimpleVoxmap) BlockBranch(com.ferreusveritas.dynamictrees.blocks.BlockBranch)

Example 7 with SimpleVoxmap

use of com.ferreusveritas.dynamictrees.util.SimpleVoxmap 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 8 with SimpleVoxmap

use of com.ferreusveritas.dynamictrees.util.SimpleVoxmap 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)

Example 9 with SimpleVoxmap

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

the class TreeHelper method ageVolume.

/**
 * Pulses an entire leafMap volume of blocks each with an age signal. Warning: CPU intensive and should be used
 * sparingly
 *
 * @param world      The world
 * @param leafMap    The voxel map of hydrovalues to use as a iterator
 * @param iterations The number of times to age the map
 */
public static void ageVolume(World world, SimpleVoxmap leafMap, int iterations, SafeChunkBounds safeBounds) {
    // The iterMap is the voxmap we will use as a discardable.  The leafMap must survive for snow
    SimpleVoxmap iterMap = leafMap != null ? new SimpleVoxmap(leafMap) : null;
    Iterable<MutableBlockPos> iterable = iterMap.getAllNonZero();
    for (int i = 0; i < iterations; i++) {
        for (MutableBlockPos iPos : iterable) {
            IBlockState blockState = world.getBlockState(iPos);
            Block block = blockState.getBlock();
            if (block instanceof BlockDynamicLeaves) {
                // Special case for leaves
                // The leafMap should contain accurate hydro data
                int prevHydro = leafMap.getVoxel(iPos);
                // Get new values from neighbors
                int newHydro = ((IAgeable) block).age(world, iPos, blockState, world.rand, safeBounds);
                if (newHydro == -1) {
                    // Leaf block died.  Take it out of the leafMap and iterMap
                    leafMap.setVoxel(iPos, (byte) 0);
                    iterMap.setVoxel(iPos, (byte) 0);
                } else {
                    // Leaf did not die so the block is still leaves
                    if (prevHydro == newHydro) {
                        // But it didn't change
                        // Stop iterating over it if it's not changing
                        iterMap.setVoxel(iPos, (byte) 0);
                    } else {
                        // Oh wait.. it did change
                        // Update both maps with this new hydro value
                        leafMap.setVoxel(iPos, (byte) newHydro);
                        iterMap.setVoxel(iPos, (byte) newHydro);
                        // Copy all the surrounding values from the leafMap to the iterMap since they now also have potential to change
                        for (EnumFacing dir : EnumFacing.values()) {
                            BlockPos dPos = iPos.offset(dir);
                            iterMap.setVoxel(dPos, leafMap.getVoxel(dPos));
                        }
                    }
                }
            } else if (block instanceof IAgeable) {
                // Treat as just a regular ageable block
                ((IAgeable) block).age(world, iPos, blockState, world.rand, safeBounds);
            } else {
                // You're not supposed to be here
                leafMap.setVoxel(iPos, (byte) 0);
                iterMap.setVoxel(iPos, (byte) 0);
            }
        }
    }
}
Also used : IBlockState(net.minecraft.block.state.IBlockState) EnumFacing(net.minecraft.util.EnumFacing) Block(net.minecraft.block.Block) SimpleVoxmap(com.ferreusveritas.dynamictrees.util.SimpleVoxmap) BlockPos(net.minecraft.util.math.BlockPos) MutableBlockPos(net.minecraft.util.math.BlockPos.MutableBlockPos) MutableBlockPos(net.minecraft.util.math.BlockPos.MutableBlockPos)

Aggregations

SimpleVoxmap (com.ferreusveritas.dynamictrees.util.SimpleVoxmap)9 IBlockState (net.minecraft.block.state.IBlockState)8 BlockPos (net.minecraft.util.math.BlockPos)8 MutableBlockPos (net.minecraft.util.math.BlockPos.MutableBlockPos)7 Cell (com.ferreusveritas.dynamictrees.util.SimpleVoxmap.Cell)4 BlockBranch (com.ferreusveritas.dynamictrees.blocks.BlockBranch)3 Block (net.minecraft.block.Block)3 MapSignal (com.ferreusveritas.dynamictrees.api.network.MapSignal)2 ILeavesProperties (com.ferreusveritas.dynamictrees.api.treedata.ILeavesProperties)2 TreeFamily (com.ferreusveritas.dynamictrees.trees.TreeFamily)2 BlockBounds (com.ferreusveritas.dynamictrees.util.BlockBounds)2 EnumFacing (net.minecraft.util.EnumFacing)2 Vec3d (net.minecraft.util.math.Vec3d)2 INodeInspector (com.ferreusveritas.dynamictrees.api.network.INodeInspector)1 ITreePart (com.ferreusveritas.dynamictrees.api.treedata.ITreePart)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