Merge & resolve conflicts
This commit is contained in:
@@ -2,10 +2,10 @@ package mc.world.generated_world.chunk;
|
||||
|
||||
import lombok.Getter;
|
||||
import mc.core.exception.ResourceUnloadedException;
|
||||
import mc.core.world.Chunk;
|
||||
import mc.core.world.ChunkSection;
|
||||
import mc.core.world.Region;
|
||||
import mc.core.world.World;
|
||||
import mc.core.world.chunk.Chunk;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package mc.world.generated_world.chunk;
|
||||
|
||||
import lombok.Getter;
|
||||
import mc.core.block.Block;
|
||||
import mc.core.block.BlockType;
|
||||
import mc.core.exception.ResourceUnloadedException;
|
||||
import mc.core.world.Biome;
|
||||
import mc.core.world.ChunkSection;
|
||||
import mc.core.world.Region;
|
||||
import mc.core.world.World;
|
||||
import mc.core.world.block.Block;
|
||||
import mc.core.world.block.BlockFactory;
|
||||
import mc.core.world.block.BlockType;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
@@ -23,6 +24,7 @@ public class ChunkSectionImpl implements ChunkSection {
|
||||
private final int z;
|
||||
private final Block[][][] blocks = new Block[WORLD_CHUNK_SIZE][WORLD_CHUNK_SIZE][WORLD_CHUNK_SIZE];
|
||||
private final transient Reference<Region> region;
|
||||
private BlockFactory blockFactory = new BlockFactory();
|
||||
|
||||
public ChunkSectionImpl(int x, int y, int z, Region region) {
|
||||
this.x = x;
|
||||
@@ -31,36 +33,6 @@ public class ChunkSectionImpl implements ChunkSection {
|
||||
this.region = new WeakReference<>(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockType(int x, int y, int z) {
|
||||
return blocks[x][y][z].getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockType(int x, int y, int z, int type) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockMetadata(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockMetadata(int x, int y, int z, int metadata) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockLight(int x, int y, int z) {
|
||||
return 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockLight(int x, int y, int z, int lightLevel) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
return 15;
|
||||
@@ -92,19 +64,19 @@ public class ChunkSectionImpl implements ChunkSection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, Block block) {
|
||||
public void setBlock(Block block) {
|
||||
if (block.getBlockType() == BlockType.AIR) {
|
||||
blocks[x][y][z] = null;
|
||||
blocks[block.getLocation().getBlockX()][block.getLocation().getBlockY()][block.getLocation().getBlockZ()] = null;
|
||||
return;
|
||||
}
|
||||
blocks[x][y][z] = block;
|
||||
blocks[block.getLocation().getBlockX()][block.getLocation().getBlockY()][block.getLocation().getBlockZ()] = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block getBlock(int x, int y, int z) {
|
||||
Block block = blocks[x][y][z];
|
||||
if (block == null) {
|
||||
return Block.airBlock(x, y, z);
|
||||
return blockFactory.create(BlockType.AIR, 0, x, y, z);
|
||||
}
|
||||
return blocks[x][y][z];
|
||||
}
|
||||
|
||||
@@ -1,146 +1,108 @@
|
||||
package mc.world.generated_world.chunk;
|
||||
|
||||
import mc.core.block.Block;
|
||||
import mc.core.world.Biome;
|
||||
import mc.core.world.ChunkSection;
|
||||
import mc.core.world.Region;
|
||||
import mc.core.world.World;
|
||||
import mc.core.world.block.Block;
|
||||
import mc.core.world.Biome;
|
||||
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public class ChunkSectionProxy implements ChunkSection {
|
||||
private final ChunkSection chunkSection;
|
||||
private final ChunkSection chunk;
|
||||
private volatile transient long lastUsage = System.currentTimeMillis();
|
||||
private final transient ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
|
||||
|
||||
public ChunkSectionProxy(ChunkSection chunkSection) {
|
||||
this.chunkSection = chunkSection;
|
||||
public ChunkSectionProxy(ChunkSection chunk) {
|
||||
this.chunk = chunk;
|
||||
}
|
||||
|
||||
public long getLastUsage() {
|
||||
synchronized (chunkSection) {
|
||||
synchronized (chunk) {
|
||||
return lastUsage;
|
||||
}
|
||||
}
|
||||
|
||||
private final void use () {
|
||||
synchronized (chunkSection) {
|
||||
synchronized (chunk) {
|
||||
lastUsage = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockType(int x, int y, int z) {
|
||||
public Block getBlock(int x, int y, int z) {
|
||||
use();
|
||||
return chunkSection.getBlockType(x, y, z);
|
||||
return chunk.getBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockType(int x, int y, int z, int type) {
|
||||
use();
|
||||
chunkSection.setBlockType(x, y, z, type);
|
||||
public Region getRegion() {
|
||||
return chunk.getRegion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockMetadata(int x, int y, int z) {
|
||||
use();
|
||||
return chunkSection.getBlockMetadata(x, y, z);
|
||||
public World getWorld() {
|
||||
return chunk.getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockMetadata(int x, int y, int z, int metadata) {
|
||||
public void setBlock(Block block) {
|
||||
use();
|
||||
chunkSection.setBlockMetadata(x, y, z, metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockLight(int x, int y, int z) {
|
||||
use();
|
||||
return chunkSection.getBlockLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockLight(int x, int y, int z, int lightLevel) {
|
||||
use();
|
||||
chunkSection.setBlockLight(x, y, z, lightLevel);
|
||||
chunk.setBlock(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
use();
|
||||
return chunkSection.getSkyLight(x, y, z);
|
||||
return chunk.getSkyLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLight(int x, int y, int z, int lightLevel) {
|
||||
use();
|
||||
chunkSection.setSkyLight(x, y, z, lightLevel);
|
||||
chunk.setSkyLight(x, y, z, lightLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAddition(int x, int y, int z) {
|
||||
use();
|
||||
return chunkSection.getAddition(x, y, z);
|
||||
return chunk.getAddition(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAddition(int x, int y, int z, int value) {
|
||||
use();
|
||||
chunkSection.setAddition(x, y, z, value);
|
||||
chunk.setAddition(x, y, z, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int z) {
|
||||
use();
|
||||
return chunkSection.getBiome(x, z);
|
||||
return chunk.getBiome(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int z, Biome biome) {
|
||||
use();
|
||||
chunkSection.setBiome(x, z, biome);
|
||||
chunk.setBiome(x, z, biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
use();
|
||||
return chunkSection.getX();
|
||||
return chunk.getX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
use();
|
||||
return chunkSection.getY();
|
||||
return chunk.getY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
use();
|
||||
return chunkSection.getZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, Block block) {
|
||||
use();
|
||||
chunkSection.setBlock(x, y, z, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block getBlock(int x, int y, int z) {
|
||||
use();
|
||||
return chunkSection.getBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region getRegion() {
|
||||
use();
|
||||
return chunkSection.getRegion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getWorld() {
|
||||
use();
|
||||
return chunkSection.getWorld();
|
||||
return chunk.getZ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package mc.world.generated_world.chunk;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mc.core.serialization.Serializer;
|
||||
import mc.core.world.*;
|
||||
import mc.core.world.chunk.Chunk;
|
||||
import mc.core.world.chunk.ChunkLoader;
|
||||
import mc.world.generated_world.serialization.ChunkReader;
|
||||
import mc.world.generated_world.serialization.RegionReaderWriter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,10 @@ package mc.world.generated_world.generator;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mc.core.block.BlockFactory;
|
||||
import mc.core.block.BlockType;
|
||||
import mc.core.world.block.BlockFactory;
|
||||
import mc.core.world.block.BlockType;
|
||||
import mc.core.world.*;
|
||||
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.world.CubicWorld;
|
||||
import mc.world.generated_world.world.Temperature;
|
||||
import mc.world.generated_world.world.Wetness;
|
||||
@@ -15,6 +13,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.*;
|
||||
@@ -25,24 +24,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;
|
||||
@@ -50,87 +51,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
|
||||
@@ -160,7 +80,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());
|
||||
@@ -305,37 +225,37 @@ public class SeedBasedWorldGenerator implements WorldGenerator {
|
||||
region.setBiome(x, z, biomes[x][z]);
|
||||
if (heightMap[x][z] < WORLD_SEA_LEVEL) {
|
||||
for (int y = 0; y < WORLD_SEA_LEVEL; y ++) {
|
||||
ChunkSection chunkSection = region.getChunkAt(x / 16, y / 16, z / 16);
|
||||
ChunkSection chunk = region.getChunkAt(x / 16, y / 16, z / 16);
|
||||
if (y == 0) {
|
||||
chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.BEDROCK, 0));
|
||||
chunk.setBlock(blockFactory.create(BlockType.BEDROCK, 0, x % 16, y % 16, z % 16));
|
||||
continue;
|
||||
}
|
||||
if (y < heightMap[x][z]) {
|
||||
if (y < heightMap[x][z] - grassMap[x][z]) {
|
||||
chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.STONE, 0));
|
||||
chunk.setBlock(blockFactory.create(BlockType.STONE, 0, x % 16, y % 16, z % 16));
|
||||
} else {
|
||||
chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.SAND, 0));
|
||||
chunk.setBlock(blockFactory.create(BlockType.SAND, 0, x % 16, y % 16, z % 16));
|
||||
}
|
||||
} else {
|
||||
chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.WATER, 0));
|
||||
chunk.setBlock(blockFactory.create(BlockType.WATER, 0, x % 16, y % 16, z % 16));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < heightMap[x][z]; y++) {
|
||||
ChunkSection chunkSection = region.getChunkAt(x / 16, y / 16, z / 16);
|
||||
ChunkSection chunk = region.getChunkAt(x / 16, y / 16, z / 16);
|
||||
if (y == 0) {
|
||||
chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.BEDROCK, 0));
|
||||
chunk.setBlock(blockFactory.create(BlockType.BEDROCK, 0, x % 16, y % 16, z % 16));
|
||||
continue;
|
||||
}
|
||||
if (y < heightMap[x][z] - grassMap[x][z]) {
|
||||
chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.STONE, 0));
|
||||
chunk.setBlock(blockFactory.create(BlockType.STONE, 0, x % 16, y % 16, z % 16));
|
||||
} else {
|
||||
if (biomes[x][z] == Biome.DESERT || biomes[x][z] == Biome.DESERT_HILLS) {
|
||||
chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.SAND, 0));
|
||||
chunk.setBlock(blockFactory.create(BlockType.SAND, 0, x % 16, y % 16, z % 16));
|
||||
} else if (biomes[x][z] == Biome.TAIGA || biomes[x][z] == Biome.TAIGA_HILLS) {
|
||||
chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.DIRT, 0));
|
||||
chunk.setBlock(blockFactory.create(BlockType.DIRT, 0, x % 16, y % 16, z % 16));
|
||||
} else {
|
||||
chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.GRASS, 0));
|
||||
chunk.setBlock(blockFactory.create(BlockType.GRASS, 0, x % 16, y % 16, z % 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,7 +299,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;
|
||||
@@ -433,7 +353,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator {
|
||||
return Biome.FOREST;
|
||||
}
|
||||
} else {
|
||||
return Biome.SAVANNA_FOREST;
|
||||
return Biome.SAVANNA_PLATO;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,54 +388,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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,10 +6,12 @@ import mc.core.exception.ResourceUnloadedException;
|
||||
import mc.core.serialization.IRegionReaderWriter;
|
||||
import mc.core.serialization.Serializer;
|
||||
import mc.core.world.*;
|
||||
import mc.world.generated_world.chunk.ChunkImpl;
|
||||
import mc.world.generated_world.chunk.ChunkSectionImpl;
|
||||
import mc.core.world.chunk.Chunk;
|
||||
import mc.core.world.chunk.ChunkLoader;
|
||||
import mc.world.generated_world.chunk.ChunkSectionProxy;
|
||||
import mc.world.generated_world.chunk.InMemoryCacheChunkLoader;
|
||||
import mc.world.generated_world.chunk.ChunkImpl;
|
||||
import mc.world.generated_world.chunk.ChunkSectionImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package mc.world.generated_world.serialization;
|
||||
|
||||
import mc.core.block.Block;
|
||||
import mc.core.block.BlockFactory;
|
||||
import mc.core.block.BlockType;
|
||||
import mc.core.world.block.Block;
|
||||
import mc.core.world.block.BlockFactory;
|
||||
import mc.core.world.block.BlockType;
|
||||
import mc.core.serialization.Deserializer;
|
||||
import mc.core.serialization.Serializer;
|
||||
import mc.core.world.ChunkSection;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package mc.world.generated_world.serialization;
|
||||
|
||||
import mc.core.Location;
|
||||
import mc.core.block.Block;
|
||||
import mc.core.world.block.Block;
|
||||
import mc.core.serialization.Deserializer;
|
||||
import mc.core.serialization.IChunkReader;
|
||||
import mc.core.world.ChunkSection;
|
||||
@@ -41,8 +41,7 @@ public class ChunkReader implements IChunkReader{
|
||||
blockBytes[1] = chunkBytes[1 + 3 * i];
|
||||
blockBytes[2] = chunkBytes[2 + 3 * i];
|
||||
Block block = blockDeserializer.deserialize(blockBytes);
|
||||
Location blockLocation = block.getLocation();
|
||||
chunkSection.setBlock(blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ(), block);
|
||||
chunkSection.setBlock(block);
|
||||
}
|
||||
return chunkSection;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package mc.world.generated_world.serialization;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mc.core.block.Block;
|
||||
import mc.core.block.BlockFactory;
|
||||
import mc.core.block.BlockType;
|
||||
import mc.core.world.block.Block;
|
||||
import mc.core.world.block.BlockFactory;
|
||||
import mc.core.world.block.BlockType;
|
||||
import mc.core.serialization.Serializer;
|
||||
import mc.core.world.ChunkSection;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@@ -4,34 +4,66 @@ import com.flowpowered.nbt.Tag;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mc.core.Direction;
|
||||
import mc.core.Location;
|
||||
import mc.core.WarpPosition;
|
||||
import mc.core.block.BlockType;
|
||||
import mc.core.player.Look;
|
||||
import mc.core.world.ChunkSection;
|
||||
import mc.core.world.IWorldType;
|
||||
import mc.core.world.Region;
|
||||
import mc.core.world.World;
|
||||
import mc.core.world.WorldGenerator;
|
||||
import mc.core.world.block.BlockType;
|
||||
import mc.core.world.chunk.Chunk;
|
||||
import mc.world.generated_world.serialization.RegionReaderWriter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE;
|
||||
import static mc.world.generated_world.WorldConstants.WORLD_MAX_HEIGHT;
|
||||
import static mc.world.generated_world.WorldConstants.*;
|
||||
|
||||
/*
|
||||
* NORTH
|
||||
*
|
||||
* EAST WEST
|
||||
*
|
||||
* SOUTH
|
||||
*
|
||||
* + ----> X
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* V Z
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
public class CubicWorld implements World {
|
||||
private int pointX = -1;
|
||||
private int pointZ = -1;
|
||||
private int sizeX = 2;
|
||||
private int sizeZ = 2;
|
||||
private Region[][] regions = new Region[sizeX][sizeZ];
|
||||
private final Lock regionSaveLock = new ReentrantLock();
|
||||
@Autowired
|
||||
private RegionReaderWriter regionReaderWriter;
|
||||
@Autowired
|
||||
private WorldGenerator worldGenerator;
|
||||
@Setter
|
||||
private boolean autoSaveRegionAfterGenerating = true;
|
||||
@Getter
|
||||
private final UUID worldId;
|
||||
private final int seed;
|
||||
private volatile WarpPosition warpPosition;
|
||||
private final transient Object spawnLocationLock = new Object();
|
||||
private final Map<String, Tag<?>> nbtTagMap = new HashMap<>();
|
||||
@Autowired
|
||||
private RegionManager regionManager;
|
||||
@Getter@Setter
|
||||
private String name;
|
||||
|
||||
@@ -62,23 +94,8 @@ public class CubicWorld implements World {
|
||||
|
||||
@Override
|
||||
public WarpPosition getSpawn() {
|
||||
if (warpPosition == null) {
|
||||
synchronized (spawnLocationLock) {
|
||||
if (warpPosition == null) {
|
||||
log.warn("Spawn location is not defined. Trying to select best location");
|
||||
warpPosition = new WarpPosition(Location.startPointLocation(), new Look(0, 0));
|
||||
for (int y = WORLD_MAX_HEIGHT; y > 0; y --) {
|
||||
ChunkSection chunkSection = getChunk(0,y / WORLD_CHUNK_SIZE, 0);
|
||||
if (chunkSection.getBlock(0, y, 0).getBlockType() != BlockType.AIR) {
|
||||
warpPosition = new WarpPosition(new Location(0, y + 1, 0), new Look(0, 0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
warpPosition = new WarpPosition(Location.startPointLocation(), new Look(0,0));
|
||||
}
|
||||
}
|
||||
}
|
||||
return warpPosition;
|
||||
/* FIXME */
|
||||
return new WarpPosition(new Location(0, 100, 0), new Look(0, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,12 +117,42 @@ public class CubicWorld implements World {
|
||||
|
||||
@Override
|
||||
public Region getRegion(int x, int z) {
|
||||
return null;
|
||||
checkCoordsInCache(x, z);
|
||||
Region region;
|
||||
if (regions[x - pointX][z - pointZ] == null) {
|
||||
File file = new File(new File("worlds", this.getWorldId().toString()), MessageFormat.format(REGION_FILE_NAME_TEMPLATE, x, z));
|
||||
if (!file.exists()) {
|
||||
region = worldGenerator.generateRegion(x, z, this);
|
||||
if (autoSaveRegionAfterGenerating) {
|
||||
try {
|
||||
regionReaderWriter.write(region);
|
||||
} catch (IOException e) {
|
||||
log.error("Error occurred while saving region data");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
region = regionReaderWriter.read(x, z, this);
|
||||
} catch (IOException e) {
|
||||
log.error("Error occurred while loading region");
|
||||
region = null;
|
||||
}
|
||||
}
|
||||
setRegion(region.getX(), region.getZ(), region);
|
||||
} else {
|
||||
region = regions[x - pointX][z - pointZ];
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRegion(int x, int z, Region region) {
|
||||
|
||||
try {
|
||||
regionSaveLock.lock();
|
||||
regions[x - pointX][z - pointZ] = region;
|
||||
} finally {
|
||||
regionSaveLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,4 +174,53 @@ public class CubicWorld implements World {
|
||||
public Stream<Tag<?>> tagStream() {
|
||||
return nbtTagMap.values().stream();
|
||||
}
|
||||
|
||||
private void checkCoordsInCache (int x, int z) {
|
||||
if (x < pointX) {
|
||||
addLines(Direction.EAST, pointX - x);
|
||||
} else if (x > pointX + sizeX) {
|
||||
addLines(Direction.WEST, x - (pointX + sizeX));
|
||||
} else if (z < pointZ) {
|
||||
addLines(Direction.NORTH, pointZ - z);
|
||||
} else if (z > pointZ + sizeZ) {
|
||||
addLines(Direction.SOUTH, z - (pointZ + sizeZ));
|
||||
}
|
||||
}
|
||||
|
||||
private void addLines (Direction direction, int amount) {
|
||||
int addBeforeX = 0;
|
||||
int addAfterX = 0;
|
||||
int addBeforeZ = 0;
|
||||
int addAfterZ = 0;
|
||||
switch (direction) {
|
||||
case NORTH:
|
||||
addBeforeZ = amount;
|
||||
break;
|
||||
case EAST:
|
||||
addBeforeX = amount;
|
||||
break;
|
||||
case WEST:
|
||||
addAfterX = amount;
|
||||
break;
|
||||
case SOUTH:
|
||||
addAfterZ = amount;
|
||||
break;
|
||||
}
|
||||
try {
|
||||
regionSaveLock.lock();
|
||||
int tempSizeX = sizeX + addAfterX + addBeforeX;
|
||||
int tempSizeZ = sizeZ + addAfterZ + addBeforeZ;
|
||||
Region[][] temp = new Region[tempSizeX][tempSizeZ];
|
||||
for (int x = 0; x < sizeX; x ++) {
|
||||
System.arraycopy(regions[x], 0, temp[x + addBeforeX], addBeforeZ, sizeZ);
|
||||
}
|
||||
|
||||
this.sizeX = tempSizeX;
|
||||
this.sizeZ = tempSizeZ;
|
||||
this.pointX = pointX - addBeforeX;
|
||||
this.pointZ = pointZ - addBeforeZ;
|
||||
} finally {
|
||||
regionSaveLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
package mc.world.generated_world.world;
|
||||
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mc.core.Direction;
|
||||
import mc.core.world.Region;
|
||||
import mc.core.world.World;
|
||||
import mc.core.world.WorldGenerator;
|
||||
import mc.world.generated_world.serialization.RegionReaderWriter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static mc.world.generated_world.WorldConstants.REGION_FILE_NAME_TEMPLATE;
|
||||
|
||||
/*
|
||||
* NORTH
|
||||
*
|
||||
* EAST WEST
|
||||
*
|
||||
* SOUTH
|
||||
*
|
||||
* + ----> X
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* V Z
|
||||
*/
|
||||
@Slf4j
|
||||
public class RegionManager {
|
||||
private final World world;
|
||||
private int pointX = -1;
|
||||
private int pointZ = -1;
|
||||
private int sizeX = 2;
|
||||
private int sizeZ = 2;
|
||||
private Region[][] regions = new Region[sizeX][sizeZ];
|
||||
private final Lock regionSaveLock = new ReentrantLock();
|
||||
@Autowired
|
||||
private RegionReaderWriter regionReaderWriter;
|
||||
@Autowired
|
||||
private WorldGenerator worldGenerator;
|
||||
@Setter
|
||||
private boolean autoSaveRegionAfterGenerating = true;
|
||||
|
||||
|
||||
public RegionManager(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public void setRegion (Region region) {
|
||||
int x = region.getX();
|
||||
int z = region.getZ();
|
||||
|
||||
try {
|
||||
regionSaveLock.lock();
|
||||
regions[x - pointX][z - pointZ] = region;
|
||||
} finally {
|
||||
regionSaveLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCoordsInCache (int x, int z) {
|
||||
if (x < pointX) {
|
||||
addLines(Direction.EAST, pointX - x);
|
||||
} else if (x > pointX + sizeX) {
|
||||
addLines(Direction.WEST, x - (pointX + sizeX));
|
||||
} else if (z < pointZ) {
|
||||
addLines(Direction.NORTH, pointZ - z);
|
||||
} else if (z > pointZ + sizeZ) {
|
||||
addLines(Direction.SOUTH, z - (pointZ + sizeZ));
|
||||
}
|
||||
}
|
||||
|
||||
public Region getRegion (int x, int z) {
|
||||
checkCoordsInCache(x, z);
|
||||
Region region;
|
||||
if (regions[x - pointX][z - pointZ] == null) {
|
||||
File file = new File(new File("worlds", world.getWorldId().toString()), MessageFormat.format(REGION_FILE_NAME_TEMPLATE, x, z));
|
||||
if (!file.exists()) {
|
||||
region = worldGenerator.generateRegion(x, z, world);
|
||||
if (autoSaveRegionAfterGenerating) {
|
||||
try {
|
||||
regionReaderWriter.write(region);
|
||||
} catch (IOException e) {
|
||||
log.error("Error occurred while saving region data");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
region = regionReaderWriter.read(x, z, world);
|
||||
} catch (IOException e) {
|
||||
log.error("Error occurred while loading region");
|
||||
region = null;
|
||||
}
|
||||
}
|
||||
setRegion(region);
|
||||
} else {
|
||||
region = regions[x - pointX][z - pointZ];
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
private void addLines (Direction direction, int amount) {
|
||||
int addBeforeX = 0;
|
||||
int addAfterX = 0;
|
||||
int addBeforeZ = 0;
|
||||
int addAfterZ = 0;
|
||||
switch (direction) {
|
||||
case NORTH:
|
||||
addBeforeZ = amount;
|
||||
break;
|
||||
case EAST:
|
||||
addBeforeX = amount;
|
||||
break;
|
||||
case WEST:
|
||||
addAfterX = amount;
|
||||
break;
|
||||
case SOUTH:
|
||||
addAfterZ = amount;
|
||||
break;
|
||||
}
|
||||
try {
|
||||
int tempSizeX = sizeX + addAfterX + addBeforeX;
|
||||
int tempSizeZ = sizeZ + addAfterZ + addBeforeZ;
|
||||
Region[][] temp = new Region[tempSizeX][tempSizeZ];
|
||||
for (int x = 0; x < sizeX; x ++) {
|
||||
System.arraycopy(regions[x], 0, temp[x + addBeforeX], addBeforeZ, sizeZ);
|
||||
}
|
||||
|
||||
this.sizeX = tempSizeX;
|
||||
this.sizeZ = tempSizeZ;
|
||||
this.pointX = pointX - addBeforeX;
|
||||
this.pointZ = pointZ - addBeforeZ;
|
||||
} finally {
|
||||
regionSaveLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package mc.world.generated_world;
|
||||
|
||||
import mc.world.generated_world.generator.SeedRandomGenerator;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
@@ -9,6 +10,7 @@ import java.io.File;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@Ignore
|
||||
public class SeedRandomGeneratorTest {
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user