Chunk generations & basic saving
This commit is contained in:
@@ -25,6 +25,30 @@ import mc.core.Location;
|
||||
|
||||
public interface Block {
|
||||
|
||||
static Block airBlock (int x, int y, int z) {
|
||||
return new Block() {
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMeta() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockType getBlockType() {
|
||||
return BlockType.AIR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return new Location(x, y, z);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Block id */
|
||||
int getId();
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package mc.core.block;
|
||||
|
||||
import mc.core.Location;
|
||||
|
||||
public class BlockFactory {
|
||||
|
||||
public Block create(BlockType blockType, int meta) {
|
||||
@@ -12,6 +14,7 @@ public class BlockFactory {
|
||||
private class EmbeddedBlock extends AbstractBlock {
|
||||
EmbeddedBlock(BlockType type, int meta) {
|
||||
super(type, meta);
|
||||
super.setLocation(new Location(0,0,0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ public enum BlockType {
|
||||
BEDROCK(7, "Bedrock"),
|
||||
WATER(8, "Water"),
|
||||
SAND(12, "Sand"),
|
||||
SNOW(32, "Snow");
|
||||
SNOW(32, "Snow"),
|
||||
AIR(0, "Air");
|
||||
|
||||
@Getter
|
||||
private final int id;
|
||||
|
||||
@@ -47,6 +47,7 @@ public interface Chunk {
|
||||
int getY();
|
||||
int getZ();
|
||||
|
||||
Block[] getNotAirBlocks();
|
||||
Block[] getModifiedBlocks();
|
||||
void setBlock (int x, int y, int z, Block block);
|
||||
Block getBlock (int x, int y, int z);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package mc.core.world;
|
||||
|
||||
import mc.core.serialization.Serializer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Simple world generation unit
|
||||
* 16x16x16 chunks
|
||||
@@ -23,4 +27,6 @@ public interface Region {
|
||||
|
||||
Biome getBiomeAt (int x, int z);
|
||||
void setBiome (int x, int z, Biome biome);
|
||||
|
||||
void save(Serializer<Chunk> chunkSerializer, Serializer<Region> regionSerializer) throws IOException;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
package mc.world.flat;
|
||||
|
||||
import mc.core.block.Block;
|
||||
import mc.core.block.BlockFactory;
|
||||
import mc.core.block.BlockType;
|
||||
import mc.core.world.Biome;
|
||||
import mc.core.world.Chunk;
|
||||
|
||||
@@ -89,7 +91,7 @@ public class SimpleChunk implements Chunk {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block[] getNotAirBlocks() {
|
||||
public Block[] getModifiedBlocks() {
|
||||
return new Block[0];
|
||||
}
|
||||
|
||||
@@ -97,4 +99,14 @@ public class SimpleChunk implements Chunk {
|
||||
public void setBlock(int x, int y, int z, Block block) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block getBlock(int x, int y, int z) {
|
||||
BlockFactory blockFactory = new BlockFactory();
|
||||
|
||||
if (y == 0) return blockFactory.create(BlockType.BEDROCK, 0);
|
||||
else if (y >= 1 && y <= 2) return blockFactory.create(BlockType.DIRT, 0);
|
||||
else if (y == 3) return blockFactory.create(BlockType.GRASS, 0);
|
||||
else return Block.airBlock(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package mc.world.generated_world;
|
||||
|
||||
import mc.core.block.BlockFactory;
|
||||
import mc.core.serialization.BlockDeserializer;
|
||||
import mc.core.serialization.BlockSerializer;
|
||||
import mc.core.serialization.ChunkSerializer;
|
||||
import mc.core.serialization.ChunkDeserializer;
|
||||
import mc.core.world.Chunk;
|
||||
|
||||
public class ChunkSerializerDeserializer implements ChunkSerializer, ChunkDeserializer {
|
||||
|
||||
private BlockSerializer blockSerializer;
|
||||
private BlockDeserializer blockDeserializer;
|
||||
|
||||
@Override
|
||||
public Chunk deserialize(byte[] bytes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(Chunk chunk) {
|
||||
BlockSerializer blockSerializer = new BlockSerializerDeserializer(new BlockFactory(), chunk);
|
||||
int blocks = chunk.getModifiedBlocks().length;
|
||||
byte[] bytes = new byte[6 + 3 * blocks];
|
||||
|
||||
bytes[0] = (byte) ((chunk.getX() >> 6) & 0xff);
|
||||
bytes[1] = (byte) (((chunk.getX() & 0x3f) << 2) | ((chunk.getY()) >> 2) & 0x03);
|
||||
bytes[2] = (byte) (((chunk.getY() & 0x03) << 6) | ((chunk.getZ() >> 8) & 0x3f));
|
||||
bytes[3] = (byte) (chunk.getZ() & 0xff);
|
||||
bytes[4] = (byte) ((blocks >> 5) & 0xff);
|
||||
bytes[5] = (byte) ((blocks & 0x1f) << 3);
|
||||
|
||||
for (int i = 0; i < blocks; i ++) {
|
||||
byte[] blockSerialized = blockSerializer.serialize(chunk.getModifiedBlocks()[i]);
|
||||
for (int j = 0; j < 3; j ++) {
|
||||
bytes[6 + i * 3 + j] = blockSerialized[j];
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
@@ -16,25 +16,25 @@ public class CubicWorld implements World {
|
||||
|
||||
public CubicWorld(UUID worldId, int seed) {
|
||||
this.worldId = worldId;
|
||||
chunkLoader = new InMemoryCacheChunkLoader(worldId);
|
||||
chunkLoader = new InMemoryCacheChunkLoader(this);
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
public CubicWorld(int seed) {
|
||||
this.worldId = UUID.randomUUID();
|
||||
chunkLoader = new InMemoryCacheChunkLoader(worldId);
|
||||
chunkLoader = new InMemoryCacheChunkLoader(this);
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
public CubicWorld(UUID worldId) {
|
||||
this.worldId = worldId;
|
||||
chunkLoader = new InMemoryCacheChunkLoader(worldId);
|
||||
chunkLoader = new InMemoryCacheChunkLoader(this);
|
||||
this.seed = 0;
|
||||
}
|
||||
|
||||
public CubicWorld () {
|
||||
this.worldId = UUID.randomUUID();
|
||||
chunkLoader = new InMemoryCacheChunkLoader(worldId);
|
||||
chunkLoader = new InMemoryCacheChunkLoader(this);
|
||||
this.seed = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
package mc.world.generated_world;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mc.core.serialization.ChunkDeserializer;
|
||||
import mc.core.serialization.ChunkSerializer;
|
||||
import mc.core.serialization.Deserializer;
|
||||
import mc.core.serialization.Serializer;
|
||||
import mc.core.world.*;
|
||||
import mc.world.generated_world.region.RegionImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static mc.world.generated_world.WorldConstants.*;
|
||||
|
||||
@Slf4j
|
||||
public class InMemoryCacheChunkLoader implements ChunkLoader {
|
||||
|
||||
private final World world;
|
||||
private File worldFolder;
|
||||
@Autowired
|
||||
private WorldGenerator worldGenerator;
|
||||
|
||||
@Autowired
|
||||
private ChunkDeserializer chunkDeserializer;
|
||||
@Autowired
|
||||
private ChunkSerializer chunkSerializer;
|
||||
@Autowired
|
||||
private Serializer<Region> regionSerializer;
|
||||
@Autowired
|
||||
private Deserializer<Region> regionDeserializer;
|
||||
|
||||
public InMemoryCacheChunkLoader(World world) {
|
||||
this.world = world;
|
||||
String worldPath = System.getProperty("worlds.folder", "worlds");
|
||||
worldFolder = new File(worldPath, world.getWorldId().toString());
|
||||
if (!worldFolder.exists()) {
|
||||
log.info("Created folder for world with uuid '{}'", world.getWorldId());
|
||||
worldFolder.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
private File getChuckFile(int x, int y, int z) {
|
||||
return new File(worldFolder, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Chunk> loadChunk(int x, int y, int z) {
|
||||
File file = getChuckFile(x, y, z);
|
||||
if (!file.exists()) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
try {
|
||||
byte[] bytes = Files.readAllBytes(Paths.get(file.toURI()));
|
||||
return Optional.of(chunkDeserializer.deserialize(bytes));
|
||||
} catch (IOException e) {
|
||||
log.error("Error occurred while reading chunk file: " + file.getAbsolutePath(), e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk loadOrGenerateChunk(int x, int y, int z) {
|
||||
int regX = x / WORLD_REGION_SIZE;
|
||||
int regZ = z / WORLD_REGION_SIZE;
|
||||
File regionFile = new File(worldFolder, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, regX, regZ));
|
||||
Region region;
|
||||
Chunk chunk;
|
||||
if (!regionFile.exists()) {
|
||||
log.debug("Region [{}, {}] not found. Generating!", regX, regZ);
|
||||
regionFile.mkdirs();
|
||||
region = worldGenerator.generateRegion(regX, regZ, world);
|
||||
File biomeMapFile = new File(regionFile, BIOME_FILE_NAME_TEMPLATE);
|
||||
byte[] biomeMapBytes = regionSerializer.serialize(region);
|
||||
try (FileOutputStream writer = new FileOutputStream(biomeMapFile)) {
|
||||
writer.write(biomeMapBytes);
|
||||
} catch (IOException e) {
|
||||
log.error("Error occurred while writting biome file", e);
|
||||
}
|
||||
saveRegion(region);
|
||||
chunk = region.getChunkAt(x % WORLD_CHUNK_SIZE, y % WORLD_CHUNK_SIZE, z % WORLD_CHUNK_SIZE);
|
||||
} else {
|
||||
File chunkFile = new File(regionFile, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x % WORLD_CHUNK_SIZE, y % WORLD_CHUNK_SIZE, z % WORLD_CHUNK_SIZE));
|
||||
try {
|
||||
byte[] chunkBytes = Files.readAllBytes(Paths.get(chunkFile.toURI()));
|
||||
byte[] regionBytes = Files.readAllBytes(Paths.get(new File(regionFile, BIOME_FILE_NAME_TEMPLATE).toURI()));
|
||||
region = regionDeserializer.deserialize(regionBytes);
|
||||
chunk = chunkDeserializer.deserialize(chunkBytes);
|
||||
} catch (IOException e) {
|
||||
log.error("Error occurred while reading chunk file", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
for (int tx = 0; tx < WORLD_CHUNK_SIZE; tx++) {
|
||||
for (int tz = 0; tz < WORLD_CHUNK_SIZE; tz ++) {
|
||||
chunk.setBiome(tx, tz, region.getBiomeAt(chunk.getX() * WORLD_CHUNK_SIZE + x, chunk.getZ() * WORLD_CHUNK_SIZE + z));
|
||||
}
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private void saveRegion (Region region) {
|
||||
File file = new File(worldFolder, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, region.getX(), region.getZ()));
|
||||
for (int x = 0; x < WORLD_REGION_SIZE / WORLD_CHUNK_SIZE; x ++) {
|
||||
for (int y = 0; y < WORLD_REGION_SIZE / WORLD_CHUNK_SIZE; y ++) {
|
||||
for (int z = 0; z < WORLD_REGION_SIZE / WORLD_CHUNK_SIZE; z ++) {
|
||||
byte[] chunkBytes = chunkSerializer.serialize(region.getChunkAt(x, y, z));
|
||||
File chunkFile = new File(file, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x, y, z));
|
||||
try (FileOutputStream writer = new FileOutputStream(chunkFile)) {
|
||||
writer.write(chunkBytes);
|
||||
} catch (IOException e) {
|
||||
log.error("Error occurred while writting chunk to file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package mc.world.generated_world;
|
||||
|
||||
import mc.core.serialization.Deserializer;
|
||||
import mc.core.serialization.Serializer;
|
||||
import mc.core.world.Region;
|
||||
|
||||
public class RegionSerializerDeserializer implements Serializer<Region>, Deserializer<Region> {
|
||||
@Override
|
||||
public Region deserialize(byte[] bytes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(Region region) {
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ 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;
|
||||
@@ -19,7 +20,8 @@ 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);
|
||||
Region region = worldGenerator.generateRegion(0, 0, world);
|
||||
region.save(new ChunkSerializerDeserializer(), new RegionSerializerDeserializer());
|
||||
/*worldGenerator.generateRegion(1, 0, world);
|
||||
worldGenerator.generateRegion(-1, 0, world);
|
||||
worldGenerator.generateRegion(0, 1, world);
|
||||
@@ -83,7 +85,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator {
|
||||
|
||||
@Override
|
||||
public Region generateRegion(int x, int z, World world) {
|
||||
Region region = new RegionImpl(x,z);
|
||||
Region region = new RegionImpl(x, z, world);
|
||||
RegionGenerator regionGenerator = new RegionGenerator(world, region);
|
||||
regionGenerator.generate();
|
||||
return region;
|
||||
@@ -233,7 +235,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator {
|
||||
} catch (Exception e) {}
|
||||
// ================================ DEBUG FINISH =======================================
|
||||
|
||||
/*for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) {
|
||||
for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) {
|
||||
for (int z = 0; z < WorldConstants.WORLD_REGION_SIZE; z ++) {
|
||||
region.setBiome(x, z, biomes[x][z]);
|
||||
if (heightMap[x][z] < WORLD_SEA_LEVEL) {
|
||||
@@ -274,7 +276,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
private Biome selectBiome (Temperature temperature, Wetness wetness, int height) {
|
||||
|
||||
@@ -3,13 +3,14 @@ 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 BIOME_FILE_NAME_TEMPLATE = "biomes.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 WORLD_REGION_SIZE = 256;
|
||||
public static final int WORLD_CHUNK_SIZE = 16;
|
||||
public static final int WORLD_MAX_TEMPERATURE = 100;
|
||||
public static final int WORLD_MAX_WETNESS = 100;
|
||||
public static final int WORLD_BASE_WETNESS = 80;
|
||||
@@ -23,7 +24,7 @@ public final class WorldConstants {
|
||||
|
||||
|
||||
public static final int LANDFILL_GRASS_SURFACE_THIN = 5;
|
||||
public static final double WORLD_ROUGHNRESS = 0.35;
|
||||
public static final double WORLD_ROUGHNESS = 0.35;
|
||||
|
||||
private WorldConstants () {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
package mc.world.generated_world.chunk;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import mc.core.block.Block;
|
||||
import mc.core.world.Biome;
|
||||
import mc.core.world.Chunk;
|
||||
import mc.core.world.Region;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ChunkImpl implements Chunk{
|
||||
@Getter
|
||||
private final int x;
|
||||
@Getter
|
||||
private final int y;
|
||||
@Getter
|
||||
private final int z;
|
||||
private final Block[][][] blocks = new Block[WORLD_CHUNK_SIZE][WORLD_CHUNK_SIZE][WORLD_CHUNK_SIZE];
|
||||
private final transient List<Block> modifiedBlocks = new LinkedList<>();
|
||||
private final transient Region 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLight(int x, int y, int z, int lightLevel) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAddition(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAddition(int x, int y, int z, int value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int z) {
|
||||
return region.getBiomeAt(x + this.x * WORLD_CHUNK_SIZE,z + this.z * WORLD_CHUNK_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int z, Biome biome) {
|
||||
region.setBiome(x + this.x * WORLD_CHUNK_SIZE,z + this.z * WORLD_CHUNK_SIZE, biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block[] getModifiedBlocks() {
|
||||
return modifiedBlocks.toArray(new Block[modifiedBlocks.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, Block block) {
|
||||
blocks[x][y][z] = block;
|
||||
modifiedBlocks.add(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 blocks[x][y][z];
|
||||
}
|
||||
}
|
||||
@@ -115,9 +115,9 @@ public class ChunkProxy implements Chunk {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block[] getNotAirBlocks() {
|
||||
public Block[] getModifiedBlocks() {
|
||||
use();
|
||||
return chunk.getNotAirBlocks();
|
||||
return chunk.getModifiedBlocks();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,4 +125,10 @@ public class ChunkProxy implements Chunk {
|
||||
use();
|
||||
chunk.setBlock(x, y, z, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block getBlock(int x, int y, int z) {
|
||||
use();
|
||||
return chunk.getBlock(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,21 @@ package mc.world.generated_world.region;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mc.core.serialization.Serializer;
|
||||
import mc.core.world.*;
|
||||
import mc.world.generated_world.InMemoryCacheChunkLoader;
|
||||
import mc.world.generated_world.chunk.ChunkImpl;
|
||||
import mc.world.generated_world.chunk.ChunkProxy;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import static mc.world.generated_world.WorldConstants.*;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class RegionImpl implements Region{
|
||||
@@ -17,10 +24,10 @@ public class RegionImpl implements Region{
|
||||
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;
|
||||
private final ChunkProxy[][][] chunks = new ChunkProxy[WORLD_REGION_SIZE/WORLD_CHUNK_SIZE][WORLD_REGION_SIZE/WORLD_CHUNK_SIZE][WORLD_REGION_SIZE/WORLD_CHUNK_SIZE];
|
||||
private final Biome[][] biomes = new Biome[WORLD_REGION_SIZE][WORLD_REGION_SIZE];
|
||||
@Getter
|
||||
private final transient World world;
|
||||
@Autowired
|
||||
private ChunkLoader chunkLoader;
|
||||
|
||||
@@ -29,9 +36,12 @@ public class RegionImpl implements Region{
|
||||
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));
|
||||
}
|
||||
if (chunkLoader == null) {
|
||||
chunkLoader = new InMemoryCacheChunkLoader(world);
|
||||
}
|
||||
Chunk chunk = chunks[x][y][z];
|
||||
if (chunk == null) {
|
||||
chunk = chunkLoader.loadOrGenerateChunk(x, y, z);
|
||||
chunk = chunkLoader.loadChunk(x + this.x * WORLD_REGION_SIZE, y, this.z * WORLD_REGION_SIZE).orElse(new ChunkImpl(x, y, z, this));
|
||||
chunks[x][y][z] = new ChunkProxy(chunk);
|
||||
}
|
||||
return chunk;
|
||||
@@ -60,4 +70,30 @@ public class RegionImpl implements Region{
|
||||
}
|
||||
biomes[x][z] = biome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Serializer<Chunk> chunkSerializer, Serializer<Region> regionSerializer) throws IOException {
|
||||
String worldPath = System.getProperty("worlds.folder", "worlds");
|
||||
File worldFile = new File(worldPath, world.getWorldId().toString());
|
||||
File regionFile = new File(worldFile, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, this.getX(), this.getZ()));
|
||||
if (!regionFile.exists()) {
|
||||
regionFile.mkdirs();
|
||||
}
|
||||
File biomeMapFile = new File(regionFile, BIOME_FILE_NAME_TEMPLATE);
|
||||
byte[] biomeBytes = regionSerializer.serialize(this);
|
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(biomeMapFile)){
|
||||
fileOutputStream.write(biomeBytes);
|
||||
}
|
||||
for (int x = 0; x < WORLD_CHUNK_SIZE; x ++) {
|
||||
for (int z = 0; z < WORLD_CHUNK_SIZE; z ++) {
|
||||
for (int y = 0; y < WORLD_CHUNK_SIZE; y++) {
|
||||
File chunkFile = new File(regionFile, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x, y, z));
|
||||
byte[] chunkBytes = chunkSerializer.serialize(this.getChunkAt(x, y, z));
|
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(chunkFile)){
|
||||
fileOutputStream.write(chunkBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
18
generated_world/src/main/resources/log4j2.xml
Normal file
18
generated_world/src/main/resources/log4j2.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration>
|
||||
<Appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss}] [%-5p] %m%n"/>
|
||||
</Console>
|
||||
<RollingFile name="File" fileName="log/log_file.log" filePattern="log/log_file-%d{MM-dd-yyyy}.log.gz">
|
||||
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
|
||||
<TimeBasedTriggeringPolicy />
|
||||
</RollingFile>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="Trace">
|
||||
<AppenderRef ref="Console"/>
|
||||
<AppenderRef ref="File"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
Reference in New Issue
Block a user