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;
}
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;
}
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);
}
}
}
}*/
}
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);
}
}
}
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)));
}
}
}
}
Aggregations