Tenanea feature & flowers
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.1 KiB |