Merged in forwolk/merge/location-world (pull request #6)
Forwolk/merge/location world Approved-by: DmitriyMX <dimon550@gmail.com> Approved-by: Daniil Glazko <daniil@glazko.su>
This commit is contained in:
@@ -4,15 +4,20 @@
|
|||||||
*/
|
*/
|
||||||
package mc.core;
|
package mc.core;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import mc.core.exception.ResourceUnloadedException;
|
||||||
|
import mc.core.world.Region;
|
||||||
|
import mc.core.world.World;
|
||||||
|
import mc.core.world.chunk.Chunk;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.lang.ref.Reference;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Data
|
@Data
|
||||||
public class Location implements Serializable{
|
public class Location implements Serializable{
|
||||||
private double x, y, z;
|
private double x, y, z;
|
||||||
|
private Reference<World> world;
|
||||||
|
|
||||||
private static int floor_double(double value) {
|
private static int floor_double(double value) {
|
||||||
int i = (int)value;
|
int i = (int)value;
|
||||||
@@ -23,16 +28,36 @@ public class Location implements Serializable{
|
|||||||
return new Location(
|
return new Location(
|
||||||
location.x,
|
location.x,
|
||||||
location.y,
|
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 () {
|
public static Location startPointLocation () {
|
||||||
return new Location(0,10,0);
|
return new Location(0,10,0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Location(long compactValue) {
|
public Location(long compactValue) {
|
||||||
set(compactValue);
|
set(compactValue);
|
||||||
|
this.world = new WeakReference<>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location(long compactValue, World world) {
|
||||||
|
set(compactValue);
|
||||||
|
this.world = new WeakReference<>(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(double x, double y, double z) {
|
public void set(double x, double y, double z) {
|
||||||
@@ -57,7 +82,8 @@ public class Location implements Serializable{
|
|||||||
return new Location(
|
return new Location(
|
||||||
this.x - location.x,
|
this.x - location.x,
|
||||||
this.y - location.y,
|
this.y - location.y,
|
||||||
this.z - location.z
|
this.z - location.z,
|
||||||
|
this.getWorld().equals(location.getWorld()) ? this.getWorld() : null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,4 +104,24 @@ public class Location implements Serializable{
|
|||||||
| ((floor_double(y) & 0xFFF) << 26)
|
| ((floor_double(y) & 0xFFF) << 26)
|
||||||
| (floor_double(z) & 0x3FFFFFF);
|
| (floor_double(z) & 0x3FFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public World getWorld () {
|
||||||
|
if (world == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (world.get() == null) {
|
||||||
|
throw new ResourceUnloadedException("You're trying to get unloaded world");
|
||||||
|
}
|
||||||
|
return this.world.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWorld (World world) {
|
||||||
|
this.world = new WeakReference<>(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Chunk getChunk() {
|
||||||
|
Region region = getWorld().getRegion((int) (x / 256), (int) (z / 256));
|
||||||
|
return region.getChunk((int) ((x % 256) / 16), (int) ((z % 256) / 16));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,90 @@
|
|||||||
package mc.core;
|
package mc.core;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import mc.core.player.ILook;
|
||||||
import lombok.Data;
|
|
||||||
import mc.core.player.Look;
|
import mc.core.player.Look;
|
||||||
|
import mc.core.world.World;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Data
|
public class WarpPosition extends Location implements Serializable, ILook {
|
||||||
@AllArgsConstructor
|
private ILook look;
|
||||||
public class WarpPosition implements Serializable {
|
|
||||||
private Location location;
|
public WarpPosition(double x, double y, double z, World world) {
|
||||||
private Look look;
|
super(x, y, z, world);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarpPosition(double x, double y, double z, float yaw, float pitch, World world) {
|
||||||
|
super(x, y, z, world);
|
||||||
|
this.look = new Look(yaw, pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarpPosition(double x, double y, double z) {
|
||||||
|
super(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarpPosition(double x, double y, double z, float yaw, float pitch) {
|
||||||
|
super(x, y, z);
|
||||||
|
this.look = new Look(yaw, pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarpPosition(long compactValue) {
|
||||||
|
super(compactValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarpPosition(Location location) {
|
||||||
|
super(location.getX(), location.getY(), location.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarpPosition(Location location, Look look) {
|
||||||
|
super(location.getX(), location.getY(), location.getZ());
|
||||||
|
this.look = look;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarpPosition(long compactValue, World world) {
|
||||||
|
super(compactValue, world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(Look look) {
|
||||||
|
this.look = look;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getYaw() {
|
||||||
|
return this.look.getYaw();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setYaw(float yaw) {
|
||||||
|
this.look.setYaw(yaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getPitch() {
|
||||||
|
return this.look.getPitch();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPitch(float pitch) {
|
||||||
|
this.look.setPitch(pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
if (!super.equals(o)) return false;
|
||||||
|
WarpPosition that = (WarpPosition) o;
|
||||||
|
return Objects.equals(look, that.look);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(super.hashCode(), look);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasLook() {
|
||||||
|
return look != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package mc.core.exception;
|
||||||
|
|
||||||
|
public abstract class McCoreUncheckedException extends RuntimeException {
|
||||||
|
|
||||||
|
public McCoreUncheckedException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public McCoreUncheckedException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package mc.core.exception;
|
||||||
|
|
||||||
|
public class ResourceUnloadedException extends McCoreUncheckedException {
|
||||||
|
|
||||||
|
public ResourceUnloadedException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
core/src/main/java/mc/core/player/ILook.java
Normal file
15
core/src/main/java/mc/core/player/ILook.java
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package mc.core.player;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public interface ILook extends Serializable {
|
||||||
|
void set(Look look);
|
||||||
|
|
||||||
|
float getYaw();
|
||||||
|
|
||||||
|
float getPitch();
|
||||||
|
|
||||||
|
void setYaw(float yaw);
|
||||||
|
|
||||||
|
void setPitch(float pitch);
|
||||||
|
}
|
||||||
@@ -7,13 +7,12 @@ package mc.core.player;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class Look implements Serializable{
|
public class Look implements ILook {
|
||||||
private float yaw, pitch;
|
private float yaw, pitch;
|
||||||
|
|
||||||
|
@Override
|
||||||
public void set(Look look) {
|
public void set(Look look) {
|
||||||
this.yaw = look.yaw;
|
this.yaw = look.yaw;
|
||||||
this.pitch = look.pitch;
|
this.pitch = look.pitch;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package mc.core.serialization;
|
package mc.core.serialization;
|
||||||
|
|
||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.ChunkSection;
|
||||||
import mc.core.world.Region;
|
import mc.core.world.Region;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public interface IChunkReader {
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
45
core/src/main/java/mc/core/world/ChunkSection.java
Normal file
45
core/src/main/java/mc/core/world/ChunkSection.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <dimon550@gmail.com>
|
||||||
|
* 2018-04-15
|
||||||
|
*/
|
||||||
|
package mc.core.world;
|
||||||
|
|
||||||
|
import mc.core.world.block.Block;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialization chunk info
|
||||||
|
*
|
||||||
|
* +-------------+----------------+------------+
|
||||||
|
* | param | range | bits |
|
||||||
|
* +-------------+----------------+------------+
|
||||||
|
* | blocks | array | 24*count |
|
||||||
|
* +-------------+----------------+------------+
|
||||||
|
*
|
||||||
|
* Total: 24 * block_count bits (3 * block_count bytes)
|
||||||
|
* Max size: 12288 bytes (~12 Kb per chunk)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* 16x16x16 */
|
||||||
|
public interface ChunkSection extends Serializable{
|
||||||
|
|
||||||
|
int getSkyLight(int x, int y, int z);
|
||||||
|
void setSkyLight(int x, int y, int z, int lightLevel);
|
||||||
|
|
||||||
|
int getAddition(int x, int y, int z);
|
||||||
|
void setAddition(int x, int y, int z, int value);
|
||||||
|
|
||||||
|
Biome getBiome(int x, int z);
|
||||||
|
void setBiome(int x, int z, Biome biome);
|
||||||
|
|
||||||
|
int getX();
|
||||||
|
int getY();
|
||||||
|
int getZ();
|
||||||
|
|
||||||
|
void setBlock(Block block);
|
||||||
|
Block getBlock(int x, int y, int z);
|
||||||
|
|
||||||
|
Region getRegion();
|
||||||
|
World getWorld();
|
||||||
|
}
|
||||||
@@ -22,8 +22,13 @@ import java.io.Serializable;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface Region extends Serializable{
|
public interface Region extends Serializable{
|
||||||
Chunk getChunkAt(int x, int y, int z);
|
Chunk getChunk (int x, int z);
|
||||||
void setChunk(int x, int y, 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();
|
||||||
@@ -31,5 +36,7 @@ public interface Region extends Serializable{
|
|||||||
Biome getBiomeAt (int x, int z);
|
Biome getBiomeAt (int x, int z);
|
||||||
void setBiome (int x, int z, Biome biome);
|
void setBiome (int x, int z, Biome biome);
|
||||||
|
|
||||||
void save(Serializer<Chunk> chunkSerializer, IRegionReaderWriter regionReaderWritter) throws IOException;
|
World getWorld();
|
||||||
|
|
||||||
|
void save(Serializer<ChunkSection> chunkSerializer, IRegionReaderWriter regionReaderWritter) throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package mc.core.world;
|
|||||||
|
|
||||||
import mc.core.WarpPosition;
|
import mc.core.WarpPosition;
|
||||||
import mc.core.nbt.Taggable;
|
import mc.core.nbt.Taggable;
|
||||||
import mc.core.world.chunk.Chunk;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -49,8 +48,8 @@ public interface World extends Taggable, Serializable{
|
|||||||
WarpPosition getSpawn();
|
WarpPosition getSpawn();
|
||||||
void setSpawn(WarpPosition location);
|
void setSpawn(WarpPosition location);
|
||||||
|
|
||||||
Chunk getChunk(int x, int y, int z);
|
ChunkSection getChunk(int x, int y, int z);
|
||||||
void setChunk(int x, int y, int z, Chunk chunk);
|
void setChunk(int x, int y, int z, ChunkSection chunkSection);
|
||||||
|
|
||||||
Region getRegion(int x, int z);
|
Region getRegion(int x, int z);
|
||||||
void setRegion(int x, int z, Region region);
|
void setRegion(int x, int z, Region region);
|
||||||
|
|||||||
@@ -1,46 +1,16 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2018-04-15
|
|
||||||
*/
|
|
||||||
package mc.core.world.chunk;
|
package mc.core.world.chunk;
|
||||||
|
|
||||||
import mc.core.Location;
|
import mc.core.world.ChunkSection;
|
||||||
import mc.core.world.Biome;
|
import mc.core.world.Region;
|
||||||
import mc.core.world.block.Block;
|
import mc.core.world.World;
|
||||||
|
|
||||||
import java.io.Serializable;
|
public interface Chunk {
|
||||||
|
|
||||||
/**
|
World getWorld();
|
||||||
* Serialization chunk info
|
ChunkSection getChunkSection(int height);
|
||||||
*
|
ChunkSection setChunkSection(int height, ChunkSection chunkSection);
|
||||||
* +-------------+----------------+------------+
|
Region getRegion();
|
||||||
* | param | range | bits |
|
|
||||||
* +-------------+----------------+------------+
|
|
||||||
* | blocks | array | 24*count |
|
|
||||||
* +-------------+----------------+------------+
|
|
||||||
*
|
|
||||||
* Total: 24 * block_count bits (3 * block_count bytes)
|
|
||||||
* Max size: 12288 bytes (~12 Kb per chunk)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
/* 16x16x16 */
|
|
||||||
public interface Chunk extends Serializable{
|
|
||||||
Block getBlock(int x, int y, int z);
|
|
||||||
default Block getBlock(Location location) {
|
|
||||||
return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ());
|
|
||||||
}
|
|
||||||
void setBlock(Block block);
|
|
||||||
|
|
||||||
int getSkyLight(int x, int y, int z);
|
|
||||||
void setSkyLight(int x, int y, int z, int lightLevel);
|
|
||||||
|
|
||||||
int getAddition(int x, int y, int z);
|
|
||||||
void setAddition(int x, int y, int z, int value);
|
|
||||||
|
|
||||||
Biome getBiome(int x, int z);
|
|
||||||
void setBiome(int x, int z, Biome biome);
|
|
||||||
|
|
||||||
int getX();
|
int getX();
|
||||||
int getY();
|
|
||||||
int getZ();
|
int getZ();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package mc.core.world.chunk;
|
package mc.core.world.chunk;
|
||||||
|
|
||||||
|
import mc.core.world.ChunkSection;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface ChunkLoader {
|
public interface ChunkLoader {
|
||||||
@@ -12,7 +14,7 @@ public interface ChunkLoader {
|
|||||||
* @param z chunk position
|
* @param z chunk position
|
||||||
* @return optional of chunk (nullable)
|
* @return optional of chunk (nullable)
|
||||||
*/
|
*/
|
||||||
Optional<Chunk> loadChunk (int x, int y, int z);
|
Optional<ChunkSection> loadChunk (int x, int y, int z);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to load chunk like {@link #loadChunk(int, int, int)}
|
* Tries to load chunk like {@link #loadChunk(int, int, int)}
|
||||||
@@ -23,5 +25,5 @@ public interface ChunkLoader {
|
|||||||
* @param z chunk position
|
* @param z chunk position
|
||||||
* @return chunk
|
* @return chunk
|
||||||
*/
|
*/
|
||||||
Chunk loadOrGenerateChunk (int x, int y, int z);
|
ChunkSection loadOrGenerateChunk (int x, int y, int z);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import mc.core.Location;
|
|||||||
import mc.core.WarpPosition;
|
import mc.core.WarpPosition;
|
||||||
import mc.core.player.Look;
|
import mc.core.player.Look;
|
||||||
import mc.core.world.*;
|
import mc.core.world.*;
|
||||||
import mc.core.world.chunk.Chunk;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@@ -28,7 +27,7 @@ public class FlatWorld implements World {
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private WarpPosition spawn = new WarpPosition(new Location(0, 6, 0), new Look(0, 0));
|
private WarpPosition spawn = new WarpPosition(new Location(0, 6, 0), new Look(0, 0));
|
||||||
private Chunk chunk = new SimpleChunk(0, 0, 0); //FIXME temporary dummy
|
private ChunkSection chunkSection = new SimpleChunkSection();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IWorldType getWorldType() {
|
public IWorldType getWorldType() {
|
||||||
@@ -36,12 +35,12 @@ public class FlatWorld implements World {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Chunk getChunk(int x, int y, int z) {
|
public ChunkSection getChunk(int x, int y, int z) {
|
||||||
return chunk;
|
return chunkSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,34 +5,14 @@
|
|||||||
package mc.world.flat;
|
package mc.world.flat;
|
||||||
|
|
||||||
import mc.core.world.Biome;
|
import mc.core.world.Biome;
|
||||||
|
import mc.core.world.ChunkSection;
|
||||||
|
import mc.core.world.Region;
|
||||||
|
import mc.core.world.World;
|
||||||
import mc.core.world.block.Block;
|
import mc.core.world.block.Block;
|
||||||
import mc.core.world.block.BlockFactory;
|
import mc.core.world.block.BlockFactory;
|
||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.block.BlockType;
|
||||||
|
|
||||||
import static mc.core.world.block.BlockType.*;
|
|
||||||
|
|
||||||
public class SimpleChunk implements Chunk {
|
|
||||||
private static BlockFactory blockFactory = new BlockFactory();
|
|
||||||
private final int x, y, z;
|
|
||||||
|
|
||||||
public SimpleChunk(int x, int y, int z) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Block getBlock(int x, int y, int z) {
|
|
||||||
if (y == 0) return blockFactory.create(BEDROCK);
|
|
||||||
else if (y >= 1 && y <= 2) return blockFactory.create(DIRT);
|
|
||||||
else if (y == 3) return blockFactory.create(GRASS);
|
|
||||||
else return blockFactory.create(AIR);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBlock(Block block) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public class SimpleChunkSection implements ChunkSection {
|
||||||
@Override
|
@Override
|
||||||
public int getSkyLight(int x, int y, int z) {
|
public int getSkyLight(int x, int y, int z) {
|
||||||
if (y <= 3) return 0;
|
if (y <= 3) return 0;
|
||||||
@@ -66,16 +46,41 @@ public class SimpleChunk implements Chunk {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getX() {
|
public int getX() {
|
||||||
return x;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getY() {
|
public int getY() {
|
||||||
return y;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getZ() {
|
public int getZ() {
|
||||||
return z;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBlock(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 blockFactory.create(BlockType.AIR, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Region getRegion() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public World getWorld() {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,77 +1,61 @@
|
|||||||
package mc.world.generated_world.chunk;
|
package mc.world.generated_world.chunk;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import mc.core.exception.ResourceUnloadedException;
|
||||||
import mc.core.world.block.Block;
|
import mc.core.world.ChunkSection;
|
||||||
import mc.core.world.block.BlockFactory;
|
|
||||||
import mc.core.world.block.BlockType;
|
|
||||||
import mc.core.world.Biome;
|
|
||||||
import mc.core.world.chunk.Chunk;
|
|
||||||
import mc.core.world.Region;
|
import mc.core.world.Region;
|
||||||
|
import mc.core.world.World;
|
||||||
|
import mc.core.world.chunk.Chunk;
|
||||||
|
|
||||||
|
import java.lang.ref.Reference;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE;
|
import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
public class ChunkImpl implements Chunk {
|
||||||
public class ChunkImpl implements Chunk{
|
|
||||||
private static final BlockFactory blockFactory = new BlockFactory();
|
|
||||||
@Getter
|
@Getter
|
||||||
private final int x;
|
private final int x;
|
||||||
@Getter
|
@Getter
|
||||||
private final int y;
|
|
||||||
@Getter
|
|
||||||
private final int z;
|
private final int z;
|
||||||
private final Block[][][] blocks = new Block[WORLD_CHUNK_SIZE][WORLD_CHUNK_SIZE][WORLD_CHUNK_SIZE];
|
private Reference<Region> regionReference;
|
||||||
private final transient Region region;
|
private ChunkSection[] sections = new ChunkSection[WORLD_CHUNK_SIZE];
|
||||||
|
|
||||||
@Override
|
public ChunkImpl (int x, int z, Region region) {
|
||||||
public Block getBlock(int x, int y, int z) {
|
this.x = x;
|
||||||
Block block = blocks[x][y][z];
|
this.z = z;
|
||||||
if (block == null) {
|
this.regionReference = new WeakReference<>(region);
|
||||||
block = blockFactory.create(BlockType.AIR, 0, x, y, z);
|
|
||||||
}
|
|
||||||
block.setLight(15);
|
|
||||||
return block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBlock(Block block) {
|
public World getWorld() {
|
||||||
if (block.getBlockType() == BlockType.AIR) {
|
Region region = getRegion();
|
||||||
blocks[block.getLocation().getBlockX()]
|
if (region == null) {
|
||||||
[block.getLocation().getBlockY()]
|
throw new ResourceUnloadedException("Region is unloaded");
|
||||||
[block.getLocation().getBlockZ()] = null;
|
|
||||||
}
|
}
|
||||||
blocks[block.getLocation().getBlockX()]
|
return region.getWorld();
|
||||||
[block.getLocation().getBlockY()]
|
|
||||||
[block.getLocation().getBlockZ()] = block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSkyLight(int x, int y, int z) {
|
public ChunkSection getChunkSection(int height) {
|
||||||
return 15;
|
return sections[height];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSkyLight(int x, int y, int z, int lightLevel) {
|
public ChunkSection setChunkSection(int height, ChunkSection chunkSection) {
|
||||||
throw new UnsupportedOperationException();
|
sections[height] = chunkSection;
|
||||||
|
return chunkSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getAddition(int x, int y, int z) {
|
public Region getRegion() {
|
||||||
return 0;
|
if (regionReference == null) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
if (regionReference.get() == null) {
|
||||||
public void setAddition(int x, int y, int z, int value) {
|
throw new ResourceUnloadedException("Region is unloaded");
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
return regionReference.get();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package mc.world.generated_world.chunk;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import mc.core.exception.ResourceUnloadedException;
|
||||||
|
import mc.core.world.Biome;
|
||||||
|
import mc.core.world.ChunkSection;
|
||||||
|
import mc.core.world.Region;
|
||||||
|
import mc.core.world.World;
|
||||||
|
import mc.core.world.block.Block;
|
||||||
|
import mc.core.world.block.BlockFactory;
|
||||||
|
import mc.core.world.block.BlockType;
|
||||||
|
|
||||||
|
import java.lang.ref.Reference;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
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;
|
||||||
|
private BlockFactory blockFactory = new BlockFactory();
|
||||||
|
|
||||||
|
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 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(Block block) {
|
||||||
|
if (block.getBlockType() == BlockType.AIR) {
|
||||||
|
blocks[block.getLocation().getBlockX()][block.getLocation().getBlockY()][block.getLocation().getBlockZ()] = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blocks[block.getLocation().getBlockX()][block.getLocation().getBlockY()][block.getLocation().getBlockZ()] = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Block getBlock(int x, int y, int z) {
|
||||||
|
Block block = blocks[x][y][z];
|
||||||
|
if (block == null) {
|
||||||
|
return blockFactory.create(BlockType.AIR, 0, 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,20 @@
|
|||||||
package mc.world.generated_world.chunk;
|
package mc.world.generated_world.chunk;
|
||||||
|
|
||||||
|
import mc.core.world.ChunkSection;
|
||||||
|
import mc.core.world.Region;
|
||||||
|
import mc.core.world.World;
|
||||||
import mc.core.world.block.Block;
|
import mc.core.world.block.Block;
|
||||||
import mc.core.world.Biome;
|
import mc.core.world.Biome;
|
||||||
import mc.core.world.chunk.Chunk;
|
|
||||||
|
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
public class ChunkProxy implements Chunk {
|
public class ChunkSectionProxy implements ChunkSection {
|
||||||
private final Chunk chunk;
|
private final ChunkSection chunk;
|
||||||
private volatile transient long lastUsage = System.currentTimeMillis();
|
private volatile transient long lastUsage = System.currentTimeMillis();
|
||||||
private final transient ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
|
private final transient ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
|
||||||
|
|
||||||
public ChunkProxy(Chunk chunk) {
|
public ChunkSectionProxy(ChunkSection chunk) {
|
||||||
this.chunk = chunk;
|
this.chunk = chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +36,16 @@ public class ChunkProxy implements Chunk {
|
|||||||
return chunk.getBlock(x, y, z);
|
return chunk.getBlock(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Region getRegion() {
|
||||||
|
return chunk.getRegion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public World getWorld() {
|
||||||
|
return chunk.getWorld();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBlock(Block block) {
|
public void setBlock(Block block) {
|
||||||
use();
|
use();
|
||||||
@@ -27,7 +27,7 @@ public class InMemoryCacheChunkLoader implements ChunkLoader {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ChunkReader chunkReader;
|
private ChunkReader chunkReader;
|
||||||
@Autowired
|
@Autowired
|
||||||
private Serializer<Chunk> chunkSerializer;
|
private Serializer<ChunkSection> chunkSerializer;
|
||||||
@Autowired
|
@Autowired
|
||||||
private RegionReaderWriter regionReaderWritter;
|
private RegionReaderWriter regionReaderWritter;
|
||||||
|
|
||||||
@@ -46,14 +46,14 @@ public class InMemoryCacheChunkLoader implements ChunkLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Chunk> loadChunk(int x, int y, int z) {
|
public Optional<ChunkSection> loadChunk(int x, int y, int z) {
|
||||||
File file = getChuckFile(x, y, z);
|
File file = getChuckFile(x, y, z);
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
Chunk chunk = chunkReader.read(world.getRegion(x / WORLD_CHUNK_SIZE, z / WORLD_CHUNK_SIZE), x, y, z);
|
ChunkSection chunkSection = chunkReader.read(world.getRegion(x / WORLD_CHUNK_SIZE, z / WORLD_CHUNK_SIZE), x, y, z);
|
||||||
return Optional.of(chunk);
|
return Optional.of(chunkSection);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Error occurred while reading chunk file: " + file.getAbsolutePath(), e);
|
log.error("Error occurred while reading chunk file: " + file.getAbsolutePath(), e);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
@@ -62,12 +62,12 @@ public class InMemoryCacheChunkLoader implements ChunkLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 regX = x / WORLD_CHUNK_SIZE;
|
||||||
int regZ = z / WORLD_CHUNK_SIZE;
|
int regZ = z / WORLD_CHUNK_SIZE;
|
||||||
File regionFile = new File(worldFolder, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, regX, regZ));
|
File regionFile = new File(worldFolder, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, regX, regZ));
|
||||||
Region region;
|
Region region;
|
||||||
Chunk chunk;
|
ChunkSection chunkSection;
|
||||||
if (!regionFile.exists()) {
|
if (!regionFile.exists()) {
|
||||||
log.debug("Region [{}, {}] not found. Generating!", regX, regZ);
|
log.debug("Region [{}, {}] not found. Generating!", regX, regZ);
|
||||||
regionFile.mkdirs();
|
regionFile.mkdirs();
|
||||||
@@ -78,17 +78,17 @@ public class InMemoryCacheChunkLoader implements ChunkLoader {
|
|||||||
log.error("Error occurred while writting biome file", e);
|
log.error("Error occurred while writting biome file", e);
|
||||||
}
|
}
|
||||||
saveRegion(region);
|
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 {
|
} else {
|
||||||
try {
|
try {
|
||||||
region = regionReaderWritter.read(regX, regZ, world);
|
region = regionReaderWritter.read(regX, regZ, world);
|
||||||
chunk = chunkReader.read(region, x, y, z);
|
chunkSection = chunkReader.read(region, x, y, z);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Error occurred while reading chunk file", e);
|
log.error("Error occurred while reading chunkSection file", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return chunk;
|
return chunkSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveRegion (Region region) {
|
private void saveRegion (Region region) {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import mc.core.world.block.BlockFactory;
|
import mc.core.world.block.BlockFactory;
|
||||||
import mc.core.world.block.BlockType;
|
import mc.core.world.block.BlockType;
|
||||||
import mc.core.world.*;
|
import mc.core.world.*;
|
||||||
import mc.core.world.chunk.Chunk;
|
|
||||||
import mc.world.generated_world.region.RegionImpl;
|
import mc.world.generated_world.region.RegionImpl;
|
||||||
import mc.world.generated_world.world.CubicWorld;
|
import mc.world.generated_world.world.CubicWorld;
|
||||||
import mc.world.generated_world.world.Temperature;
|
import mc.world.generated_world.world.Temperature;
|
||||||
@@ -226,7 +225,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator {
|
|||||||
region.setBiome(x, z, biomes[x][z]);
|
region.setBiome(x, z, biomes[x][z]);
|
||||||
if (heightMap[x][z] < WORLD_SEA_LEVEL) {
|
if (heightMap[x][z] < WORLD_SEA_LEVEL) {
|
||||||
for (int y = 0; y < WORLD_SEA_LEVEL; y ++) {
|
for (int y = 0; y < WORLD_SEA_LEVEL; y ++) {
|
||||||
Chunk chunk = region.getChunkAt(x / 16, y / 16, z / 16);
|
ChunkSection chunk = region.getChunkAt(x / 16, y / 16, z / 16);
|
||||||
if (y == 0) {
|
if (y == 0) {
|
||||||
chunk.setBlock(blockFactory.create(BlockType.BEDROCK, 0, x % 16, y % 16, z % 16));
|
chunk.setBlock(blockFactory.create(BlockType.BEDROCK, 0, x % 16, y % 16, z % 16));
|
||||||
continue;
|
continue;
|
||||||
@@ -243,7 +242,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int y = 0; y < heightMap[x][z]; y++) {
|
for (int y = 0; y < heightMap[x][z]; y++) {
|
||||||
Chunk chunk = region.getChunkAt(x / 16, y / 16, z / 16);
|
ChunkSection chunk = region.getChunkAt(x / 16, y / 16, z / 16);
|
||||||
if (y == 0) {
|
if (y == 0) {
|
||||||
chunk.setBlock(blockFactory.create(BlockType.BEDROCK, 0, x % 16, y % 16, z % 16));
|
chunk.setBlock(blockFactory.create(BlockType.BEDROCK, 0, x % 16, y % 16, z % 16));
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -1,61 +1,90 @@
|
|||||||
package mc.world.generated_world.region;
|
package mc.world.generated_world.region;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
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.core.world.chunk.Chunk;
|
import mc.core.world.chunk.Chunk;
|
||||||
import mc.core.world.chunk.ChunkLoader;
|
import mc.core.world.chunk.ChunkLoader;
|
||||||
|
import mc.world.generated_world.chunk.ChunkSectionProxy;
|
||||||
import mc.world.generated_world.chunk.InMemoryCacheChunkLoader;
|
import mc.world.generated_world.chunk.InMemoryCacheChunkLoader;
|
||||||
import mc.world.generated_world.chunk.ChunkImpl;
|
import mc.world.generated_world.chunk.ChunkImpl;
|
||||||
import mc.world.generated_world.chunk.ChunkProxy;
|
import mc.world.generated_world.chunk.ChunkSectionImpl;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.Reference;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
import static mc.world.generated_world.WorldConstants.*;
|
import static mc.world.generated_world.WorldConstants.*;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class RegionImpl implements Region{
|
public class RegionImpl implements Region{
|
||||||
@Getter
|
@Getter
|
||||||
private final int x;
|
private final int x;
|
||||||
@Getter
|
@Getter
|
||||||
private final int z;
|
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 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];
|
||||||
@Getter
|
private final transient Reference<World> world;
|
||||||
private final transient 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;
|
||||||
|
|
||||||
|
public RegionImpl (int x, int z, World world) {
|
||||||
|
this.x = x;
|
||||||
|
this.z = z;
|
||||||
|
this.world = new WeakReference<>(world);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Chunk getChunkAt(int x, int y, int z) {
|
public Chunk getChunk(int x, int z) {
|
||||||
if (x < 0 || y < 0 || z < 0 || x >= 16 || y >= 16 || z >= 16) {
|
if (x < 0 || z < 0 || x >= 16 || z >= 16) {
|
||||||
throw new RuntimeException(MessageFormat.format("Invalid chunk coordinates [{0} {1} {2}]", x, y, z));
|
throw new RuntimeException(MessageFormat.format("Invalid chunk coordinates [{0} {1}]", x, z));
|
||||||
}
|
}
|
||||||
if (chunkLoader == null) {
|
|
||||||
chunkLoader = new InMemoryCacheChunkLoader(world);
|
Chunk chunk = chunks[x][z];
|
||||||
}
|
|
||||||
Chunk chunk = chunks[x][y][z];
|
|
||||||
if (chunk == null) {
|
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));
|
chunk = new ChunkImpl(x, z, this);
|
||||||
chunks[x][y][z] = new ChunkProxy(chunk);
|
for (int y = 0; y < WORLD_CHUNK_SIZE; y ++) {
|
||||||
|
chunk.setChunkSection(y, getChunkAt(x, y, z));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setChunk(int x, int y, int z, Chunk chunk) {
|
public void setChunk(int x, int z, Chunk chunk) {
|
||||||
if (x < 0 || y < 0 || z < 0 || x >= 16 || y >= 16 || z >= 16) {
|
chunks[x][z] = chunk;
|
||||||
throw new RuntimeException(MessageFormat.format("Invalid chunk coordinates [{0} {1} {2}]", x, y, z));
|
|
||||||
}
|
}
|
||||||
chunks[x][y][z] = new ChunkProxy(chunk);
|
|
||||||
|
@Override
|
||||||
|
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 chunkSection coordinates [{0} {1} {2}]", x, y, z));
|
||||||
|
}
|
||||||
|
if (chunkLoader == null) {
|
||||||
|
chunkLoader = new InMemoryCacheChunkLoader(getWorld());
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
chunkSectionProxies[x][y][z] = new ChunkSectionProxy(chunkSection);
|
||||||
|
}
|
||||||
|
return chunkSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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 chunkSection coordinates [{0} {1} {2}]", x, y, z));
|
||||||
|
}
|
||||||
|
chunkSectionProxies[x][y][z] = new ChunkSectionProxy(chunkSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -75,9 +104,20 @@ public class RegionImpl implements Region{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void save(Serializer<Chunk> chunkSerializer, IRegionReaderWriter regionReaderWriter) throws IOException {
|
public World getWorld() {
|
||||||
|
if (world == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (world.get() == null) {
|
||||||
|
throw new ResourceUnloadedException("World is unloaded");
|
||||||
|
}
|
||||||
|
return world.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(Serializer<ChunkSection> chunkSerializer, IRegionReaderWriter regionReaderWriter) throws IOException {
|
||||||
String worldPath = System.getProperty("worlds.folder", "worlds");
|
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()));
|
File regionFile = new File(worldFile, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, this.getX(), this.getZ()));
|
||||||
if (!regionFile.exists()) {
|
if (!regionFile.exists()) {
|
||||||
regionFile.mkdirs();
|
regionFile.mkdirs();
|
||||||
@@ -86,8 +126,8 @@ public class RegionImpl implements Region{
|
|||||||
for (int x = 0; x < WORLD_CHUNK_SIZE; x ++) {
|
for (int x = 0; x < WORLD_CHUNK_SIZE; x ++) {
|
||||||
for (int z = 0; z < WORLD_CHUNK_SIZE; z ++) {
|
for (int z = 0; z < WORLD_CHUNK_SIZE; z ++) {
|
||||||
for (int y = 0; y < WORLD_CHUNK_SIZE; y++) {
|
for (int y = 0; y < WORLD_CHUNK_SIZE; y++) {
|
||||||
Chunk chunk = this.getChunkAt(x, y, z);
|
ChunkSection chunkSection = this.getChunkAt(x, y, z);
|
||||||
byte[] chunkBytes = chunkSerializer.serialize(chunk);
|
byte[] chunkBytes = chunkSerializer.serialize(chunkSection);
|
||||||
if (chunkBytes.length > 0) {
|
if (chunkBytes.length > 0) {
|
||||||
File chunkFile = new File(regionFile, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x, y, z));
|
File chunkFile = new File(regionFile, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x, y, z));
|
||||||
try (FileOutputStream fileOutputStream = new FileOutputStream(chunkFile)) {
|
try (FileOutputStream fileOutputStream = new FileOutputStream(chunkFile)) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import mc.core.world.block.BlockFactory;
|
|||||||
import mc.core.world.block.BlockType;
|
import mc.core.world.block.BlockType;
|
||||||
import mc.core.serialization.Deserializer;
|
import mc.core.serialization.Deserializer;
|
||||||
import mc.core.serialization.Serializer;
|
import mc.core.serialization.Serializer;
|
||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.ChunkSection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prototype
|
* Prototype
|
||||||
@@ -13,20 +13,20 @@ import mc.core.world.chunk.Chunk;
|
|||||||
public class BlockSerializerDeserializer implements Serializer<Block>, Deserializer<Block> {
|
public class BlockSerializerDeserializer implements Serializer<Block>, Deserializer<Block> {
|
||||||
|
|
||||||
private BlockFactory blockFactory;
|
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.blockFactory = blockFactory;
|
||||||
this.chunk = chunk;
|
this.chunkSection = chunkSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Block deserialize(byte[] bytes) {
|
public Block deserialize(byte[] bytes) {
|
||||||
int id = bytes[0] + 128;
|
int id = bytes[0] + 128;
|
||||||
int meta = bytes[1] >> 4;
|
int meta = bytes[1] >> 4;
|
||||||
int x = (bytes[1] & 0xf) + chunk.getX() * 16;
|
int x = (bytes[1] & 0xf) + chunkSection.getX() * 16;
|
||||||
int y = bytes[2] >> 4 + chunk.getY() * 16;
|
int y = bytes[2] >> 4 + chunkSection.getY() * 16;
|
||||||
int z = (bytes[2] & 0xf) + chunk.getZ() * 16;
|
int z = (bytes[2] & 0xf) + chunkSection.getZ() * 16;
|
||||||
BlockType type = BlockType.values()[id];
|
BlockType type = BlockType.values()[id];
|
||||||
Block block = blockFactory.create(type, meta);
|
Block block = blockFactory.create(type, meta);
|
||||||
block.getLocation().setX(x);
|
block.getLocation().setX(x);
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package mc.world.generated_world.serialization;
|
package mc.world.generated_world.serialization;
|
||||||
|
|
||||||
|
import mc.core.Location;
|
||||||
import mc.core.world.block.Block;
|
import mc.core.world.block.Block;
|
||||||
import mc.core.serialization.Deserializer;
|
import mc.core.serialization.Deserializer;
|
||||||
import mc.core.serialization.IChunkReader;
|
import mc.core.serialization.IChunkReader;
|
||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.ChunkSection;
|
||||||
import mc.core.world.Region;
|
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 org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -26,22 +27,22 @@ public class ChunkReader implements IChunkReader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
x %= WORLD_REGION_SIZE;
|
||||||
y %= WORLD_REGION_SIZE;
|
y %= WORLD_REGION_SIZE;
|
||||||
z %= 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));
|
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()));
|
byte[] chunkBytes = Files.readAllBytes(Paths.get(chunkFile.toURI()));
|
||||||
int blocks = (chunkBytes.length) / 3;
|
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 ++) {
|
for (int i = 0; i < blocks; i ++) {
|
||||||
byte[] blockBytes = new byte[3];
|
byte[] blockBytes = new byte[3];
|
||||||
blockBytes[0] = chunkBytes[3 * i];
|
blockBytes[0] = chunkBytes[3 * i];
|
||||||
blockBytes[1] = chunkBytes[1 + 3 * i];
|
blockBytes[1] = chunkBytes[1 + 3 * i];
|
||||||
blockBytes[2] = chunkBytes[2 + 3 * i];
|
blockBytes[2] = chunkBytes[2 + 3 * i];
|
||||||
Block block = blockDeserializer.deserialize(blockBytes);
|
Block block = blockDeserializer.deserialize(blockBytes);
|
||||||
chunk.setBlock(block);
|
chunkSection.setBlock(block);
|
||||||
}
|
}
|
||||||
return chunk;
|
return chunkSection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import mc.core.world.block.Block;
|
|||||||
import mc.core.world.block.BlockFactory;
|
import mc.core.world.block.BlockFactory;
|
||||||
import mc.core.world.block.BlockType;
|
import mc.core.world.block.BlockType;
|
||||||
import mc.core.serialization.Serializer;
|
import mc.core.serialization.Serializer;
|
||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.ChunkSection;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -14,20 +14,20 @@ import java.io.IOException;
|
|||||||
import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE;
|
import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ChunkSerializer implements Serializer<Chunk> {
|
public class ChunkSerializer implements Serializer<ChunkSection> {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private Serializer<Block> blockSerializer;
|
private Serializer<Block> blockSerializer;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] serialize(Chunk chunk) {
|
public byte[] serialize(ChunkSection chunkSection) {
|
||||||
Serializer<Block> blockSerializer = new BlockSerializerDeserializer(new BlockFactory(), chunk);
|
Serializer<Block> blockSerializer = new BlockSerializerDeserializer(new BlockFactory(), chunkSection);
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
Block current;
|
Block current;
|
||||||
for (int x = 0; x < WORLD_CHUNK_SIZE; x ++) {
|
for (int x = 0; x < WORLD_CHUNK_SIZE; x ++) {
|
||||||
for (int y = 0; y < WORLD_CHUNK_SIZE; y ++) {
|
for (int y = 0; y < WORLD_CHUNK_SIZE; y ++) {
|
||||||
for (int z = 0; z < WORLD_CHUNK_SIZE; z ++) {
|
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) {
|
if (current != null && current.getBlockType() != BlockType.AIR) {
|
||||||
try {
|
try {
|
||||||
baos.write(blockSerializer.serialize(current));
|
baos.write(blockSerializer.serialize(current));
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import mc.core.Direction;
|
|||||||
import mc.core.Location;
|
import mc.core.Location;
|
||||||
import mc.core.WarpPosition;
|
import mc.core.WarpPosition;
|
||||||
import mc.core.player.Look;
|
import mc.core.player.Look;
|
||||||
|
import mc.core.world.ChunkSection;
|
||||||
import mc.core.world.IWorldType;
|
import mc.core.world.IWorldType;
|
||||||
import mc.core.world.Region;
|
import mc.core.world.Region;
|
||||||
import mc.core.world.World;
|
import mc.core.world.World;
|
||||||
@@ -105,13 +106,13 @@ public class CubicWorld implements World {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Chunk getChunk(int x, int y, int z) {
|
public ChunkSection getChunk(int x, int y, int z) {
|
||||||
Region region = getRegion(x / 16, z / 16);
|
Region region = getRegion(x / 16, z / 16);
|
||||||
return region.getChunkAt(x % 16, y % 16, z % 16);
|
return region.getChunkAt(x % 16, y % 16, z % 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setChunk(int x, int y, int z, Chunk chunk) {
|
public void setChunk(int x, int y, int z, ChunkSection chunkSection) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import mc.core.network.NetOutputStream;
|
import mc.core.network.NetOutputStream;
|
||||||
import mc.core.network.SCPacket;
|
import mc.core.network.SCPacket;
|
||||||
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
|
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
|
||||||
|
import mc.core.world.ChunkSection;
|
||||||
import mc.core.world.block.Block;
|
import mc.core.world.block.Block;
|
||||||
import mc.core.world.chunk.Chunk;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -76,7 +76,7 @@ public class ChunkDataPacket implements SCPacket {
|
|||||||
@Setter
|
@Setter
|
||||||
private boolean initChunk = true; // "Ground-Up Continuous"
|
private boolean initChunk = true; // "Ground-Up Continuous"
|
||||||
@Getter
|
@Getter
|
||||||
private List<Chunk> chunks = new ArrayList<>();
|
private List<ChunkSection> chunks = new ArrayList<>();
|
||||||
|
|
||||||
private int serializeBlockState(int id, int meta) {
|
private int serializeBlockState(int id, int meta) {
|
||||||
return (id << 4) | meta;
|
return (id << 4) | meta;
|
||||||
@@ -93,7 +93,7 @@ public class ChunkDataPacket implements SCPacket {
|
|||||||
int dataItems = 0;
|
int dataItems = 0;
|
||||||
final int airBlockPalette = serializeBlockState(0, 0);
|
final int airBlockPalette = serializeBlockState(0, 0);
|
||||||
|
|
||||||
for (Chunk chunk : chunks) {
|
for (ChunkSection chunk : chunks) {
|
||||||
final List<Integer> palette = new ArrayList<>();
|
final List<Integer> palette = new ArrayList<>();
|
||||||
palette.add(airBlockPalette);
|
palette.add(airBlockPalette);
|
||||||
final ByteArrayOutputNetStream dataArray = new ByteArrayOutputNetStream();
|
final ByteArrayOutputNetStream dataArray = new ByteArrayOutputNetStream();
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand
|
|||||||
Player player = playerManager.getPlayer(packet.getPlayerName())
|
Player player = playerManager.getPlayer(packet.getPlayerName())
|
||||||
.orElseGet(() -> playerManager.createPlayer(
|
.orElseGet(() -> playerManager.createPlayer(
|
||||||
packet.getPlayerName(),
|
packet.getPlayerName(),
|
||||||
world.getSpawn().getLocation(),
|
world.getSpawn(),
|
||||||
new Look(0f, 0f)));
|
new Look(0f, 0f)));
|
||||||
|
|
||||||
channel.writeAndFlush(new LoginSuccessPacket(
|
channel.writeAndFlush(new LoginSuccessPacket(
|
||||||
@@ -68,7 +68,7 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand
|
|||||||
|
|
||||||
// Spawn Position
|
// Spawn Position
|
||||||
SpawnPositionPacket pkt2 = new SpawnPositionPacket();
|
SpawnPositionPacket pkt2 = new SpawnPositionPacket();
|
||||||
pkt2.setLocation(world.getSpawn().getLocation());
|
pkt2.setLocation(world.getSpawn());
|
||||||
channel.write(pkt2);
|
channel.write(pkt2);
|
||||||
|
|
||||||
// Player Abilities
|
// Player Abilities
|
||||||
|
|||||||
Reference in New Issue
Block a user