From c9346da1ee5b9a49a4539ebf0f45f0a192d88f50 Mon Sep 17 00:00:00 2001 From: paulevsGitch Date: Wed, 14 Oct 2020 22:24:53 +0300 Subject: [PATCH] Tree changes --- src/main/java/ru/betterend/util/MHelper.java | 242 +++++++++--------- .../java/ru/betterend/util/SplineHelper.java | 72 +++++- .../features/OldPythadendronTreeFeature.java | 114 +++++++++ .../features/PythadendronTreeFeature.java | 61 ++--- 4 files changed, 324 insertions(+), 165 deletions(-) create mode 100644 src/main/java/ru/betterend/world/features/OldPythadendronTreeFeature.java diff --git a/src/main/java/ru/betterend/util/MHelper.java b/src/main/java/ru/betterend/util/MHelper.java index f20f9e91..505a3773 100644 --- a/src/main/java/ru/betterend/util/MHelper.java +++ b/src/main/java/ru/betterend/util/MHelper.java @@ -1,119 +1,123 @@ -package ru.betterend.util; - -import java.util.Random; - -public class MHelper { - public static final float PI2 = (float) (Math.PI * 2); - private static final int ALPHA = 255 << 24; - public static final Random RANDOM = new Random(); - - public static int color(int r, int g, int b) { - return ALPHA | (r << 16) | (g << 8) | b; - } - - public static int randRange(int min, int max, Random random) { - return min + random.nextInt(max - min + 1); - } - - public static double randRange(double min, double max, Random random) { - return min + random.nextDouble() * (max - min); - } - - public static float randRange(float min, float max, Random random) { - return min + random.nextFloat() * (max - min); - } - - public static byte setBit(byte source, int pos, boolean value) { - return value ? setBitTrue(source, pos) : setBitFalse(source, pos); - } - - public static byte setBitTrue(byte source, int pos) { - source |= 1 << pos; - return source; - } - - public static byte setBitFalse(byte source, int pos) { - source &= ~(1 << pos); - return source; - } - - public static boolean getBit(byte source, int pos) { - return ((source >> pos) & 1) == 1; - } - - public static int floor(float x) { - return x < 0 ? (int) (x - 1) : (int) x; - } - - public static float wrap(float x, float side) { - return x - floor(x / side) * side; - } - - public static int floor(double x) { - return x < 0 ? (int) (x - 1) : (int) x; - } - - public static int min(int a, int b) { - return a < b ? a : b; - } - - public static int max(int a, int b) { - return a > b ? a : b; - } - - public static float min(float a, float b) { - return a < b ? a : b; - } - - public static float max(float a, float b) { - return a > b ? a : b; - } - - public static float lengthSqr(float x, float y, float z) { - return x * x + y * y + z * z; - } - - public static double lengthSqr(double x, double y, double z) { - return x * x + y * y + z * z; - } - - public static float length(float x, float y, float z) { - return (float) Math.sqrt(lengthSqr(x, y, z)); - } - - public static float lengthSqr(float x, float y) { - return x * x + y * y; - } - - public static double lengthSqr(double x, double y) { - return x * x + y * y; - } - - public static float length(float x, float y) { - return (float) Math.sqrt(lengthSqr(x, y)); - } - - public static double length(double x, double y) { - return Math.sqrt(lengthSqr(x, y)); - } - - public static float dot(float x1, float y1, float z1, float x2, float y2, float z2) { - return x1 * x2 + y1 * y2 + z1 * z2; - } - - public static float dot(float x1, float y1, float x2, float y2) { - return x1 * x2 + y1 * y2; - } - - public static int getSeed(int seed, int x, int y) { - int h = seed + x * 374761393 + y * 668265263; - h = (h ^ (h >> 13)) * 1274126177; - return h ^ (h >> 16); - } - - public static int getSeed(int seed, int x, int y, int z) { - int h = seed + x * 374761393 + y * 668265263 + z; - h = (h ^ (h >> 13)) * 1274126177; - return h ^ (h >> 16); - } -} +package ru.betterend.util; + +import java.util.Random; + +public class MHelper { + public static final float PI2 = (float) (Math.PI * 2); + private static final int ALPHA = 255 << 24; + public static final Random RANDOM = new Random(); + + public static int color(int r, int g, int b) { + return ALPHA | (r << 16) | (g << 8) | b; + } + + public static int randRange(int min, int max, Random random) { + return min + random.nextInt(max - min + 1); + } + + public static double randRange(double min, double max, Random random) { + return min + random.nextDouble() * (max - min); + } + + public static float randRange(float min, float max, Random random) { + return min + random.nextFloat() * (max - min); + } + + public static byte setBit(byte source, int pos, boolean value) { + return value ? setBitTrue(source, pos) : setBitFalse(source, pos); + } + + public static byte setBitTrue(byte source, int pos) { + source |= 1 << pos; + return source; + } + + public static byte setBitFalse(byte source, int pos) { + source &= ~(1 << pos); + return source; + } + + public static boolean getBit(byte source, int pos) { + return ((source >> pos) & 1) == 1; + } + + public static int floor(float x) { + return x < 0 ? (int) (x - 1) : (int) x; + } + + public static float wrap(float x, float side) { + return x - floor(x / side) * side; + } + + public static int floor(double x) { + return x < 0 ? (int) (x - 1) : (int) x; + } + + public static int min(int a, int b) { + return a < b ? a : b; + } + + public static int max(int a, int b) { + return a > b ? a : b; + } + + public static float min(float a, float b) { + return a < b ? a : b; + } + + public static float max(float a, float b) { + return a > b ? a : b; + } + + public static float max(float a, float b, float c) { + return max(a, max(b, c)); + } + + public static float lengthSqr(float x, float y, float z) { + return x * x + y * y + z * z; + } + + public static double lengthSqr(double x, double y, double z) { + return x * x + y * y + z * z; + } + + public static float length(float x, float y, float z) { + return (float) Math.sqrt(lengthSqr(x, y, z)); + } + + public static float lengthSqr(float x, float y) { + return x * x + y * y; + } + + public static double lengthSqr(double x, double y) { + return x * x + y * y; + } + + public static float length(float x, float y) { + return (float) Math.sqrt(lengthSqr(x, y)); + } + + public static double length(double x, double y) { + return Math.sqrt(lengthSqr(x, y)); + } + + public static float dot(float x1, float y1, float z1, float x2, float y2, float z2) { + return x1 * x2 + y1 * y2 + z1 * z2; + } + + public static float dot(float x1, float y1, float x2, float y2) { + return x1 * x2 + y1 * y2; + } + + public static int getSeed(int seed, int x, int y) { + int h = seed + x * 374761393 + y * 668265263; + h = (h ^ (h >> 13)) * 1274126177; + return h ^ (h >> 16); + } + + public static int getSeed(int seed, int x, int y, int z) { + int h = seed + x * 374761393 + y * 668265263 + z; + h = (h ^ (h >> 13)) * 1274126177; + return h ^ (h >> 16); + } +} diff --git a/src/main/java/ru/betterend/util/SplineHelper.java b/src/main/java/ru/betterend/util/SplineHelper.java index fce13b66..4be70918 100644 --- a/src/main/java/ru/betterend/util/SplineHelper.java +++ b/src/main/java/ru/betterend/util/SplineHelper.java @@ -9,7 +9,9 @@ import com.google.common.collect.Lists; import net.minecraft.block.BlockState; 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.MathHelper; +import net.minecraft.world.StructureWorldAccess; import ru.betterend.util.sdf.SDF; import ru.betterend.util.sdf.operator.SDFUnion; import ru.betterend.util.sdf.primitive.SDFLine; @@ -41,12 +43,13 @@ public class SplineHelper { } } - public static void parableOffset(List spline, float distance) { + public static void powerOffset(List spline, float distance, float power) { int count = spline.size(); + float max = count + 1; for (int i = 1; i < count; i++) { Vector3f pos = spline.get(i); - float x = (float) i / (float) (count + 1); - float y = pos.getY() + x * x * distance; + float x = (float) i / max; + float y = pos.getY() + (float) Math.pow(x, power) * distance; pos.set(pos.getX(), y, pos.getZ()); } } @@ -69,4 +72,67 @@ public class SplineHelper { } return result; } + + public static boolean fillSpline(List spline, StructureWorldAccess world, BlockState state, BlockPos pos, Function replace) { + Vector3f startPos = spline.get(0); + for (int i = 1; i < spline.size(); i++) { + Vector3f endPos = spline.get(i); + if (!(fillLine(startPos, endPos, world, state, pos, replace))) { + return false; + } + startPos = endPos; + } + + return true; + } + + private static boolean fillLine(Vector3f start, Vector3f end, StructureWorldAccess world, BlockState state, BlockPos pos, Function replace) { + float dx = end.getX() - start.getX(); + float dy = end.getY() - start.getY(); + float dz = end.getZ() - start.getZ(); + float max = MHelper.max(Math.abs(dx), Math.abs(dy), Math.abs(dz)); + int count = MHelper.floor(max + 1); + dx /= max; + dy /= max; + dz /= max; + float x = start.getX(); + float y = start.getY(); + float z = start.getZ(); + boolean down = Math.abs(dy) > 0.2; + + BlockState bState; + Mutable bPos = new Mutable(); + for (int i = 0; i < count; i++) { + bPos.set(x + pos.getX(), y + pos.getY(), z + pos.getZ()); + bState = world.getBlockState(bPos); + if (bState.equals(state) || replace.apply(bState)) { + BlocksHelper.setWithoutUpdate(world, bPos, state); + bPos.setY(bPos.getY() - 1); + bState = world.getBlockState(bPos); + if (down && bState.equals(state) || replace.apply(bState)) { + BlocksHelper.setWithoutUpdate(world, bPos, state); + } + } + else { + return false; + } + x += dx; + y += dy; + z += dz; + } + bPos.set(end.getX() + pos.getX(), end.getY() + pos.getY(), end.getZ() + pos.getZ()); + bState = world.getBlockState(bPos); + if (bState.equals(state) || replace.apply(bState)) { + BlocksHelper.setWithoutUpdate(world, bPos, state); + bPos.setY(bPos.getY() - 1); + bState = world.getBlockState(bPos); + if (down && bState.equals(state) || replace.apply(bState)) { + BlocksHelper.setWithoutUpdate(world, bPos, state); + } + return true; + } + else { + return false; + } + } } diff --git a/src/main/java/ru/betterend/world/features/OldPythadendronTreeFeature.java b/src/main/java/ru/betterend/world/features/OldPythadendronTreeFeature.java new file mode 100644 index 00000000..cd466546 --- /dev/null +++ b/src/main/java/ru/betterend/world/features/OldPythadendronTreeFeature.java @@ -0,0 +1,114 @@ +package ru.betterend.world.features; + +import java.util.List; +import java.util.Random; +import java.util.function.Function; + +import com.google.common.collect.Lists; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Material; +import net.minecraft.client.util.math.Vector3f; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.StructureWorldAccess; +import net.minecraft.world.gen.chunk.ChunkGenerator; +import net.minecraft.world.gen.feature.DefaultFeatureConfig; +import ru.betterend.noise.OpenSimplexNoise; +import ru.betterend.registry.BlockRegistry; +import ru.betterend.registry.BlockTagRegistry; +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.SDFTranslate; +import ru.betterend.util.sdf.operator.SDFUnion; +import ru.betterend.util.sdf.primitive.SDFSphere; + +@Deprecated +public class OldPythadendronTreeFeature extends DefaultFeature { + private static final Function REPLACE; + + @Override + public boolean generate(StructureWorldAccess world, ChunkGenerator chunkGenerator, Random random, BlockPos pos, DefaultFeatureConfig config) { + if (world.getBlockState(pos.down()).getBlock() != BlockRegistry.CHORUS_NYLIUM) return false; + + float size = MHelper.randRange(10, 13, random); + List> splines = Lists.newArrayList(); + List spline = SplineHelper.makeSpline(0, 0, 0, 0, size, 0, 4); + SplineHelper.offsetParts(spline, random, 0.7F, 0, 0.7F); + Vector3f last = spline.get(spline.size() - 1); + List ends = Lists.newArrayList(); + branch(splines, ends, last.getX(), last.getY(), last.getZ(), size * 0.6F, MHelper.randRange(0, MHelper.PI2, random), random, MHelper.floor(Math.log(size) * 1.5F)); + + SDF function = SplineHelper.buildSDF(spline, 1.4F, 0.8F, (bpos) -> { + return BlockRegistry.PYTHADENDRON.bark.getDefaultState(); + }); + + for (List sp: splines) { + float width = 0.8F - (sp.get(0).getY() - size) / 40; + SDF funcSp = SplineHelper.buildSDF(sp, width, width, (bpos) -> { + return BlockRegistry.PYTHADENDRON.bark.getDefaultState(); + }); + function = new SDFUnion().setSourceA(function).setSourceB(funcSp); + } + + OpenSimplexNoise noise = new OpenSimplexNoise(random.nextInt()); + for (Vector3f v: ends) { + SDF sphere = new SDFSphere().setRadius(MHelper.randRange(2.5F, 3.5F, random)).setBlock(BlockRegistry.PYTHADENDRON_LEAVES); + sphere = new SDFTranslate().setTranslate(v.getX(), v.getY(), v.getZ()).setSource(sphere); + sphere = new SDFDisplacement().setFunction((vec) -> { return (float) noise.eval(vec.getX() * 0.2, vec.getY() * 0.2, vec.getZ() * 0.2); }).setSource(sphere); + function = new SDFUnion().setSourceA(function).setSourceB(sphere); + } + + function = new SDFScale().setScale(MHelper.randRange(1.6F, 2.0F, random)).setSource(function); + function.setReplaceFunction(REPLACE); + function.fillRecursive(world, pos); + + return true; + } + + private void branch(List> splines, List ends, float x, float y, float z, float size, float angle, Random random, int depth) { + if (depth == 0) return; + + float dx = (float) Math.cos(angle) * size * 0.3F; + float dz = (float) Math.sin(angle) * size * 0.3F; + + float x1 = x + dx; + float z1 = z + dz; + float x2 = x - dx; + float z2 = z - dz; + + List spline = SplineHelper.makeSpline(x, y, z, x1, y, z1, 5); + SplineHelper.powerOffset(spline, size, 2); + SplineHelper.offsetParts(spline, random, 0.3F, 0, 0.3F); + splines.add(spline); + Vector3f pos1 = spline.get(spline.size() - 1); + + spline = SplineHelper.makeSpline(x, y, z, x2, y, z2, 5); + SplineHelper.powerOffset(spline, size, 2); + SplineHelper.offsetParts(spline, random, 0.3F, 0, 0.3F); + splines.add(spline); + Vector3f pos2 = spline.get(spline.size() - 1); + + if (depth == 1) { + ends.add(pos1); + ends.add(pos2); + } + + branch(splines, ends, pos1.getX(), pos1.getY(), pos1.getZ(), size * 0.8F, angle + (float) Math.PI * 0.5F, random, depth - 1); + branch(splines, ends, pos2.getX(), pos2.getY(), pos2.getZ(), size * 0.8F, angle + (float) Math.PI * 0.5F, random, depth - 1); + } + + static { + REPLACE = (state) -> { + if (state.isIn(BlockTagRegistry.END_GROUND)) { + return true; + } + if (state.getMaterial().equals(Material.PLANT)) { + return true; + } + return state.getMaterial().isReplaceable(); + }; + } +} diff --git a/src/main/java/ru/betterend/world/features/PythadendronTreeFeature.java b/src/main/java/ru/betterend/world/features/PythadendronTreeFeature.java index 78577afc..e443fc3a 100644 --- a/src/main/java/ru/betterend/world/features/PythadendronTreeFeature.java +++ b/src/main/java/ru/betterend/world/features/PythadendronTreeFeature.java @@ -4,8 +4,6 @@ import java.util.List; import java.util.Random; import java.util.function.Function; -import com.google.common.collect.Lists; - import net.minecraft.block.BlockState; import net.minecraft.block.Material; import net.minecraft.client.util.math.Vector3f; @@ -13,17 +11,11 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.StructureWorldAccess; import net.minecraft.world.gen.chunk.ChunkGenerator; import net.minecraft.world.gen.feature.DefaultFeatureConfig; -import ru.betterend.noise.OpenSimplexNoise; import ru.betterend.registry.BlockRegistry; import ru.betterend.registry.BlockTagRegistry; 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.SDFTranslate; -import ru.betterend.util.sdf.operator.SDFUnion; -import ru.betterend.util.sdf.primitive.SDFSphere; public class PythadendronTreeFeature extends DefaultFeature { private static final Function REPLACE; @@ -32,46 +24,28 @@ public class PythadendronTreeFeature extends DefaultFeature { public boolean generate(StructureWorldAccess world, ChunkGenerator chunkGenerator, Random random, BlockPos pos, DefaultFeatureConfig config) { if (world.getBlockState(pos.down()).getBlock() != BlockRegistry.CHORUS_NYLIUM) return false; - float size = MHelper.randRange(10, 13, random); - List> splines = Lists.newArrayList(); + float size = MHelper.randRange(10, 20, random); List spline = SplineHelper.makeSpline(0, 0, 0, 0, size, 0, 4); SplineHelper.offsetParts(spline, random, 0.7F, 0, 0.7F); Vector3f last = spline.get(spline.size() - 1); - List ends = Lists.newArrayList(); - branch(splines, ends, last.getX(), last.getY(), last.getZ(), size * 0.6F, MHelper.randRange(0, MHelper.PI2, random), random, MHelper.floor(Math.log(size) * 1.5F)); - SDF function = SplineHelper.buildSDF(spline, 1.4F, 0.8F, (bpos) -> { + branch(last.getX(), last.getY(), last.getZ(), size * 1.5F, MHelper.randRange(0, MHelper.PI2, random), random, 3, world, pos); + + SDF function = SplineHelper.buildSDF(spline, 1.5F, 0.8F, (bpos) -> { return BlockRegistry.PYTHADENDRON.bark.getDefaultState(); }); - for (List sp: splines) { - float width = 0.8F - (sp.get(0).getY() - size) / 40; - SDF funcSp = SplineHelper.buildSDF(sp, width, width, (bpos) -> { - return BlockRegistry.PYTHADENDRON.bark.getDefaultState(); - }); - function = new SDFUnion().setSourceA(function).setSourceB(funcSp); - } - - OpenSimplexNoise noise = new OpenSimplexNoise(random.nextInt()); - for (Vector3f v: ends) { - SDF sphere = new SDFSphere().setRadius(MHelper.randRange(2.5F, 3.5F, random)).setBlock(BlockRegistry.PYTHADENDRON_LEAVES); - sphere = new SDFTranslate().setTranslate(v.getX(), v.getY(), v.getZ()).setSource(sphere); - sphere = new SDFDisplacement().setFunction((vec) -> { return (float) noise.eval(vec.getX() * 0.2, vec.getY() * 0.2, vec.getZ() * 0.2); }).setSource(sphere); - function = new SDFUnion().setSourceA(function).setSourceB(sphere); - } - - function = new SDFScale().setScale(MHelper.randRange(1.6F, 2.0F, random)).setSource(function); function.setReplaceFunction(REPLACE); function.fillRecursive(world, pos); return true; } - private void branch(List> splines, List ends, float x, float y, float z, float size, float angle, Random random, int depth) { + private void branch(float x, float y, float z, float size, float angle, Random random, int depth, StructureWorldAccess world, BlockPos pos) { if (depth == 0) return; - float dx = (float) Math.cos(angle) * size * 0.3F; - float dz = (float) Math.sin(angle) * size * 0.3F; + float dx = (float) Math.cos(angle) * size * 0.2F; + float dz = (float) Math.sin(angle) * size * 0.2F; float x1 = x + dx; float z1 = z + dz; @@ -79,24 +53,25 @@ public class PythadendronTreeFeature extends DefaultFeature { float z2 = z - dz; List spline = SplineHelper.makeSpline(x, y, z, x1, y, z1, 5); - SplineHelper.parableOffset(spline, size); + SplineHelper.powerOffset(spline, size * MHelper.randRange(1.0F, 2.0F, random), 4); SplineHelper.offsetParts(spline, random, 0.3F, 0, 0.3F); - splines.add(spline); Vector3f pos1 = spline.get(spline.size() - 1); + SplineHelper.fillSpline(spline, world, BlockRegistry.PYTHADENDRON.bark.getDefaultState(), pos, REPLACE); + spline = SplineHelper.makeSpline(x, y, z, x2, y, z2, 5); - SplineHelper.parableOffset(spline, size); + SplineHelper.powerOffset(spline, size * MHelper.randRange(1.0F, 2.0F, random), 4); SplineHelper.offsetParts(spline, random, 0.3F, 0, 0.3F); - splines.add(spline); Vector3f pos2 = spline.get(spline.size() - 1); - if (depth == 1) { - ends.add(pos1); - ends.add(pos2); - } + SplineHelper.fillSpline(spline, world, BlockRegistry.PYTHADENDRON.bark.getDefaultState(), pos, REPLACE); - branch(splines, ends, pos1.getX(), pos1.getY(), pos1.getZ(), size * 0.8F, angle + (float) Math.PI * 0.5F, random, depth - 1); - branch(splines, ends, pos2.getX(), pos2.getY(), pos2.getZ(), size * 0.8F, angle + (float) Math.PI * 0.5F, random, depth - 1); + float size1 = size * MHelper.randRange(0.75F, 0.95F, random); + float size2 = size * MHelper.randRange(0.75F, 0.95F, random); + float angle1 = angle + (float) Math.PI * 0.5F + MHelper.randRange(-0.1F, 0.1F, random); + float angle2 = angle + (float) Math.PI * 0.5F + MHelper.randRange(-0.1F, 0.1F, random); + branch(pos1.getX(), pos1.getY(), pos1.getZ(), size1, angle1, random, depth - 1, world, pos); + branch(pos2.getX(), pos2.getY(), pos2.getZ(), size2, angle2, random, depth - 1, world, pos); } static {