Archived
0

Merge & resolve conflicts

This commit is contained in:
Forwolk
2018-08-09 20:59:02 +03:00
34 changed files with 591 additions and 557 deletions

View File

@@ -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;

View File

@@ -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];
}

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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));
}
}

View File

@@ -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));
}
}
}

View File

@@ -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;

View 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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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