minecraft-source/src/net/minecraft/world/level/levelgen/feature/AbstractTreeFeature.java

219 lines
11 KiB
Java

package net.minecraft.world.level.levelgen.feature;
import net.minecraft.world.level.block.state.AbstractStateHolder;
import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecorator;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
import java.util.Iterator;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.core.Direction;
import net.minecraft.world.phys.shapes.BitSetDiscreteVoxelShape;
import net.minecraft.world.phys.shapes.DiscreteVoxelShape;
import java.util.List;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import java.util.Comparator;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import net.minecraft.world.level.levelgen.ChunkGeneratorSettings;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.core.Vec3i;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import java.util.Set;
import java.util.Random;
import net.minecraft.world.level.LevelWriter;
import net.minecraft.world.level.LevelSimulatedRW;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.tags.BlockTags;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LevelSimulatedReader;
import com.mojang.datafixers.Dynamic;
import java.util.function.Function;
import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration;
public abstract class AbstractTreeFeature<T extends TreeConfiguration> extends Feature<T> {
public AbstractTreeFeature(final Function<Dynamic<?>, ? extends T> function) {
super(function);
}
protected static boolean isFree(final LevelSimulatedReader bjz, final BlockPos fk) {
final Block bpe2;
return bjz.isStateAtPosition(fk, byg -> {
bpe2 = byg.getBlock();
return byg.isAir() || byg.is(BlockTags.LEAVES) || Feature.isDirt(bpe2) || bpe2.is(BlockTags.LOGS) || bpe2.is(BlockTags.SAPLINGS) || bpe2 == Blocks.VINE;
});
}
public static boolean isAir(final LevelSimulatedReader bjz, final BlockPos fk) {
return bjz.isStateAtPosition(fk, BlockState::isAir);
}
protected static boolean isDirt(final LevelSimulatedReader bjz, final BlockPos fk) {
final Block bpe2;
return bjz.isStateAtPosition(fk, byg -> {
bpe2 = byg.getBlock();
return Feature.isDirt(bpe2) && bpe2 != Blocks.GRASS_BLOCK && bpe2 != Blocks.MYCELIUM;
});
}
protected static boolean isVine(final LevelSimulatedReader bjz, final BlockPos fk) {
return bjz.isStateAtPosition(fk, byg -> byg.getBlock() == Blocks.VINE);
}
public static boolean isBlockWater(final LevelSimulatedReader bjz, final BlockPos fk) {
return bjz.isStateAtPosition(fk, byg -> byg.getBlock() == Blocks.WATER);
}
public static boolean isAirOrLeaves(final LevelSimulatedReader bjz, final BlockPos fk) {
return bjz.isStateAtPosition(fk, byg -> byg.isAir() || byg.is(BlockTags.LEAVES));
}
public static boolean isGrassOrDirt(final LevelSimulatedReader bjz, final BlockPos fk) {
return bjz.isStateAtPosition(fk, byg -> Feature.isDirt(byg.getBlock()));
}
protected static boolean isGrassOrDirtOrFarmland(final LevelSimulatedReader bjz, final BlockPos fk) {
final Block bpe2;
return bjz.isStateAtPosition(fk, byg -> {
bpe2 = byg.getBlock();
return Feature.isDirt(bpe2) || bpe2 == Blocks.FARMLAND;
});
}
public static boolean isReplaceablePlant(final LevelSimulatedReader bjz, final BlockPos fk) {
final Material cok2;
return bjz.isStateAtPosition(fk, byg -> {
cok2 = byg.getMaterial();
return cok2 == Material.REPLACEABLE_PLANT;
});
}
protected void setDirtAt(final LevelSimulatedRW bjy, final BlockPos fk) {
if (!isDirt(bjy, fk)) {
this.setBlock(bjy, fk, Blocks.DIRT.defaultBlockState());
}
}
protected boolean placeLog(final LevelSimulatedRW bjy, final Random random, final BlockPos fk, final Set<BlockPos> set, final BoundingBox cky, final TreeConfiguration chi) {
if (isAirOrLeaves(bjy, fk) || isReplaceablePlant(bjy, fk) || isBlockWater(bjy, fk)) {
this.setBlock(bjy, fk, chi.trunkProvider.getState(random, fk), cky);
set.add(fk.immutable());
return true;
}
return false;
}
protected boolean placeLeaf(final LevelSimulatedRW bjy, final Random random, final BlockPos fk, final Set<BlockPos> set, final BoundingBox cky, final TreeConfiguration chi) {
if (isAirOrLeaves(bjy, fk) || isReplaceablePlant(bjy, fk) || isBlockWater(bjy, fk)) {
this.setBlock(bjy, fk, chi.leavesProvider.getState(random, fk), cky);
set.add(fk.immutable());
return true;
}
return false;
}
@Override
protected void setBlock(final LevelWriter bkb, final BlockPos fk, final BlockState byg) {
this.setBlockKnownShape(bkb, fk, byg);
}
protected final void setBlock(final LevelWriter bkb, final BlockPos fk, final BlockState byg, final BoundingBox cky) {
this.setBlockKnownShape(bkb, fk, byg);
cky.expand(new BoundingBox(fk, fk));
}
private void setBlockKnownShape(final LevelWriter bkb, final BlockPos fk, final BlockState byg) {
bkb.setBlock(fk, byg, 19);
}
@Override
public final boolean place(final LevelAccessor bju, final ChunkGenerator<? extends ChunkGeneratorSettings> bzx, final Random random, final BlockPos fk, final T chi) {
final Set<BlockPos> set7 = Sets.newHashSet();
final Set<BlockPos> set8 = Sets.newHashSet();
final Set<BlockPos> set9 = Sets.newHashSet();
final BoundingBox cky10 = BoundingBox.getUnknownBox();
final boolean boolean11 = this.doPlace(bju, random, fk, set7, set8, cky10, chi);
if (cky10.x0 > cky10.x1 || !boolean11 || set7.isEmpty()) {
return false;
}
if (!chi.decorators.isEmpty()) {
final List<BlockPos> list12 = Lists.newArrayList(set7);
final List<BlockPos> list13 = Lists.newArrayList(set8);
list12.sort(Comparator.comparingInt(Vec3i::getY));
list13.sort(Comparator.comparingInt(Vec3i::getY));
chi.decorators.forEach(ciq -> ciq.place(bju, random, list12, list13, set9, cky10));
}
final DiscreteVoxelShape cvr12 = this.updateLeaves(bju, cky10, set7, set9);
StructureTemplate.updateShapeAtEdge(bju, 3, cvr12, cky10.x0, cky10.y0, cky10.z0);
return true;
}
private DiscreteVoxelShape updateLeaves(final LevelAccessor bju, final BoundingBox cky, final Set<BlockPos> set3, final Set<BlockPos> set4) {
final List<Set<BlockPos>> list6 = Lists.newArrayList();
final DiscreteVoxelShape cvr7 = new BitSetDiscreteVoxelShape(cky.getXSpan(), cky.getYSpan(), cky.getZSpan());
final int integer8 = 6;
for (int integer9 = 0; integer9 < 6; ++integer9) {
list6.add(Sets.newHashSet());
}
try (final BlockPos.PooledMutableBlockPos b9 = BlockPos.PooledMutableBlockPos.acquire()) {
for (final BlockPos fk12 : Lists.<BlockPos>newArrayList(set4)) {
if (cky.isInside(fk12)) {
cvr7.setFull(fk12.getX() - cky.x0, fk12.getY() - cky.y0, fk12.getZ() - cky.z0, true, true);
}
}
for (final BlockPos fk12 : Lists.<BlockPos>newArrayList(set3)) {
if (cky.isInside(fk12)) {
cvr7.setFull(fk12.getX() - cky.x0, fk12.getY() - cky.y0, fk12.getZ() - cky.z0, true, true);
}
for (final Direction fp16 : Direction.values()) {
b9.set((Vec3i)fk12).move(fp16);
if (!set3.contains(b9)) {
final BlockState byg17 = bju.getBlockState(b9);
if (byg17.<Comparable>hasProperty((Property<Comparable>)BlockStateProperties.DISTANCE)) {
list6.get(0).add(b9.immutable());
this.setBlockKnownShape(bju, b9, ((AbstractStateHolder<O, BlockState>)byg17).<Comparable, Integer>setValue((Property<Comparable>)BlockStateProperties.DISTANCE, 1));
if (cky.isInside(b9)) {
cvr7.setFull(b9.getX() - cky.x0, b9.getY() - cky.y0, b9.getZ() - cky.z0, true, true);
}
}
}
}
}
for (int integer10 = 1; integer10 < 6; ++integer10) {
final Set<BlockPos> set5 = list6.get(integer10 - 1);
final Set<BlockPos> set6 = list6.get(integer10);
for (final BlockPos fk13 : set5) {
if (cky.isInside(fk13)) {
cvr7.setFull(fk13.getX() - cky.x0, fk13.getY() - cky.y0, fk13.getZ() - cky.z0, true, true);
}
for (final Direction fp17 : Direction.values()) {
b9.set((Vec3i)fk13).move(fp17);
if (!set5.contains(b9)) {
if (!set6.contains(b9)) {
final BlockState byg18 = bju.getBlockState(b9);
if (byg18.<Comparable>hasProperty((Property<Comparable>)BlockStateProperties.DISTANCE)) {
final int integer11 = byg18.<Integer>getValue((Property<Integer>)BlockStateProperties.DISTANCE);
if (integer11 > integer10 + 1) {
final BlockState byg19 = ((AbstractStateHolder<O, BlockState>)byg18).<Comparable, Integer>setValue((Property<Comparable>)BlockStateProperties.DISTANCE, integer10 + 1);
this.setBlockKnownShape(bju, b9, byg19);
if (cky.isInside(b9)) {
cvr7.setFull(b9.getX() - cky.x0, b9.getY() - cky.y0, b9.getZ() - cky.z0, true, true);
}
set6.add(b9.immutable());
}
}
}
}
}
}
}
}
return cvr7;
}
protected abstract boolean doPlace(final LevelSimulatedRW bjy, final Random random, final BlockPos fk, final Set<BlockPos> set4, final Set<BlockPos> set5, final BoundingBox cky, final T chi);
}