diff --git a/core/src/main/java/mc/core/world/Biome.java b/core/src/main/java/mc/core/world/Biome.java index 5a60047..6753ad4 100644 --- a/core/src/main/java/mc/core/world/Biome.java +++ b/core/src/main/java/mc/core/world/Biome.java @@ -2,6 +2,8 @@ package mc.core.world; import lombok.Getter; +import java.util.EnumSet; + public enum Biome { OCEAN(0, "Ocean", 0x0000cd), PLAINS(1, "Plains", 0x008000), @@ -23,13 +25,24 @@ public enum Biome { DESERT_HILLS(17, "Desert hills", 0xffe4b5), FOREST_HILLS(18, "Forest hills", 0x006400), TAIGA_HILLS(19, "Taiga hills", 0xf0f8ff), - EXTREME_HILLS_EDGE(20, "Extreme hills edge", 0xffffff), + EXTREME_HILLS_ED(20, "Extreme hills edge", 0xffffff), JUNGLE(21, "Jungle", 0xadff2f), JUNGLE_HILLS(22, "Jungle hills", 0xadff2f), - DEEP_OCEAN(23, "Deep ocean", 0x000080), - TUNDRA(24, "Tundra", 0xc0c0c0), - SAVANNA(25, "Savana", 0xcd8513), - SAVANNA_FOREST(26, "Savana forest", 0x8b4513); + JUNGLE_HILLS_2(23, "Jungle hills", 0xadff2f), //WTF? + DEEP_OCEAN(24, "Deep ocean", 0x000080), + STONE_BEACH(25, "Stone beach", 0xffffff), + COLD_BEACH(26, "Cold beach", 0xffffff), + BIRCH_FOREST(27, "Birch forest", 0xffffff), + BIRCH_FOREST_HILLS(28, "Birch forest hills", 0xffffff), + DARK_FOREST(29, "Dark forest", 0xffffff), + COLD_TAIGA(30, "Cold taiga", 0xffffff), + COLD_TAIGA_HILLS(31, "Cold taiga hills", 0xffffff), + MEGA_TAIGA(32, "Mega taiga", 0xffffff), + MEGA_TAIGA_HILLS(33, "Mega taiga hills", 0xffffff), + EXTREME_HILLS_PLUS(34, "Extreme hills plus", 0xffffff), + SAVANNA(35, "Savana", 0xcd8513), + SAVANNA_PLATO(36, "Savana plato", 0x8b4513), + VOID(127, "Void", 0xffffff); @Getter private final int id; @@ -38,6 +51,8 @@ public enum Biome { @Getter private final int color; + private final static EnumSet waterBiomes = EnumSet.of(OCEAN, RIVER, FROZEN_OCEAN, FROZEN_RIVER, DEEP_OCEAN); + Biome(int id, String name, int color) { this.id = id; this.name = name; @@ -47,4 +62,8 @@ public enum Biome { public static Biome getById(int id) { return Biome.values()[id]; } + + public static boolean isWaterBiome (Biome biome) { + return waterBiomes.contains(biome); + } } diff --git a/generated_world/src/main/java/mc/world/generated_world/generator/NoiseGenerator.java b/generated_world/src/main/java/mc/world/generated_world/generator/NoiseGenerator.java new file mode 100644 index 0000000..b3c84c7 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/generator/NoiseGenerator.java @@ -0,0 +1,57 @@ +package mc.world.generated_world.generator; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import static mc.world.generated_world.WorldConstants.WORLD_REGION_SIZE; + +@Slf4j +@RequiredArgsConstructor +public class NoiseGenerator { + private int[] perm = new int[WORLD_REGION_SIZE]; + private double[] gradsX = new double[WORLD_REGION_SIZE]; + private double[] gradsY = new double[WORLD_REGION_SIZE]; + private final int seed; + + void init() { + for (int i = 0; i < WORLD_REGION_SIZE; ++i) { + int other = rand(i) % (i + 1); + if (i > other) + perm[i] = perm[other]; + perm[other] = i; + gradsX[i] = Math.cos(2.0f * Math.PI * i / WORLD_REGION_SIZE); + gradsY[i] = Math.sin(2.0f * Math.PI * i / WORLD_REGION_SIZE); + } + log.debug("Noise generator is initialized"); + } + + double f(double t) { + t = Math.abs(t); + return t >= 1.0f ? 0.0f : 1.0f - + (3.0f - 2.0f * t) * t * t; + } + + private double surflet(double x, double y, double gradX, double gradY) { + return f(x) * f(y) * (gradX * x + gradY * y); + } + + double noise(double x, double y) { + float result = 0.0f; + int cellX = (int)(x); + int cellY = (int)(y); + int mask = WORLD_REGION_SIZE - 1; + for (int gridY = cellY; gridY <= cellY + 1; ++gridY) + for (int gridX = cellX; gridX <= cellX + 1; ++gridX) { + int hash = perm[(perm[gridX & mask] + gridY) & mask]; + result += surflet(x - gridX, y - gridY, + gradsX[hash], gradsY[hash]); + } + return (result + 1) / 2; + } + + private int rand(int i) { + int x = (i * i) % WORLD_REGION_SIZE; + int y = (i + i * x) % WORLD_REGION_SIZE; + return (int) (Integer.MAX_VALUE * SeedRandomGenerator.random(x, y, seed)); + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java index 8b8ce2d..dedaf29 100644 --- a/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java @@ -7,9 +7,6 @@ import mc.core.world.block.BlockType; import mc.core.world.*; import mc.core.world.chunk.Chunk; import mc.world.generated_world.region.RegionImpl; -import mc.world.generated_world.serialization.ChunkSerializer; -import mc.world.generated_world.serialization.RegionReaderWriter; -import mc.world.generated_world.serialization.WorldReaderWriter; import mc.world.generated_world.world.CubicWorld; import mc.world.generated_world.world.Temperature; import mc.world.generated_world.world.Wetness; @@ -17,6 +14,7 @@ import mc.world.generated_world.world.Wetness; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; +import java.io.IOException; import java.util.UUID; import static mc.world.generated_world.WorldConstants.*; @@ -27,24 +25,26 @@ public class SeedBasedWorldGenerator implements WorldGenerator { public static void main(String[] args) throws Exception{ WorldGenerator worldGenerator = new SeedBasedWorldGenerator(); World world = new CubicWorld(UUID.fromString("00000000-0000-0000-C000-000000000046"), 2626949); - Region region = worldGenerator.generateRegion(0, 0, world); + /*Region region = worldGenerator.generateRegion(0, 0, world); region.save(new ChunkSerializer(), new RegionReaderWriter(new File("worlds", world.getWorldId().toString()))); - new WorldReaderWriter(new File("worlds")).writeWorldInfo(world); - /*worldGenerator.generateRegion(1, 0, world); - worldGenerator.generateRegion(-1, 0, world); - worldGenerator.generateRegion(0, 1, world); - worldGenerator.generateRegion(0, -1, world); - worldGenerator.generateRegion(-1, -1, world); - worldGenerator.generateRegion(1, -1, world); - worldGenerator.generateRegion(-1, 1, world); - worldGenerator.generateRegion(1, 1, world); + new WorldReaderWriter(new File("worlds")).writeWorldInfo(world);*/ + + createBigImage(worldGenerator, world); + } + + private static void createBigImage (WorldGenerator worldGenerator, World world) throws IOException { BufferedImage image = new BufferedImage(3 * 256, 3 * 256, BufferedImage.TYPE_INT_RGB); - BufferedImage currentImage; - int shiftX; - int shiftY; - currentImage = ImageIO.read(new File("out/0.0", "biomeMap.png")); - shiftX = 1; - shiftY = 1; + for (int x = 0; x <= 2; x ++) { + for (int z = 0; z <= 2; z ++) { + worldGenerator.generateRegion(x - 1, z - 1, world); + addToBigImage(x, z, image); + } + } + ImageIO.write(image, "png", new File("out", "merged.png")); + } + + private static void addToBigImage (int shiftX, int shiftY, BufferedImage image) throws IOException{ + BufferedImage currentImage = ImageIO.read(new File("out/" + (shiftX - 1) + "." + (shiftY - 1), "biomeMap.png")); for (int x = 0; x < 256; x ++){ for (int y = 0; y < 256; y ++){ int tx = 256 * shiftX + x; @@ -52,87 +52,6 @@ public class SeedBasedWorldGenerator implements WorldGenerator { image.setRGB(tx, ty, currentImage.getRGB(x, y)); } } - currentImage = ImageIO.read(new File("out/0.1", "biomeMap.png")); - shiftX = 1; - shiftY = 2; - for (int x = 0; x < 256; x ++){ - for (int y = 0; y < 256; y ++){ - int tx = 256 * shiftX + x; - int ty = 256 * shiftY + y; - image.setRGB(tx, ty, currentImage.getRGB(x, y)); - } - } - currentImage = ImageIO.read(new File("out/1.0", "biomeMap.png")); - shiftX = 2; - shiftY = 1; - for (int x = 0; x < 256; x ++){ - for (int y = 0; y < 256; y ++){ - int tx = 256 * shiftX + x; - int ty = 256 * shiftY + y; - image.setRGB(tx, ty, currentImage.getRGB(x, y)); - } - } - currentImage = ImageIO.read(new File("out/-1.0", "biomeMap.png")); - shiftX = 0; - shiftY = 1; - for (int x = 0; x < 256; x ++){ - for (int y = 0; y < 256; y ++){ - int tx = 256 * shiftX + x; - int ty = 256 * shiftY + y; - image.setRGB(tx, ty, currentImage.getRGB(x, y)); - } - } - currentImage = ImageIO.read(new File("out/0.-1", "biomeMap.png")); - shiftX = 1; - shiftY = 0; - for (int x = 0; x < 256; x ++){ - for (int y = 0; y < 256; y ++){ - int tx = 256 * shiftX + x; - int ty = 256 * shiftY + y; - image.setRGB(tx, ty, currentImage.getRGB(x, y)); - } - } - currentImage = ImageIO.read(new File("out/-1.-1", "biomeMap.png")); - shiftX = 0; - shiftY = 0; - for (int x = 0; x < 256; x ++){ - for (int y = 0; y < 256; y ++){ - int tx = 256 * shiftX + x; - int ty = 256 * shiftY + y; - image.setRGB(tx, ty, currentImage.getRGB(x, y)); - } - } - currentImage = ImageIO.read(new File("out/1.-1", "biomeMap.png")); - shiftX = 2; - shiftY = 0; - for (int x = 0; x < 256; x ++){ - for (int y = 0; y < 256; y ++){ - int tx = 256 * shiftX + x; - int ty = 256 * shiftY + y; - image.setRGB(tx, ty, currentImage.getRGB(x, y)); - } - } - currentImage = ImageIO.read(new File("out/1.1", "biomeMap.png")); - shiftX = 2; - shiftY = 2; - for (int x = 0; x < 256; x ++){ - for (int y = 0; y < 256; y ++){ - int tx = 256 * shiftX + x; - int ty = 256 * shiftY + y; - image.setRGB(tx, ty, currentImage.getRGB(x, y)); - } - } - currentImage = ImageIO.read(new File("out/-1.1", "biomeMap.png")); - shiftX = 0; - shiftY = 2; - for (int x = 0; x < 256; x ++){ - for (int y = 0; y < 256; y ++){ - int tx = 256 * shiftX + x; - int ty = 256 * shiftY + y; - image.setRGB(tx, ty, currentImage.getRGB(x, y)); - } - } - ImageIO.write(image, "png", new File("out", "merged.png"));*/ } @Override @@ -162,7 +81,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { return 40960 + x; } - public void generate() { + private void generate() { log.debug("Starting generating region [{}, {}] for world '{}' with seed '{}'", region.getX(), region.getZ(), world.getWorldId(), world.getSeed()); noiseGenerator = new NoiseGenerator(world.getSeed()); @@ -381,7 +300,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { if (temperature == Temperature.FROST) { if (wetness == Wetness.DRIEST || wetness == Wetness.DRY) { - return Biome.TUNDRA; + return Biome.COLD_TAIGA; } else { if (height > HILLS_HEIGHT) { return Biome.ICE_MOUNTAINS; @@ -435,7 +354,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { return Biome.FOREST; } } else { - return Biome.SAVANNA_FOREST; + return Biome.SAVANNA_PLATO; } } @@ -470,54 +389,4 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } } - @RequiredArgsConstructor - private class NoiseGenerator { - int mask = WORLD_REGION_SIZE - 1; - int[] perm = new int[WORLD_REGION_SIZE]; - double[] gradsX = new double[WORLD_REGION_SIZE]; - double[] gradsY = new double[WORLD_REGION_SIZE]; - private final int seed; - - void init() { - for (int i = 0; i < WORLD_REGION_SIZE; ++i) { - int other = rand(i) % (i + 1); - if (i > other) - perm[i] = perm[other]; - perm[other] = i; - gradsX[i] = Math.cos(2.0f * Math.PI * i / WORLD_REGION_SIZE); - gradsY[i] = Math.sin(2.0f * Math.PI * i / WORLD_REGION_SIZE); - } - log.debug("Noise generator is initialized"); - } - - double f(double t) { - t = Math.abs(t); - return t >= 1.0f ? 0.0f : 1.0f - - (3.0f - 2.0f * t) * t * t; - } - - double surflet(double x, double y, double gradX, double gradY) { - return f(x) * f(y) * (gradX * x + gradY * y); - } - - double noise(double x, double y) { - float result = 0.0f; - int cellX = (int)(x); - int cellY = (int)(y); - for (int gridY = cellY; gridY <= cellY + 1; ++gridY) - for (int gridX = cellX; gridX <= cellX + 1; ++gridX) { - int hash = perm[(perm[gridX & mask] + gridY) & mask]; - result += surflet(x - gridX, y - gridY, - gradsX[hash], gradsY[hash]); - } - return (result + 1) / 2; - } - - int rand(int i) { - int x = (i * i) % WORLD_REGION_SIZE; - int y = (i + i * x) % WORLD_REGION_SIZE; - return (int) (Integer.MAX_VALUE * SeedRandomGenerator.random(x, y, seed)); - } - } - } \ No newline at end of file