From f8e07222cace73dc65cdb97c939bd4d086f5486e Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 14 Jan 2024 20:11:15 -0800 Subject: [PATCH] Add 2D Biomes back in --- .../java/world/bentobox/skygrid/SkyGrid.java | 12 +++- .../generators/SkyGridBiomeProvider.java | 62 +++++++++++++++++++ .../{Biomes.java => SkyGridBiomes.java} | 39 +++++++----- .../skygrid/generators/SkyGridGen.java | 48 +++++++++++++- 4 files changed, 142 insertions(+), 19 deletions(-) create mode 100644 src/main/java/world/bentobox/skygrid/generators/SkyGridBiomeProvider.java rename src/main/java/world/bentobox/skygrid/generators/{Biomes.java => SkyGridBiomes.java} (83%) diff --git a/src/main/java/world/bentobox/skygrid/SkyGrid.java b/src/main/java/world/bentobox/skygrid/SkyGrid.java index 3c15765..9193dfd 100644 --- a/src/main/java/world/bentobox/skygrid/SkyGrid.java +++ b/src/main/java/world/bentobox/skygrid/SkyGrid.java @@ -2,6 +2,7 @@ import org.bukkit.World; import org.bukkit.WorldCreator; +import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.ChunkGenerator; import org.eclipse.jdt.annotation.NonNull; @@ -12,6 +13,7 @@ import world.bentobox.bentobox.api.configuration.WorldSettings; import world.bentobox.bentobox.api.flags.Flag.Type; import world.bentobox.bentobox.lists.Flags; +import world.bentobox.skygrid.generators.SkyGridBiomeProvider; import world.bentobox.skygrid.generators.SkyGridGen; import world.bentobox.skygrid.generators.WorldStyles; @@ -88,22 +90,26 @@ public void createWorlds() { if (getServer().getWorld(worldName) == null) { getLogger().info("Creating SkyGrid world ..."); } + BiomeProvider bp = new SkyGridBiomeProvider(); // Create the world if it does not exist - islandWorld = WorldCreator.name(worldName).environment(World.Environment.NORMAL).generator(gen).createWorld(); + islandWorld = WorldCreator.name(worldName).environment(World.Environment.NORMAL).generator(gen) + .biomeProvider(bp).createWorld(); // Make the nether if it does not exist if (settings.isNetherGenerate()) { if (getServer().getWorld(worldName + NETHER) == null) { log("Creating SkyGrid's Nether..."); } - netherWorld = WorldCreator.name(worldName + NETHER).generator(gen).environment(World.Environment.NETHER).createWorld(); + netherWorld = WorldCreator.name(worldName + NETHER).generator(gen).environment(World.Environment.NETHER) + .biomeProvider(bp).createWorld(); } // Make the end if it does not exist if (settings.isEndGenerate()) { if (getServer().getWorld(worldName + THE_END) == null) { log("Creating SkyGrid's End World..."); } - endWorld = WorldCreator.name(worldName + THE_END).generator(gen).environment(World.Environment.THE_END).createWorld(); + endWorld = WorldCreator.name(worldName + THE_END).generator(gen).environment(World.Environment.THE_END) + .biomeProvider(bp).createWorld(); } } diff --git a/src/main/java/world/bentobox/skygrid/generators/SkyGridBiomeProvider.java b/src/main/java/world/bentobox/skygrid/generators/SkyGridBiomeProvider.java new file mode 100644 index 0000000..c4687f3 --- /dev/null +++ b/src/main/java/world/bentobox/skygrid/generators/SkyGridBiomeProvider.java @@ -0,0 +1,62 @@ +package world.bentobox.skygrid.generators; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.WorldInfo; +import org.bukkit.util.noise.PerlinOctaveGenerator; + +/** + * @author tastybento + */ +public class SkyGridBiomeProvider extends BiomeProvider { + + private final Map temperatureGenMap = new ConcurrentHashMap<>(); + private final Map rainfallGenMap = new ConcurrentHashMap<>(); + + + @Override + public Biome getBiome(WorldInfo worldInfo, int realX, int y, int realZ) { + + // Make and cache the PerlinOctaveGenerator for the environment + PerlinOctaveGenerator temperatureGen = temperatureGenMap.computeIfAbsent(worldInfo.getEnvironment(), wf -> { + PerlinOctaveGenerator tg = new PerlinOctaveGenerator(worldInfo.getSeed(), 16); + tg.setScale(1.0 / 100.0); + return tg; + }); + PerlinOctaveGenerator rainfallGen = rainfallGenMap.computeIfAbsent(worldInfo.getEnvironment(), wf -> { + PerlinOctaveGenerator rg = new PerlinOctaveGenerator(worldInfo.getSeed() + 1, 15); + rg.setScale(1.0 / 100.0); + return rg; + }); + + //We get the 3 closest biome's to the temperature and rainfall at this block + Map biomes = SkyGridBiomes.getBiomes(worldInfo.getEnvironment(), + Math.abs(temperatureGen.noise(realX, realZ, 0.5, 0.5) * 100.0), + Math.abs(rainfallGen.noise(realX, realZ, 0.5, 0.5) * 100.0)); + + double maxNoiz = 0.0; + SkyGridBiomes maxBiome = null; + + for (Entry biome : biomes.entrySet()) { + if (biome.getValue() >= maxNoiz) { + maxNoiz = biome.getValue(); + maxBiome = biome.getKey(); + } + } + return Objects.requireNonNull(maxBiome).biome; + } + + @Override + public List getBiomes(WorldInfo worldInfo) { + return Arrays.stream(SkyGridBiomes.values()).map(SkyGridBiomes::getBiome).toList(); + } + +} diff --git a/src/main/java/world/bentobox/skygrid/generators/Biomes.java b/src/main/java/world/bentobox/skygrid/generators/SkyGridBiomes.java similarity index 83% rename from src/main/java/world/bentobox/skygrid/generators/Biomes.java rename to src/main/java/world/bentobox/skygrid/generators/SkyGridBiomes.java index ba5ecc5..fb716f9 100644 --- a/src/main/java/world/bentobox/skygrid/generators/Biomes.java +++ b/src/main/java/world/bentobox/skygrid/generators/SkyGridBiomes.java @@ -17,20 +17,15 @@ * is a tundra, but it is also much closer to a desert than a rain forest. * */ -public enum Biomes { +public enum SkyGridBiomes { //We store the biome, the temperature and rainfall for each biome. - SNOWY_PLAINS(Environment.NORMAL, Biome.SNOWY_PLAINS, 0, 100), - SNOWY_TAIGA(Environment.NORMAL, Biome.SNOWY_TAIGA, 0, 100), - FROZEN_RIVER(Environment.NORMAL, Biome.FROZEN_RIVER, 0, 10), - SNOWY_BEACH(Environment.NORMAL, Biome.SNOWY_BEACH, 0, 100), - STONY_PEAKS(Environment.NORMAL, Biome.STONY_PEAKS, 20, 60), + PLAINS(Environment.NORMAL, Biome.PLAINS, 40, 30), DESERT(Environment.NORMAL, Biome.DESERT, 60, 4), BADLANDS(Environment.NORMAL, Biome.BADLANDS, 90, 1), FOREST(Environment.NORMAL, Biome.FOREST, 50, 60), FLOWER_FOREST(Environment.NORMAL, Biome.FLOWER_FOREST, 50, 60), BIRCH_FOREST(Environment.NORMAL, Biome.BIRCH_FOREST, 50, 59), - PLAINS(Environment.NORMAL, Biome.PLAINS, 40, 30), CHERRY_GROVE(Environment.NORMAL, Biome.CHERRY_GROVE, 45, 35), SWAMP(Environment.NORMAL, Biome.SWAMP, 40, 70), JUNGLE(Environment.NORMAL, Biome.JUNGLE, 60, 50), @@ -38,6 +33,12 @@ public enum Biomes { SAVANNA(Environment.NORMAL, Biome.SAVANNA, 40, 10), TAIGA(Environment.NORMAL, Biome.TAIGA, 30, 5), MUSHROOM_FIELDS(Environment.NORMAL, Biome.MUSHROOM_FIELDS, 50, 50), + SNOWY_PLAINS(Environment.NORMAL, Biome.SNOWY_PLAINS, 0, 100), + SNOWY_TAIGA(Environment.NORMAL, Biome.SNOWY_TAIGA, 0, 15), + FROZEN_RIVER(Environment.NORMAL, Biome.FROZEN_RIVER, 10, 10), + SNOWY_BEACH(Environment.NORMAL, Biome.SNOWY_BEACH, 10, 100), + STONY_PEAKS(Environment.NORMAL, Biome.STONY_PEAKS, 20, 60), + // Nether NETHER_WASTES(Environment.NETHER, Biome.NETHER_WASTES, 40, 30), SOUL_SAND_VALLEY(Environment.NETHER, Biome.SOUL_SAND_VALLEY, 40, 70), @@ -56,7 +57,7 @@ public enum Biomes { public final double optimumTemperature; public final double optimumRainfall; - Biomes(Environment env, Biome biome, double temp, double rain) { + SkyGridBiomes(Environment env, Biome biome, double temp, double rain) { this.env = env; this.biome = biome; this.optimumTemperature = temp; @@ -71,18 +72,19 @@ public enum Biomes { * @param rain - rain * @return Map of 3 biomes */ - public static Map getBiomes(Environment env, double temp, double rain) { + public static Map getBiomes(Environment env, double temp, double rain) { // We tell it the capacity we need to avoid expensive dynamic lengthening - Map biomes = new EnumMap<>(Biomes.class); + Map biomes = new EnumMap<>(SkyGridBiomes.class); - Biomes closestBiome = null; - Biomes secondClosestBiome = null; - Biomes thirdClosestBiome = null; + SkyGridBiomes closestBiome = null; + SkyGridBiomes secondClosestBiome = null; + SkyGridBiomes thirdClosestBiome = null; double closestDist = 10000000; double secondClosestDist = 10000000; double thirdClosestDist = 10000000; - for (Biomes biome : Biomes.values()) { + for (SkyGridBiomes biome : SkyGridBiomes.values()) { + // Only cover biomes for this environment, e.g., Nether if (!env.equals(biome.env)) continue; // To avoid having to do an expensive square root per biome per block, // we just compare the square distances, and take the square root at the @@ -113,8 +115,15 @@ else if (dist <= thirdClosestDist) { return biomes; } - private static double getSquaredDistance(Biomes biome, double temp, double rain) { + private static double getSquaredDistance(SkyGridBiomes biome, double temp, double rain) { return Math.abs((biome.optimumTemperature-temp)*(biome.optimumTemperature-temp) + (biome.optimumRainfall-rain)*(biome.optimumRainfall-rain)); } + /** + * @return the biome + */ + public Biome getBiome() { + return biome; + } + } \ No newline at end of file diff --git a/src/main/java/world/bentobox/skygrid/generators/SkyGridGen.java b/src/main/java/world/bentobox/skygrid/generators/SkyGridGen.java index 7a58b0a..beae04b 100644 --- a/src/main/java/world/bentobox/skygrid/generators/SkyGridGen.java +++ b/src/main/java/world/bentobox/skygrid/generators/SkyGridGen.java @@ -33,7 +33,6 @@ public SkyGridGen(SkyGrid addon) { public void generateNoise(WorldInfo worldInfo, Random r, int x, int z, ChunkData result) { result.setRegion(0, worldInfo.getMinHeight(), 0, 16, worldInfo.getMaxHeight(), 16, Material.AIR); preMade.getSkyGridChunk(worldInfo.getEnvironment()).forEach(b -> result.setBlock(b.getX(), b.getY(), b.getZ(), b.getBd())); - } @Override @@ -46,5 +45,52 @@ public Location getFixedSpawnLocation(World world, Random random) { return new Location(world, 0, addon.getSettings().getIslandHeight() + 2D, 0); } + /** + * Gets if the server should generate Vanilla surface. + * @return true if the server should generate Vanilla surface + */ + @Override + public boolean shouldGenerateSurface() { + return true; + } + + /** + * Gets if the server should generate Vanilla caves. + * @return true if the server should generate Vanilla caves + */ + @Override + public boolean shouldGenerateCaves() { + return true; + } + + /** + * Gets if the server should generate Vanilla decorations after this + * ChunkGenerator. + * @return true if the server should generate Vanilla decorations + */ + @Override + public boolean shouldGenerateDecorations() { + return true; + } + + /** + * Gets if the server should generate Vanilla mobs after this + * ChunkGenerator. + * @return true if the server should generate Vanilla mobs + */ + @Override + public boolean shouldGenerateMobs() { + return true; + } + + /** + * Gets if the server should generate Vanilla structures after this + * ChunkGenerator. + * @return true if the server should generate Vanilla structures + */ + @Override + public boolean shouldGenerateStructures() { + return true; + } } \ No newline at end of file