Chunk implementation
This commit is contained in:
@@ -7,6 +7,7 @@ package mc.core;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import mc.core.exception.ResourceUnloadedException;
|
import mc.core.exception.ResourceUnloadedException;
|
||||||
import mc.core.world.Chunk;
|
import mc.core.world.Chunk;
|
||||||
|
import mc.core.world.Region;
|
||||||
import mc.core.world.World;
|
import mc.core.world.World;
|
||||||
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
|
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
|
||||||
|
|
||||||
@@ -114,7 +115,8 @@ public class Location implements Serializable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Chunk getChunk() {
|
public Chunk getChunk() {
|
||||||
throw new NotImplementedException();
|
Region region = getWorld().getRegion((int) (x / 256), (int) (z / 256));
|
||||||
|
return region.getChunk((int) ((x % 256) / 16), (int) ((z % 256) / 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ public interface Region extends Serializable{
|
|||||||
Chunk getChunk (int x, int z);
|
Chunk getChunk (int x, int z);
|
||||||
void setChunk(int x, int z, Chunk chunk);
|
void setChunk(int x, int z, Chunk chunk);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
ChunkSection getChunkAt(int x, int y, int z);
|
||||||
|
@Deprecated
|
||||||
|
void setChunk(int x, int y, int z, ChunkSection chunkSection);
|
||||||
|
|
||||||
int getX();
|
int getX();
|
||||||
int getZ();
|
int getZ();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
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 java.lang.ref.Reference;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE;
|
||||||
|
|
||||||
|
public class ChunkImpl implements Chunk {
|
||||||
|
@Getter
|
||||||
|
private final int x;
|
||||||
|
@Getter
|
||||||
|
private final int z;
|
||||||
|
private Reference<Region> regionReference;
|
||||||
|
private ChunkSection[] sections = new ChunkSection[WORLD_CHUNK_SIZE];
|
||||||
|
|
||||||
|
public ChunkImpl (int x, int z, Region region) {
|
||||||
|
this.x = x;
|
||||||
|
this.z = z;
|
||||||
|
this.regionReference = new WeakReference<>(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public World getWorld() {
|
||||||
|
Region region = getRegion();
|
||||||
|
if (region == null) {
|
||||||
|
throw new ResourceUnloadedException("Region is unloaded");
|
||||||
|
}
|
||||||
|
return region.getWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChunkSection getChunkSection(int height) {
|
||||||
|
return sections[height];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChunkSection setChunkSection(int height, ChunkSection chunkSection) {
|
||||||
|
sections[height] = chunkSection;
|
||||||
|
return chunkSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Region getRegion() {
|
||||||
|
if (regionReference == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regionReference.get() == null) {
|
||||||
|
throw new ResourceUnloadedException("Region is unloaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
return regionReference.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
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 java.lang.ref.Reference;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE;
|
||||||
|
|
||||||
|
public class ChunkSectionImpl implements ChunkSection {
|
||||||
|
@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 Reference<Region> region;
|
||||||
|
|
||||||
|
public ChunkSectionImpl(int x, int y, int z, Region region) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 getRegion().getBiomeAt(x + this.x * WORLD_CHUNK_SIZE,z + this.z * WORLD_CHUNK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBiome(int x, int z, Biome biome) {
|
||||||
|
getRegion().setBiome(x + this.x * WORLD_CHUNK_SIZE,z + this.z * WORLD_CHUNK_SIZE, biome);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBlock(int x, int y, int z, Block block) {
|
||||||
|
if (block.getBlockType() == BlockType.AIR) {
|
||||||
|
blocks[x][y][z] = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blocks[x][y][z] = 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Region getRegion() {
|
||||||
|
if (region == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (region.get() == null) {
|
||||||
|
throw new ResourceUnloadedException("Region is unloaded");
|
||||||
|
}
|
||||||
|
return region.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public World getWorld() {
|
||||||
|
return getRegion().getWorld();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
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 java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
|
public class ChunkSectionProxy implements ChunkSection {
|
||||||
|
private final ChunkSection chunkSection;
|
||||||
|
private volatile transient long lastUsage = System.currentTimeMillis();
|
||||||
|
private final transient ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
|
||||||
|
|
||||||
|
public ChunkSectionProxy(ChunkSection chunkSection) {
|
||||||
|
this.chunkSection = chunkSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastUsage() {
|
||||||
|
synchronized (chunkSection) {
|
||||||
|
return lastUsage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final void use () {
|
||||||
|
synchronized (chunkSection) {
|
||||||
|
lastUsage = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockType(int x, int y, int z) {
|
||||||
|
use();
|
||||||
|
return chunkSection.getBlockType(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBlockType(int x, int y, int z, int type) {
|
||||||
|
use();
|
||||||
|
chunkSection.setBlockType(x, y, z, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockMetadata(int x, int y, int z) {
|
||||||
|
use();
|
||||||
|
return chunkSection.getBlockMetadata(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBlockMetadata(int x, int y, int z, int metadata) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSkyLight(int x, int y, int z) {
|
||||||
|
use();
|
||||||
|
return chunkSection.getSkyLight(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSkyLight(int x, int y, int z, int lightLevel) {
|
||||||
|
use();
|
||||||
|
chunkSection.setSkyLight(x, y, z, lightLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAddition(int x, int y, int z) {
|
||||||
|
use();
|
||||||
|
return chunkSection.getAddition(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAddition(int x, int y, int z, int value) {
|
||||||
|
use();
|
||||||
|
chunkSection.setAddition(x, y, z, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Biome getBiome(int x, int z) {
|
||||||
|
use();
|
||||||
|
return chunkSection.getBiome(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBiome(int x, int z, Biome biome) {
|
||||||
|
use();
|
||||||
|
chunkSection.setBiome(x, z, biome);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
use();
|
||||||
|
return chunkSection.getX();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getY() {
|
||||||
|
use();
|
||||||
|
return chunkSection.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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import mc.core.exception.ResourceUnloadedException;
|
|||||||
import mc.core.serialization.IRegionReaderWriter;
|
import mc.core.serialization.IRegionReaderWriter;
|
||||||
import mc.core.serialization.Serializer;
|
import mc.core.serialization.Serializer;
|
||||||
import mc.core.world.*;
|
import mc.core.world.*;
|
||||||
|
import mc.world.generated_world.chunk.ChunkImpl;
|
||||||
import mc.world.generated_world.chunk.ChunkSectionImpl;
|
import mc.world.generated_world.chunk.ChunkSectionImpl;
|
||||||
import mc.world.generated_world.chunk.ChunkSectionProxy;
|
import mc.world.generated_world.chunk.ChunkSectionProxy;
|
||||||
import mc.world.generated_world.chunk.InMemoryCacheChunkLoader;
|
import mc.world.generated_world.chunk.InMemoryCacheChunkLoader;
|
||||||
@@ -26,9 +27,10 @@ public class RegionImpl implements Region{
|
|||||||
private final int x;
|
private final int x;
|
||||||
@Getter
|
@Getter
|
||||||
private final int z;
|
private final int z;
|
||||||
private final ChunkSectionProxy[][][] chunks = new ChunkSectionProxy[WORLD_REGION_SIZE/WORLD_CHUNK_SIZE][WORLD_REGION_SIZE/WORLD_CHUNK_SIZE][WORLD_REGION_SIZE/WORLD_CHUNK_SIZE];
|
private final ChunkSection[][][] chunkSectionProxies = new ChunkSectionProxy[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];
|
private final Biome[][] biomes = new Biome[WORLD_REGION_SIZE][WORLD_REGION_SIZE];
|
||||||
private final transient Reference<World> world;
|
private final transient Reference<World> world;
|
||||||
|
private final Chunk[][] chunks = new Chunk[WORLD_REGION_SIZE/WORLD_CHUNK_SIZE][WORLD_REGION_SIZE/WORLD_CHUNK_SIZE];
|
||||||
@Autowired
|
@Autowired
|
||||||
private ChunkLoader chunkLoader;
|
private ChunkLoader chunkLoader;
|
||||||
|
|
||||||
@@ -38,6 +40,27 @@ public class RegionImpl implements Region{
|
|||||||
this.world = new WeakReference<>(world);
|
this.world = new WeakReference<>(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Chunk getChunk(int x, int z) {
|
||||||
|
if (x < 0 || z < 0 || x >= 16 || z >= 16) {
|
||||||
|
throw new RuntimeException(MessageFormat.format("Invalid chunk coordinates [{0} {1}]", x, z));
|
||||||
|
}
|
||||||
|
|
||||||
|
Chunk chunk = chunks[x][z];
|
||||||
|
if (chunk == null) {
|
||||||
|
chunk = new ChunkImpl(x, z, this);
|
||||||
|
for (int y = 0; y < WORLD_CHUNK_SIZE; y ++) {
|
||||||
|
chunk.setChunkSection(y, getChunkAt(x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChunk(int x, int z, Chunk chunk) {
|
||||||
|
chunks[x][z] = chunk;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ChunkSection getChunkAt(int x, int y, int z) {
|
public ChunkSection getChunkAt(int x, int y, int z) {
|
||||||
if (x < 0 || y < 0 || z < 0 || x >= 16 || y >= 16 || z >= 16) {
|
if (x < 0 || y < 0 || z < 0 || x >= 16 || y >= 16 || z >= 16) {
|
||||||
@@ -46,10 +69,10 @@ public class RegionImpl implements Region{
|
|||||||
if (chunkLoader == null) {
|
if (chunkLoader == null) {
|
||||||
chunkLoader = new InMemoryCacheChunkLoader(getWorld());
|
chunkLoader = new InMemoryCacheChunkLoader(getWorld());
|
||||||
}
|
}
|
||||||
ChunkSection chunkSection = chunks[x][y][z];
|
ChunkSection chunkSection = chunkSectionProxies[x][y][z];
|
||||||
if (chunkSection == null) {
|
if (chunkSection == null) {
|
||||||
chunkSection = chunkLoader.loadChunk(x + this.x * WORLD_REGION_SIZE, y, this.z * WORLD_REGION_SIZE).orElse(new ChunkSectionImpl(x, y, z, this));
|
chunkSection = chunkLoader.loadChunk(x + this.x * WORLD_REGION_SIZE, y, this.z * WORLD_REGION_SIZE).orElse(new ChunkSectionImpl(x, y, z, this));
|
||||||
chunks[x][y][z] = new ChunkSectionProxy(chunkSection);
|
chunkSectionProxies[x][y][z] = new ChunkSectionProxy(chunkSection);
|
||||||
}
|
}
|
||||||
return chunkSection;
|
return chunkSection;
|
||||||
}
|
}
|
||||||
@@ -59,7 +82,7 @@ public class RegionImpl implements Region{
|
|||||||
if (x < 0 || y < 0 || z < 0 || x >= 16 || y >= 16 || z >= 16) {
|
if (x < 0 || y < 0 || z < 0 || x >= 16 || y >= 16 || z >= 16) {
|
||||||
throw new RuntimeException(MessageFormat.format("Invalid chunkSection coordinates [{0} {1} {2}]", x, y, z));
|
throw new RuntimeException(MessageFormat.format("Invalid chunkSection coordinates [{0} {1} {2}]", x, y, z));
|
||||||
}
|
}
|
||||||
chunks[x][y][z] = new ChunkSectionProxy(chunkSection);
|
chunkSectionProxies[x][y][z] = new ChunkSectionProxy(chunkSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user