Archived
0

WorldGenerator gen 1

This commit is contained in:
Forwolk
2018-08-01 10:43:37 +03:00
parent b2f5af9a84
commit ff55368db2
15 changed files with 799 additions and 34 deletions

View File

@@ -3,9 +3,13 @@ package mc.core.block;
import lombok.Getter; import lombok.Getter;
public enum BlockType { public enum BlockType {
DIRT(1, "Dirt"), STONE(1, "Stone"),
GRASS(2, "Grass"), GRASS(2, "Grass"),
BEDROCK(7, "Bedrock"); DIRT(3, "Dirt"),
BEDROCK(7, "Bedrock"),
WATER(8, "Water"),
SAND(12, "Sand"),
SNOW(32, "Snow");
@Getter @Getter
private final int id; private final int id;

View File

@@ -3,37 +3,41 @@ package mc.core.world;
import lombok.Getter; import lombok.Getter;
public enum Biome { public enum Biome {
OCEAN(0, "Ocean"), OCEAN(0, "Ocean", 0x000080),
PLAINS(1, "Plains"), PLAINS(1, "Plains", 0x008000),
DESERT(2, "Desert"), DESERT(2, "Desert", 0xbdb76b),
EXTREME_HILLS(3, "Extreme hills"), EXTREME_HILLS(3, "Extreme hills", 0xffffff),
FOREST(4, "Forest"), FOREST(4, "Forest", 0x006400),
TAIGA(5, "Taiga"), TAIGA(5, "Taiga", 0xf0f8ff),
SWAMPLAND(6, "Swampland"), SWAMPLAND(6, "Swampland", 0x808000),
RIVER(7, "River"), RIVER(7, "River", 0xffffff),
HELL(8, "Hell"), HELL(8, "Hell", 0xffffff),
SKY(9, "Sky"), SKY(9, "Sky", 0xffffff),
FROZEN_OCEAN(10, "Frozen ocean"), FROZEN_OCEAN(10, "Frozen ocean", 0xe0ffff),
FROZEN_RIVER(11, "Frozen river"), FROZEN_RIVER(11, "Frozen river", 0xffffff),
ICE_PLAINS(12, "Ice plains"), ICE_PLAINS(12, "Ice plains", 0xfffafa),
ICE_MOUNTAINS(13, "Ice mountains"), ICE_MOUNTAINS(13, "Ice mountains", 0xfffafa),
MUSHROOM_ISLAND(14, "Mushroom island"), MUSHROOM_ISLAND(14, "Mushroom island", 0xffffff),
MUSHROOM_ISLAND_SHORE(15, "Mushroom island shore"), MUSHROOM_ISLAND_SHORE(15, "Mushroom island shore", 0xffffff),
BEACH(16, "Beach"), BEACH(16, "Beach", 0xffffff),
DESERT_HILLS(17, "Desert hills"), DESERT_HILLS(17, "Desert hills", 0xbdb76b),
FOREST_HILLS(18, "Forest hills"), FOREST_HILLS(18, "Forest hills", 0x006400),
TAIGA_HILLS(19, "Taiga hills"), TAIGA_HILLS(19, "Taiga hills", 0xf0f8ff),
EXTREME_HILLS_EDGE(20, "Extreme hills edge"), EXTREME_HILLS_EDGE(20, "Extreme hills edge", 0xffffff),
JUNGLE(21, "Jungle"), JUNGLE(21, "Jungle", 0xadff2f),
JUNGLE_HILLS(22, "Jungle hills"); JUNGLE_HILLS(22, "Jungle hills", 0xadff2f),
DEEP_OCEAN(23, "Deep ocean", 0x191970);
@Getter @Getter
private final int id; private final int id;
@Getter @Getter
private final String name; private final String name;
@Getter
private final int color;
Biome(int id, String name) { Biome(int id, String name, int color) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.color = color;
} }
} }

View File

@@ -19,7 +19,6 @@ public interface Region {
void setChunk(int x, int y, int z, Chunk chunk); void setChunk(int x, int y, int z, Chunk chunk);
int getX(); int getX();
int getY();
int getZ(); int getZ();
Biome getBiomeAt (int x, int z); Biome getBiomeAt (int x, int z);

View File

@@ -49,5 +49,8 @@ public interface World {
Chunk getChunk(int x, int y, int z); Chunk getChunk(int x, int y, int z);
void setChunk(int x, int y, int z, Chunk chunk); void setChunk(int x, int y, int z, Chunk chunk);
long getSeed (); Region getRegion (int x, int z);
void setRegion (int x, int z, Region region);
int getSeed ();
} }

View File

@@ -7,10 +7,7 @@ package mc.world.flat;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import mc.core.Location; import mc.core.Location;
import mc.core.world.Chunk; import mc.core.world.*;
import mc.core.world.IWorldType;
import mc.core.world.World;
import mc.core.world.WorldType;
import java.util.UUID; import java.util.UUID;
@@ -40,7 +37,17 @@ public class FlatWorld implements World {
} }
@Override @Override
public long getSeed() { public Region getRegion(int x, int z) {
return null;
}
@Override
public void setRegion(int x, int z, Region region) {
}
@Override
public int getSeed() {
return 0; return 0;
} }
} }

View File

@@ -0,0 +1,89 @@
package mc.world.generated_world;
import lombok.Getter;
import mc.core.Location;
import mc.core.world.*;
import java.util.UUID;
public class CubicWorld implements World {
@Getter
private final UUID worldId;
private final int seed;
private volatile Location spawnLocation;
private final transient Object spawnLocationLock = new Object();
private final transient ChunkLoader chunkLoader;
public CubicWorld(UUID worldId, int seed) {
this.worldId = worldId;
chunkLoader = new InMemoryCacheChunkLoader(worldId);
this.seed = seed;
}
public CubicWorld(int seed) {
this.worldId = UUID.randomUUID();
chunkLoader = new InMemoryCacheChunkLoader(worldId);
this.seed = seed;
}
public CubicWorld(UUID worldId) {
this.worldId = worldId;
chunkLoader = new InMemoryCacheChunkLoader(worldId);
this.seed = 0;
}
public CubicWorld () {
this.worldId = UUID.randomUUID();
chunkLoader = new InMemoryCacheChunkLoader(worldId);
this.seed = 0;
}
@Override
public IWorldType getWorldType() {
return null;
}
@Override
public Location getSpawn() {
if (spawnLocation == null) {
synchronized (spawnLocationLock) {
if (spawnLocation == null) {
spawnLocation = Location.startPointLocation();
}
}
}
return spawnLocation;
}
@Override
public void setSpawn(Location location) {
synchronized (spawnLocationLock) {
this.spawnLocation = location;
}
}
@Override
public Chunk getChunk(int x, int y, int z) {
return null;
}
@Override
public void setChunk(int x, int y, int z, Chunk chunk) {
}
@Override
public Region getRegion(int x, int z) {
return null;
}
@Override
public void setRegion(int x, int z, Region region) {
}
@Override
public int getSeed() {
return seed;
}
}

View File

@@ -0,0 +1,390 @@
package mc.world.generated_world;
import lombok.RequiredArgsConstructor;
import mc.core.block.BlockFactory;
import mc.core.block.BlockType;
import mc.core.world.*;
import mc.world.generated_world.region.RegionImpl;
import mc.world.generated_world.word.Temperature;
import mc.world.generated_world.word.Wetness;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.UUID;
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"), 123);
worldGenerator.generateRegion(0, 0, world);
worldGenerator.generateRegion(1, 0, world);
worldGenerator.generateRegion(-1, 0, world);
worldGenerator.generateRegion(0, 1, world);
worldGenerator.generateRegion(0, -1, world);
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 < 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 = 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));
}
}
ImageIO.write(image, "png", new File("out", "merged.png"));
}
@Override
public Region generateRegion(int x, int z, World world) {
Region region = new RegionImpl(x,z);
RegionGenerator regionGenerator = new RegionGenerator(world, region);
regionGenerator.generate();
return region;
}
@RequiredArgsConstructor
private class RegionGenerator {
private final World world;
private final Region region;
private final int size = 256;
private NoiseGenerator noiseGenerator;
private BlockFactory blockFactory;
private double sigmoid (double x) {
x -= 0.5;
x *= 15;
return 1.0 / (1.0 + Math.exp(-x));
}
private int convert (int x) {
return 40960 + x;
}
public void generate() {
noiseGenerator = new NoiseGenerator(world.getSeed());
noiseGenerator.init();
File file = new File("out", region.getX() + "." + region.getZ());
file.mkdirs();
int[][] heightMap = new int[size][size];
int[][] grassMap = new int[size][size];
int[][] temperatureMap = new int[size][size];
int[][] wetMap = new int[size][size];
Biome[][] biomes = new Biome[size][size];
for (int x = 0; x < size; x ++) {
for (int z = 0; z < size; z ++) {
int tx = convert(x + region.getX() * 256);
int tz = convert(z + region.getZ() * 256);
double p = sigmoid(noiseGenerator.noise(tx / 53d, tz / 53d));
double r = Math.sqrt(noiseGenerator.noise(tx / 6d, tz / 6d));
double h = (WorldConstants.WORLD_MAX_HEIGHT - WorldConstants.WORLD_MIN_HEIGHT) * Math.min(p * r, 1);
h = Math.min(WorldConstants.WORLD_MAX_HEIGHT, h + WorldConstants.WORLD_MIN_HEIGHT);
heightMap[x][z] = (int)(h);
grassMap[x][z] = (int) (1 + SeedRandomGenerator.random(tx, tz, world.getSeed()) * (WorldConstants.LANDFILL_GRASS_SURFACE_THIN - 1));
double k = Math.sqrt(noiseGenerator.noise(tx * 2.99, tz * 2.99));
double q = Math.sqrt(noiseGenerator.noise(tx / 41.0, tz / 41.0));
temperatureMap[x][z] = (int) (100 * Math.min((k * k + q * q + k * q) * k * q, 0.99));
if (heightMap[x][z] < WorldConstants.WORLD_SEA_LEVEL) {
biomes[x][z] = Biome.OCEAN;
wetMap[x][z] = 100;
}
}
}
for (int x = 1; x < size - 1; x ++) {
for (int z = 1; z < size - 1; z++) {
int mid = 0;
for (int tx = x - 1; tx <= x + 1; tx ++) {
for (int tz = z - 1; tz <= z + 1; tz ++) {
mid += wetMap[tx][tz];
}
}
wetMap[x][z] = mid / 9;
}
}
for (int z = 1; z < size - 1; z++) {
for (int x = 1; x < size - 1; x ++) {
int mid = 0;
for (int tx = x - 1; tx <= x + 1; tx ++) {
for (int tz = z - 1; tz <= z + 1; tz ++) {
mid += wetMap[tx][tz];
}
}
wetMap[x][z] = (int) (mid / 9 * (1 + 0.1 * SeedRandomGenerator.random(x, z, world.getSeed())));
}
}
for (int z = 1; z < size - 1; z++) {
for (int x = 1; x < size - 1; x ++) {
wetMap[x][z] = (int) Math.min(100, 60 * noiseGenerator.noise(x / 31d, z / 67d) + wetMap[x][z] * (1 + 0.2 * SeedRandomGenerator.random(x, z, world.getSeed())));
}
}
smooth(grassMap);
smooth(temperatureMap);
smooth(wetMap);
//smooth(heightMap);
for (int x = 0; x < 256; x ++) {
for (int z = 0; z < 256; z ++) {
Temperature temperature = Temperature.values()[temperatureMap[x][z] / 20];
Wetness wetness = Wetness.values()[(Math.min(wetMap[x][z], 100) - 1) / 100 * Wetness.values().length];
biomes[x][z] = selectBiome(temperature, wetness, heightMap[x][z]);
}
}
// ================================ DEBUG =======================================
try {
BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB);
BufferedImage subImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < 256; x ++) {
for (int z = 0; z < 256; z ++) {
int h = heightMap[x][z];
h = h << 16 | h << 8 | h;
image.setRGB(x, z, h);
}
}
ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() +"/hightmap.png"));
image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < 256; x ++) {
for (int z = 0; z < 256; z ++) {
int temp = 0xff * temperatureMap[x][z] / 100;
temp = temp << 16;
image.setRGB(x, z, temp);
subImage.setRGB(x, z, (0xff * (int) (temperatureMap[x][z] / 20) / 5) << 16);
}
}
ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() + "/temperatureMap.png"));
ImageIO.write(subImage, "png", new File("out/" + region.getX() + "." +region.getZ() + "/reg_temperatureMap.png"));
image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < 256; x ++) {
for (int z = 0; z < 256; z ++) {
int wet = 0xff * wetMap[x][z] / 100;
image.setRGB(x, z, wet);
}
}
ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() + "/wetMap.png"));
image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < 256; x ++) {
for (int z = 0; z < 256; z ++) {
image.setRGB(x, z, biomes[x][z].getColor());
}
}
ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() + "/biomeMap.png"));
} catch (Exception e) {}
// ================================ DEBUG FINISH =======================================
for (int x = 0; x < size; x ++) {
for (int z = 0; z < size; z ++) {
region.setBiome(x, z, biomes[x][z]);
if (heightMap[x][z] < WorldConstants.WORLD_SEA_LEVEL) {
for (int y = 0; y < WorldConstants.WORLD_SEA_LEVEL; y ++) {
Chunk chunk = region.getChunkAt(x / 16, y / 16, z / 16);
if (y == 0) {
chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.BEDROCK, 0));
continue;
}
if (y < heightMap[x][z]) {
if (y < heightMap[x][z] - grassMap[x][z]) {
chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.STONE, 0));
} else {
chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.SAND, 0));
}
} else {
chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.WATER, 0));
}
}
} else {
for (int y = 0; y < heightMap[x][z]; y++) {
Chunk chunk = region.getChunkAt(x / 16, y / 16, z / 16);
if (y == 0) {
chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.BEDROCK, 0));
continue;
}
if (y < heightMap[x][z] - grassMap[x][z]) {
chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.STONE, 0));
} else {
if (biomes[x][z] == Biome.DESERT || biomes[x][z] == Biome.DESERT_HILLS) {
chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.SAND, 0));
} else if (biomes[x][z] == Biome.TAIGA || biomes[x][z] == Biome.TAIGA_HILLS) {
chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.DIRT, 0));
} else {
chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.GRASS, 0));
}
}
}
}
}
}
}
private Biome selectBiome (Temperature temperature, Wetness wetness, int height) {
if (temperature == Temperature.FROST) {
if (height < WorldConstants.WORLD_SEA_LEVEL) {
return Biome.FROZEN_OCEAN;
} else {
if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) {
return Biome.ICE_MOUNTAINS;
} else {
return Biome.ICE_PLAINS;
}
}
}
if (height < WorldConstants.WORLD_SEA_LEVEL) {
if (height < (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MIN_HEIGHT) / 2){
return Biome.DEEP_OCEAN;
} else {
return Biome.OCEAN;
}
}
if (temperature == Temperature.COLD) {
if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) {
return Biome.TAIGA_HILLS;
} else {
return Biome.TAIGA;
}
}
if (temperature == Temperature.WARM) {
if (wetness.ordinal() < 2) {
return Biome.PLAINS;
} else if (wetness == Wetness.WATER){
return Biome.SWAMPLAND;
} else {
if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) {
return Biome.FOREST_HILLS;
} else {
return Biome.FOREST;
}
}
}
if (temperature == Temperature.HOTTEST && wetness.ordinal() < 2) {
if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) {
return Biome.DESERT_HILLS;
} else {
return Biome.DESERT;
}
}
if (wetness.ordinal() > 2) {
if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) {
return Biome.JUNGLE_HILLS;
} else {
return Biome.JUNGLE;
}
}
return Biome.PLAINS;
}
private void smooth (int [][] map) {
final int[][] original = map.clone();
for (int y = 1; y < map.length - 1; y ++) {
for (int x = 1; x < map[0].length - 1; x ++) {
int mid = 0;
for (int tx = x - 1; tx <= x + 1; tx ++) {
for (int ty = y - 1; ty <= y + 1; ty ++) {
mid += original[tx][ty];
}
}
map[x][y] = mid / 9;
}
}
}
}
@RequiredArgsConstructor
private class NoiseGenerator {
int size = 256;
int mask = size - 1;
int[] perm = new int[size];
double[] gradsX = new double[size];
double[] gradsY = new double[size];
private final int seed;
void init() {
for (int i = 0; i < 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 / size);
gradsY[i] = Math.sin(2.0f * Math.PI * i / size);
}
}
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) % 256;
int y = (i + i * x) % 256;
return (int) (Integer.MAX_VALUE * SeedRandomGenerator.random(x, y, seed));
}
}
}

View File

@@ -5,7 +5,7 @@ public final class SeedRandomGenerator {
public static double random (int x, int y, int seed) { public static double random (int x, int y, int seed) {
x = Math.abs(x - y) + 1; x = Math.abs(x - y) + 1;
y = Math.abs(y - x) + 1; y = Math.abs(y - x) + 1;
for (int i = 0; i < 40; i ++) { for (int i = 0; i < 20; i ++) {
int a1 = x % 13; int a1 = x % 13;
int a2 = x % 31; int a2 = x % 31;
int a3 = x % 89; int a3 = x % 89;

View File

@@ -0,0 +1,17 @@
package mc.world.generated_world;
public final class WorldConstants {
public static final String CHUNK_FILE_NAME_TEMPLATE = "chunk_{0}_{1}_{2}.dat";
public static final String BIOME_FILE_NAME_TEMPLATE = "biome_{0}_{1}.dat";
public static final String REGION_FILE_NAME_TEMPLATE = "r.{0}.{1}";
public static final int WORLD_MIN_HEIGHT = 28;
public static final int WORLD_SEA_LEVEL = 64;
public static final int WORLD_MAX_HEIGHT = 128;
public static final int LANDFILL_GRASS_SURFACE_THIN = 5;
public static final double WORLD_ROUGHNRESS = 0.35;
private WorldConstants () {}
}

View File

@@ -0,0 +1,128 @@
package mc.world.generated_world.chunk;
import mc.core.block.Block;
import mc.core.world.Biome;
import mc.core.world.Chunk;
public class ChunkProxy implements Chunk {
private final Chunk chunk;
private volatile long lastUsage = System.currentTimeMillis();
public ChunkProxy(Chunk chunk) {
this.chunk = chunk;
}
public long getLastUsage() {
synchronized (chunk) {
return lastUsage;
}
}
private void use () {
synchronized (chunk) {
lastUsage = System.currentTimeMillis();
}
}
@Override
public int getBlockType(int x, int y, int z) {
use();
return chunk.getBlockType(x, y, z);
}
@Override
public void setBlockType(int x, int y, int z, int type) {
use();
chunk.setBlockType(x, y, z, type);
}
@Override
public int getBlockMetadata(int x, int y, int z) {
use();
return chunk.getBlockMetadata(x, y, z);
}
@Override
public void setBlockMetadata(int x, int y, int z, int metadata) {
use();
chunk.setBlockMetadata(x, y, z, metadata);
}
@Override
public int getBlockLight(int x, int y, int z) {
use();
return chunk.getBlockLight(x, y, z);
}
@Override
public void setBlockLight(int x, int y, int z, int lightLevel) {
use();
chunk.setBlockLight(x, y, z, lightLevel);
}
@Override
public int getSkyLight(int x, int y, int z) {
use();
return chunk.getSkyLight(x, y, z);
}
@Override
public void setSkyLight(int x, int y, int z, int lightLevel) {
use();
chunk.setSkyLight(x, y, z, lightLevel);
}
@Override
public int getAddition(int x, int y, int z) {
use();
return chunk.getAddition(x, y, z);
}
@Override
public void setAddition(int x, int y, int z, int value) {
use();
chunk.setAddition(x, y, z, value);
}
@Override
public Biome getBiome(int x, int z) {
use();
return chunk.getBiome(x, z);
}
@Override
public void setBiome(int x, int z, Biome biome) {
use();
chunk.setBiome(x, z, biome);
}
@Override
public int getX() {
use();
return chunk.getX();
}
@Override
public int getY() {
use();
return chunk.getY();
}
@Override
public int getZ() {
use();
return chunk.getZ();
}
@Override
public Block[] getNotAirBlocks() {
use();
return chunk.getNotAirBlocks();
}
@Override
public void setBlock(int x, int y, int z, Block block) {
use();
chunk.setBlock(x, y, z, block);
}
}

View File

@@ -0,0 +1,9 @@
package mc.world.generated_world.chunk;
import mc.core.world.Chunk;
import mc.core.world.ChunkLoader;
public interface ProxiedChunkLoader extends ChunkLoader {
@Override
Chunk loadOrGenerateChunk(int x, int y, int z);
}

View File

@@ -0,0 +1,63 @@
package mc.world.generated_world.region;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import mc.core.world.*;
import mc.world.generated_world.chunk.ChunkProxy;
import org.springframework.beans.factory.annotation.Autowired;
import java.text.MessageFormat;
@Slf4j
@RequiredArgsConstructor
public class RegionImpl implements Region{
@Getter
private final int x;
@Getter
private final int z;
private final ChunkProxy[][][] chunks = new ChunkProxy[16][16][16];
private final Biome[][] biomes = new Biome[16][16];
@Getter@Setter
private transient World world;
@Autowired
private ChunkLoader chunkLoader;
@Override
public Chunk getChunkAt(int x, int y, int z) {
if (x < 0 || y < 0 || z < 0 || x >= 16 || y >= 16 || z >= 16) {
throw new RuntimeException(MessageFormat.format("Invalid chunk coordinates [{0} {1} {2}]", x, y, z));
}
Chunk chunk = chunks[x][y][z];
if (chunk == null) {
chunk = chunkLoader.loadOrGenerateChunk(x, y, z);
chunks[x][y][z] = new ChunkProxy(chunk);
}
return chunk;
}
@Override
public void setChunk(int x, int y, int z, Chunk chunk) {
if (x < 0 || y < 0 || z < 0 || x >= 16 || y >= 16 || z >= 16) {
throw new RuntimeException(MessageFormat.format("Invalid chunk coordinates [{0} {1} {2}]", x, y, z));
}
chunks[x][y][z] = new ChunkProxy(chunk);
}
@Override
public Biome getBiomeAt(int x, int z) {
if (x < 0 || z < 0 || x >= 16 || z >= 16) {
throw new RuntimeException(MessageFormat.format("Invalid biome coordinates [{0} {1}]", x, z));
}
return biomes[x][z];
}
@Override
public void setBiome(int x, int z, Biome biome) {
if (x < 0 || z < 0 || x >= 16 || z >= 16) {
throw new RuntimeException(MessageFormat.format("Invalid biome coordinates [{0} {1}]", x, z));
}
biomes[x][z] = biome;
}
}

View File

@@ -0,0 +1,9 @@
package mc.world.generated_world.word;
public enum Temperature {
FROST,
COLD,
WARM,
HOT,
HOTTEST
}

View File

@@ -0,0 +1,9 @@
package mc.world.generated_world.word;
public enum Wetness {
DRYEST,
DRY,
WET,
WETTER,
WATER
}

View File

@@ -9,6 +9,38 @@ import java.io.File;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class SeedRandomGeneratorTest { public class SeedRandomGeneratorTest {
@Test
public void randomGenSpeed () {
SeedRandomGenerator.random(0, 0, 0);
long avg = 0;
long min = -1;
long max = 0;
for (int i = 0; i < 500; i ++) {
int x = (int) (Math.random() * 10000);
int y = (int) (Math.random() * 10000);
int seed = (int) (Math.random() * 10000);
long time = System.nanoTime();
SeedRandomGenerator.random(x, y, seed);
time = System.nanoTime() - time;
System.out.printf("[%s] \t%.3fms\n", i+1, time/1000d);
avg += time;
if (min == -1) {
min = time;
} else if (min > time) {
min = time;
}
if (max < time) {
max = time;
}
}
System.out.println();
System.out.printf("Average time: %.3fms\n", avg/500000d);
System.out.printf("Minimum time: %.3fms\n", min/1000d);
System.out.printf("Maximum time: %.3fms\n", max/1000d);
assertTrue(avg/500 < 5000);
}
@Test @Test
public void randomTest() throws Exception { public void randomTest() throws Exception {
double maxDiff = 0; double maxDiff = 0;
@@ -33,10 +65,12 @@ public class SeedRandomGeneratorTest {
maxDisp = disp; maxDisp = disp;
} }
System.out.printf("Iteration %d.\t mid: %.3f, \tdisp %.6f\n", i + 1, mid, disp); System.out.printf("Iteration %d.\t mid: %.3f, \tdisp %.6f\n", i + 1, mid, disp);
assertTrue(Math.abs(mid - 0.5) < 0.15);
} }
System.out.printf("Max diff: %.3f\n", maxDiff); System.out.printf("Max diff: %.3f\n", maxDiff);
System.out.printf("Max disp: %.6f\n", maxDisp); System.out.printf("Max disp: %.6f\n", maxDisp);
assertTrue(maxDiff > 0); assertTrue(maxDiff > 0);
} }