use of com.ferreusveritas.dynamictrees.api.network.MapSignal in project DynamicTrees by DynamicTreesTeam.
the class FeatureGenFruit method postGrow.
@Override
public boolean postGrow(World world, BlockPos rootPos, BlockPos treePos, Species species, int soilLife, boolean natural) {
IBlockState blockState = world.getBlockState(treePos);
BlockBranch branch = TreeHelper.getBranch(blockState);
if (branch != null && branch.getRadius(blockState) >= fruitingRadius && natural) {
if (species.seasonalFruitProductionFactor(world, rootPos) > world.rand.nextFloat()) {
NodeFindEnds endFinder = new NodeFindEnds();
TreeHelper.startAnalysisFromRoot(world, rootPos, new MapSignal(endFinder));
List<BlockPos> endPoints = endFinder.getEnds();
int qty = getQuantity(false);
if (!endPoints.isEmpty()) {
for (int i = 0; i < qty; i++) {
BlockPos endPoint = endPoints.get(world.rand.nextInt(endPoints.size()));
addFruit(world, species, rootPos.up(), endPoint, false, true, SafeChunkBounds.ANY);
}
}
}
}
return true;
}
use of com.ferreusveritas.dynamictrees.api.network.MapSignal in project DynamicTrees by DynamicTreesTeam.
the class FeatureGenPodzol method postGrow.
@Override
public boolean postGrow(World world, BlockPos rootPos, BlockPos treePos, Species species, int soilLife, boolean natural) {
if (ModConfigs.podzolGen) {
NodeFindEnds endFinder = new NodeFindEnds();
TreeHelper.startAnalysisFromRoot(world, rootPos, new MapSignal(endFinder));
List<BlockPos> endPoints = endFinder.getEnds();
if (!endPoints.isEmpty()) {
Random random = world.rand;
BlockPos pos = endPoints.get(random.nextInt(endPoints.size()));
int x = pos.getX() + random.nextInt(5) - 2;
int z = pos.getZ() + random.nextInt(5) - 2;
final int darkThreshold = 4;
for (int i = 0; i < 32; i++) {
BlockPos offPos = new BlockPos(x, pos.getY() - 1 - i, z);
if (!world.isAirBlock(offPos)) {
Block block = world.getBlockState(offPos).getBlock();
if (block instanceof BlockBranch || block instanceof BlockMushroom || block instanceof BlockLeaves) {
// Skip past Mushrooms and branches on the way down
continue;
} else if (block instanceof BlockFlower || block instanceof BlockTallGrass || block instanceof BlockDoublePlant) {
// Kill Plants
if (world.getLightFor(EnumSkyBlock.SKY, offPos) <= darkThreshold) {
world.setBlockToAir(pos);
}
continue;
} else if (block == Blocks.DIRT || block == Blocks.GRASS) {
// Convert grass or dirt to podzol
if (world.getLightFor(EnumSkyBlock.SKY, offPos.up()) <= darkThreshold) {
world.setBlockState(offPos, ModBlocks.blockStates.podzol);
} else {
spreadPodzol(world, pos);
}
}
break;
}
}
}
}
return true;
}
use of com.ferreusveritas.dynamictrees.api.network.MapSignal 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.api.network.MapSignal in project DynamicTrees by DynamicTreesTeam.
the class BlockBranch method destroyBranchFromNode.
/**
* Destroys all branches recursively not facing the branching direction with the root node
*
* @param world The world
* @param cutPos The position of the branch being lobbed
* @param toolDir The face that was pounded on when breaking the block at cutPos
* @param wholeTree Indicates if the whole tree should be destroyed or just the branch
* @return The volume of the portion of the tree that was destroyed
*/
public BranchDestructionData destroyBranchFromNode(World world, BlockPos cutPos, EnumFacing toolDir, boolean wholeTree) {
IBlockState blockState = world.getBlockState(cutPos);
NodeSpecies nodeSpecies = new NodeSpecies();
// Analyze entire tree network to find root node and species
MapSignal signal = analyse(blockState, world, cutPos, null, new MapSignal(nodeSpecies));
// Get the species from the root node
Species species = nodeSpecies.getSpecies();
// Analyze only part of the tree beyond the break point and map out the extended block states
// We can't destroy the branches during this step since we need accurate extended block states that include connections
NodeExtState extStateMapper = new NodeExtState(cutPos);
analyse(blockState, world, cutPos, wholeTree ? null : signal.localRootDir, new MapSignal(extStateMapper));
// Analyze only part of the tree beyond the break point and calculate it's volume, then destroy the branches
NodeNetVolume volumeSum = new NodeNetVolume();
NodeDestroyer destroyer = new NodeDestroyer(species);
destroyMode = EnumDestroyMode.HARVEST;
analyse(blockState, world, cutPos, wholeTree ? null : signal.localRootDir, new MapSignal(volumeSum, destroyer));
destroyMode = EnumDestroyMode.SLOPPY;
// Destroy all the leaves on the branch, store them in a map and convert endpoint coordinates from absolute to relative
List<BlockPos> endPoints = destroyer.getEnds();
Map<BlockPos, IBlockState> destroyedLeaves = new HashMap<>();
List<BlockItemStack> leavesDropsList = new ArrayList<>();
destroyLeaves(world, cutPos, species, endPoints, destroyedLeaves, leavesDropsList);
endPoints = endPoints.stream().map(p -> p.subtract(cutPos)).collect(Collectors.toList());
// Calculate main trunk height
int trunkHeight = 1;
for (BlockPos iter = new BlockPos(0, 1, 0); extStateMapper.getExtStateMap().containsKey(iter); iter = iter.up()) {
trunkHeight++;
}
EnumFacing cutDir = signal.localRootDir;
if (cutDir == null) {
cutDir = EnumFacing.DOWN;
}
return new BranchDestructionData(species, extStateMapper.getExtStateMap(), destroyedLeaves, leavesDropsList, endPoints, volumeSum.getVolume(), cutPos, cutDir, toolDir, trunkHeight);
}
use of com.ferreusveritas.dynamictrees.api.network.MapSignal in project DynamicTrees by DynamicTreesTeam.
the class TreeHelper method findRootNode.
/**
* Find the root node of a tree.
*
* @param world The world
* @param pos The position being analyzed
* @return The position of the root node of the tree or BlockPos.ORIGIN if nothing was found.
*/
public static BlockPos findRootNode(World world, BlockPos pos) {
pos = dereferenceTrunkShell(world, pos);
IBlockState state = world.getBlockState(pos);
ITreePart treePart = TreeHelper.getTreePart(state);
switch(treePart.getTreePartType()) {
case BRANCH:
// Analyze entire tree network to find root node
MapSignal signal = treePart.analyse(state, world, pos, null, new MapSignal());
if (signal.found) {
return signal.root;
}
break;
case ROOT:
return pos;
default:
return BlockPos.ORIGIN;
}
return BlockPos.ORIGIN;
}
Aggregations