Tenanea feature & flowers

This commit is contained in:
paulevsGitch 2020-11-26 14:15:29 +03:00
parent 55bf037041
commit e3d5065e12
6 changed files with 128 additions and 103 deletions

View file

@ -39,7 +39,7 @@ public class EndFeatures {
public static final EndFeature PYTHADENDRON_TREE = new EndFeature("pythadendron_tree", new PythadendronTreeFeature(), 2);
public static final EndFeature LACUGROVE = new EndFeature("lacugrove", new LacugroveFeature(), 4);
public static final EndFeature DRAGON_TREE = new EndFeature("dragon_tree", new DragonTreeFeature(), 3);
public static final EndFeature TENANEA = new EndFeature("tenanea", new TenaneaFeature(), 7);
public static final EndFeature TENANEA = new EndFeature("tenanea", new TenaneaFeature(), 3);
// Bushes //
public static final EndFeature PYTHADENDRON_BUSH = new EndFeature("pythadendron_bush", new BushFeature(EndBlocks.PYTHADENDRON_LEAVES, EndBlocks.PYTHADENDRON.bark), 4);

View file

@ -1,139 +1,164 @@
package ru.betterend.world.features.trees;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.function.Function;
import com.google.common.collect.Sets;
import com.google.common.collect.Lists;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.LeavesBlock;
import net.minecraft.block.Material;
import net.minecraft.client.util.math.Vector3f;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockPos.Mutable;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.StructureWorldAccess;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
import ru.betterend.blocks.BlockProperties;
import ru.betterend.blocks.BlockProperties.TripleShape;
import ru.betterend.noise.OpenSimplexNoise;
import ru.betterend.registry.EndBlocks;
import ru.betterend.registry.EndTags;
import ru.betterend.util.BlocksHelper;
import ru.betterend.util.MHelper;
import ru.betterend.util.SplineHelper;
import ru.betterend.util.sdf.SDF;
import ru.betterend.util.sdf.operator.SDFDisplacement;
import ru.betterend.util.sdf.operator.SDFScale;
import ru.betterend.util.sdf.operator.SDFScale3D;
import ru.betterend.util.sdf.operator.SDFSubtraction;
import ru.betterend.util.sdf.operator.SDFTranslate;
import ru.betterend.util.sdf.primitive.SDFSphere;
import ru.betterend.world.features.DefaultFeature;
public class TenaneaFeature extends DefaultFeature {
private static final Vec3i[] DIRECTIONS;
private static final Vec3i UP;
private static final Function<BlockState, Boolean> REPLACE;
private static final Function<BlockState, Boolean> IGNORE;
private static final List<Vector3f> SPLINE;
@Override
public boolean generate(StructureWorldAccess world, ChunkGenerator chunkGenerator, Random random, BlockPos pos, DefaultFeatureConfig config) {
Set<BlockPos> set = branch(Sets.newHashSet(), world, pos, UP, 100, random);
set.forEach((bpos) -> {
BlocksHelper.setWithoutUpdate(world, bpos, Blocks.DIAMOND_BLOCK);
});
if (!world.getBlockState(pos.down()).getBlock().isIn(EndTags.END_GROUND)) return false;
float size = MHelper.randRange(7, 10, random);
int count = (int) (size * 0.45F);
float var = MHelper.PI2 / (float) (count * 3);
float start = MHelper.randRange(0, MHelper.PI2, random);
for (int i = 0; i < count; i++) {
float angle = (float) i / (float) count * MHelper.PI2 + MHelper.randRange(0, var, random) + start;
List<Vector3f> spline = SplineHelper.copySpline(SPLINE);
SplineHelper.rotateSpline(spline, angle);
SplineHelper.scale(spline, size + MHelper.randRange(0, size * 0.5F, random));
SplineHelper.offsetParts(spline, random, 1F, 0, 1F);
SplineHelper.fillSpline(spline, world, EndBlocks.TENANEA.bark.getDefaultState(), pos, REPLACE);
Vector3f last = spline.get(spline.size() - 1);
float leavesRadius = (size * 0.3F + MHelper.randRange(0.8F, 1.5F, random));
OpenSimplexNoise noise = new OpenSimplexNoise(random.nextLong());
leavesBall(world, pos.add(last.getX(), last.getY(), last.getZ()), leavesRadius, random, noise);
}
return true;
}
private Set<BlockPos> branch(Set<BlockPos> set, StructureWorldAccess world, BlockPos pos, Vec3i dir, int length, Random random) {
Mutable mut = new Mutable().set(pos);
int upCount = 0;
for (int i = 0; i < length; i++) {
MHelper.shuffle(DIRECTIONS, random);
boolean up = false;
set.add(mut.toImmutable());
for (Direction hor: BlocksHelper.HORIZONTAL) {
if (!isReplaceable(world.getBlockState(mut.offset(hor))) || !isReplaceable(world.getBlockState(mut.offset(hor).down()))) {
upCount = -1;
up = true;
break;
}
private void leavesBall(StructureWorldAccess world, BlockPos pos, float radius, Random random, OpenSimplexNoise noise) {
SDF sphere = new SDFSphere().setRadius(radius).setBlock(EndBlocks.TENANEA_LEAVES.getDefaultState().with(LeavesBlock.DISTANCE, 6));
SDF sub = new SDFScale().setScale(5).setSource(sphere);
sub = new SDFTranslate().setTranslate(0, -radius * 5, 0).setSource(sub);
sphere = new SDFSubtraction().setSourceA(sphere).setSourceB(sub);
sphere = new SDFScale3D().setScale(1, 0.5F, 1).setSource(sphere);
sphere = new SDFDisplacement().setFunction((vec) -> { return (float) noise.eval(vec.getX() * 0.2, vec.getY() * 0.2, vec.getZ() * 0.2) * 1F; }).setSource(sphere);
sphere = new SDFDisplacement().setFunction((vec) -> { return random.nextFloat() * 3F - 1.5F; }).setSource(sphere);
Mutable mut = new Mutable();
List<BlockPos> support = Lists.newArrayList();
sphere.setPostProcess((info) -> {
if (random.nextBoolean() && info.getStateDown().isAir()) {
support.add(info.getPos().toImmutable());
}
if (up) {
upCount ++;
mut.move(Direction.UP);
if (upCount > 8) {
break;
}
if (random.nextInt(4) == 0) {
Direction d = BlocksHelper.randomHorizontal(random);
mut.move(d);
}
/*if (random.nextInt(16) == 0) {
int l = length - i;
if (l > 5) {
l = MHelper.randRange(l / 2, l, random);
Vec3i d = DIRECTIONS[random.nextInt(DIRECTIONS.length)];
if (d != dir) {
branch(set, world, mut.add(d), d, l, random);
}
if (random.nextInt(5) == 0) {
for (Direction dir: Direction.values()) {
BlockState state = info.getState(dir, 2);
if (state.isAir()) {
return info.getState();
}
}*/
continue;
}
else {
up = true;
for (Vec3i d: DIRECTIONS) {
BlockPos offseted = mut.add(d.getX(), d.getY(), d.getZ());
boolean canOffset = Math.abs(offseted.getX() - pos.getX()) < 16 && Math.abs(offseted.getZ() - pos.getZ()) < 16;
if (canOffset && isReplaceable(world.getBlockState(offseted))) {
int dist = BlocksHelper.raycastSqr(world, offseted, d.getX(), d.getY(), d.getZ(), 10);
if (dist < 64) {
mut.move(d.getX(), d.getY(), d.getZ());
upCount = 0;
up = false;
dir = d;
break;
}
info.setState(EndBlocks.TENANEA.bark.getDefaultState());
for (int x = -6; x < 7; x++) {
int ax = Math.abs(x);
mut.setX(x + info.getPos().getX());
for (int z = -6; z < 7; z++) {
int az = Math.abs(z);
mut.setZ(z + info.getPos().getZ());
for (int y = -6; y < 7; y++) {
int ay = Math.abs(y);
int d = ax + ay + az;
if (d < 7) {
mut.setY(y + info.getPos().getY());
BlockState state = info.getState(mut);
if (state.getBlock() instanceof LeavesBlock) {
int distance = state.get(LeavesBlock.DISTANCE);
if (d < distance) {
info.setState(mut, state.with(LeavesBlock.DISTANCE, d));
}
}
}
}
}
}
if (up) {
upCount ++;
mut.move(Direction.UP);
if (upCount > 8) {
break;
}
}
}
return info.getState();
});
sphere.fillRecursiveIgnore(world, pos, IGNORE);
if (!world.getBlockState(mut).getMaterial().isReplaceable()) {
boolean br = true;
for (Direction hor: BlocksHelper.HORIZONTAL) {
if (isReplaceable(world.getBlockState(mut.offset(hor)))) {
mut.move(hor);
br = false;
}
BlocksHelper.setWithoutUpdate(world, pos, EndBlocks.TENANEA.bark);
BlockState top = EndBlocks.TENANEA_FLOWERS.getDefaultState().with(BlockProperties.TRIPLE_SHAPE, TripleShape.TOP);
BlockState middle = EndBlocks.TENANEA_FLOWERS.getDefaultState().with(BlockProperties.TRIPLE_SHAPE, TripleShape.MIDDLE);
BlockState bottom = EndBlocks.TENANEA_FLOWERS.getDefaultState().with(BlockProperties.TRIPLE_SHAPE, TripleShape.BOTTOM);
support.forEach((bpos) -> {
int count = MHelper.randRange(5, 9, random);
mut.set(bpos).move(Direction.DOWN);
BlocksHelper.setWithoutUpdate(world, mut, top);
for (int i = 1; i < count; i++) {
mut.setY(mut.getY() - 1);
if (world.isAir(mut.down())) {
BlocksHelper.setWithoutUpdate(world, mut, middle);
}
if (br) {
else {
break;
}
}
}
return set;
}
private boolean isReplaceable(BlockState state) {
return state.getMaterial().isReplaceable();
BlocksHelper.setWithoutUpdate(world, mut, bottom);
});
}
static {
DIRECTIONS = new Vec3i[] {
new Vec3i(0, 0, 1),
new Vec3i(0, 0, -1),
new Vec3i(1, 0, 0),
new Vec3i(-1, 0, 0),
new Vec3i(1, 0, 1),
new Vec3i(1, 0, -1),
new Vec3i(-1, 0, 1),
new Vec3i(-1, 0, -1),
new Vec3i(1, 1, 1),
new Vec3i(1, 1, -1),
new Vec3i(-1, 1, 1),
new Vec3i(-1, 1, -1)
REPLACE = (state) -> {
if (state.isIn(EndTags.END_GROUND)) {
return true;
}
if (state.getBlock() == EndBlocks.TENANEA_LEAVES) {
return true;
}
if (state.getMaterial().equals(Material.PLANT)) {
return true;
}
return state.getMaterial().isReplaceable();
};
UP = new Vec3i(0, 1, 0);
IGNORE = (state) -> {
return EndBlocks.TENANEA.isTreeLog(state);
};
SPLINE = Lists.newArrayList(
new Vector3f(0.00F, 0.00F, 0.00F),
new Vector3f(0.10F, 0.35F, 0.00F),
new Vector3f(0.20F, 0.50F, 0.00F),
new Vector3f(0.30F, 0.55F, 0.00F),
new Vector3f(0.42F, 0.70F, 0.00F),
new Vector3f(0.50F, 1.00F, 0.00F)
);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Before After
Before After