From cfbd6533dde2c317493992048987265a413f0b7a Mon Sep 17 00:00:00 2001 From: dfsek Date: Sun, 27 Sep 2020 16:11:36 -0700 Subject: [PATCH] Add advanced biome blending --- pom.xml | 2 +- .../java/com/dfsek/terra/TerraCommand.java | 3 ++- .../dfsek/terra/biome/CoordinatePerturb.java | 21 ++++++++++++++++ .../com/dfsek/terra/biome/TerraBiomeGrid.java | 24 +++++++++++++++---- .../dfsek/terra/biome/UserDefinedGrid.java | 10 ++++---- .../terra/carving/UserDefinedCarver.java | 3 ++- .../com/dfsek/terra/config/WorldConfig.java | 11 ++++++++- .../dfsek/terra/generation/SlabGenerator.java | 3 ++- .../generation/UserDefinedGenerator.java | 16 ++++++++----- .../com/dfsek/terra/image/DebugFrame.java | 3 ++- .../com/dfsek/terra/math/NoiseFunction2.java | 4 ++-- .../com/dfsek/terra/math/NoiseFunction3.java | 4 ++-- .../terra/population/FloraPopulator.java | 3 ++- .../dfsek/terra/population/OrePopulator.java | 3 ++- .../dfsek/terra/population/TreePopulator.java | 5 ++-- 15 files changed, 87 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/dfsek/terra/biome/CoordinatePerturb.java diff --git a/pom.xml b/pom.xml index e6d172e23..1a5ea3402 100644 --- a/pom.xml +++ b/pom.xml @@ -95,7 +95,7 @@ org.polydev gaea - 1.10.45 + 1.10.46 me.lucko diff --git a/src/main/java/com/dfsek/terra/TerraCommand.java b/src/main/java/com/dfsek/terra/TerraCommand.java index d66b72cfc..80b3fa25d 100644 --- a/src/main/java/com/dfsek/terra/TerraCommand.java +++ b/src/main/java/com/dfsek/terra/TerraCommand.java @@ -26,6 +26,7 @@ import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.profiler.WorldProfiler; import java.io.File; @@ -46,7 +47,7 @@ public class TerraCommand implements CommandExecutor, TabExecutor { return true; case "biome": if(! (sender instanceof Player)) return false; - sender.sendMessage("You are in " + BiomeConfig.fromBiome((UserDefinedBiome) TerraBiomeGrid.fromWorld(((Player) sender).getWorld()).getBiome(((Player) sender).getLocation())).getFriendlyName()); + sender.sendMessage("You are in " + BiomeConfig.fromBiome((UserDefinedBiome) TerraBiomeGrid.fromWorld(((Player) sender).getWorld()).getBiome(((Player) sender).getLocation(), GenerationPhase.POPULATE)).getFriendlyName()); return true; case "profile": if(! (sender instanceof Player)) { diff --git a/src/main/java/com/dfsek/terra/biome/CoordinatePerturb.java b/src/main/java/com/dfsek/terra/biome/CoordinatePerturb.java new file mode 100644 index 000000000..f28ef145c --- /dev/null +++ b/src/main/java/com/dfsek/terra/biome/CoordinatePerturb.java @@ -0,0 +1,21 @@ +package com.dfsek.terra.biome; + +import org.polydev.gaea.math.FastNoise; + +public class CoordinatePerturb { + private final FastNoise perturbX; + private final FastNoise perturbZ; + private final int amplitude; + public CoordinatePerturb(float frequency, int amplitude, long seed) { + perturbX = new FastNoise((int) seed); + perturbX.setNoiseType(FastNoise.NoiseType.Simplex); + perturbX.setFrequency(frequency); + perturbZ = new FastNoise((int) seed+1); + perturbZ.setNoiseType(FastNoise.NoiseType.Simplex); + perturbZ.setFrequency(frequency); + this.amplitude = amplitude; + } + public int[] getShiftedCoords(int x, int z) { + return new int[] {(int) (perturbX.getNoise(x, z)*amplitude+x), (int) (perturbZ.getNoise(x, z)*amplitude+z)}; + } +} diff --git a/src/main/java/com/dfsek/terra/biome/TerraBiomeGrid.java b/src/main/java/com/dfsek/terra/biome/TerraBiomeGrid.java index 3bd120459..0c267043c 100644 --- a/src/main/java/com/dfsek/terra/biome/TerraBiomeGrid.java +++ b/src/main/java/com/dfsek/terra/biome/TerraBiomeGrid.java @@ -7,21 +7,29 @@ import org.bukkit.Location; import org.bukkit.World; import org.polydev.gaea.biome.Biome; import org.polydev.gaea.biome.BiomeGrid; +import org.polydev.gaea.generation.GenerationPhase; import java.util.HashMap; import java.util.Map; public class TerraBiomeGrid extends BiomeGrid { private static int failNum = 0; + private CoordinatePerturb perturb; private static final Map grids = new HashMap<>(); private final World w; private final BiomeZone zone; + private final boolean perturbPaletteOnly; private TerraBiomeGrid(World w, float freq1, float freq2, boolean blank) { super(w, freq1, freq2); + WorldConfig c = WorldConfig.fromWorld(w); + if(c.biomeBlend) { + perturb = new CoordinatePerturb(c.blendFreq, c.blendAmp, w.getSeed()); + } + perturbPaletteOnly = c.perturbPaletteOnly; this.w = w; this.zone = BiomeZone.fromWorld(w); if(!blank) grids.put(w, this); @@ -41,9 +49,17 @@ public class TerraBiomeGrid extends BiomeGrid { } @Override - public Biome getBiome(int x, int z) { + public Biome getBiome(int x, int z, GenerationPhase phase) { + int xp = x; + int zp = z; + if(perturb != null && (!perturbPaletteOnly || phase.equals(GenerationPhase.PALETTE_APPLY))) { + int[] perturbCoords = perturb.getShiftedCoords(x, z); + xp = perturbCoords[0]; + zp = perturbCoords[1]; + } + try { - return zone.getGrid(x, z).getBiome(x, z); + return zone.getGrid(xp, zp).getBiome(xp, zp, phase); } catch(NullPointerException e) { if(ConfigUtil.debug) e.printStackTrace(); if(failNum % 256 == 0) Bukkit.getLogger().severe("[Terra] A severe configuration error has prevented Terra from properly generating terrain at coordinates: " + x + ", " + z + ". Please check your configuration for errors. Any config errors will have been reported above."); @@ -53,8 +69,8 @@ public class TerraBiomeGrid extends BiomeGrid { } @Override - public Biome getBiome(Location l) { - return getBiome(l.getBlockX(), l.getBlockZ()); + public Biome getBiome(Location l, GenerationPhase phase) { + return getBiome(l.getBlockX(), l.getBlockZ(), phase); } public static void invalidate() { diff --git a/src/main/java/com/dfsek/terra/biome/UserDefinedGrid.java b/src/main/java/com/dfsek/terra/biome/UserDefinedGrid.java index 3c69dc26f..1f851da47 100644 --- a/src/main/java/com/dfsek/terra/biome/UserDefinedGrid.java +++ b/src/main/java/com/dfsek/terra/biome/UserDefinedGrid.java @@ -8,6 +8,8 @@ import org.bukkit.World; import org.polydev.gaea.biome.Biome; import org.polydev.gaea.biome.BiomeGrid; import org.polydev.gaea.biome.NormalizationUtil; +import org.polydev.gaea.generation.GenerationPhase; +import org.polydev.gaea.math.Interpolator; public class UserDefinedGrid extends BiomeGrid { private final ImageLoader imageLoader; @@ -26,17 +28,17 @@ public class UserDefinedGrid extends BiomeGrid { } @Override - public Biome getBiome(int x, int z) { + public Biome getBiome(int x, int z, GenerationPhase phase) { if(fromImage) { double xi = imageLoader.getNoiseVal(x, z, channelX); double zi = imageLoader.getNoiseVal(x, z, channelZ); return super.getGrid()[NormalizationUtil.normalize(xi, getSizeX())][NormalizationUtil.normalize(zi, getSizeZ())]; } - return super.getBiome(x, z); + return super.getBiome(x, z, phase); } @Override - public Biome getBiome(Location l) { - return this.getBiome(l.getBlockX(), l.getBlockZ()); + public Biome getBiome(Location l, GenerationPhase phase) { + return this.getBiome(l.getBlockX(), l.getBlockZ(), phase); } } diff --git a/src/main/java/com/dfsek/terra/carving/UserDefinedCarver.java b/src/main/java/com/dfsek/terra/carving/UserDefinedCarver.java index 0b088cba8..8fbcf69f5 100644 --- a/src/main/java/com/dfsek/terra/carving/UserDefinedCarver.java +++ b/src/main/java/com/dfsek/terra/carving/UserDefinedCarver.java @@ -6,6 +6,7 @@ import com.dfsek.terra.biome.UserDefinedBiome; import com.dfsek.terra.config.genconfig.BiomeConfig; import org.bukkit.World; import org.bukkit.util.Vector; +import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.world.carving.Carver; import org.polydev.gaea.world.carving.Worm; @@ -40,7 +41,7 @@ public class UserDefinedCarver extends Carver { @Override public boolean isChunkCarved(World w, int chunkX, int chunkZ, Random random) { - return random.nextInt(100) < BiomeConfig.fromBiome((UserDefinedBiome) TerraBiomeGrid.fromWorld(w).getBiome(chunkX << 4, chunkZ << 4)).getCarverChance(this); + return random.nextInt(100) < BiomeConfig.fromBiome((UserDefinedBiome) TerraBiomeGrid.fromWorld(w).getBiome(chunkX << 4, chunkZ << 4, GenerationPhase.POPULATE)).getCarverChance(this); } private class UserDefinedWorm extends Worm { diff --git a/src/main/java/com/dfsek/terra/config/WorldConfig.java b/src/main/java/com/dfsek/terra/config/WorldConfig.java index 14322ba58..5c2185d4d 100644 --- a/src/main/java/com/dfsek/terra/config/WorldConfig.java +++ b/src/main/java/com/dfsek/terra/config/WorldConfig.java @@ -34,8 +34,11 @@ public class WorldConfig { public ImageLoader.Channel biomeXChannel; public ImageLoader.Channel biomeZChannel; public ImageLoader.Channel zoneChannel; - public ImageLoader.Channel terrainChannel; + public boolean biomeBlend; public ImageLoader imageLoader; + public int blendAmp; + public float blendFreq; + public boolean perturbPaletteOnly; public WorldConfig(World w, JavaPlugin main) { @@ -74,6 +77,12 @@ public class WorldConfig { freq1 = 1f/config.getInt("frequencies.grid-x", 256); freq2 = 1f/config.getInt("frequencies.grid-z", 512); fromImage = config.getBoolean("image.use-image", false); + biomeBlend = config.getBoolean("blend.enable", false); + blendAmp = config.getInt("blend.amplitude", 8); + blendFreq = (float) config.getDouble("blend.frequency", 0.01); + perturbPaletteOnly = config.getBoolean("blend.ignore-terrain", true); + + // Load image stuff try { diff --git a/src/main/java/com/dfsek/terra/generation/SlabGenerator.java b/src/main/java/com/dfsek/terra/generation/SlabGenerator.java index 66d1ff293..2624193f3 100644 --- a/src/main/java/com/dfsek/terra/generation/SlabGenerator.java +++ b/src/main/java/com/dfsek/terra/generation/SlabGenerator.java @@ -13,6 +13,7 @@ import org.bukkit.block.data.type.Slab; import org.bukkit.block.data.type.Stairs; import org.bukkit.generator.ChunkGenerator; import org.bukkit.util.Vector; +import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.generation.GenerationPopulator; import org.polydev.gaea.math.ChunkInterpolator; import org.polydev.gaea.world.palette.Palette; @@ -32,7 +33,7 @@ public class SlabGenerator extends GenerationPopulator { for(byte z = 0; z < 16; z++) { int xi = (chunkX << 4) + x; int zi = (chunkZ << 4) + z; - BiomeConfig config = BiomeConfig.fromBiome((UserDefinedBiome) g.getBiome(xi, zi)); + BiomeConfig config = BiomeConfig.fromBiome((UserDefinedBiome) g.getBiome(xi, zi, GenerationPhase.PALETTE_APPLY)); if(config.getSlabs() == null) continue; double thresh = config.getSlabThreshold(); for(int y = 0; y < world.getMaxHeight(); y++) { diff --git a/src/main/java/com/dfsek/terra/generation/UserDefinedGenerator.java b/src/main/java/com/dfsek/terra/generation/UserDefinedGenerator.java index d1065f5df..a0c363497 100644 --- a/src/main/java/com/dfsek/terra/generation/UserDefinedGenerator.java +++ b/src/main/java/com/dfsek/terra/generation/UserDefinedGenerator.java @@ -1,10 +1,14 @@ package com.dfsek.terra.generation; +import com.dfsek.terra.biome.TerraBiomeGrid; +import com.dfsek.terra.biome.UserDefinedBiome; +import com.dfsek.terra.biome.UserDefinedGrid; import com.dfsek.terra.math.NoiseFunction2; import com.dfsek.terra.math.NoiseFunction3; import org.bukkit.World; import org.bukkit.block.data.BlockData; import org.polydev.gaea.biome.Generator; +import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.math.FastNoise; import org.polydev.gaea.math.parsii.eval.Expression; import org.polydev.gaea.math.parsii.eval.Parser; @@ -20,9 +24,9 @@ import java.util.TreeMap; public class UserDefinedGenerator extends Generator { private final Expression noiseExp; private final Scope s = new Scope(); - private final Variable xVar = s.getVariable("x");; + private final Variable xVar = s.getVariable("x"); private final Variable yVar = s.getVariable("y"); - private final Variable zVar = s.getVariable("z");; + private final Variable zVar = s.getVariable("z"); private final TreeMap> paletteMap; private final NoiseFunction2 n2 = new NoiseFunction2(); private final NoiseFunction3 n3 = new NoiseFunction3(); @@ -51,8 +55,8 @@ public class UserDefinedGenerator extends Generator { xVar.setValue(x); yVar.setValue(0); zVar.setValue(z); - n2.setNoise(gen, false); - n3.setNoise(gen, false); + n2.setNoise(gen); + n3.setNoise(gen); return noiseExp.evaluate(); } } @@ -72,8 +76,8 @@ public class UserDefinedGenerator extends Generator { xVar.setValue(x); yVar.setValue(y); zVar.setValue(z); - n2.setNoise(gen, false); - n3.setNoise(gen, false); + n2.setNoise(gen); + n3.setNoise(gen); return noiseExp.evaluate(); } } diff --git a/src/main/java/com/dfsek/terra/image/DebugFrame.java b/src/main/java/com/dfsek/terra/image/DebugFrame.java index 8f782c84b..1b1995668 100644 --- a/src/main/java/com/dfsek/terra/image/DebugFrame.java +++ b/src/main/java/com/dfsek/terra/image/DebugFrame.java @@ -7,6 +7,7 @@ import com.dfsek.terra.config.WorldConfig; import com.dfsek.terra.config.genconfig.BiomeConfig; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.polydev.gaea.generation.GenerationPhase; import javax.swing.*; import java.awt.*; @@ -37,7 +38,7 @@ public class DebugFrame extends JFrame implements ActionListener { xp = (int) (((double) Math.floorMod(p.getLocation().getBlockX() - (img.getWidth() / 2), x) / x) * getWidth()); zp = (int) (((double) Math.floorMod(p.getLocation().getBlockZ() - (img.getHeight() / 2), z) / z) * getHeight()); } - String str = BiomeConfig.fromBiome((UserDefinedBiome) TerraBiomeGrid.fromWorld(p.getWorld()).getBiome(p.getLocation())).getID(); + String str = BiomeConfig.fromBiome((UserDefinedBiome) TerraBiomeGrid.fromWorld(p.getWorld()).getBiome(p.getLocation(), GenerationPhase.POPULATE)).getID(); g.setColor(new Color(255, 255, 255, 128)); g.fillRect(xp + 13, zp - 13, (int) (8 + 8.25 * str.length()), 33); g.setColor(Color.BLACK); diff --git a/src/main/java/com/dfsek/terra/math/NoiseFunction2.java b/src/main/java/com/dfsek/terra/math/NoiseFunction2.java index 94d1416fa..8249aa0aa 100644 --- a/src/main/java/com/dfsek/terra/math/NoiseFunction2.java +++ b/src/main/java/com/dfsek/terra/math/NoiseFunction2.java @@ -19,8 +19,8 @@ public class NoiseFunction2 implements Function { return gen.getSimplexFractal((float) list.get(0).evaluate(), (float) list.get(1).evaluate()); } - public void setNoise(FastNoise gen, boolean override) { - if(this.gen == null || override) this.gen = gen; + public void setNoise(FastNoise gen) { + this.gen = gen; } @Override diff --git a/src/main/java/com/dfsek/terra/math/NoiseFunction3.java b/src/main/java/com/dfsek/terra/math/NoiseFunction3.java index a1c5ac416..61963e346 100644 --- a/src/main/java/com/dfsek/terra/math/NoiseFunction3.java +++ b/src/main/java/com/dfsek/terra/math/NoiseFunction3.java @@ -18,8 +18,8 @@ public class NoiseFunction3 implements Function { return gen.getSimplexFractal((float) list.get(0).evaluate(), (float) list.get(1).evaluate(), (float) list.get(2).evaluate()); } - public void setNoise(FastNoise gen, boolean override) { - if(this.gen == null || override) this.gen = gen; + public void setNoise(FastNoise gen) { + this.gen = gen; } @Override diff --git a/src/main/java/com/dfsek/terra/population/FloraPopulator.java b/src/main/java/com/dfsek/terra/population/FloraPopulator.java index b5d56ed8d..dfbd2326a 100644 --- a/src/main/java/com/dfsek/terra/population/FloraPopulator.java +++ b/src/main/java/com/dfsek/terra/population/FloraPopulator.java @@ -10,6 +10,7 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.jetbrains.annotations.NotNull; import org.polydev.gaea.biome.Biome; +import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.population.GaeaBlockPopulator; import org.polydev.gaea.profiler.ProfileFuture; import org.polydev.gaea.world.Flora; @@ -27,7 +28,7 @@ public class FloraPopulator extends GaeaBlockPopulator { pop.add(chunk); for(int x = 0; x < 16; x++) { for(int z = 0; z < 16; z++) { - UserDefinedBiome biome = (UserDefinedBiome) TerraBiomeGrid.fromWorld(world).getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z); + UserDefinedBiome biome = (UserDefinedBiome) TerraBiomeGrid.fromWorld(world).getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z, GenerationPhase.POPULATE); if(biome.getDecorator().getFloraChance() <= 0 || random.nextInt(100) > biome.getDecorator().getFloraChance()) continue; try { diff --git a/src/main/java/com/dfsek/terra/population/OrePopulator.java b/src/main/java/com/dfsek/terra/population/OrePopulator.java index 29350dabb..90c6bbdb5 100644 --- a/src/main/java/com/dfsek/terra/population/OrePopulator.java +++ b/src/main/java/com/dfsek/terra/population/OrePopulator.java @@ -11,6 +11,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.jetbrains.annotations.NotNull; import org.polydev.gaea.biome.Biome; +import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.population.GaeaBlockPopulator; import org.polydev.gaea.profiler.ProfileFuture; @@ -22,7 +23,7 @@ public class OrePopulator extends GaeaBlockPopulator { public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) { try (ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("OreTime")) { Location l = chunk.getBlock(8, 0, 0).getLocation(); - Biome b = TerraBiomeGrid.fromWorld(world).getBiome(l.getBlockX(), l.getBlockZ()); + Biome b = TerraBiomeGrid.fromWorld(world).getBiome(l.getBlockX(), l.getBlockZ(), GenerationPhase.POPULATE); for(Map.Entry e : BiomeConfig.fromBiome((UserDefinedBiome) b).getOres().entrySet()) { int num = e.getValue().get(random); for(int i = 0; i < num; i++) { diff --git a/src/main/java/com/dfsek/terra/population/TreePopulator.java b/src/main/java/com/dfsek/terra/population/TreePopulator.java index 6634ae6bd..2bf12b967 100644 --- a/src/main/java/com/dfsek/terra/population/TreePopulator.java +++ b/src/main/java/com/dfsek/terra/population/TreePopulator.java @@ -9,6 +9,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.jetbrains.annotations.NotNull; import org.polydev.gaea.biome.Biome; +import org.polydev.gaea.generation.GenerationPhase; import org.polydev.gaea.population.GaeaBlockPopulator; import org.polydev.gaea.profiler.ProfileFuture; import org.polydev.gaea.util.WorldUtil; @@ -22,14 +23,14 @@ public class TreePopulator extends GaeaBlockPopulator { int x = random.nextInt(16); // Decrease chances of chunk-crossing trees int z = random.nextInt(16); Location origin = chunk.getBlock(x, 0, z).getLocation(); - Biome b = TerraBiomeGrid.fromWorld(world).getBiome(origin); + Biome b = TerraBiomeGrid.fromWorld(world).getBiome(origin, GenerationPhase.POPULATE); if(((UserDefinedDecorator) b.getDecorator()).getTreeChance() < random.nextInt(100)) return; int numTrees = 0; for(int i = 0; i < 48; i++) { int y = WorldUtil.getHighestValidSpawnAt(chunk, x, z); if(y <= 0) continue; origin = chunk.getBlock(x, y, z).getLocation().add(0, 1, 0); - b = TerraBiomeGrid.fromWorld(world).getBiome(origin); + b = TerraBiomeGrid.fromWorld(world).getBiome(origin, GenerationPhase.POPULATE); numTrees++; try { b.getDecorator().getTrees().get(random).plant(origin, random, false, Terra.getInstance());