From b1b243fd1c57596ce1205e292b5636c703f84aaf Mon Sep 17 00:00:00 2001 From: Ninjdai Date: Thu, 3 Oct 2024 22:00:56 +0200 Subject: [PATCH] feat: worldgen improvements --- gradle.properties | 2 +- .../dev/ninjdai/werewolf/EventHandler.java | 6 +- src/main/java/dev/ninjdai/werewolf/Main.java | 6 +- .../werewolf/worldgen/InterpolatedNoises.java | 68 ++++++++++++ .../werewolf/worldgen/LGGenerator.java | 104 +++++++++++++----- .../werewolf/worldgen/LGTerrainBuilder.java | 29 +++++ .../dev/ninjdai/werewolf/worldgen/Noises.java | 45 ++++++++ .../worldgen/SplineInterpolatorBuilder.java | 25 +++++ .../werewolf/worldgen/TerrainBuilder.java | 12 ++ .../worldgen/utils/AbsClampNoiseModifier.java | 10 ++ 10 files changed, 277 insertions(+), 30 deletions(-) create mode 100644 src/main/java/dev/ninjdai/werewolf/worldgen/InterpolatedNoises.java create mode 100644 src/main/java/dev/ninjdai/werewolf/worldgen/LGTerrainBuilder.java create mode 100644 src/main/java/dev/ninjdai/werewolf/worldgen/Noises.java create mode 100644 src/main/java/dev/ninjdai/werewolf/worldgen/SplineInterpolatorBuilder.java create mode 100644 src/main/java/dev/ninjdai/werewolf/worldgen/TerrainBuilder.java create mode 100644 src/main/java/dev/ninjdai/werewolf/worldgen/utils/AbsClampNoiseModifier.java diff --git a/gradle.properties b/gradle.properties index 24a7cce..20111e1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -minestom_version = d0754f2a15 +minestom_version = e8f34c317a minestompvp_version = 547b6e95af vri_version = a79a2d9422 jnoise_version = 5.0.0-SNAPSHOT diff --git a/src/main/java/dev/ninjdai/werewolf/EventHandler.java b/src/main/java/dev/ninjdai/werewolf/EventHandler.java index 984db16..e7dc6ff 100644 --- a/src/main/java/dev/ninjdai/werewolf/EventHandler.java +++ b/src/main/java/dev/ninjdai/werewolf/EventHandler.java @@ -30,7 +30,11 @@ public class EventHandler { public static void onPlayerConfiguration(AsyncPlayerConfigurationEvent event) { final Player player = event.getPlayer(); event.setSpawningInstance(Main.overworld); - player.setRespawnPoint(new Pos(0, 42, 0)); + int y = 200; + while (Main.overworld.getBlock(0, y, 0) == Block.AIR) { + y--; + } + player.setRespawnPoint(new Pos(0, y, 0)); }; public static void onPlayerDeath(EntityPreDeathEvent event) { diff --git a/src/main/java/dev/ninjdai/werewolf/Main.java b/src/main/java/dev/ninjdai/werewolf/Main.java index 67181a0..452e0ba 100644 --- a/src/main/java/dev/ninjdai/werewolf/Main.java +++ b/src/main/java/dev/ninjdai/werewolf/Main.java @@ -6,6 +6,8 @@ import dev.ninjdai.werewolf.commands.PlayerKillCommand; import dev.ninjdai.werewolf.gui.Gui; import dev.ninjdai.werewolf.uhc.UHCPlayer; import dev.ninjdai.werewolf.worldgen.LGGenerator; +import dev.ninjdai.werewolf.worldgen.LGTerrainBuilder; +import dev.ninjdai.werewolf.worldgen.TerrainBuilder; import io.github.togar2.pvp.MinestomPvP; import io.github.togar2.pvp.feature.CombatFeatureSet; import io.github.togar2.pvp.feature.CombatFeatures; @@ -33,8 +35,8 @@ public class Main { //VanillaReimplementation vri = VanillaReimplementation.hook(MinecraftServer.process()); - overworld.setGenerator(LGGenerator::generate); overworld.setChunkSupplier(LightingChunk::new); + overworld.setGenerator(new LGGenerator(new LGTerrainBuilder(3301))); GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler(); EventHandler.register(globalEventHandler); @@ -50,6 +52,8 @@ public class Main { MinecraftServer.getConnectionManager().setPlayerProvider(UHCPlayer::new); + overworld.loadChunk(0, 0); + OpenToLAN.open(); MinecraftServer.setBrandName("Playground"); //VelocityProxy.enable("cMkrrJ8tdUS6"); diff --git a/src/main/java/dev/ninjdai/werewolf/worldgen/InterpolatedNoises.java b/src/main/java/dev/ninjdai/werewolf/worldgen/InterpolatedNoises.java new file mode 100644 index 0000000..6c95226 --- /dev/null +++ b/src/main/java/dev/ninjdai/werewolf/worldgen/InterpolatedNoises.java @@ -0,0 +1,68 @@ +package dev.ninjdai.werewolf.worldgen; + +import de.articdive.jnoise.generators.noisegen.opensimplex.FastSimplexNoiseGenerator; +import de.articdive.jnoise.modules.octavation.fractal_functions.FractalFunction; +import de.articdive.jnoise.pipeline.JNoise; +import dev.ninjdai.werewolf.worldgen.utils.AbsClampNoiseModifier; +import net.minestom.vanilla.datapack.worldgen.math.SplineInterpolator; + +public enum InterpolatedNoises { + CONTINENTALNESS( + JNoise.newBuilder() + .fastSimplex(FastSimplexNoiseGenerator.newBuilder() + .setSeed(0) + .build()) + .octavate(5, 0.5, 2.2, FractalFunction.FBM, false) + .scale(0.002) + .addModifier(new AbsClampNoiseModifier()) + .build(), + new SplineInterpolatorBuilder() + .add(0.0, 0.0) + .add(0.25, 0.1) + .add(0.285, 0.38) + .add(0.3, 0.444) + .add(0.39, 0.666) + .add(0.433, 0.777) + .add(0.5, 0.888) + .add(0.7, 0.97) + .add(1, 1) + .build() + ), + EROSION( + JNoise.newBuilder() + .fastSimplex(FastSimplexNoiseGenerator.newBuilder() + .setSeed(0) + .build()) + .octavate(5, 0.3, 3, FractalFunction.FBM, false) + .scale(0.0015) + .invert() + .addModifier(new AbsClampNoiseModifier()) + .build(), + new SplineInterpolatorBuilder() + .add(0, 0) + .add(0.1, 0.3) + .add(0.5, 0.9) + .add(0.6, 0.91) + .add(0.62, 0.7) + .add(0.7, 0.71) + .add(0.72, 0.91) + .add(1, 1) + .build() + ); + + final private JNoise noise; + final private SplineInterpolator interpolator; + + InterpolatedNoises(JNoise noise, SplineInterpolator interpolator) { + this.noise = noise; + this.interpolator = interpolator; + } + + public double evaluateNoise(int x, int z) { + return interpolator.interpolate(noise.evaluateNoise(x, z)); + } + + double evaluateNoise(int x, int y, int z) { + return interpolator.interpolate(noise.evaluateNoise(x, y, z)); + } +} \ No newline at end of file diff --git a/src/main/java/dev/ninjdai/werewolf/worldgen/LGGenerator.java b/src/main/java/dev/ninjdai/werewolf/worldgen/LGGenerator.java index 49e48d9..aca8229 100644 --- a/src/main/java/dev/ninjdai/werewolf/worldgen/LGGenerator.java +++ b/src/main/java/dev/ninjdai/werewolf/worldgen/LGGenerator.java @@ -1,39 +1,89 @@ package dev.ninjdai.werewolf.worldgen; -import de.articdive.jnoise.core.api.functions.Interpolation; -import de.articdive.jnoise.core.api.modifiers.NoiseModifier; -import de.articdive.jnoise.generators.noise_parameters.fade_functions.FadeFunction; -import de.articdive.jnoise.modifiers.clamp.ClampModifier; -import de.articdive.jnoise.modules.octavation.fractal_functions.FractalFunction; -import de.articdive.jnoise.pipeline.JNoise; import net.minestom.server.coordinate.Point; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Vec; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.generator.GenerationUnit; +import net.minestom.server.instance.generator.Generator; +import net.minestom.server.world.biome.Biome; +import net.minestom.vanilla.generation.VanillaWorldGenerationFeature; +import net.minestom.vanilla.tag.Tags; import org.jetbrains.annotations.NotNull; -public class LGGenerator { - static final JNoise noise1 = JNoise.newBuilder() - .perlin(3301, Interpolation.LINEAR, FadeFunction.QUINTIC_POLY) - .scale(1/48.0) - .addModifier(v -> (v + 1) / 2.0) - .clamp(0.0, 1.0) - .octavate(3, 0.5, .75, FractalFunction.TURBULENCE, true) - .build(); +import java.util.Random; - public static void generate(@NotNull GenerationUnit unit) { - Point start = unit.absoluteStart(); - for (int x = 0; x < unit.size().x(); x++) { - for (int z = 0; z < unit.size().z(); z++) { - Point bottom = start.add(x, 0, z); +public class LGGenerator implements Generator { + TerrainBuilder terrainBuilder; + Random random; + double densityThreshold = 1;//0.6; + int upperRelativeDensityLimit = 50; + int lowerRelativeDensityLimit = 50; - synchronized (noise1) { - double height = noise1.evaluateNoise(bottom.x(), bottom.z()) * 16 + 20; - // * 16 means the height will be between -16 and +16 - unit.modifier().fill(bottom, bottom.add(1, 0, 1).withY(height), Block.STONE); - unit.modifier().fill(bottom.withY(height), bottom.add(1, 0, 1).withY(height+3), Block.DIRT); - unit.modifier().fill(bottom.withY(height+3), bottom.add(1, 0, 1).withY(height+4), Block.GRASS_BLOCK); - } + public LGGenerator(TerrainBuilder tb) { + this.terrainBuilder = tb; + this.random = new Random(tb.seed); + } + + @Override + public void generate(@NotNull GenerationUnit unit) { + final Point min = unit.absoluteStart(); + final Point max = unit.absoluteEnd(); + + for (int x = min.blockX(); x < max.blockX(); x++) { + for (int z = min.blockZ(); z < max.blockZ(); z++) { + generate3D(min, max, x, z, unit); } } } -} + + private void generate3D(Point min, Point max, int x, int z, GenerationUnit unit) { + int height = terrainBuilder.getSurfaceHeight(x, z); + int upperDensityLimit = height + upperRelativeDensityLimit; + int lowerDensityLimit = height - lowerRelativeDensityLimit; + int terrainHeight = lowerDensityLimit; + + for (int y = upperDensityLimit; y >= lowerDensityLimit; y--) { + if (y == lowerDensityLimit) { + unit.modifier().fill(min.withX(x).withZ(z), new Vec(x + 1, lowerDensityLimit + 1, z + 1), Block.STONE); + break; + } + + Vec pos = new Vec(x, y, z); + if (terrainBuilder.getDensity(x, y, z) > densityThreshold) { + unit.modifier().setBlock(pos, Block.STONE); + terrainHeight = Math.max(terrainHeight, y); + } + } + decorate(x, terrainHeight, z, unit); + } + + private void decorate(int x, int y, int z, GenerationUnit unit) { + unit.modifier().setBlock(x, y + 4, z, Block.GRASS_BLOCK); + for (int i = 0; i < 4; i++) { + Block b = switch ((int) (2*Noises.FEATURES.evaluateNoise(x, y+i, z))) { + case 0 -> Block.COARSE_DIRT; + case 1 -> Block.ROOTED_DIRT; + default -> Block.DIRT; + }; + unit.modifier().setBlock(x, y + i, z, b); + } + int ry = y+5; + double ft = Noises.FEATURES.evaluateNoise(x, z); + if (ft > 0.995) { + int height = (int) (3 + 3*Noises.FEATURES.evaluateNoise(x, y, z)); + + GenerationUnit fork = unit.fork(new Vec(x-2, ry, z-2), new Vec(x+3, ry+height+4, z+3)); + fork.modifier().fill(new Vec(x, ry, z), new Vec(x+1, ry+height, z+1), Block.OAK_LOG); + fork.modifier().fill(new Vec(x-2, ry+height, z-2), new Vec(x+3, ry+height+2, z+3), Block.OAK_LEAVES); + fork.modifier().fill(new Vec(x-1, ry+height+2, z-1), new Vec(x+2, ry+height+3, z+2), Block.OAK_LEAVES); + } else if (ft > 0.95) { + unit.modifier().setBlock(x, ry, z, Block.TALL_GRASS); + unit.modifier().setBlock(x, ry+1, z, Block.TALL_GRASS.withProperty("half", "upper")); + } else if (ft > 0.8) { + unit.modifier().setBlock(x, ry, z, Block.SHORT_GRASS); + } else if (ft < -0.99) { + unit.modifier().setBlock(x, ry, z, Block.POPPY); + } + } +} \ No newline at end of file diff --git a/src/main/java/dev/ninjdai/werewolf/worldgen/LGTerrainBuilder.java b/src/main/java/dev/ninjdai/werewolf/worldgen/LGTerrainBuilder.java new file mode 100644 index 0000000..146bdfc --- /dev/null +++ b/src/main/java/dev/ninjdai/werewolf/worldgen/LGTerrainBuilder.java @@ -0,0 +1,29 @@ +package dev.ninjdai.werewolf.worldgen; + +public class LGTerrainBuilder extends TerrainBuilder { + // 0: no squashing the terrain, 1: basically the surface height + private final double squashingFactor = 1.5; + + + public LGTerrainBuilder(long seed) { + super(seed); + } + + @Override + public int getSurfaceHeight(int x, int z) { + double continentalness = InterpolatedNoises.CONTINENTALNESS.evaluateNoise(x, z); + double erosion = InterpolatedNoises.EROSION.evaluateNoise(x, z); + + return (int) ((continentalness + erosion) * 50); + } + + @Override + public double getDensity(int x, int y, int z) { + double density = Noises.DENSITY.evaluateNoise(x, y, z); + int surfaceHeight = getSurfaceHeight(x, z); + + density *= (double) surfaceHeight / y; + + return density; + } +} diff --git a/src/main/java/dev/ninjdai/werewolf/worldgen/Noises.java b/src/main/java/dev/ninjdai/werewolf/worldgen/Noises.java new file mode 100644 index 0000000..2bf2e96 --- /dev/null +++ b/src/main/java/dev/ninjdai/werewolf/worldgen/Noises.java @@ -0,0 +1,45 @@ +package dev.ninjdai.werewolf.worldgen; + +import de.articdive.jnoise.generators.noisegen.opensimplex.FastSimplexNoiseGenerator; +import de.articdive.jnoise.generators.noisegen.random.white.WhiteNoiseGenerator; +import de.articdive.jnoise.modules.octavation.fractal_functions.FractalFunction; +import de.articdive.jnoise.pipeline.JNoise; +import dev.ninjdai.werewolf.worldgen.utils.AbsClampNoiseModifier; + +public enum Noises { + WEIRDNESS(JNoise.newBuilder() + .fastSimplex(FastSimplexNoiseGenerator.newBuilder() + .setSeed(0) + .build()) + .octavate(5, 0.5, 1.2, FractalFunction.FBM, false) + .scale(0.005) + .addModifier(new AbsClampNoiseModifier()) + .build()), + DENSITY(JNoise.newBuilder() + .fastSimplex(FastSimplexNoiseGenerator.newBuilder() + .setSeed(0) + .build()) + .octavate(5, 0.7, 1.6, FractalFunction.FBM, true) + .scale(0.006) + .addModifier(new AbsClampNoiseModifier()) + .build()), + + FEATURES(JNoise.newBuilder() + .white(WhiteNoiseGenerator.newBuilder().setSeed(0).build()) + .addModifier(new AbsClampNoiseModifier()) + .build()); + + final private JNoise noise; + + Noises(JNoise noise) { + this.noise = noise; + } + + public double evaluateNoise(int x, int z) { + return noise.evaluateNoise(x, z); + } + + public double evaluateNoise(int x, int y, int z) { + return noise.evaluateNoise(x, y, z); + } +} \ No newline at end of file diff --git a/src/main/java/dev/ninjdai/werewolf/worldgen/SplineInterpolatorBuilder.java b/src/main/java/dev/ninjdai/werewolf/worldgen/SplineInterpolatorBuilder.java new file mode 100644 index 0000000..06fea90 --- /dev/null +++ b/src/main/java/dev/ninjdai/werewolf/worldgen/SplineInterpolatorBuilder.java @@ -0,0 +1,25 @@ +package dev.ninjdai.werewolf.worldgen; + +import it.unimi.dsi.fastutil.doubles.DoubleArrayList; +import it.unimi.dsi.fastutil.doubles.DoubleList; +import net.minestom.vanilla.datapack.worldgen.math.SplineInterpolator; + +public class SplineInterpolatorBuilder { + private DoubleList xList; + private DoubleList yList; + + SplineInterpolatorBuilder() { + this.xList = new DoubleArrayList(); + this.yList = new DoubleArrayList(); + } + + public SplineInterpolatorBuilder add(double x, double y) { + this.xList.add(x); + this.yList.add(y); + return this; + } + + public SplineInterpolator build() { + return SplineInterpolator.createMonotoneCubicSpline(xList, yList); + } +} diff --git a/src/main/java/dev/ninjdai/werewolf/worldgen/TerrainBuilder.java b/src/main/java/dev/ninjdai/werewolf/worldgen/TerrainBuilder.java new file mode 100644 index 0000000..ea8e63f --- /dev/null +++ b/src/main/java/dev/ninjdai/werewolf/worldgen/TerrainBuilder.java @@ -0,0 +1,12 @@ +package dev.ninjdai.werewolf.worldgen; + +public abstract class TerrainBuilder { + long seed; + + TerrainBuilder(long seed) { + this.seed = seed; + } + + abstract int getSurfaceHeight(int x, int z); + abstract double getDensity(int x, int y, int z); +} diff --git a/src/main/java/dev/ninjdai/werewolf/worldgen/utils/AbsClampNoiseModifier.java b/src/main/java/dev/ninjdai/werewolf/worldgen/utils/AbsClampNoiseModifier.java new file mode 100644 index 0000000..84c5c3c --- /dev/null +++ b/src/main/java/dev/ninjdai/werewolf/worldgen/utils/AbsClampNoiseModifier.java @@ -0,0 +1,10 @@ +package dev.ninjdai.werewolf.worldgen.utils; + +import de.articdive.jnoise.core.api.modifiers.NoiseModifier; + +public class AbsClampNoiseModifier implements NoiseModifier { + @Override + public double apply(double result) { + return (result + 1) * 0.5; + } +}