Merge tag 'WG-1' into develop
World Generator Gen1
This commit is contained in:
@@ -2,6 +2,8 @@ package mc.core.world;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
public enum Biome {
|
public enum Biome {
|
||||||
OCEAN(0, "Ocean", 0x0000cd),
|
OCEAN(0, "Ocean", 0x0000cd),
|
||||||
PLAINS(1, "Plains", 0x008000),
|
PLAINS(1, "Plains", 0x008000),
|
||||||
@@ -23,13 +25,24 @@ public enum Biome {
|
|||||||
DESERT_HILLS(17, "Desert hills", 0xffe4b5),
|
DESERT_HILLS(17, "Desert hills", 0xffe4b5),
|
||||||
FOREST_HILLS(18, "Forest hills", 0x006400),
|
FOREST_HILLS(18, "Forest hills", 0x006400),
|
||||||
TAIGA_HILLS(19, "Taiga hills", 0xf0f8ff),
|
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(21, "Jungle", 0xadff2f),
|
||||||
JUNGLE_HILLS(22, "Jungle hills", 0xadff2f),
|
JUNGLE_HILLS(22, "Jungle hills", 0xadff2f),
|
||||||
DEEP_OCEAN(23, "Deep ocean", 0x000080),
|
JUNGLE_HILLS_2(23, "Jungle hills", 0xadff2f), //WTF?
|
||||||
TUNDRA(24, "Tundra", 0xc0c0c0),
|
DEEP_OCEAN(24, "Deep ocean", 0x000080),
|
||||||
SAVANNA(25, "Savana", 0xcd8513),
|
STONE_BEACH(25, "Stone beach", 0xffffff),
|
||||||
SAVANNA_FOREST(26, "Savana forest", 0x8b4513);
|
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
|
@Getter
|
||||||
private final int id;
|
private final int id;
|
||||||
@@ -38,6 +51,8 @@ public enum Biome {
|
|||||||
@Getter
|
@Getter
|
||||||
private final int color;
|
private final int color;
|
||||||
|
|
||||||
|
private final static EnumSet<Biome> waterBiomes = EnumSet.of(OCEAN, RIVER, FROZEN_OCEAN, FROZEN_RIVER, DEEP_OCEAN);
|
||||||
|
|
||||||
Biome(int id, String name, int color) {
|
Biome(int id, String name, int color) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -47,4 +62,8 @@ public enum Biome {
|
|||||||
public static Biome getById(int id) {
|
public static Biome getById(int id) {
|
||||||
return Biome.values()[id];
|
return Biome.values()[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isWaterBiome (Biome biome) {
|
||||||
|
return waterBiomes.contains(biome);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,9 +7,6 @@ import mc.core.world.block.BlockType;
|
|||||||
import mc.core.world.*;
|
import mc.core.world.*;
|
||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.chunk.Chunk;
|
||||||
import mc.world.generated_world.region.RegionImpl;
|
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.CubicWorld;
|
||||||
import mc.world.generated_world.world.Temperature;
|
import mc.world.generated_world.world.Temperature;
|
||||||
import mc.world.generated_world.world.Wetness;
|
import mc.world.generated_world.world.Wetness;
|
||||||
@@ -17,6 +14,7 @@ import mc.world.generated_world.world.Wetness;
|
|||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static mc.world.generated_world.WorldConstants.*;
|
import static mc.world.generated_world.WorldConstants.*;
|
||||||
@@ -27,24 +25,26 @@ public class SeedBasedWorldGenerator implements WorldGenerator {
|
|||||||
public static void main(String[] args) throws Exception{
|
public static void main(String[] args) throws Exception{
|
||||||
WorldGenerator worldGenerator = new SeedBasedWorldGenerator();
|
WorldGenerator worldGenerator = new SeedBasedWorldGenerator();
|
||||||
World world = new CubicWorld(UUID.fromString("00000000-0000-0000-C000-000000000046"), 2626949);
|
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())));
|
region.save(new ChunkSerializer(), new RegionReaderWriter(new File("worlds", world.getWorldId().toString())));
|
||||||
new WorldReaderWriter(new File("worlds")).writeWorldInfo(world);
|
new WorldReaderWriter(new File("worlds")).writeWorldInfo(world);*/
|
||||||
/*worldGenerator.generateRegion(1, 0, world);
|
|
||||||
worldGenerator.generateRegion(-1, 0, world);
|
createBigImage(worldGenerator, world);
|
||||||
worldGenerator.generateRegion(0, 1, world);
|
}
|
||||||
worldGenerator.generateRegion(0, -1, world);
|
|
||||||
worldGenerator.generateRegion(-1, -1, world);
|
private static void createBigImage (WorldGenerator worldGenerator, World world) throws IOException {
|
||||||
worldGenerator.generateRegion(1, -1, world);
|
|
||||||
worldGenerator.generateRegion(-1, 1, world);
|
|
||||||
worldGenerator.generateRegion(1, 1, world);
|
|
||||||
BufferedImage image = new BufferedImage(3 * 256, 3 * 256, BufferedImage.TYPE_INT_RGB);
|
BufferedImage image = new BufferedImage(3 * 256, 3 * 256, BufferedImage.TYPE_INT_RGB);
|
||||||
BufferedImage currentImage;
|
for (int x = 0; x <= 2; x ++) {
|
||||||
int shiftX;
|
for (int z = 0; z <= 2; z ++) {
|
||||||
int shiftY;
|
worldGenerator.generateRegion(x - 1, z - 1, world);
|
||||||
currentImage = ImageIO.read(new File("out/0.0", "biomeMap.png"));
|
addToBigImage(x, z, image);
|
||||||
shiftX = 1;
|
}
|
||||||
shiftY = 1;
|
}
|
||||||
|
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 x = 0; x < 256; x ++){
|
||||||
for (int y = 0; y < 256; y ++){
|
for (int y = 0; y < 256; y ++){
|
||||||
int tx = 256 * shiftX + x;
|
int tx = 256 * shiftX + x;
|
||||||
@@ -52,87 +52,6 @@ public class SeedBasedWorldGenerator implements WorldGenerator {
|
|||||||
image.setRGB(tx, ty, currentImage.getRGB(x, y));
|
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
|
@Override
|
||||||
@@ -162,7 +81,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator {
|
|||||||
return 40960 + x;
|
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());
|
log.debug("Starting generating region [{}, {}] for world '{}' with seed '{}'", region.getX(), region.getZ(), world.getWorldId(), world.getSeed());
|
||||||
|
|
||||||
noiseGenerator = new NoiseGenerator(world.getSeed());
|
noiseGenerator = new NoiseGenerator(world.getSeed());
|
||||||
@@ -381,7 +300,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator {
|
|||||||
|
|
||||||
if (temperature == Temperature.FROST) {
|
if (temperature == Temperature.FROST) {
|
||||||
if (wetness == Wetness.DRIEST || wetness == Wetness.DRY) {
|
if (wetness == Wetness.DRIEST || wetness == Wetness.DRY) {
|
||||||
return Biome.TUNDRA;
|
return Biome.COLD_TAIGA;
|
||||||
} else {
|
} else {
|
||||||
if (height > HILLS_HEIGHT) {
|
if (height > HILLS_HEIGHT) {
|
||||||
return Biome.ICE_MOUNTAINS;
|
return Biome.ICE_MOUNTAINS;
|
||||||
@@ -435,7 +354,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator {
|
|||||||
return Biome.FOREST;
|
return Biome.FOREST;
|
||||||
}
|
}
|
||||||
} else {
|
} 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user