From d84e6ca7499d473eb56c50a67efcc9ea0f378799 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Sat, 4 Aug 2018 11:46:28 +0300 Subject: [PATCH 1/9] Location world reference --- core/src/main/java/mc/core/Location.java | 39 ++++++++++++++++--- .../generated_world/chunk/ChunkImpl.java | 1 + .../generator/SeedBasedWorldGenerator.java | 2 +- .../netty/handlers/LoginHandler.java | 6 +-- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/mc/core/Location.java b/core/src/main/java/mc/core/Location.java index 7e560f3..fc7ea47 100644 --- a/core/src/main/java/mc/core/Location.java +++ b/core/src/main/java/mc/core/Location.java @@ -4,15 +4,16 @@ */ package mc.core; -import lombok.AllArgsConstructor; import lombok.Data; +import mc.core.world.World; import java.io.Serializable; +import java.lang.ref.WeakReference; -@AllArgsConstructor @Data public class Location implements Serializable{ private double x, y, z; + private WeakReference world; private static int floor_double(double value) { int i = (int)value; @@ -23,16 +24,35 @@ public class Location implements Serializable{ return new Location( location.x, location.y, - location.z + location.z, + location.getWorld() ); } + public Location (double x, double y, double z, World world) { + this.x = x; + this.y = y; + this.z = z; + this.world = new WeakReference<>(world); + } + + public Location (double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + public static Location startPointLocation () { - return new Location(0,10,0); + return new Location(0,10,0, null); } public Location(long compactValue) { set(compactValue); + this.world = new WeakReference<>(null); + } + + public Location(long compactValue, World world) { + set(compactValue); } public void set(Location location) { @@ -51,7 +71,8 @@ public class Location implements Serializable{ return new Location( this.x - location.x, this.y - location.y, - this.z - location.z + this.z - location.z, + this.getWorld().equals(location.getWorld()) ? this.getWorld() : null ); } @@ -72,4 +93,12 @@ public class Location implements Serializable{ | ((floor_double(y) & 0xFFF) << 26) | (floor_double(z) & 0x3FFFFFF); } + + public World getWorld () { + return this.world.get(); + } + + public void setWorld (World world) { + this.world = new WeakReference<>(world); + } } diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java index 464b980..f9abc9a 100644 --- a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java @@ -85,6 +85,7 @@ public class ChunkImpl implements Chunk{ 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; } diff --git a/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java index 8253165..381173f 100644 --- a/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java @@ -28,7 +28,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { World world = new CubicWorld(UUID.fromString("00000000-0000-0000-C000-000000000046"), 2626949); 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); +// new WorldReaderWriter(new File("worlds")).writeWorldInfo(world); /*worldGenerator.generateRegion(1, 0, world); worldGenerator.generateRegion(-1, 0, world); worldGenerator.generateRegion(0, 1, world); diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/handlers/LoginHandler.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/handlers/LoginHandler.java index eb5cd65..bbbbb6d 100644 --- a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/handlers/LoginHandler.java +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/handlers/LoginHandler.java @@ -48,8 +48,8 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand Player player = playerManager.getPlayer(packet.getPlayerName()) .orElseGet(() -> playerManager.createPlayer( packet.getPlayerName(), - world.getSpawn(), - new Look(0f, 0f))); + world.getSpawn().getLocation(), + world.getSpawn().getLook())); channel.writeAndFlush(new LoginSuccessPacket( player.getUUID(), @@ -68,7 +68,7 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand // Spawn Position SpawnPositionPacket pkt2 = new SpawnPositionPacket(); - pkt2.setLocation(world.getSpawn()); + pkt2.setLocation(world.getSpawn().getLocation()); channel.write(pkt2); // Player Abilities From 610981b7b8e305695ec9ec739abfc9038cfa8d98 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Sat, 4 Aug 2018 13:19:08 +0300 Subject: [PATCH 2/9] World <-- Region <-- Chunk Weak references --- core/src/main/java/mc/core/world/Chunk.java | 7 +++-- core/src/main/java/mc/core/world/Region.java | 2 ++ .../main/java/mc/world/flat/SimpleChunk.java | 12 ++++++++ .../generated_world/chunk/ChunkImpl.java | 28 +++++++++++++++---- .../generated_world/chunk/ChunkProxy.java | 14 ++++++++++ .../generated_world/region/RegionImpl.java | 20 +++++++++---- 6 files changed, 71 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/mc/core/world/Chunk.java b/core/src/main/java/mc/core/world/Chunk.java index 0b712b0..6b63845 100644 --- a/core/src/main/java/mc/core/world/Chunk.java +++ b/core/src/main/java/mc/core/world/Chunk.java @@ -45,6 +45,9 @@ public interface Chunk extends Serializable{ int getY(); int getZ(); - void setBlock (int x, int y, int z, Block block); - Block getBlock (int x, int y, int z); + void setBlock(int x, int y, int z, Block block); + Block getBlock(int x, int y, int z); + + Region getRegion(); + World getWorld(); } diff --git a/core/src/main/java/mc/core/world/Region.java b/core/src/main/java/mc/core/world/Region.java index dec2730..e2f1371 100644 --- a/core/src/main/java/mc/core/world/Region.java +++ b/core/src/main/java/mc/core/world/Region.java @@ -30,5 +30,7 @@ public interface Region extends Serializable{ Biome getBiomeAt (int x, int z); void setBiome (int x, int z, Biome biome); + World getWorld(); + void save(Serializer chunkSerializer, IRegionReaderWriter regionReaderWritter) throws IOException; } diff --git a/flat_world/src/main/java/mc/world/flat/SimpleChunk.java b/flat_world/src/main/java/mc/world/flat/SimpleChunk.java index 03ad6ad..ee5eaab 100644 --- a/flat_world/src/main/java/mc/world/flat/SimpleChunk.java +++ b/flat_world/src/main/java/mc/world/flat/SimpleChunk.java @@ -9,6 +9,8 @@ import mc.core.block.BlockFactory; import mc.core.block.BlockType; import mc.core.world.Biome; import mc.core.world.Chunk; +import mc.core.world.Region; +import mc.core.world.World; public class SimpleChunk implements Chunk { @Override @@ -104,4 +106,14 @@ public class SimpleChunk implements Chunk { else if (y == 3) return blockFactory.create(BlockType.GRASS, 0); else return Block.airBlock(x, y, z); } + + @Override + public Region getRegion() { + throw new UnsupportedOperationException(); + } + + @Override + public World getWorld() { + throw new UnsupportedOperationException(); + } } diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java index f9abc9a..fad881c 100644 --- a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java @@ -1,16 +1,17 @@ package mc.world.generated_world.chunk; import lombok.Getter; -import lombok.RequiredArgsConstructor; import mc.core.block.Block; import mc.core.block.BlockType; import mc.core.world.Biome; import mc.core.world.Chunk; import mc.core.world.Region; +import mc.core.world.World; + +import java.lang.ref.WeakReference; import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE; -@RequiredArgsConstructor public class ChunkImpl implements Chunk{ @Getter private final int x; @@ -19,7 +20,14 @@ public class ChunkImpl implements Chunk{ @Getter private final int z; private final Block[][][] blocks = new Block[WORLD_CHUNK_SIZE][WORLD_CHUNK_SIZE][WORLD_CHUNK_SIZE]; - private final transient Region region; + private final transient WeakReference region; + + public ChunkImpl(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) { @@ -73,12 +81,12 @@ public class ChunkImpl implements Chunk{ @Override public Biome getBiome(int x, int z) { - return region.getBiomeAt(x + this.x * WORLD_CHUNK_SIZE,z + this.z * WORLD_CHUNK_SIZE); + 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) { - region.setBiome(x + this.x * WORLD_CHUNK_SIZE,z + this.z * WORLD_CHUNK_SIZE, biome); + getRegion().setBiome(x + this.x * WORLD_CHUNK_SIZE,z + this.z * WORLD_CHUNK_SIZE, biome); } @Override @@ -98,4 +106,14 @@ public class ChunkImpl implements Chunk{ } return blocks[x][y][z]; } + + @Override + public Region getRegion() { + return region.get(); + } + + @Override + public World getWorld() { + return getRegion().getWorld(); + } } diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkProxy.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkProxy.java index 4490001..fb03d6d 100644 --- a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkProxy.java +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkProxy.java @@ -3,6 +3,8 @@ package mc.world.generated_world.chunk; import mc.core.block.Block; import mc.core.world.Biome; import mc.core.world.Chunk; +import mc.core.world.Region; +import mc.core.world.World; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -129,4 +131,16 @@ public class ChunkProxy implements Chunk { use(); return chunk.getBlock(x, y, z); } + + @Override + public Region getRegion() { + use(); + return chunk.getRegion(); + } + + @Override + public World getWorld() { + use(); + return chunk.getWorld(); + } } diff --git a/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java index 812512f..643644d 100644 --- a/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java +++ b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java @@ -14,12 +14,12 @@ import org.springframework.beans.factory.annotation.Autowired; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.lang.ref.WeakReference; import java.text.MessageFormat; import static mc.world.generated_world.WorldConstants.*; @Slf4j -@RequiredArgsConstructor public class RegionImpl implements Region{ @Getter private final int x; @@ -27,18 +27,23 @@ public class RegionImpl implements Region{ private final int z; 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; + private final transient WeakReference world; @Autowired private ChunkLoader chunkLoader; + public RegionImpl (int x, int z, World world) { + this.x = x; + this.z = z; + this.world = new WeakReference<>(world); + } + @Override public Chunk getChunkAt(int x, int y, int z) { if (x < 0 || y < 0 || z < 0 || x >= 16 || y >= 16 || z >= 16) { throw new RuntimeException(MessageFormat.format("Invalid chunk coordinates [{0} {1} {2}]", x, y, z)); } if (chunkLoader == null) { - chunkLoader = new InMemoryCacheChunkLoader(world); + chunkLoader = new InMemoryCacheChunkLoader(getWorld()); } Chunk chunk = chunks[x][y][z]; if (chunk == null) { @@ -72,10 +77,15 @@ public class RegionImpl implements Region{ biomes[x][z] = biome; } + @Override + public World getWorld() { + return world.get(); + } + @Override public void save(Serializer chunkSerializer, IRegionReaderWriter regionReaderWriter) throws IOException { String worldPath = System.getProperty("worlds.folder", "worlds"); - File worldFile = new File(worldPath, world.getWorldId().toString()); + File worldFile = new File(worldPath, getWorld().getWorldId().toString()); File regionFile = new File(worldFile, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, this.getX(), this.getZ())); if (!regionFile.exists()) { regionFile.mkdirs(); From eab9947aa9b06dbbe9a34a2a75b8e56e0097b19d Mon Sep 17 00:00:00 2001 From: Forwolk Date: Sat, 4 Aug 2018 14:31:43 +0300 Subject: [PATCH 3/9] Checking on unloading --- core/src/main/java/mc/core/Location.java | 8 +++++++- .../mc/core/exception/McCoreUncheckedException.java | 12 ++++++++++++ .../mc/core/exception/ResourceUnloadException.java | 8 ++++++++ .../mc/world/generated_world/chunk/ChunkImpl.java | 7 ++++++- .../mc/world/generated_world/region/RegionImpl.java | 7 ++++++- 5 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 core/src/main/java/mc/core/exception/McCoreUncheckedException.java create mode 100644 core/src/main/java/mc/core/exception/ResourceUnloadException.java diff --git a/core/src/main/java/mc/core/Location.java b/core/src/main/java/mc/core/Location.java index fc7ea47..2816f25 100644 --- a/core/src/main/java/mc/core/Location.java +++ b/core/src/main/java/mc/core/Location.java @@ -5,15 +5,17 @@ package mc.core; import lombok.Data; +import mc.core.exception.ResourceUnloadException; import mc.core.world.World; import java.io.Serializable; +import java.lang.ref.Reference; import java.lang.ref.WeakReference; @Data public class Location implements Serializable{ private double x, y, z; - private WeakReference world; + private Reference world; private static int floor_double(double value) { int i = (int)value; @@ -53,6 +55,7 @@ public class Location implements Serializable{ public Location(long compactValue, World world) { set(compactValue); + this.world = new WeakReference<>(world); } public void set(Location location) { @@ -95,6 +98,9 @@ public class Location implements Serializable{ } public World getWorld () { + if (world.get() == null) { + throw new ResourceUnloadException("You're trying to get unloaded world"); + } return this.world.get(); } diff --git a/core/src/main/java/mc/core/exception/McCoreUncheckedException.java b/core/src/main/java/mc/core/exception/McCoreUncheckedException.java new file mode 100644 index 0000000..15313f3 --- /dev/null +++ b/core/src/main/java/mc/core/exception/McCoreUncheckedException.java @@ -0,0 +1,12 @@ +package mc.core.exception; + +public abstract class McCoreUncheckedException extends RuntimeException { + + public McCoreUncheckedException() { + super(); + } + + public McCoreUncheckedException(String msg) { + super(msg); + } +} diff --git a/core/src/main/java/mc/core/exception/ResourceUnloadException.java b/core/src/main/java/mc/core/exception/ResourceUnloadException.java new file mode 100644 index 0000000..b277411 --- /dev/null +++ b/core/src/main/java/mc/core/exception/ResourceUnloadException.java @@ -0,0 +1,8 @@ +package mc.core.exception; + +public class ResourceUnloadException extends McCoreUncheckedException { + + public ResourceUnloadException(String msg) { + super(msg); + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java index fad881c..5dd5951 100644 --- a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java @@ -3,11 +3,13 @@ package mc.world.generated_world.chunk; import lombok.Getter; import mc.core.block.Block; import mc.core.block.BlockType; +import mc.core.exception.ResourceUnloadException; import mc.core.world.Biome; import mc.core.world.Chunk; 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; @@ -20,7 +22,7 @@ public class ChunkImpl implements Chunk{ @Getter private final int z; private final Block[][][] blocks = new Block[WORLD_CHUNK_SIZE][WORLD_CHUNK_SIZE][WORLD_CHUNK_SIZE]; - private final transient WeakReference region; + private final transient Reference region; public ChunkImpl(int x, int y, int z, Region region) { this.x = x; @@ -109,6 +111,9 @@ public class ChunkImpl implements Chunk{ @Override public Region getRegion() { + if (region.get() == null) { + throw new ResourceUnloadException("Region is unloaded"); + } return region.get(); } diff --git a/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java index 643644d..c5aea75 100644 --- a/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java +++ b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java @@ -3,6 +3,7 @@ package mc.world.generated_world.region; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import mc.core.exception.ResourceUnloadException; import mc.core.serialization.IRegionReaderWriter; import mc.core.serialization.Serializer; import mc.core.world.*; @@ -14,6 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.text.MessageFormat; @@ -27,7 +29,7 @@ public class RegionImpl implements Region{ private final int z; 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]; - private final transient WeakReference world; + private final transient Reference world; @Autowired private ChunkLoader chunkLoader; @@ -79,6 +81,9 @@ public class RegionImpl implements Region{ @Override public World getWorld() { + if (world.get() == null) { + throw new ResourceUnloadException("World is unloaded"); + } return world.get(); } From 72989c60b7476f96ed694811df812def152738f5 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Sat, 4 Aug 2018 14:56:03 +0300 Subject: [PATCH 4/9] Checking reference is not initialized --- core/src/main/java/mc/core/Location.java | 7 +++++-- .../mc/core/exception/ResourceUnloadException.java | 8 -------- .../mc/core/exception/ResourceUnloadedException.java | 8 ++++++++ .../java/mc/world/generated_world/chunk/ChunkImpl.java | 7 +++++-- .../mc/world/generated_world/region/RegionImpl.java | 10 ++++++---- 5 files changed, 24 insertions(+), 16 deletions(-) delete mode 100644 core/src/main/java/mc/core/exception/ResourceUnloadException.java create mode 100644 core/src/main/java/mc/core/exception/ResourceUnloadedException.java diff --git a/core/src/main/java/mc/core/Location.java b/core/src/main/java/mc/core/Location.java index 2816f25..6f5d7d7 100644 --- a/core/src/main/java/mc/core/Location.java +++ b/core/src/main/java/mc/core/Location.java @@ -5,7 +5,7 @@ package mc.core; import lombok.Data; -import mc.core.exception.ResourceUnloadException; +import mc.core.exception.ResourceUnloadedException; import mc.core.world.World; import java.io.Serializable; @@ -98,8 +98,11 @@ public class Location implements Serializable{ } public World getWorld () { + if (world == null) { + throw new IllegalStateException("World is not initialized"); + } if (world.get() == null) { - throw new ResourceUnloadException("You're trying to get unloaded world"); + throw new ResourceUnloadedException("You're trying to get unloaded world"); } return this.world.get(); } diff --git a/core/src/main/java/mc/core/exception/ResourceUnloadException.java b/core/src/main/java/mc/core/exception/ResourceUnloadException.java deleted file mode 100644 index b277411..0000000 --- a/core/src/main/java/mc/core/exception/ResourceUnloadException.java +++ /dev/null @@ -1,8 +0,0 @@ -package mc.core.exception; - -public class ResourceUnloadException extends McCoreUncheckedException { - - public ResourceUnloadException(String msg) { - super(msg); - } -} diff --git a/core/src/main/java/mc/core/exception/ResourceUnloadedException.java b/core/src/main/java/mc/core/exception/ResourceUnloadedException.java new file mode 100644 index 0000000..07ac21f --- /dev/null +++ b/core/src/main/java/mc/core/exception/ResourceUnloadedException.java @@ -0,0 +1,8 @@ +package mc.core.exception; + +public class ResourceUnloadedException extends McCoreUncheckedException { + + public ResourceUnloadedException(String msg) { + super(msg); + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java index 5dd5951..d47cb1f 100644 --- a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java @@ -3,7 +3,7 @@ package mc.world.generated_world.chunk; import lombok.Getter; import mc.core.block.Block; import mc.core.block.BlockType; -import mc.core.exception.ResourceUnloadException; +import mc.core.exception.ResourceUnloadedException; import mc.core.world.Biome; import mc.core.world.Chunk; import mc.core.world.Region; @@ -111,8 +111,11 @@ public class ChunkImpl implements Chunk{ @Override public Region getRegion() { + if (region == null) { + throw new IllegalStateException("Region is not initialized"); + } if (region.get() == null) { - throw new ResourceUnloadException("Region is unloaded"); + throw new ResourceUnloadedException("Region is unloaded"); } return region.get(); } diff --git a/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java index c5aea75..69bfbcb 100644 --- a/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java +++ b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java @@ -1,15 +1,14 @@ package mc.world.generated_world.region; import lombok.Getter; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import mc.core.exception.ResourceUnloadException; +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.InMemoryCacheChunkLoader; import mc.world.generated_world.chunk.ChunkImpl; import mc.world.generated_world.chunk.ChunkProxy; +import mc.world.generated_world.chunk.InMemoryCacheChunkLoader; import org.springframework.beans.factory.annotation.Autowired; import java.io.File; @@ -81,8 +80,11 @@ public class RegionImpl implements Region{ @Override public World getWorld() { + if (world == null) { + throw new IllegalStateException("World is not initialized"); + } if (world.get() == null) { - throw new ResourceUnloadException("World is unloaded"); + throw new ResourceUnloadedException("World is unloaded"); } return world.get(); } From aa001b5fe2b894793776d4c8b1f8e11919d3035a Mon Sep 17 00:00:00 2001 From: Forwolk Date: Sat, 4 Aug 2018 16:17:31 +0300 Subject: [PATCH 5/9] fix: return null if reference is null --- core/src/main/java/mc/core/Location.java | 2 +- .../src/main/java/mc/world/generated_world/chunk/ChunkImpl.java | 2 +- .../main/java/mc/world/generated_world/region/RegionImpl.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/mc/core/Location.java b/core/src/main/java/mc/core/Location.java index 6f5d7d7..6f58136 100644 --- a/core/src/main/java/mc/core/Location.java +++ b/core/src/main/java/mc/core/Location.java @@ -99,7 +99,7 @@ public class Location implements Serializable{ public World getWorld () { if (world == null) { - throw new IllegalStateException("World is not initialized"); + return null; } if (world.get() == null) { throw new ResourceUnloadedException("You're trying to get unloaded world"); diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java index d47cb1f..2eb78a0 100644 --- a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java @@ -112,7 +112,7 @@ public class ChunkImpl implements Chunk{ @Override public Region getRegion() { if (region == null) { - throw new IllegalStateException("Region is not initialized"); + return null; } if (region.get() == null) { throw new ResourceUnloadedException("Region is unloaded"); diff --git a/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java index 69bfbcb..1c48196 100644 --- a/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java +++ b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java @@ -81,7 +81,7 @@ public class RegionImpl implements Region{ @Override public World getWorld() { if (world == null) { - throw new IllegalStateException("World is not initialized"); + return null; } if (world.get() == null) { throw new ResourceUnloadedException("World is unloaded"); From be98784668fbaabc03989dafb485ba50f521573b Mon Sep 17 00:00:00 2001 From: Forwolk Date: Sat, 4 Aug 2018 20:43:07 +0300 Subject: [PATCH 6/9] renamed: Chunk --> ChunkSection --- core/src/main/java/mc/core/Location.java | 1 + .../mc/core/serialization/IChunkReader.java | 4 +- .../main/java/mc/core/world/ChunkLoader.java | 4 +- .../world/{Chunk.java => ChunkSection.java} | 2 +- core/src/main/java/mc/core/world/Region.java | 6 +- core/src/main/java/mc/core/world/World.java | 5 +- .../main/java/mc/world/flat/FlatWorld.java | 8 +- .../main/java/mc/world/flat/SimpleChunk.java | 119 -------------- .../generated_world/chunk/ChunkImpl.java | 127 --------------- .../generated_world/chunk/ChunkProxy.java | 146 ------------------ .../chunk/InMemoryCacheChunkLoader.java | 20 +-- .../generator/SeedBasedWorldGenerator.java | 23 ++- .../generated_world/region/RegionImpl.java | 32 ++-- .../BlockSerializerDeserializer.java | 14 +- .../serialization/ChunkReader.java | 12 +- .../serialization/ChunkSerializer.java | 10 +- .../generated_world/world/CubicWorld.java | 10 +- 17 files changed, 75 insertions(+), 468 deletions(-) rename core/src/main/java/mc/core/world/{Chunk.java => ChunkSection.java} (96%) delete mode 100644 flat_world/src/main/java/mc/world/flat/SimpleChunk.java delete mode 100644 generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java delete mode 100644 generated_world/src/main/java/mc/world/generated_world/chunk/ChunkProxy.java diff --git a/core/src/main/java/mc/core/Location.java b/core/src/main/java/mc/core/Location.java index 6f58136..191aa99 100644 --- a/core/src/main/java/mc/core/Location.java +++ b/core/src/main/java/mc/core/Location.java @@ -110,4 +110,5 @@ public class Location implements Serializable{ public void setWorld (World world) { this.world = new WeakReference<>(world); } + } diff --git a/core/src/main/java/mc/core/serialization/IChunkReader.java b/core/src/main/java/mc/core/serialization/IChunkReader.java index 0ecf126..a332385 100644 --- a/core/src/main/java/mc/core/serialization/IChunkReader.java +++ b/core/src/main/java/mc/core/serialization/IChunkReader.java @@ -1,10 +1,10 @@ package mc.core.serialization; -import mc.core.world.Chunk; +import mc.core.world.ChunkSection; import mc.core.world.Region; import java.io.IOException; public interface IChunkReader { - Chunk read (Region region, int x, int y, int z) throws IOException; + ChunkSection read (Region region, int x, int y, int z) throws IOException; } diff --git a/core/src/main/java/mc/core/world/ChunkLoader.java b/core/src/main/java/mc/core/world/ChunkLoader.java index a8213e4..4a0c7b3 100644 --- a/core/src/main/java/mc/core/world/ChunkLoader.java +++ b/core/src/main/java/mc/core/world/ChunkLoader.java @@ -12,7 +12,7 @@ public interface ChunkLoader { * @param z chunk position * @return optional of chunk (nullable) */ - Optional loadChunk (int x, int y, int z); + Optional loadChunk (int x, int y, int z); /** * Tries to load chunk like {@link #loadChunk(int, int, int)} @@ -23,5 +23,5 @@ public interface ChunkLoader { * @param z chunk position * @return chunk */ - Chunk loadOrGenerateChunk (int x, int y, int z); + ChunkSection loadOrGenerateChunk (int x, int y, int z); } diff --git a/core/src/main/java/mc/core/world/Chunk.java b/core/src/main/java/mc/core/world/ChunkSection.java similarity index 96% rename from core/src/main/java/mc/core/world/Chunk.java rename to core/src/main/java/mc/core/world/ChunkSection.java index 6b63845..3cd2d59 100644 --- a/core/src/main/java/mc/core/world/Chunk.java +++ b/core/src/main/java/mc/core/world/ChunkSection.java @@ -22,7 +22,7 @@ import java.io.Serializable; * */ /* 16x16x16 */ -public interface Chunk extends Serializable{ +public interface ChunkSection extends Serializable{ int getBlockType(int x, int y, int z); void setBlockType(int x, int y, int z, int type); diff --git a/core/src/main/java/mc/core/world/Region.java b/core/src/main/java/mc/core/world/Region.java index e2f1371..17e936b 100644 --- a/core/src/main/java/mc/core/world/Region.java +++ b/core/src/main/java/mc/core/world/Region.java @@ -21,8 +21,8 @@ import java.io.Serializable; * */ public interface Region extends Serializable{ - Chunk getChunkAt(int x, int y, int z); - void setChunk(int x, int y, int z, Chunk chunk); + ChunkSection getChunkAt(int x, int y, int z); + void setChunk(int x, int y, int z, ChunkSection chunkSection); int getX(); int getZ(); @@ -32,5 +32,5 @@ public interface Region extends Serializable{ World getWorld(); - void save(Serializer chunkSerializer, IRegionReaderWriter regionReaderWritter) throws IOException; + void save(Serializer chunkSerializer, IRegionReaderWriter regionReaderWritter) throws IOException; } diff --git a/core/src/main/java/mc/core/world/World.java b/core/src/main/java/mc/core/world/World.java index bc18bf8..1202b4c 100644 --- a/core/src/main/java/mc/core/world/World.java +++ b/core/src/main/java/mc/core/world/World.java @@ -4,7 +4,6 @@ */ package mc.core.world; -import mc.core.Location; import mc.core.WarpPosition; import mc.core.nbt.Taggable; @@ -49,8 +48,8 @@ public interface World extends Taggable, Serializable{ WarpPosition getSpawn(); void setSpawn(WarpPosition location); - Chunk getChunk(int x, int y, int z); - void setChunk(int x, int y, int z, Chunk chunk); + ChunkSection getChunk(int x, int y, int z); + void setChunk(int x, int y, int z, ChunkSection chunkSection); Region getRegion(int x, int z); void setRegion(int x, int z, Region region); diff --git a/flat_world/src/main/java/mc/world/flat/FlatWorld.java b/flat_world/src/main/java/mc/world/flat/FlatWorld.java index 4f7ef22..62c32fe 100644 --- a/flat_world/src/main/java/mc/world/flat/FlatWorld.java +++ b/flat_world/src/main/java/mc/world/flat/FlatWorld.java @@ -25,7 +25,7 @@ public class FlatWorld implements World { @Getter @Setter private WarpPosition spawn = new WarpPosition(new Location(0, 6, 0), new Look(0, 0)); - private Chunk chunk = new SimpleChunk(); + private ChunkSection chunkSection = new SimpleChunkSection(); @Override public IWorldType getWorldType() { @@ -33,12 +33,12 @@ public class FlatWorld implements World { } @Override - public Chunk getChunk(int x, int y, int z) { - return chunk; + public ChunkSection getChunk(int x, int y, int z) { + return chunkSection; } @Override - public void setChunk(int x, int y, int z, Chunk chunk) { + public void setChunk(int x, int y, int z, ChunkSection chunkSection) { throw new UnsupportedOperationException(); } diff --git a/flat_world/src/main/java/mc/world/flat/SimpleChunk.java b/flat_world/src/main/java/mc/world/flat/SimpleChunk.java deleted file mode 100644 index ee5eaab..0000000 --- a/flat_world/src/main/java/mc/world/flat/SimpleChunk.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * DmitriyMX - * 2018-04-28 - */ -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; -import mc.core.world.Region; -import mc.core.world.World; - -public class SimpleChunk implements Chunk { - @Override - public int getBlockType(int x, int y, int z) { - if (y == 0) return 7; - else if (y >= 1 && y <= 2) return 3; - else if (y == 3) return 2; - else return 0; - } - - @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 0; - } - - @Override - public void setBlockLight(int x, int y, int z, int lightLevel) { - - } - - @Override - public int getSkyLight(int x, int y, int z) { - if (y <= 3) return 0; - else 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 Biome.PLAINS; - } - - @Override - public void setBiome(int x, int z, Biome biome) { - - } - - @Override - public int getX() { - return 0; - } - - @Override - public int getY() { - return 0; - } - - @Override - public int getZ() { - return 0; - } - - @Override - 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); - } - - @Override - public Region getRegion() { - throw new UnsupportedOperationException(); - } - - @Override - public World getWorld() { - throw new UnsupportedOperationException(); - } -} diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java deleted file mode 100644 index 2eb78a0..0000000 --- a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java +++ /dev/null @@ -1,127 +0,0 @@ -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.Chunk; -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 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; - - public ChunkImpl(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(); - } -} diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkProxy.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkProxy.java deleted file mode 100644 index fb03d6d..0000000 --- a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkProxy.java +++ /dev/null @@ -1,146 +0,0 @@ -package mc.world.generated_world.chunk; - -import mc.core.block.Block; -import mc.core.world.Biome; -import mc.core.world.Chunk; -import mc.core.world.Region; -import mc.core.world.World; - -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -public class ChunkProxy implements Chunk { - private final Chunk chunk; - private volatile transient long lastUsage = System.currentTimeMillis(); - private final transient ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); - - public ChunkProxy(Chunk chunk) { - this.chunk = chunk; - } - - public long getLastUsage() { - synchronized (chunk) { - return lastUsage; - } - } - - private final void use () { - synchronized (chunk) { - lastUsage = System.currentTimeMillis(); - } - } - - @Override - public int getBlockType(int x, int y, int z) { - use(); - return chunk.getBlockType(x, y, z); - } - - @Override - public void setBlockType(int x, int y, int z, int type) { - use(); - chunk.setBlockType(x, y, z, type); - } - - @Override - public int getBlockMetadata(int x, int y, int z) { - use(); - return chunk.getBlockMetadata(x, y, z); - } - - @Override - public void setBlockMetadata(int x, int y, int z, int metadata) { - use(); - chunk.setBlockMetadata(x, y, z, metadata); - } - - @Override - public int getBlockLight(int x, int y, int z) { - use(); - return chunk.getBlockLight(x, y, z); - } - - @Override - public void setBlockLight(int x, int y, int z, int lightLevel) { - use(); - chunk.setBlockLight(x, y, z, lightLevel); - } - - @Override - public int getSkyLight(int x, int y, int z) { - use(); - return chunk.getSkyLight(x, y, z); - } - - @Override - public void setSkyLight(int x, int y, int z, int lightLevel) { - use(); - chunk.setSkyLight(x, y, z, lightLevel); - } - - @Override - public int getAddition(int x, int y, int z) { - use(); - return chunk.getAddition(x, y, z); - } - - @Override - public void setAddition(int x, int y, int z, int value) { - use(); - chunk.setAddition(x, y, z, value); - } - - @Override - public Biome getBiome(int x, int z) { - use(); - return chunk.getBiome(x, z); - } - - @Override - public void setBiome(int x, int z, Biome biome) { - use(); - chunk.setBiome(x, z, biome); - } - - @Override - public int getX() { - use(); - return chunk.getX(); - } - - @Override - public int getY() { - use(); - return chunk.getY(); - } - - @Override - public int getZ() { - use(); - return chunk.getZ(); - } - - @Override - public void setBlock(int x, int y, int z, Block block) { - use(); - chunk.setBlock(x, y, z, block); - } - - @Override - public Block getBlock(int x, int y, int z) { - use(); - return chunk.getBlock(x, y, z); - } - - @Override - public Region getRegion() { - use(); - return chunk.getRegion(); - } - - @Override - public World getWorld() { - use(); - return chunk.getWorld(); - } -} diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/InMemoryCacheChunkLoader.java b/generated_world/src/main/java/mc/world/generated_world/chunk/InMemoryCacheChunkLoader.java index 2724497..f304f84 100644 --- a/generated_world/src/main/java/mc/world/generated_world/chunk/InMemoryCacheChunkLoader.java +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/InMemoryCacheChunkLoader.java @@ -25,7 +25,7 @@ public class InMemoryCacheChunkLoader implements ChunkLoader { @Autowired private ChunkReader chunkReader; @Autowired - private Serializer chunkSerializer; + private Serializer chunkSerializer; @Autowired private RegionReaderWriter regionReaderWritter; @@ -44,14 +44,14 @@ public class InMemoryCacheChunkLoader implements ChunkLoader { } @Override - public Optional loadChunk(int x, int y, int z) { + public Optional loadChunk(int x, int y, int z) { File file = getChuckFile(x, y, z); if (!file.exists()) { return Optional.empty(); } else { try { - Chunk chunk = chunkReader.read(world.getRegion(x / WORLD_CHUNK_SIZE, z / WORLD_CHUNK_SIZE), x, y, z); - return Optional.of(chunk); + ChunkSection chunkSection = chunkReader.read(world.getRegion(x / WORLD_CHUNK_SIZE, z / WORLD_CHUNK_SIZE), x, y, z); + return Optional.of(chunkSection); } catch (IOException e) { log.error("Error occurred while reading chunk file: " + file.getAbsolutePath(), e); return Optional.empty(); @@ -60,12 +60,12 @@ public class InMemoryCacheChunkLoader implements ChunkLoader { } @Override - public Chunk loadOrGenerateChunk(int x, int y, int z) { + public ChunkSection loadOrGenerateChunk(int x, int y, int z) { int regX = x / WORLD_CHUNK_SIZE; int regZ = z / WORLD_CHUNK_SIZE; File regionFile = new File(worldFolder, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, regX, regZ)); Region region; - Chunk chunk; + ChunkSection chunkSection; if (!regionFile.exists()) { log.debug("Region [{}, {}] not found. Generating!", regX, regZ); regionFile.mkdirs(); @@ -76,17 +76,17 @@ public class InMemoryCacheChunkLoader implements ChunkLoader { 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); + chunkSection = region.getChunkAt(x % WORLD_CHUNK_SIZE, y % WORLD_CHUNK_SIZE, z % WORLD_CHUNK_SIZE); } else { try { region = regionReaderWritter.read(regX, regZ, world); - chunk = chunkReader.read(region, x, y, z); + chunkSection = chunkReader.read(region, x, y, z); } catch (IOException e) { - log.error("Error occurred while reading chunk file", e); + log.error("Error occurred while reading chunkSection file", e); return null; } } - return chunk; + return chunkSection; } private void saveRegion (Region region) { diff --git a/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java index 381173f..1b5d8dd 100644 --- a/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java @@ -8,7 +8,6 @@ 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.serialization.WorldReaderWriter; import mc.world.generated_world.world.CubicWorld; import mc.world.generated_world.world.Temperature; import mc.world.generated_world.world.Wetness; @@ -306,37 +305,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 ++) { - Chunk chunk = region.getChunkAt(x / 16, y / 16, z / 16); + ChunkSection chunkSection = region.getChunkAt(x / 16, y / 16, z / 16); if (y == 0) { - chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.BEDROCK, 0)); + chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.BEDROCK, 0)); continue; } if (y < heightMap[x][z]) { if (y < heightMap[x][z] - grassMap[x][z]) { - chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.STONE, 0)); + chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.STONE, 0)); } else { - chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.SAND, 0)); + chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.SAND, 0)); } } else { - chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.WATER, 0)); + chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.WATER, 0)); } } } else { for (int y = 0; y < heightMap[x][z]; y++) { - Chunk chunk = region.getChunkAt(x / 16, y / 16, z / 16); + ChunkSection chunkSection = region.getChunkAt(x / 16, y / 16, z / 16); if (y == 0) { - chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.BEDROCK, 0)); + chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.BEDROCK, 0)); continue; } if (y < heightMap[x][z] - grassMap[x][z]) { - chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.STONE, 0)); + chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.STONE, 0)); } else { if (biomes[x][z] == Biome.DESERT || biomes[x][z] == Biome.DESERT_HILLS) { - chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.SAND, 0)); + chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.SAND, 0)); } else if (biomes[x][z] == Biome.TAIGA || biomes[x][z] == Biome.TAIGA_HILLS) { - chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.DIRT, 0)); + chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.DIRT, 0)); } else { - chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.GRASS, 0)); + chunkSection.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.GRASS, 0)); } } } diff --git a/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java index 1c48196..acd8e57 100644 --- a/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java +++ b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java @@ -6,8 +6,8 @@ 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.ChunkProxy; +import mc.world.generated_world.chunk.ChunkSectionImpl; +import mc.world.generated_world.chunk.ChunkSectionProxy; import mc.world.generated_world.chunk.InMemoryCacheChunkLoader; import org.springframework.beans.factory.annotation.Autowired; @@ -26,7 +26,7 @@ public class RegionImpl implements Region{ private final int x; @Getter private final int z; - 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 ChunkSectionProxy[][][] chunks = 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 transient Reference world; @Autowired @@ -39,27 +39,27 @@ public class RegionImpl implements Region{ } @Override - public Chunk 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) { - throw new RuntimeException(MessageFormat.format("Invalid chunk coordinates [{0} {1} {2}]", x, y, z)); + throw new RuntimeException(MessageFormat.format("Invalid chunkSection coordinates [{0} {1} {2}]", x, y, z)); } if (chunkLoader == null) { chunkLoader = new InMemoryCacheChunkLoader(getWorld()); } - Chunk chunk = chunks[x][y][z]; - if (chunk == null) { - 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); + ChunkSection chunkSection = chunks[x][y][z]; + 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)); + chunks[x][y][z] = new ChunkSectionProxy(chunkSection); } - return chunk; + return chunkSection; } @Override - public void setChunk(int x, int y, int z, Chunk chunk) { + public void setChunk(int x, int y, int z, ChunkSection chunkSection) { 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)); + throw new RuntimeException(MessageFormat.format("Invalid chunkSection coordinates [{0} {1} {2}]", x, y, z)); } - chunks[x][y][z] = new ChunkProxy(chunk); + chunks[x][y][z] = new ChunkSectionProxy(chunkSection); } @Override @@ -90,7 +90,7 @@ public class RegionImpl implements Region{ } @Override - public void save(Serializer chunkSerializer, IRegionReaderWriter regionReaderWriter) throws IOException { + public void save(Serializer chunkSerializer, IRegionReaderWriter regionReaderWriter) throws IOException { String worldPath = System.getProperty("worlds.folder", "worlds"); File worldFile = new File(worldPath, getWorld().getWorldId().toString()); File regionFile = new File(worldFile, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, this.getX(), this.getZ())); @@ -101,8 +101,8 @@ public class RegionImpl implements Region{ 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++) { - Chunk chunk = this.getChunkAt(x, y, z); - byte[] chunkBytes = chunkSerializer.serialize(chunk); + ChunkSection chunkSection = this.getChunkAt(x, y, z); + byte[] chunkBytes = chunkSerializer.serialize(chunkSection); if (chunkBytes.length > 0) { File chunkFile = new File(regionFile, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x, y, z)); try (FileOutputStream fileOutputStream = new FileOutputStream(chunkFile)) { diff --git a/generated_world/src/main/java/mc/world/generated_world/serialization/BlockSerializerDeserializer.java b/generated_world/src/main/java/mc/world/generated_world/serialization/BlockSerializerDeserializer.java index a176afe..ae308fb 100644 --- a/generated_world/src/main/java/mc/world/generated_world/serialization/BlockSerializerDeserializer.java +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/BlockSerializerDeserializer.java @@ -5,7 +5,7 @@ import mc.core.block.BlockFactory; import mc.core.block.BlockType; import mc.core.serialization.Deserializer; import mc.core.serialization.Serializer; -import mc.core.world.Chunk; +import mc.core.world.ChunkSection; /** * Prototype @@ -13,20 +13,20 @@ import mc.core.world.Chunk; public class BlockSerializerDeserializer implements Serializer, Deserializer { private BlockFactory blockFactory; - private Chunk chunk; + private ChunkSection chunkSection; - public BlockSerializerDeserializer(BlockFactory blockFactory, Chunk chunk) { + public BlockSerializerDeserializer(BlockFactory blockFactory, ChunkSection chunkSection) { this.blockFactory = blockFactory; - this.chunk = chunk; + this.chunkSection = chunkSection; } @Override public Block deserialize(byte[] bytes) { int id = bytes[0] + 128; int meta = bytes[1] >> 4; - int x = (bytes[1] & 0xf) + chunk.getX() * 16; - int y = bytes[2] >> 4 + chunk.getY() * 16; - int z = (bytes[2] & 0xf) + chunk.getZ() * 16; + int x = (bytes[1] & 0xf) + chunkSection.getX() * 16; + int y = bytes[2] >> 4 + chunkSection.getY() * 16; + int z = (bytes[2] & 0xf) + chunkSection.getZ() * 16; BlockType type = BlockType.values()[id]; Block block = blockFactory.create(type, meta); block.getLocation().setX(x); diff --git a/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkReader.java b/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkReader.java index 8b77dde..c117150 100644 --- a/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkReader.java +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkReader.java @@ -4,9 +4,9 @@ import mc.core.Location; import mc.core.block.Block; import mc.core.serialization.Deserializer; import mc.core.serialization.IChunkReader; -import mc.core.world.Chunk; +import mc.core.world.ChunkSection; import mc.core.world.Region; -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; @@ -27,14 +27,14 @@ public class ChunkReader implements IChunkReader{ } @Override - public Chunk read (Region region, int x, int y, int z) throws IOException { + public ChunkSection read (Region region, int x, int y, int z) throws IOException { x %= WORLD_REGION_SIZE; y %= WORLD_REGION_SIZE; z %= WORLD_REGION_SIZE; File chunkFile = new File(new File(worldFolder, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, region.getX(), region.getZ())), MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x, y, z)); byte[] chunkBytes = Files.readAllBytes(Paths.get(chunkFile.toURI())); int blocks = (chunkBytes.length) / 3; - Chunk chunk = new ChunkImpl(x, y, z, region); + ChunkSection chunkSection = new ChunkSectionImpl(x, y, z, region); for (int i = 0; i < blocks; i ++) { byte[] blockBytes = new byte[3]; blockBytes[0] = chunkBytes[3 * i]; @@ -42,8 +42,8 @@ public class ChunkReader implements IChunkReader{ blockBytes[2] = chunkBytes[2 + 3 * i]; Block block = blockDeserializer.deserialize(blockBytes); Location blockLocation = block.getLocation(); - chunk.setBlock(blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ(), block); + chunkSection.setBlock(blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ(), block); } - return chunk; + return chunkSection; } } diff --git a/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializer.java b/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializer.java index aae910b..ce592ce 100644 --- a/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializer.java +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializer.java @@ -5,7 +5,7 @@ import mc.core.block.Block; import mc.core.block.BlockFactory; import mc.core.block.BlockType; import mc.core.serialization.Serializer; -import mc.core.world.Chunk; +import mc.core.world.ChunkSection; import org.springframework.beans.factory.annotation.Autowired; import java.io.ByteArrayOutputStream; @@ -14,20 +14,20 @@ import java.io.IOException; import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE; @Slf4j -public class ChunkSerializer implements Serializer { +public class ChunkSerializer implements Serializer { @Autowired private Serializer blockSerializer; @Override - public byte[] serialize(Chunk chunk) { - Serializer blockSerializer = new BlockSerializerDeserializer(new BlockFactory(), chunk); + public byte[] serialize(ChunkSection chunkSection) { + Serializer blockSerializer = new BlockSerializerDeserializer(new BlockFactory(), chunkSection); ByteArrayOutputStream baos = new ByteArrayOutputStream(); Block current; for (int x = 0; x < WORLD_CHUNK_SIZE; x ++) { for (int y = 0; y < WORLD_CHUNK_SIZE; y ++) { for (int z = 0; z < WORLD_CHUNK_SIZE; z ++) { - current = chunk.getBlock(x, y, z); + current = chunkSection.getBlock(x, y, z); if (current != null && current.getBlockType() != BlockType.AIR) { try { baos.write(blockSerializer.serialize(current)); diff --git a/generated_world/src/main/java/mc/world/generated_world/world/CubicWorld.java b/generated_world/src/main/java/mc/world/generated_world/world/CubicWorld.java index 6c39781..8dc502c 100644 --- a/generated_world/src/main/java/mc/world/generated_world/world/CubicWorld.java +++ b/generated_world/src/main/java/mc/world/generated_world/world/CubicWorld.java @@ -8,7 +8,7 @@ import mc.core.Location; import mc.core.WarpPosition; import mc.core.block.BlockType; import mc.core.player.Look; -import mc.core.world.Chunk; +import mc.core.world.ChunkSection; import mc.core.world.IWorldType; import mc.core.world.Region; import mc.core.world.World; @@ -68,8 +68,8 @@ public class CubicWorld implements World { 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 --) { - Chunk chunk = getChunk(0,y / WORLD_CHUNK_SIZE, 0); - if (chunk.getBlock(0, y, 0).getBlockType() != BlockType.AIR) { + 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; } @@ -89,12 +89,12 @@ public class CubicWorld implements World { } @Override - public Chunk getChunk(int x, int y, int z) { + public ChunkSection getChunk(int x, int y, int z) { return null; } @Override - public void setChunk(int x, int y, int z, Chunk chunk) { + public void setChunk(int x, int y, int z, ChunkSection chunkSection) { } From 895f59189d8ece7d05aa21bdfdffda3026d46124 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Sat, 4 Aug 2018 21:03:05 +0300 Subject: [PATCH 7/9] Chunk 16x256x16 --- core/src/main/java/mc/core/world/Chunk.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 core/src/main/java/mc/core/world/Chunk.java diff --git a/core/src/main/java/mc/core/world/Chunk.java b/core/src/main/java/mc/core/world/Chunk.java new file mode 100644 index 0000000..694ce54 --- /dev/null +++ b/core/src/main/java/mc/core/world/Chunk.java @@ -0,0 +1,12 @@ +package mc.core.world; + +public interface Chunk { + + World getWorld(); + ChunkSection getChunkSection(int height); + ChunkSection setChunkSection(int height, ChunkSection chunkSection); + Region getRegion(); + + int getX(); + int getZ(); +} From a1ee3a240ea632e5a208fcda74697385d514a12a Mon Sep 17 00:00:00 2001 From: Forwolk Date: Sat, 4 Aug 2018 21:05:16 +0300 Subject: [PATCH 8/9] Location.getChunk(); --- core/src/main/java/mc/core/Location.java | 6 ++++++ core/src/main/java/mc/core/world/Region.java | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/mc/core/Location.java b/core/src/main/java/mc/core/Location.java index 191aa99..1171d68 100644 --- a/core/src/main/java/mc/core/Location.java +++ b/core/src/main/java/mc/core/Location.java @@ -6,7 +6,9 @@ package mc.core; import lombok.Data; import mc.core.exception.ResourceUnloadedException; +import mc.core.world.Chunk; import mc.core.world.World; +import sun.reflect.generics.reflectiveObjects.NotImplementedException; import java.io.Serializable; import java.lang.ref.Reference; @@ -111,4 +113,8 @@ public class Location implements Serializable{ this.world = new WeakReference<>(world); } + public Chunk getChunk() { + throw new NotImplementedException(); + } + } diff --git a/core/src/main/java/mc/core/world/Region.java b/core/src/main/java/mc/core/world/Region.java index 17e936b..fc91637 100644 --- a/core/src/main/java/mc/core/world/Region.java +++ b/core/src/main/java/mc/core/world/Region.java @@ -21,8 +21,8 @@ import java.io.Serializable; * */ public interface Region extends Serializable{ - ChunkSection getChunkAt(int x, int y, int z); - void setChunk(int x, int y, int z, ChunkSection chunkSection); + Chunk getChunk (int x, int z); + void setChunk(int x, int z, Chunk chunk); int getX(); int getZ(); From a23f7b15b55b47d5a7bb2866c9d01e13e5bc8a5c Mon Sep 17 00:00:00 2001 From: Forwolk Date: Sat, 4 Aug 2018 21:56:04 +0300 Subject: [PATCH 9/9] Chunk implementation --- core/src/main/java/mc/core/Location.java | 4 +- core/src/main/java/mc/core/world/Region.java | 5 + .../generated_world/chunk/ChunkImpl.java | 61 ++++++++ .../chunk/ChunkSectionImpl.java | 127 +++++++++++++++ .../chunk/ChunkSectionProxy.java | 146 ++++++++++++++++++ .../generated_world/region/RegionImpl.java | 31 +++- 6 files changed, 369 insertions(+), 5 deletions(-) create mode 100644 generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/chunk/ChunkSectionImpl.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/chunk/ChunkSectionProxy.java diff --git a/core/src/main/java/mc/core/Location.java b/core/src/main/java/mc/core/Location.java index 1171d68..9332165 100644 --- a/core/src/main/java/mc/core/Location.java +++ b/core/src/main/java/mc/core/Location.java @@ -7,6 +7,7 @@ package mc.core; import lombok.Data; import mc.core.exception.ResourceUnloadedException; import mc.core.world.Chunk; +import mc.core.world.Region; import mc.core.world.World; import sun.reflect.generics.reflectiveObjects.NotImplementedException; @@ -114,7 +115,8 @@ public class Location implements Serializable{ } 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)); } } diff --git a/core/src/main/java/mc/core/world/Region.java b/core/src/main/java/mc/core/world/Region.java index fc91637..7b57123 100644 --- a/core/src/main/java/mc/core/world/Region.java +++ b/core/src/main/java/mc/core/world/Region.java @@ -24,6 +24,11 @@ public interface Region extends Serializable{ Chunk getChunk (int x, int z); 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 getZ(); diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java new file mode 100644 index 0000000..7954603 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java @@ -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 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(); + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkSectionImpl.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkSectionImpl.java new file mode 100644 index 0000000..dce85eb --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkSectionImpl.java @@ -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; + + 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(); + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkSectionProxy.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkSectionProxy.java new file mode 100644 index 0000000..c945af8 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkSectionProxy.java @@ -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(); + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java index acd8e57..9f96d49 100644 --- a/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java +++ b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java @@ -6,6 +6,7 @@ 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.world.generated_world.chunk.ChunkSectionProxy; import mc.world.generated_world.chunk.InMemoryCacheChunkLoader; @@ -26,9 +27,10 @@ public class RegionImpl implements Region{ private final int x; @Getter 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 transient Reference world; + private final Chunk[][] chunks = new Chunk[WORLD_REGION_SIZE/WORLD_CHUNK_SIZE][WORLD_REGION_SIZE/WORLD_CHUNK_SIZE]; @Autowired private ChunkLoader chunkLoader; @@ -38,6 +40,27 @@ public class RegionImpl implements Region{ 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 public ChunkSection getChunkAt(int x, int y, int z) { 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) { chunkLoader = new InMemoryCacheChunkLoader(getWorld()); } - ChunkSection chunkSection = chunks[x][y][z]; + ChunkSection chunkSection = chunkSectionProxies[x][y][z]; 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)); - chunks[x][y][z] = new ChunkSectionProxy(chunkSection); + chunkSectionProxies[x][y][z] = new ChunkSectionProxy(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) { 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