From 0da566acb0e988bf757d6cf3b5c337b550bd70a9 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 26 Jul 2018 08:56:00 +0300 Subject: [PATCH 01/37] Interfaces fix --- core/src/main/java/mc/core/Location.java | 4 +++ .../main/java/mc/core/world/ChunkLoader.java | 27 +++++++++++++++++++ core/src/main/java/mc/core/world/World.java | 8 ++++-- .../java/mc/core/world/WorldGenerator.java | 6 +++++ .../main/java/mc/world/flat/FlatWorld.java | 10 +++++-- generated_world/build.gradle | 7 +++++ settings.gradle | 2 ++ 7 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 core/src/main/java/mc/core/world/ChunkLoader.java create mode 100644 core/src/main/java/mc/core/world/WorldGenerator.java create mode 100644 generated_world/build.gradle diff --git a/core/src/main/java/mc/core/Location.java b/core/src/main/java/mc/core/Location.java index fa1e00b..78b25c8 100644 --- a/core/src/main/java/mc/core/Location.java +++ b/core/src/main/java/mc/core/Location.java @@ -20,6 +20,10 @@ public class Location { ); } + public static Location startPointLocation () { + return new Location(0,10,0); + } + public void set(Location location) { this.x = location.x; this.y = location.y; diff --git a/core/src/main/java/mc/core/world/ChunkLoader.java b/core/src/main/java/mc/core/world/ChunkLoader.java new file mode 100644 index 0000000..a8213e4 --- /dev/null +++ b/core/src/main/java/mc/core/world/ChunkLoader.java @@ -0,0 +1,27 @@ +package mc.core.world; + +import java.util.Optional; + +public interface ChunkLoader { + + /** + * Loads chunk from cache. If chunk in cache doesn't exist, loads from file (or other storage) + * + * @param x chunk position + * @param y chunk position + * @param z chunk position + * @return optional of chunk (nullable) + */ + Optional loadChunk (int x, int y, int z); + + /** + * Tries to load chunk like {@link #loadChunk(int, int, int)} + * If chunk doesn't exist, generates it with selected world generator + * + * @param x chunk position + * @param y chunk position + * @param z chunk position + * @return chunk + */ + Chunk loadOrGenerateChunk (int x, int y, int z); +} diff --git a/core/src/main/java/mc/core/world/World.java b/core/src/main/java/mc/core/world/World.java index be5002b..6da22a8 100644 --- a/core/src/main/java/mc/core/world/World.java +++ b/core/src/main/java/mc/core/world/World.java @@ -6,10 +6,14 @@ package mc.core.world; import mc.core.Location; +import java.util.UUID; + public interface World { + UUID getWorldId(); + Location getSpawn(); void setSpawn(Location location); - Chunk getChunk(int x, int z); - void setChunk(int x, int z, Chunk chunk); + Chunk getChunk(int x, int y, int z); + void setChunk(int x, int y, int z, Chunk chunk); } diff --git a/core/src/main/java/mc/core/world/WorldGenerator.java b/core/src/main/java/mc/core/world/WorldGenerator.java new file mode 100644 index 0000000..4b5fd30 --- /dev/null +++ b/core/src/main/java/mc/core/world/WorldGenerator.java @@ -0,0 +1,6 @@ +package mc.core.world; + +public interface WorldGenerator { + + Chunk generateChunk (int x, int z, World world); +} 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 8340979..2e612a8 100644 --- a/flat_world/src/main/java/mc/world/flat/FlatWorld.java +++ b/flat_world/src/main/java/mc/world/flat/FlatWorld.java @@ -10,19 +10,25 @@ import mc.core.Location; import mc.core.world.Chunk; import mc.core.world.World; +import java.util.UUID; + public class FlatWorld implements World { + + @Getter@Setter + private UUID worldId; + @Getter @Setter private Location spawn = new Location(0, 6, 0); private Chunk chunk = new SimpleChunk(); @Override - public Chunk getChunk(int x, int z) { + public Chunk getChunk(int x, int y, int z) { return chunk; } @Override - public void setChunk(int x, int z, Chunk chunk) { + public void setChunk(int x, int y, int z, Chunk chunk) { throw new UnsupportedOperationException(); } } diff --git a/generated_world/build.gradle b/generated_world/build.gradle new file mode 100644 index 0000000..5c7cdc7 --- /dev/null +++ b/generated_world/build.gradle @@ -0,0 +1,7 @@ +group 'mc' +version '1.0-SNAPSHOT' + +dependencies { + compile_excludeCopy project(':core') + testCompile group: 'junit', name: 'junit', version: '4.12' +} diff --git a/settings.gradle b/settings.gradle index 52ad5e4..7855426 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,3 +5,5 @@ include('flat_world') include('vanilla_commands') include('proto_1.12.2') // Protocol 1.12.2 include('proto_1.12.2_netty') // Protocol 1.12.2 (Netty impl.) +include 'generated_world' + From 39b85bd64d443df6e2b8acc3b13d67d162abc927 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 26 Jul 2018 09:00:53 +0300 Subject: [PATCH 02/37] World types --- .../main/java/mc/core/world/IWorldType.java | 6 ++++++ core/src/main/java/mc/core/world/World.java | 1 + .../src/main/java/mc/core/world/WorldType.java | 18 ++++++++++++++++++ .../src/main/java/mc/world/flat/FlatWorld.java | 7 +++++++ 4 files changed, 32 insertions(+) create mode 100644 core/src/main/java/mc/core/world/IWorldType.java create mode 100644 core/src/main/java/mc/core/world/WorldType.java diff --git a/core/src/main/java/mc/core/world/IWorldType.java b/core/src/main/java/mc/core/world/IWorldType.java new file mode 100644 index 0000000..64d5643 --- /dev/null +++ b/core/src/main/java/mc/core/world/IWorldType.java @@ -0,0 +1,6 @@ +package mc.core.world; + +public interface IWorldType { + String name(); + String description(); +} diff --git a/core/src/main/java/mc/core/world/World.java b/core/src/main/java/mc/core/world/World.java index 6da22a8..4491769 100644 --- a/core/src/main/java/mc/core/world/World.java +++ b/core/src/main/java/mc/core/world/World.java @@ -10,6 +10,7 @@ import java.util.UUID; public interface World { UUID getWorldId(); + IWorldType getWorldType(); Location getSpawn(); void setSpawn(Location location); diff --git a/core/src/main/java/mc/core/world/WorldType.java b/core/src/main/java/mc/core/world/WorldType.java new file mode 100644 index 0000000..59b42a4 --- /dev/null +++ b/core/src/main/java/mc/core/world/WorldType.java @@ -0,0 +1,18 @@ +package mc.core.world; + +public enum WorldType implements IWorldType { + GENERAl ("Standard world type"), + NETHER ("Nether world type"), + END ("End world type"); + + private final String description; + + WorldType(String description) { + this.description = description; + } + + @Override + public String description() { + return description; + } +} 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 2e612a8..7595550 100644 --- a/flat_world/src/main/java/mc/world/flat/FlatWorld.java +++ b/flat_world/src/main/java/mc/world/flat/FlatWorld.java @@ -8,7 +8,9 @@ import lombok.Getter; import lombok.Setter; import mc.core.Location; import mc.core.world.Chunk; +import mc.core.world.IWorldType; import mc.core.world.World; +import mc.core.world.WorldType; import java.util.UUID; @@ -22,6 +24,11 @@ public class FlatWorld implements World { private Location spawn = new Location(0, 6, 0); private Chunk chunk = new SimpleChunk(); + @Override + public IWorldType getWorldType() { + return WorldType.GENERAl; + } + @Override public Chunk getChunk(int x, int y, int z) { return chunk; From 4f214ed2508f0fee7713b31349fe93412b4ae484 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 26 Jul 2018 12:25:48 +0300 Subject: [PATCH 03/37] Block --- .../java/mc/core/block/AbstractBlock.java | 23 ++++++++++ core/src/main/java/mc/core/block/Block.java | 46 +++++++++++++++++++ .../main/java/mc/core/block/BlockType.java | 20 ++++++++ .../main/java/mc/core/world/WorldType.java | 2 +- .../main/java/mc/world/flat/FlatWorld.java | 2 +- 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/mc/core/block/AbstractBlock.java create mode 100644 core/src/main/java/mc/core/block/Block.java create mode 100644 core/src/main/java/mc/core/block/BlockType.java diff --git a/core/src/main/java/mc/core/block/AbstractBlock.java b/core/src/main/java/mc/core/block/AbstractBlock.java new file mode 100644 index 0000000..7b17761 --- /dev/null +++ b/core/src/main/java/mc/core/block/AbstractBlock.java @@ -0,0 +1,23 @@ +package mc.core.block; + +import lombok.Getter; +import lombok.Setter; +import mc.core.Location; + +public abstract class AbstractBlock implements Block { + @Getter@Setter + private Location location; + @Getter@Setter + private int meta; + @Getter + private final BlockType blockType; + + protected AbstractBlock(BlockType type) { + this.blockType = type; + } + + @Override + public int getId() { + return blockType.getId(); + } +} diff --git a/core/src/main/java/mc/core/block/Block.java b/core/src/main/java/mc/core/block/Block.java new file mode 100644 index 0000000..a34f328 --- /dev/null +++ b/core/src/main/java/mc/core/block/Block.java @@ -0,0 +1,46 @@ +package mc.core.block; + +import mc.core.Location; + +/** + * Serialize info about block + * + * +------------+--------+------------+ + * | param | range | bits | + * +------------+--------+------------+ + * | id | 0-255 | 8 | + * +------------+--------+------------+ + * | meta | 0-15 | 4 | + * +------------+--------+------------+ + * | x | 0-15 | 4 | + * +------------+--------+------------+ + * | y | 0-15 | 4 | + * +------------+--------+------------+ + * | z | 0-15 | 4 | + * +------------+--------+------------+ + * + * Total: 24 bits per block (3 bytes) + * + */ + +public interface Block { + + /** Block id */ + int getId(); + + /** + * Addition in 0-15 + * F.e. 35:0 - white wool + * 35:15 - black wool + */ + int getMeta(); + + /** + * Getting block type + */ + BlockType getBlockType(); + + /** Block location */ + Location getLocation(); + +} diff --git a/core/src/main/java/mc/core/block/BlockType.java b/core/src/main/java/mc/core/block/BlockType.java new file mode 100644 index 0000000..cf6cc1a --- /dev/null +++ b/core/src/main/java/mc/core/block/BlockType.java @@ -0,0 +1,20 @@ +package mc.core.block; + +import lombok.Getter; + +public enum BlockType { + DIRT(1, "Dirt"), + GRASS(2, "Grass"), + BEDROCK(7, "Bedrock"); + + @Getter + private final int id; + @Getter + private final String name; + + BlockType(int id, String name) { + this.id = id; + this.name = name; + } + +} diff --git a/core/src/main/java/mc/core/world/WorldType.java b/core/src/main/java/mc/core/world/WorldType.java index 59b42a4..73533fa 100644 --- a/core/src/main/java/mc/core/world/WorldType.java +++ b/core/src/main/java/mc/core/world/WorldType.java @@ -1,7 +1,7 @@ package mc.core.world; public enum WorldType implements IWorldType { - GENERAl ("Standard world type"), + GENERAL("Standard world type"), NETHER ("Nether world type"), END ("End world type"); 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 7595550..d12b034 100644 --- a/flat_world/src/main/java/mc/world/flat/FlatWorld.java +++ b/flat_world/src/main/java/mc/world/flat/FlatWorld.java @@ -26,7 +26,7 @@ public class FlatWorld implements World { @Override public IWorldType getWorldType() { - return WorldType.GENERAl; + return WorldType.GENERAL; } @Override From be91e114df0b5b35919965d00145fca72eca53df Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 26 Jul 2018 13:51:46 +0300 Subject: [PATCH 04/37] Block serialization --- .../java/mc/core/block/AbstractBlock.java | 7 ++- core/src/main/java/mc/core/block/Block.java | 12 ++--- .../main/java/mc/core/block/BlockFactory.java | 17 +++++++ .../core/serialization/BlockDeserializer.java | 6 +++ .../core/serialization/BlockSerializer.java | 6 +++ .../mc/core/serialization/Deserializer.java | 5 ++ .../mc/core/serialization/Serializer.java | 5 ++ .../BlockSerializerDeserializer.java | 46 +++++++++++++++++++ 8 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 core/src/main/java/mc/core/block/BlockFactory.java create mode 100644 core/src/main/java/mc/core/serialization/BlockDeserializer.java create mode 100644 core/src/main/java/mc/core/serialization/BlockSerializer.java create mode 100644 core/src/main/java/mc/core/serialization/Deserializer.java create mode 100644 core/src/main/java/mc/core/serialization/Serializer.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/BlockSerializerDeserializer.java diff --git a/core/src/main/java/mc/core/block/AbstractBlock.java b/core/src/main/java/mc/core/block/AbstractBlock.java index 7b17761..11f3f7f 100644 --- a/core/src/main/java/mc/core/block/AbstractBlock.java +++ b/core/src/main/java/mc/core/block/AbstractBlock.java @@ -7,7 +7,7 @@ import mc.core.Location; public abstract class AbstractBlock implements Block { @Getter@Setter private Location location; - @Getter@Setter + @Getter private int meta; @Getter private final BlockType blockType; @@ -16,6 +16,11 @@ public abstract class AbstractBlock implements Block { this.blockType = type; } + protected AbstractBlock(BlockType type, int meta) { + this.blockType = type; + this.meta = meta; + } + @Override public int getId() { return blockType.getId(); diff --git a/core/src/main/java/mc/core/block/Block.java b/core/src/main/java/mc/core/block/Block.java index a34f328..ea03afb 100644 --- a/core/src/main/java/mc/core/block/Block.java +++ b/core/src/main/java/mc/core/block/Block.java @@ -3,20 +3,20 @@ package mc.core.block; import mc.core.Location; /** - * Serialize info about block + * Serialization block info * * +------------+--------+------------+ * | param | range | bits | * +------------+--------+------------+ - * | id | 0-255 | 8 | + * | id | 0:255 | 8 | * +------------+--------+------------+ - * | meta | 0-15 | 4 | + * | meta | 0:15 | 4 | * +------------+--------+------------+ - * | x | 0-15 | 4 | + * | x | 0:15 | 4 | * +------------+--------+------------+ - * | y | 0-15 | 4 | + * | y | 0:15 | 4 | * +------------+--------+------------+ - * | z | 0-15 | 4 | + * | z | 0:15 | 4 | * +------------+--------+------------+ * * Total: 24 bits per block (3 bytes) diff --git a/core/src/main/java/mc/core/block/BlockFactory.java b/core/src/main/java/mc/core/block/BlockFactory.java new file mode 100644 index 0000000..2007c48 --- /dev/null +++ b/core/src/main/java/mc/core/block/BlockFactory.java @@ -0,0 +1,17 @@ +package mc.core.block; + +public class BlockFactory { + + public Block create(BlockType blockType, int meta) { + return new EmbeddedBlock(blockType, meta); + } + + /** + * For first-time generation + */ + private class EmbeddedBlock extends AbstractBlock { + EmbeddedBlock(BlockType type, int meta) { + super(type, meta); + } + } +} diff --git a/core/src/main/java/mc/core/serialization/BlockDeserializer.java b/core/src/main/java/mc/core/serialization/BlockDeserializer.java new file mode 100644 index 0000000..dfdbc89 --- /dev/null +++ b/core/src/main/java/mc/core/serialization/BlockDeserializer.java @@ -0,0 +1,6 @@ +package mc.core.serialization; + +import mc.core.block.Block; + +public interface BlockDeserializer extends Deserializer { +} diff --git a/core/src/main/java/mc/core/serialization/BlockSerializer.java b/core/src/main/java/mc/core/serialization/BlockSerializer.java new file mode 100644 index 0000000..1e5730d --- /dev/null +++ b/core/src/main/java/mc/core/serialization/BlockSerializer.java @@ -0,0 +1,6 @@ +package mc.core.serialization; + +import mc.core.block.Block; + +public interface BlockSerializer extends Serializer { +} diff --git a/core/src/main/java/mc/core/serialization/Deserializer.java b/core/src/main/java/mc/core/serialization/Deserializer.java new file mode 100644 index 0000000..ab4332b --- /dev/null +++ b/core/src/main/java/mc/core/serialization/Deserializer.java @@ -0,0 +1,5 @@ +package mc.core.serialization; + +public interface Deserializer { + T deserialize (byte[] bytes); +} diff --git a/core/src/main/java/mc/core/serialization/Serializer.java b/core/src/main/java/mc/core/serialization/Serializer.java new file mode 100644 index 0000000..8823b3c --- /dev/null +++ b/core/src/main/java/mc/core/serialization/Serializer.java @@ -0,0 +1,5 @@ +package mc.core.serialization; + +public interface Serializer { + byte[] serialize (T t); +} diff --git a/generated_world/src/main/java/mc/world/generated_world/BlockSerializerDeserializer.java b/generated_world/src/main/java/mc/world/generated_world/BlockSerializerDeserializer.java new file mode 100644 index 0000000..718a420 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/BlockSerializerDeserializer.java @@ -0,0 +1,46 @@ +package mc.world.generated_world; + +import mc.core.block.Block; +import mc.core.block.BlockFactory; +import mc.core.block.BlockType; +import mc.core.serialization.BlockDeserializer; +import mc.core.serialization.BlockSerializer; +import mc.core.world.Chunk; + +/** + * Prototype + */ +public class BlockSerializerDeserializer implements BlockSerializer, BlockDeserializer { + + private BlockFactory blockFactory; + private Chunk chunk; + + public BlockSerializerDeserializer(BlockFactory blockFactory, Chunk chunk) { + this.blockFactory = blockFactory; + this.chunk = chunk; + } + + @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; + BlockType type = BlockType.values()[id]; + Block block = blockFactory.create(type, meta); + block.getLocation().setX(x); + block.getLocation().setY(y); + block.getLocation().setZ(z); + return block; + } + + @Override + public byte[] serialize(Block block) { + byte[] bytes = new byte[3]; + bytes[0] = (byte) ((block.getId() - 128) & 0xff); + bytes[1] = (byte) ((block.getMeta() << 4) | (block.getLocation().getBlockX() % 16)); + bytes[2] = (byte) (((block.getLocation().getBlockZ() % 16) << 4) | (block.getLocation().getBlockZ() % 16)); + return bytes; + } +} From f67958de5a635795d648f7cc748dfdb870eb5dfb Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 26 Jul 2018 15:47:01 +0300 Subject: [PATCH 05/37] UUID utils --- .../main/java/mc/core/utils/UuidUtils.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 core/src/main/java/mc/core/utils/UuidUtils.java diff --git a/core/src/main/java/mc/core/utils/UuidUtils.java b/core/src/main/java/mc/core/utils/UuidUtils.java new file mode 100644 index 0000000..dab5299 --- /dev/null +++ b/core/src/main/java/mc/core/utils/UuidUtils.java @@ -0,0 +1,21 @@ +package mc.core.utils; + +import java.nio.ByteBuffer; +import java.util.UUID; + +public class UuidUtils { + + public static UUID asUuid(byte[] bytes) { + ByteBuffer bb = ByteBuffer.wrap(bytes); + long firstLong = bb.getLong(); + long secondLong = bb.getLong(); + return new UUID(firstLong, secondLong); + } + + public static byte[] asBytes(UUID uuid) { + ByteBuffer bb = ByteBuffer.wrap(new byte[16]); + bb.putLong(uuid.getMostSignificantBits()); + bb.putLong(uuid.getLeastSignificantBits()); + return bb.array(); + } +} From 19ee6d73fc529e2e91aa888b50ce856a592d384e Mon Sep 17 00:00:00 2001 From: Forwolk Date: Fri, 27 Jul 2018 08:16:13 +0300 Subject: [PATCH 06/37] Chunk serializer/deserializer --- .../main/java/mc/core/serialization/ChunkDeserializer.java | 6 ++++++ .../main/java/mc/core/serialization/ChunkSerializer.java | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 core/src/main/java/mc/core/serialization/ChunkDeserializer.java create mode 100644 core/src/main/java/mc/core/serialization/ChunkSerializer.java diff --git a/core/src/main/java/mc/core/serialization/ChunkDeserializer.java b/core/src/main/java/mc/core/serialization/ChunkDeserializer.java new file mode 100644 index 0000000..edff066 --- /dev/null +++ b/core/src/main/java/mc/core/serialization/ChunkDeserializer.java @@ -0,0 +1,6 @@ +package mc.core.serialization; + +import mc.core.world.Chunk; + +public interface ChunkDeserializer extends Deserializer{ +} diff --git a/core/src/main/java/mc/core/serialization/ChunkSerializer.java b/core/src/main/java/mc/core/serialization/ChunkSerializer.java new file mode 100644 index 0000000..3614951 --- /dev/null +++ b/core/src/main/java/mc/core/serialization/ChunkSerializer.java @@ -0,0 +1,6 @@ +package mc.core.serialization; + +import mc.core.world.Chunk; + +public interface ChunkSerializer extends Serializer{ +} From a9e44c98d642d6a1a3826c91911f29a301955833 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Fri, 27 Jul 2018 08:16:29 +0300 Subject: [PATCH 07/37] Biome --- core/src/main/java/mc/core/world/Biome.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 core/src/main/java/mc/core/world/Biome.java diff --git a/core/src/main/java/mc/core/world/Biome.java b/core/src/main/java/mc/core/world/Biome.java new file mode 100644 index 0000000..4d05677 --- /dev/null +++ b/core/src/main/java/mc/core/world/Biome.java @@ -0,0 +1,18 @@ +package mc.core.world; + +import lombok.Getter; + +public enum Biome { + PLAIN(0, "Plain"), + DESERT(1, "Desert"); + + @Getter + private final int id; + @Getter + private final String name; + + Biome(int id, String name) { + this.id = id; + this.name = name; + } +} From ec67dc328ec69228d70d00fc7c8af3ddf72aea58 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Fri, 27 Jul 2018 08:16:46 +0300 Subject: [PATCH 08/37] Region --- core/src/main/java/mc/core/world/Region.java | 17 +++++++++++++++++ .../main/java/mc/core/world/WorldGenerator.java | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/mc/core/world/Region.java diff --git a/core/src/main/java/mc/core/world/Region.java b/core/src/main/java/mc/core/world/Region.java new file mode 100644 index 0000000..615af3e --- /dev/null +++ b/core/src/main/java/mc/core/world/Region.java @@ -0,0 +1,17 @@ +package mc.core.world; + +/** + * Simple world generation unit + * 16x16x16 chunks + */ +public interface Region { + Chunk getChunkAt(int x, int y, int z); + void setChunk(int x, int y, int z, Chunk chunk); + + int getX(); + int getY(); + int getZ(); + + Biome getBiomeAt (int x, int z); + void setBiome (int x, int z, Biome biome); +} diff --git a/core/src/main/java/mc/core/world/WorldGenerator.java b/core/src/main/java/mc/core/world/WorldGenerator.java index 4b5fd30..817012c 100644 --- a/core/src/main/java/mc/core/world/WorldGenerator.java +++ b/core/src/main/java/mc/core/world/WorldGenerator.java @@ -2,5 +2,5 @@ package mc.core.world; public interface WorldGenerator { - Chunk generateChunk (int x, int z, World world); + Region generateRegion (int x, int z, World world); } From bf2352c747ebd061f1e80f9d4aa6695926055dd0 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Fri, 27 Jul 2018 08:17:19 +0300 Subject: [PATCH 09/37] Chunk changes --- core/src/main/java/mc/core/world/Chunk.java | 32 +++++++++++++++++-- .../main/java/mc/world/flat/FlatWorld.java | 2 +- .../main/java/mc/world/flat/SimpleChunk.java | 31 ++++++++++++++++-- generated_world/README.MD | 3 ++ 4 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 generated_world/README.MD diff --git a/core/src/main/java/mc/core/world/Chunk.java b/core/src/main/java/mc/core/world/Chunk.java index 15ee0fa..4effb4e 100644 --- a/core/src/main/java/mc/core/world/Chunk.java +++ b/core/src/main/java/mc/core/world/Chunk.java @@ -4,6 +4,27 @@ */ package mc.core.world; +import mc.core.block.Block; + +/** + * Serialization chunk info + * + * +-------------+----------------+------------+ + * | param | range | bits | + * +-------------+----------------+------------+ + * | biomeMap | 16x16 0-16 | 4096 | + * +-------------+----------------+------------+ + * | | | 3 | + * +-------------+----------------+------------+ + * | block_count | 0:4096 | 13 | + * +-------------+----------------+------------+ + * | blocks | array | 24*count | + * +-------------+----------------+------------+ + * + * Total: 4112 bits header (514 bytes) + 24 * block_count bits (3 * block_count bytes) + * Max size: 12802 bytes (~13 Mb per chunk) + * + */ /* 16x16x16 */ public interface Chunk { int getBlockType(int x, int y, int z); @@ -21,6 +42,13 @@ public interface Chunk { int getAddition(int x, int y, int z); void setAddition(int x, int y, int z, int value); - int getBiome(int x, int z); - void setBiome(int x, int z, int value); + Biome getBiome(int x, int z); + void setBiome(int x, int z, Biome biome); + + int getX(); + int getY(); + int getZ(); + + Block[] getNotAirBlocks(); + void setBlock (int x, int y, int z, Block block); } 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 d12b034..7c05692 100644 --- a/flat_world/src/main/java/mc/world/flat/FlatWorld.java +++ b/flat_world/src/main/java/mc/world/flat/FlatWorld.java @@ -17,7 +17,7 @@ import java.util.UUID; public class FlatWorld implements World { @Getter@Setter - private UUID worldId; + private UUID worldId = UUID.fromString("00000000-0000-0000-C000-000000000046"); @Getter @Setter 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 5186615..fbc6b44 100644 --- a/flat_world/src/main/java/mc/world/flat/SimpleChunk.java +++ b/flat_world/src/main/java/mc/world/flat/SimpleChunk.java @@ -4,6 +4,8 @@ */ package mc.world.flat; +import mc.core.block.Block; +import mc.core.world.Biome; import mc.core.world.Chunk; public class SimpleChunk implements Chunk { @@ -62,12 +64,37 @@ public class SimpleChunk implements Chunk { } @Override - public int getBiome(int x, int z) { + public Biome getBiome(int x, int z) { + return Biome.PLAIN; + } + + @Override + public void setBiome(int x, int z, Biome biome) { + + } + + @Override + public int getX() { return 0; } @Override - public void setBiome(int x, int z, int value) { + public int getY() { + return 0; + } + + @Override + public int getZ() { + return 0; + } + + @Override + public Block[] getNotAirBlocks() { + return new Block[0]; + } + + @Override + public void setBlock(int x, int y, int z, Block block) { } } diff --git a/generated_world/README.MD b/generated_world/README.MD new file mode 100644 index 0000000..f49eaf7 --- /dev/null +++ b/generated_world/README.MD @@ -0,0 +1,3 @@ +### System properties: + +* `worlds.folder` -- folder where worlds will be located \ No newline at end of file From 0464fa576471dd670c80ea05748d881e76840f8a Mon Sep 17 00:00:00 2001 From: Forwolk Date: Fri, 27 Jul 2018 09:10:19 +0300 Subject: [PATCH 10/37] More biomes --- core/src/main/java/mc/core/world/Biome.java | 25 +++++++++++++++++-- core/src/main/java/mc/core/world/Chunk.java | 6 ++--- core/src/main/java/mc/core/world/Region.java | 10 ++++++++ core/src/main/java/mc/core/world/World.java | 22 ++++++++++++++++ .../main/java/mc/world/flat/SimpleChunk.java | 2 +- 5 files changed, 58 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/mc/core/world/Biome.java b/core/src/main/java/mc/core/world/Biome.java index 4d05677..ef59d8f 100644 --- a/core/src/main/java/mc/core/world/Biome.java +++ b/core/src/main/java/mc/core/world/Biome.java @@ -3,8 +3,29 @@ package mc.core.world; import lombok.Getter; public enum Biome { - PLAIN(0, "Plain"), - DESERT(1, "Desert"); + OCEAN(0, "Ocean"), + PLAINS(1, "Plains"), + DESERT(2, "Desert"), + EXTREME_HILLS(3, "Extreme hills"), + FOREST(4, "Forest"), + TAIGA(5, "Taiga"), + SWAMPLAND(6, "Swampland"), + RIVER(7, "River"), + HELL(8, "Hell"), + SKY(9, "Sky"), + FROZEN_OCEAN(10, "Frozen ocean"), + FROZEN_RIVER(11, "Frozen river"), + ICE_PLAINS(12, "Ice plains"), + ICE_MOUNTAINS(13, "Ice mountains"), + MUSHROOM_ISLAND(14, "Mushroom island"), + MUSHROOM_ISLAND_SHORE(15, "Mushroom island shore"), + BEACH(16, "Beach"), + DESERT_HILLS(17, "Desert hills"), + FOREST_HILLS(18, "Forest hills"), + TAIGA_HILLS(19, "Taiga hills"), + EXTREME_HILLS_EDGE(20, "Extreme hills edge"), + JUNGLE(21, "Jungle"), + JUNGLE_HILLS(22, "Jungle hills"); @Getter private final int id; diff --git a/core/src/main/java/mc/core/world/Chunk.java b/core/src/main/java/mc/core/world/Chunk.java index 4effb4e..6d7f889 100644 --- a/core/src/main/java/mc/core/world/Chunk.java +++ b/core/src/main/java/mc/core/world/Chunk.java @@ -12,8 +12,6 @@ import mc.core.block.Block; * +-------------+----------------+------------+ * | param | range | bits | * +-------------+----------------+------------+ - * | biomeMap | 16x16 0-16 | 4096 | - * +-------------+----------------+------------+ * | | | 3 | * +-------------+----------------+------------+ * | block_count | 0:4096 | 13 | @@ -21,8 +19,8 @@ import mc.core.block.Block; * | blocks | array | 24*count | * +-------------+----------------+------------+ * - * Total: 4112 bits header (514 bytes) + 24 * block_count bits (3 * block_count bytes) - * Max size: 12802 bytes (~13 Mb per chunk) + * Total: 16 bits header (2 bytes) + 24 * block_count bits (3 * block_count bytes) + * Max size: 12290 bytes (~12 Mb per chunk) * */ /* 16x16x16 */ diff --git a/core/src/main/java/mc/core/world/Region.java b/core/src/main/java/mc/core/world/Region.java index 615af3e..2e35834 100644 --- a/core/src/main/java/mc/core/world/Region.java +++ b/core/src/main/java/mc/core/world/Region.java @@ -3,6 +3,16 @@ package mc.core.world; /** * Simple world generation unit * 16x16x16 chunks + * + * + * +-------------+----------------+------------+ + * | param | range | bits | + * +-------------+----------------+------------+ + * | biome_map | 256x256 0-32 | 2097152 | + * +-------------+----------------+------------+ + * + * Total: 2097152 bits (262144 bytes = 256 Mb) + * */ public interface Region { Chunk getChunkAt(int x, int y, int z); diff --git a/core/src/main/java/mc/core/world/World.java b/core/src/main/java/mc/core/world/World.java index 4491769..2c0f69a 100644 --- a/core/src/main/java/mc/core/world/World.java +++ b/core/src/main/java/mc/core/world/World.java @@ -8,6 +8,26 @@ import mc.core.Location; import java.util.UUID; +/** + * WorldInfo + * +-------------+----------------+------------+ + * | param | range | bits | + * +-------------+----------------+------------+ + * | worldId | uuid | 128 | + * +-------------+----------------+------------+ + * | worldName | string [0-64] | 512 | + * +-------------+----------------+------------+ + * | spawnX | -524288:524287 | 20 | + * +-------------+----------------+------------+ + * | spawnY | 0:255 | 8 | + * +-------------+----------------+------------+ + * | spawnZ | -524288:524287 | 20 | + * +-------------+----------------+------------+ + * | seed | long | 64 | + * +-------------+----------------+------------+ + * + */ + public interface World { UUID getWorldId(); IWorldType getWorldType(); @@ -17,4 +37,6 @@ public interface World { Chunk getChunk(int x, int y, int z); void setChunk(int x, int y, int z, Chunk chunk); + + long getSeed (); } 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 fbc6b44..09cbb5d 100644 --- a/flat_world/src/main/java/mc/world/flat/SimpleChunk.java +++ b/flat_world/src/main/java/mc/world/flat/SimpleChunk.java @@ -65,7 +65,7 @@ public class SimpleChunk implements Chunk { @Override public Biome getBiome(int x, int z) { - return Biome.PLAIN; + return Biome.PLAINS; } @Override From 7d4809543078f1631fa51ddb4a8af1717fa84aae Mon Sep 17 00:00:00 2001 From: Forwolk Date: Fri, 27 Jul 2018 12:31:22 +0300 Subject: [PATCH 11/37] fix: flat world --- flat_world/src/main/java/mc/world/flat/FlatWorld.java | 5 +++++ 1 file changed, 5 insertions(+) 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 7c05692..abeb0d0 100644 --- a/flat_world/src/main/java/mc/world/flat/FlatWorld.java +++ b/flat_world/src/main/java/mc/world/flat/FlatWorld.java @@ -38,4 +38,9 @@ public class FlatWorld implements World { public void setChunk(int x, int y, int z, Chunk chunk) { throw new UnsupportedOperationException(); } + + @Override + public long getSeed() { + return 0; + } } From b2f5af9a8411700ffa4f324423b8348a2eff8e9a Mon Sep 17 00:00:00 2001 From: Forwolk Date: Fri, 27 Jul 2018 13:29:31 +0300 Subject: [PATCH 12/37] Seed based random generator --- core/src/main/java/mc/core/world/Chunk.java | 2 +- core/src/main/java/mc/core/world/Region.java | 2 +- core/src/main/java/mc/core/world/World.java | 11 ++++ .../generated_world/SeedRandomGenerator.java | 23 ++++++++ .../SeedRandomGeneratorTest.java | 58 +++++++++++++++++++ 5 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 generated_world/src/main/java/mc/world/generated_world/SeedRandomGenerator.java create mode 100644 generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java diff --git a/core/src/main/java/mc/core/world/Chunk.java b/core/src/main/java/mc/core/world/Chunk.java index 6d7f889..4138f4d 100644 --- a/core/src/main/java/mc/core/world/Chunk.java +++ b/core/src/main/java/mc/core/world/Chunk.java @@ -20,7 +20,7 @@ import mc.core.block.Block; * +-------------+----------------+------------+ * * Total: 16 bits header (2 bytes) + 24 * block_count bits (3 * block_count bytes) - * Max size: 12290 bytes (~12 Mb per chunk) + * Max size: 12290 bytes (~12 Kb per chunk) * */ /* 16x16x16 */ diff --git a/core/src/main/java/mc/core/world/Region.java b/core/src/main/java/mc/core/world/Region.java index 2e35834..efee50a 100644 --- a/core/src/main/java/mc/core/world/Region.java +++ b/core/src/main/java/mc/core/world/Region.java @@ -11,7 +11,7 @@ package mc.core.world; * | biome_map | 256x256 0-32 | 2097152 | * +-------------+----------------+------------+ * - * Total: 2097152 bits (262144 bytes = 256 Mb) + * Total: 2097152 bits (256 Kb) * */ public interface Region { diff --git a/core/src/main/java/mc/core/world/World.java b/core/src/main/java/mc/core/world/World.java index 2c0f69a..e0e7df2 100644 --- a/core/src/main/java/mc/core/world/World.java +++ b/core/src/main/java/mc/core/world/World.java @@ -25,7 +25,18 @@ import java.util.UUID; * +-------------+----------------+------------+ * | seed | long | 64 | * +-------------+----------------+------------+ + * | type | 0-255 | 8 | + * +-------------+----------------+------------+ * + * /worlds/ + * --> []/world_uuid/ + * --> world.dat + * --> []/r.X.Z/ + * --> biomes.dat + * --> []chunk_x_y_z.dat + * --> entities.dat + * --> /playerdata/ + * --> []player_uuid.dat */ public interface World { diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedRandomGenerator.java b/generated_world/src/main/java/mc/world/generated_world/SeedRandomGenerator.java new file mode 100644 index 0000000..a466791 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/SeedRandomGenerator.java @@ -0,0 +1,23 @@ +package mc.world.generated_world; + +public final class SeedRandomGenerator { + + public static double random (int x, int y, int seed) { + x = Math.abs(x - y) + 1; + y = Math.abs(y - x) + 1; + for (int i = 0; i < 40; i ++) { + int a1 = x % 13; + int a2 = x % 31; + int a3 = x % 89; + int a4 = y % 359; + int a5 = y % 7; + int a6 = y % 313; + int a7 = y % 8461; + int a8 = y % 105467; + int a9 = x % 105943; + y = x + seed; + x += a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; + } + return ((x + y) % 100000) / 100000d; + } +} diff --git a/generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java b/generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java new file mode 100644 index 0000000..795654a --- /dev/null +++ b/generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java @@ -0,0 +1,58 @@ +package mc.world.generated_world; + +import org.junit.Test; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; + +import static org.junit.Assert.*; + +public class SeedRandomGeneratorTest { + @Test + public void randomTest() throws Exception { + double maxDiff = 0; + double maxDisp = 0; + for (int i = 0; i < 100; i ++) { + double mid = 0; + double disp = 0; + int seed = (int) (Math.random() * Integer.MAX_VALUE); + for (int x = -1000; x < 1000; x++) { + for (int y = -1000; y < 1000; y++) { + double rnd = SeedRandomGenerator.random(x, y, seed); + mid += rnd; + disp += (rnd - 0.5) * (rnd - 0.5); + } + } + mid = mid/4000000; + disp = Math.sqrt(disp)/4000000; + if (maxDiff < Math.abs(mid - 0.5)) { + maxDiff = Math.abs(mid - 0.5); + } + if (maxDisp < disp) { + maxDisp = disp; + } + System.out.printf("Iteration %d.\t mid: %.3f, \tdisp %.6f\n", i + 1, mid, disp); + } + System.out.printf("Max diff: %.3f\n", maxDiff); + System.out.printf("Max disp: %.6f\n", maxDisp); + + assertTrue(maxDiff > 0); + } + + @Test + public void generateImage () throws Exception { + int h = 500; + int w = 500; + BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + + int seed = (int) (Math.random() * Integer.MAX_VALUE) / 1024; + for (int x = 0; x < w; x ++) { + for (int y = 0; y < h; y ++) { + image.setRGB(x, y, (int) (0xffffff * SeedRandomGenerator.random(x, y, seed))); + } + } + ImageIO.write(image, "bmp", new File("out", "seed_random.png")); + } + +} \ No newline at end of file From ff55368db26ac48062598918ee184b585ccea2d6 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Wed, 1 Aug 2018 10:43:37 +0300 Subject: [PATCH 13/37] WorldGenerator gen 1 --- .../main/java/mc/core/block/BlockType.java | 8 +- core/src/main/java/mc/core/world/Biome.java | 52 +-- core/src/main/java/mc/core/world/Region.java | 1 - core/src/main/java/mc/core/world/World.java | 5 +- .../main/java/mc/world/flat/FlatWorld.java | 17 +- .../mc/world/generated_world/CubicWorld.java | 89 ++++ .../SeedBasedWorldGenerator.java | 390 ++++++++++++++++++ .../generated_world/SeedRandomGenerator.java | 2 +- .../world/generated_world/WorldConstants.java | 17 + .../generated_world/chunk/ChunkProxy.java | 128 ++++++ .../chunk/ProxiedChunkLoader.java | 9 + .../generated_world/region/RegionImpl.java | 63 +++ .../generated_world/word/Temperature.java | 9 + .../world/generated_world/word/Wetness.java | 9 + .../SeedRandomGeneratorTest.java | 34 ++ 15 files changed, 799 insertions(+), 34 deletions(-) create mode 100644 generated_world/src/main/java/mc/world/generated_world/CubicWorld.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/WorldConstants.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/chunk/ChunkProxy.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/chunk/ProxiedChunkLoader.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/word/Temperature.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/word/Wetness.java diff --git a/core/src/main/java/mc/core/block/BlockType.java b/core/src/main/java/mc/core/block/BlockType.java index cf6cc1a..f4a8648 100644 --- a/core/src/main/java/mc/core/block/BlockType.java +++ b/core/src/main/java/mc/core/block/BlockType.java @@ -3,9 +3,13 @@ package mc.core.block; import lombok.Getter; public enum BlockType { - DIRT(1, "Dirt"), + STONE(1, "Stone"), GRASS(2, "Grass"), - BEDROCK(7, "Bedrock"); + DIRT(3, "Dirt"), + BEDROCK(7, "Bedrock"), + WATER(8, "Water"), + SAND(12, "Sand"), + SNOW(32, "Snow"); @Getter private final int id; diff --git a/core/src/main/java/mc/core/world/Biome.java b/core/src/main/java/mc/core/world/Biome.java index ef59d8f..9826a68 100644 --- a/core/src/main/java/mc/core/world/Biome.java +++ b/core/src/main/java/mc/core/world/Biome.java @@ -3,37 +3,41 @@ package mc.core.world; import lombok.Getter; public enum Biome { - OCEAN(0, "Ocean"), - PLAINS(1, "Plains"), - DESERT(2, "Desert"), - EXTREME_HILLS(3, "Extreme hills"), - FOREST(4, "Forest"), - TAIGA(5, "Taiga"), - SWAMPLAND(6, "Swampland"), - RIVER(7, "River"), - HELL(8, "Hell"), - SKY(9, "Sky"), - FROZEN_OCEAN(10, "Frozen ocean"), - FROZEN_RIVER(11, "Frozen river"), - ICE_PLAINS(12, "Ice plains"), - ICE_MOUNTAINS(13, "Ice mountains"), - MUSHROOM_ISLAND(14, "Mushroom island"), - MUSHROOM_ISLAND_SHORE(15, "Mushroom island shore"), - BEACH(16, "Beach"), - DESERT_HILLS(17, "Desert hills"), - FOREST_HILLS(18, "Forest hills"), - TAIGA_HILLS(19, "Taiga hills"), - EXTREME_HILLS_EDGE(20, "Extreme hills edge"), - JUNGLE(21, "Jungle"), - JUNGLE_HILLS(22, "Jungle hills"); + OCEAN(0, "Ocean", 0x000080), + PLAINS(1, "Plains", 0x008000), + DESERT(2, "Desert", 0xbdb76b), + EXTREME_HILLS(3, "Extreme hills", 0xffffff), + FOREST(4, "Forest", 0x006400), + TAIGA(5, "Taiga", 0xf0f8ff), + SWAMPLAND(6, "Swampland", 0x808000), + RIVER(7, "River", 0xffffff), + HELL(8, "Hell", 0xffffff), + SKY(9, "Sky", 0xffffff), + FROZEN_OCEAN(10, "Frozen ocean", 0xe0ffff), + FROZEN_RIVER(11, "Frozen river", 0xffffff), + ICE_PLAINS(12, "Ice plains", 0xfffafa), + ICE_MOUNTAINS(13, "Ice mountains", 0xfffafa), + MUSHROOM_ISLAND(14, "Mushroom island", 0xffffff), + MUSHROOM_ISLAND_SHORE(15, "Mushroom island shore", 0xffffff), + BEACH(16, "Beach", 0xffffff), + DESERT_HILLS(17, "Desert hills", 0xbdb76b), + FOREST_HILLS(18, "Forest hills", 0x006400), + TAIGA_HILLS(19, "Taiga hills", 0xf0f8ff), + EXTREME_HILLS_EDGE(20, "Extreme hills edge", 0xffffff), + JUNGLE(21, "Jungle", 0xadff2f), + JUNGLE_HILLS(22, "Jungle hills", 0xadff2f), + DEEP_OCEAN(23, "Deep ocean", 0x191970); @Getter private final int id; @Getter private final String name; + @Getter + private final int color; - Biome(int id, String name) { + Biome(int id, String name, int color) { this.id = id; this.name = name; + this.color = color; } } diff --git a/core/src/main/java/mc/core/world/Region.java b/core/src/main/java/mc/core/world/Region.java index efee50a..11b197c 100644 --- a/core/src/main/java/mc/core/world/Region.java +++ b/core/src/main/java/mc/core/world/Region.java @@ -19,7 +19,6 @@ public interface Region { void setChunk(int x, int y, int z, Chunk chunk); int getX(); - int getY(); int getZ(); Biome getBiomeAt (int x, int z); diff --git a/core/src/main/java/mc/core/world/World.java b/core/src/main/java/mc/core/world/World.java index e0e7df2..aafdc2e 100644 --- a/core/src/main/java/mc/core/world/World.java +++ b/core/src/main/java/mc/core/world/World.java @@ -49,5 +49,8 @@ public interface World { Chunk getChunk(int x, int y, int z); void setChunk(int x, int y, int z, Chunk chunk); - long getSeed (); + Region getRegion (int x, int z); + void setRegion (int x, int z, Region region); + + int getSeed (); } 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 abeb0d0..418fbab 100644 --- a/flat_world/src/main/java/mc/world/flat/FlatWorld.java +++ b/flat_world/src/main/java/mc/world/flat/FlatWorld.java @@ -7,10 +7,7 @@ package mc.world.flat; import lombok.Getter; import lombok.Setter; import mc.core.Location; -import mc.core.world.Chunk; -import mc.core.world.IWorldType; -import mc.core.world.World; -import mc.core.world.WorldType; +import mc.core.world.*; import java.util.UUID; @@ -40,7 +37,17 @@ public class FlatWorld implements World { } @Override - public long getSeed() { + public Region getRegion(int x, int z) { + return null; + } + + @Override + public void setRegion(int x, int z, Region region) { + + } + + @Override + public int getSeed() { return 0; } } diff --git a/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java b/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java new file mode 100644 index 0000000..d22fed4 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java @@ -0,0 +1,89 @@ +package mc.world.generated_world; + +import lombok.Getter; +import mc.core.Location; +import mc.core.world.*; + +import java.util.UUID; + +public class CubicWorld implements World { + @Getter + private final UUID worldId; + private final int seed; + private volatile Location spawnLocation; + private final transient Object spawnLocationLock = new Object(); + private final transient ChunkLoader chunkLoader; + + public CubicWorld(UUID worldId, int seed) { + this.worldId = worldId; + chunkLoader = new InMemoryCacheChunkLoader(worldId); + this.seed = seed; + } + + public CubicWorld(int seed) { + this.worldId = UUID.randomUUID(); + chunkLoader = new InMemoryCacheChunkLoader(worldId); + this.seed = seed; + } + + public CubicWorld(UUID worldId) { + this.worldId = worldId; + chunkLoader = new InMemoryCacheChunkLoader(worldId); + this.seed = 0; + } + + public CubicWorld () { + this.worldId = UUID.randomUUID(); + chunkLoader = new InMemoryCacheChunkLoader(worldId); + this.seed = 0; + } + + @Override + public IWorldType getWorldType() { + return null; + } + + @Override + public Location getSpawn() { + if (spawnLocation == null) { + synchronized (spawnLocationLock) { + if (spawnLocation == null) { + spawnLocation = Location.startPointLocation(); + } + } + } + return spawnLocation; + } + + @Override + public void setSpawn(Location location) { + synchronized (spawnLocationLock) { + this.spawnLocation = location; + } + } + + @Override + public Chunk getChunk(int x, int y, int z) { + return null; + } + + @Override + public void setChunk(int x, int y, int z, Chunk chunk) { + + } + + @Override + public Region getRegion(int x, int z) { + return null; + } + + @Override + public void setRegion(int x, int z, Region region) { + + } + + @Override + public int getSeed() { + return seed; + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java new file mode 100644 index 0000000..0ef4239 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java @@ -0,0 +1,390 @@ +package mc.world.generated_world; + +import lombok.RequiredArgsConstructor; +import mc.core.block.BlockFactory; +import mc.core.block.BlockType; +import mc.core.world.*; +import mc.world.generated_world.region.RegionImpl; +import mc.world.generated_world.word.Temperature; +import mc.world.generated_world.word.Wetness; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.UUID; + +public class SeedBasedWorldGenerator implements WorldGenerator { + + public static void main(String[] args) throws Exception{ + WorldGenerator worldGenerator = new SeedBasedWorldGenerator(); + World world = new CubicWorld(UUID.fromString("00000000-0000-0000-C000-000000000046"), 123); + worldGenerator.generateRegion(0, 0, world); + worldGenerator.generateRegion(1, 0, world); + worldGenerator.generateRegion(-1, 0, world); + worldGenerator.generateRegion(0, 1, world); + worldGenerator.generateRegion(0, -1, world); + BufferedImage image = new BufferedImage(3 * 256, 3 * 256, BufferedImage.TYPE_INT_RGB); + BufferedImage currentImage; + int shiftX; + int shiftY; + currentImage = ImageIO.read(new File("out/0.0", "biomeMap.png")); + shiftX = 1; + shiftY = 1; + for (int x = 0; x < 256; x ++){ + for (int y = 0; y < 256; y ++){ + int tx = 256 * shiftX + x; + int ty = 256 * shiftY + y; + image.setRGB(tx, ty, currentImage.getRGB(x, y)); + } + } + currentImage = ImageIO.read(new File("out/0.1", "biomeMap.png")); + shiftX = 1; + shiftY = 2; + for (int x = 0; x < 256; x ++){ + for (int y = 0; y < 256; y ++){ + int tx = 256 * shiftX + x; + int ty = 256 * shiftY + y; + image.setRGB(tx, ty, currentImage.getRGB(x, y)); + } + } + currentImage = ImageIO.read(new File("out/1.0", "biomeMap.png")); + shiftX = 2; + shiftY = 1; + for (int x = 0; x < 256; x ++){ + for (int y = 0; y < 256; y ++){ + int tx = 256 * shiftX + x; + int ty = 256 * shiftY + y; + image.setRGB(tx, ty, currentImage.getRGB(x, y)); + } + } + currentImage = ImageIO.read(new File("out/-1.0", "biomeMap.png")); + shiftX = 0; + shiftY = 1; + for (int x = 0; x < 256; x ++){ + for (int y = 0; y < 256; y ++){ + int tx = 256 * shiftX + x; + int ty = 256 * shiftY + y; + image.setRGB(tx, ty, currentImage.getRGB(x, y)); + } + } + currentImage = ImageIO.read(new File("out/0.-1", "biomeMap.png")); + shiftX = 1; + shiftY = 0; + for (int x = 0; x < 256; x ++){ + for (int y = 0; y < 256; y ++){ + int tx = 256 * shiftX + x; + int ty = 256 * shiftY + y; + image.setRGB(tx, ty, currentImage.getRGB(x, y)); + } + } + ImageIO.write(image, "png", new File("out", "merged.png")); + } + + @Override + public Region generateRegion(int x, int z, World world) { + Region region = new RegionImpl(x,z); + RegionGenerator regionGenerator = new RegionGenerator(world, region); + regionGenerator.generate(); + return region; + } + + @RequiredArgsConstructor + private class RegionGenerator { + private final World world; + private final Region region; + private final int size = 256; + private NoiseGenerator noiseGenerator; + private BlockFactory blockFactory; + + private double sigmoid (double x) { + x -= 0.5; + x *= 15; + return 1.0 / (1.0 + Math.exp(-x)); + } + + private int convert (int x) { + return 40960 + x; + } + + public void generate() { + noiseGenerator = new NoiseGenerator(world.getSeed()); + noiseGenerator.init(); + File file = new File("out", region.getX() + "." + region.getZ()); + file.mkdirs(); + int[][] heightMap = new int[size][size]; + int[][] grassMap = new int[size][size]; + int[][] temperatureMap = new int[size][size]; + int[][] wetMap = new int[size][size]; + Biome[][] biomes = new Biome[size][size]; + for (int x = 0; x < size; x ++) { + for (int z = 0; z < size; z ++) { + int tx = convert(x + region.getX() * 256); + int tz = convert(z + region.getZ() * 256); + double p = sigmoid(noiseGenerator.noise(tx / 53d, tz / 53d)); + double r = Math.sqrt(noiseGenerator.noise(tx / 6d, tz / 6d)); + double h = (WorldConstants.WORLD_MAX_HEIGHT - WorldConstants.WORLD_MIN_HEIGHT) * Math.min(p * r, 1); + h = Math.min(WorldConstants.WORLD_MAX_HEIGHT, h + WorldConstants.WORLD_MIN_HEIGHT); + heightMap[x][z] = (int)(h); + grassMap[x][z] = (int) (1 + SeedRandomGenerator.random(tx, tz, world.getSeed()) * (WorldConstants.LANDFILL_GRASS_SURFACE_THIN - 1)); + double k = Math.sqrt(noiseGenerator.noise(tx * 2.99, tz * 2.99)); + double q = Math.sqrt(noiseGenerator.noise(tx / 41.0, tz / 41.0)); + temperatureMap[x][z] = (int) (100 * Math.min((k * k + q * q + k * q) * k * q, 0.99)); + if (heightMap[x][z] < WorldConstants.WORLD_SEA_LEVEL) { + biomes[x][z] = Biome.OCEAN; + wetMap[x][z] = 100; + } + } + } + for (int x = 1; x < size - 1; x ++) { + for (int z = 1; z < size - 1; z++) { + int mid = 0; + for (int tx = x - 1; tx <= x + 1; tx ++) { + for (int tz = z - 1; tz <= z + 1; tz ++) { + mid += wetMap[tx][tz]; + } + } + wetMap[x][z] = mid / 9; + } + } + for (int z = 1; z < size - 1; z++) { + for (int x = 1; x < size - 1; x ++) { + int mid = 0; + for (int tx = x - 1; tx <= x + 1; tx ++) { + for (int tz = z - 1; tz <= z + 1; tz ++) { + mid += wetMap[tx][tz]; + } + } + wetMap[x][z] = (int) (mid / 9 * (1 + 0.1 * SeedRandomGenerator.random(x, z, world.getSeed()))); + } + } + + for (int z = 1; z < size - 1; z++) { + for (int x = 1; x < size - 1; x ++) { + wetMap[x][z] = (int) Math.min(100, 60 * noiseGenerator.noise(x / 31d, z / 67d) + wetMap[x][z] * (1 + 0.2 * SeedRandomGenerator.random(x, z, world.getSeed()))); + } + } + + smooth(grassMap); + smooth(temperatureMap); + smooth(wetMap); + //smooth(heightMap); + + for (int x = 0; x < 256; x ++) { + for (int z = 0; z < 256; z ++) { + Temperature temperature = Temperature.values()[temperatureMap[x][z] / 20]; + Wetness wetness = Wetness.values()[(Math.min(wetMap[x][z], 100) - 1) / 100 * Wetness.values().length]; + biomes[x][z] = selectBiome(temperature, wetness, heightMap[x][z]); + } + } + + // ================================ DEBUG ======================================= + try { + BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); + BufferedImage subImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < 256; x ++) { + for (int z = 0; z < 256; z ++) { + int h = heightMap[x][z]; + h = h << 16 | h << 8 | h; + image.setRGB(x, z, h); + } + } + ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() +"/hightmap.png")); + image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < 256; x ++) { + for (int z = 0; z < 256; z ++) { + int temp = 0xff * temperatureMap[x][z] / 100; + temp = temp << 16; + image.setRGB(x, z, temp); + subImage.setRGB(x, z, (0xff * (int) (temperatureMap[x][z] / 20) / 5) << 16); + } + } + ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() + "/temperatureMap.png")); + ImageIO.write(subImage, "png", new File("out/" + region.getX() + "." +region.getZ() + "/reg_temperatureMap.png")); + image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < 256; x ++) { + for (int z = 0; z < 256; z ++) { + int wet = 0xff * wetMap[x][z] / 100; + image.setRGB(x, z, wet); + } + } + ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() + "/wetMap.png")); + image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < 256; x ++) { + for (int z = 0; z < 256; z ++) { + image.setRGB(x, z, biomes[x][z].getColor()); + } + } + ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() + "/biomeMap.png")); + } catch (Exception e) {} + // ================================ DEBUG FINISH ======================================= + + for (int x = 0; x < size; x ++) { + for (int z = 0; z < size; z ++) { + region.setBiome(x, z, biomes[x][z]); + if (heightMap[x][z] < WorldConstants.WORLD_SEA_LEVEL) { + for (int y = 0; y < WorldConstants.WORLD_SEA_LEVEL; y ++) { + Chunk chunk = region.getChunkAt(x / 16, y / 16, z / 16); + if (y == 0) { + chunk.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)); + } else { + chunk.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)); + } + } + } else { + for (int y = 0; y < heightMap[x][z]; y++) { + Chunk chunk = region.getChunkAt(x / 16, y / 16, z / 16); + if (y == 0) { + chunk.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)); + } 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)); + } 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)); + } else { + chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.GRASS, 0)); + } + } + } + } + } + } + } + + private Biome selectBiome (Temperature temperature, Wetness wetness, int height) { + if (temperature == Temperature.FROST) { + if (height < WorldConstants.WORLD_SEA_LEVEL) { + return Biome.FROZEN_OCEAN; + } else { + if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) { + return Biome.ICE_MOUNTAINS; + } else { + return Biome.ICE_PLAINS; + } + } + } + if (height < WorldConstants.WORLD_SEA_LEVEL) { + if (height < (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MIN_HEIGHT) / 2){ + return Biome.DEEP_OCEAN; + } else { + return Biome.OCEAN; + } + } + if (temperature == Temperature.COLD) { + if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) { + return Biome.TAIGA_HILLS; + } else { + return Biome.TAIGA; + } + } + if (temperature == Temperature.WARM) { + if (wetness.ordinal() < 2) { + return Biome.PLAINS; + } else if (wetness == Wetness.WATER){ + return Biome.SWAMPLAND; + } else { + if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) { + return Biome.FOREST_HILLS; + } else { + return Biome.FOREST; + } + } + } + if (temperature == Temperature.HOTTEST && wetness.ordinal() < 2) { + if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) { + return Biome.DESERT_HILLS; + } else { + return Biome.DESERT; + } + } + + if (wetness.ordinal() > 2) { + if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) { + return Biome.JUNGLE_HILLS; + } else { + return Biome.JUNGLE; + } + } + + + return Biome.PLAINS; + } + + private void smooth (int [][] map) { + final int[][] original = map.clone(); + for (int y = 1; y < map.length - 1; y ++) { + for (int x = 1; x < map[0].length - 1; x ++) { + int mid = 0; + for (int tx = x - 1; tx <= x + 1; tx ++) { + for (int ty = y - 1; ty <= y + 1; ty ++) { + mid += original[tx][ty]; + } + } + map[x][y] = mid / 9; + } + } + } + } + + @RequiredArgsConstructor + private class NoiseGenerator { + int size = 256; + int mask = size - 1; + int[] perm = new int[size]; + double[] gradsX = new double[size]; + double[] gradsY = new double[size]; + private final int seed; + + void init() { + for (int i = 0; i < size; ++i) { + int other = rand(i) % (i + 1); + if (i > other) + perm[i] = perm[other]; + perm[other] = i; + gradsX[i] = Math.cos(2.0f * Math.PI * i / size); + gradsY[i] = Math.sin(2.0f * Math.PI * i / size); + } + } + + double f(double t) { + t = Math.abs(t); + return t >= 1.0f ? 0.0f : 1.0f - + (3.0f - 2.0f * t) * t * t; + } + + double surflet(double x, double y, double gradX, double gradY) { + return f(x) * f(y) * (gradX * x + gradY * y); + } + + double noise(double x, double y) { + float result = 0.0f; + int cellX = (int)(x); + int cellY = (int)(y); + for (int gridY = cellY; gridY <= cellY + 1; ++gridY) + for (int gridX = cellX; gridX <= cellX + 1; ++gridX) { + int hash = perm[(perm[gridX & mask] + gridY) & mask]; + result += surflet(x - gridX, y - gridY, + gradsX[hash], gradsY[hash]); + } + return (result + 1) / 2; + } + + int rand(int i) { + int x = (i * i) % 256; + int y = (i + i * x) % 256; + return (int) (Integer.MAX_VALUE * SeedRandomGenerator.random(x, y, seed)); + } + } + +} \ No newline at end of file diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedRandomGenerator.java b/generated_world/src/main/java/mc/world/generated_world/SeedRandomGenerator.java index a466791..b4af1ab 100644 --- a/generated_world/src/main/java/mc/world/generated_world/SeedRandomGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/SeedRandomGenerator.java @@ -5,7 +5,7 @@ public final class SeedRandomGenerator { public static double random (int x, int y, int seed) { x = Math.abs(x - y) + 1; y = Math.abs(y - x) + 1; - for (int i = 0; i < 40; i ++) { + for (int i = 0; i < 20; i ++) { int a1 = x % 13; int a2 = x % 31; int a3 = x % 89; diff --git a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java new file mode 100644 index 0000000..e82acb0 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java @@ -0,0 +1,17 @@ +package mc.world.generated_world; + +public final class WorldConstants { + + public static final String CHUNK_FILE_NAME_TEMPLATE = "chunk_{0}_{1}_{2}.dat"; + public static final String BIOME_FILE_NAME_TEMPLATE = "biome_{0}_{1}.dat"; + public static final String REGION_FILE_NAME_TEMPLATE = "r.{0}.{1}"; + + public static final int WORLD_MIN_HEIGHT = 28; + public static final int WORLD_SEA_LEVEL = 64; + public static final int WORLD_MAX_HEIGHT = 128; + + public static final int LANDFILL_GRASS_SURFACE_THIN = 5; + public static final double WORLD_ROUGHNRESS = 0.35; + + private WorldConstants () {} +} 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 new file mode 100644 index 0000000..e1c1d47 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkProxy.java @@ -0,0 +1,128 @@ +package mc.world.generated_world.chunk; + +import mc.core.block.Block; +import mc.core.world.Biome; +import mc.core.world.Chunk; + +public class ChunkProxy implements Chunk { + private final Chunk chunk; + private volatile long lastUsage = System.currentTimeMillis(); + + public ChunkProxy(Chunk chunk) { + this.chunk = chunk; + } + + public long getLastUsage() { + synchronized (chunk) { + return lastUsage; + } + } + + private 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 Block[] getNotAirBlocks() { + use(); + return chunk.getNotAirBlocks(); + } + + @Override + public void setBlock(int x, int y, int z, Block block) { + use(); + chunk.setBlock(x, y, z, block); + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ProxiedChunkLoader.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ProxiedChunkLoader.java new file mode 100644 index 0000000..f5aa630 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ProxiedChunkLoader.java @@ -0,0 +1,9 @@ +package mc.world.generated_world.chunk; + +import mc.core.world.Chunk; +import mc.core.world.ChunkLoader; + +public interface ProxiedChunkLoader extends ChunkLoader { + @Override + Chunk loadOrGenerateChunk(int x, int y, int z); +} 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 new file mode 100644 index 0000000..7c62c63 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java @@ -0,0 +1,63 @@ +package mc.world.generated_world.region; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import mc.core.world.*; +import mc.world.generated_world.chunk.ChunkProxy; +import org.springframework.beans.factory.annotation.Autowired; + +import java.text.MessageFormat; + +@Slf4j +@RequiredArgsConstructor +public class RegionImpl implements Region{ + @Getter + private final int x; + @Getter + private final int z; + private final ChunkProxy[][][] chunks = new ChunkProxy[16][16][16]; + private final Biome[][] biomes = new Biome[16][16]; + @Getter@Setter + private transient World world; + @Autowired + private ChunkLoader chunkLoader; + + @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)); + } + Chunk chunk = chunks[x][y][z]; + if (chunk == null) { + chunk = chunkLoader.loadOrGenerateChunk(x, y, z); + chunks[x][y][z] = new ChunkProxy(chunk); + } + return chunk; + } + + @Override + public void setChunk(int x, int y, int z, Chunk chunk) { + 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)); + } + chunks[x][y][z] = new ChunkProxy(chunk); + } + + @Override + public Biome getBiomeAt(int x, int z) { + if (x < 0 || z < 0 || x >= 16 || z >= 16) { + throw new RuntimeException(MessageFormat.format("Invalid biome coordinates [{0} {1}]", x, z)); + } + return biomes[x][z]; + } + + @Override + public void setBiome(int x, int z, Biome biome) { + if (x < 0 || z < 0 || x >= 16 || z >= 16) { + throw new RuntimeException(MessageFormat.format("Invalid biome coordinates [{0} {1}]", x, z)); + } + biomes[x][z] = biome; + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/word/Temperature.java b/generated_world/src/main/java/mc/world/generated_world/word/Temperature.java new file mode 100644 index 0000000..1c2cb80 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/word/Temperature.java @@ -0,0 +1,9 @@ +package mc.world.generated_world.word; + +public enum Temperature { + FROST, + COLD, + WARM, + HOT, + HOTTEST +} diff --git a/generated_world/src/main/java/mc/world/generated_world/word/Wetness.java b/generated_world/src/main/java/mc/world/generated_world/word/Wetness.java new file mode 100644 index 0000000..b0c7e49 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/word/Wetness.java @@ -0,0 +1,9 @@ +package mc.world.generated_world.word; + +public enum Wetness { + DRYEST, + DRY, + WET, + WETTER, + WATER +} diff --git a/generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java b/generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java index 795654a..4b4b2a7 100644 --- a/generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java +++ b/generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java @@ -9,6 +9,38 @@ import java.io.File; import static org.junit.Assert.*; public class SeedRandomGeneratorTest { + + @Test + public void randomGenSpeed () { + SeedRandomGenerator.random(0, 0, 0); + long avg = 0; + long min = -1; + long max = 0; + for (int i = 0; i < 500; i ++) { + int x = (int) (Math.random() * 10000); + int y = (int) (Math.random() * 10000); + int seed = (int) (Math.random() * 10000); + long time = System.nanoTime(); + SeedRandomGenerator.random(x, y, seed); + time = System.nanoTime() - time; + System.out.printf("[%s] \t%.3fms\n", i+1, time/1000d); + avg += time; + if (min == -1) { + min = time; + } else if (min > time) { + min = time; + } + if (max < time) { + max = time; + } + } + System.out.println(); + System.out.printf("Average time: %.3fms\n", avg/500000d); + System.out.printf("Minimum time: %.3fms\n", min/1000d); + System.out.printf("Maximum time: %.3fms\n", max/1000d); + assertTrue(avg/500 < 5000); + } + @Test public void randomTest() throws Exception { double maxDiff = 0; @@ -33,10 +65,12 @@ public class SeedRandomGeneratorTest { maxDisp = disp; } System.out.printf("Iteration %d.\t mid: %.3f, \tdisp %.6f\n", i + 1, mid, disp); + assertTrue(Math.abs(mid - 0.5) < 0.15); } System.out.printf("Max diff: %.3f\n", maxDiff); System.out.printf("Max disp: %.6f\n", maxDisp); + assertTrue(maxDiff > 0); } From 01a037f1f5578bd84e88f941aa3d7195000940c7 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Wed, 1 Aug 2018 10:45:57 +0300 Subject: [PATCH 14/37] fix: block factory --- .../java/mc/world/generated_world/SeedBasedWorldGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java index 0ef4239..d9fcb79 100644 --- a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java @@ -94,7 +94,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { private final Region region; private final int size = 256; private NoiseGenerator noiseGenerator; - private BlockFactory blockFactory; + private BlockFactory blockFactory = new BlockFactory(); private double sigmoid (double x) { x -= 0.5; From 4511fc40b149d9266a995ebe586cacab54cdd2a6 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Wed, 1 Aug 2018 10:52:29 +0300 Subject: [PATCH 15/37] region biome map: 256 x 256 --- .../main/java/mc/world/generated_world/region/RegionImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 7c62c63..b61f053 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 @@ -47,7 +47,7 @@ public class RegionImpl implements Region{ @Override public Biome getBiomeAt(int x, int z) { - if (x < 0 || z < 0 || x >= 16 || z >= 16) { + if (x < 0 || z < 0 || x >= 256 || z >= 256) { throw new RuntimeException(MessageFormat.format("Invalid biome coordinates [{0} {1}]", x, z)); } return biomes[x][z]; @@ -55,7 +55,7 @@ public class RegionImpl implements Region{ @Override public void setBiome(int x, int z, Biome biome) { - if (x < 0 || z < 0 || x >= 16 || z >= 16) { + if (x < 0 || z < 0 || x >= 256 || z >= 256) { throw new RuntimeException(MessageFormat.format("Invalid biome coordinates [{0} {1}]", x, z)); } biomes[x][z] = biome; From a71d152528bf295f2319d46ec7563672a5028f6a Mon Sep 17 00:00:00 2001 From: Forwolk Date: Wed, 1 Aug 2018 11:02:45 +0300 Subject: [PATCH 16/37] World constants --- .../SeedBasedWorldGenerator.java | 106 +++++++++--------- .../world/generated_world/WorldConstants.java | 9 ++ 2 files changed, 62 insertions(+), 53 deletions(-) diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java index d9fcb79..2143bc6 100644 --- a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java @@ -13,6 +13,8 @@ import java.awt.image.BufferedImage; import java.io.File; import java.util.UUID; +import static mc.world.generated_world.WorldConstants.*; + public class SeedBasedWorldGenerator implements WorldGenerator { public static void main(String[] args) throws Exception{ @@ -92,7 +94,6 @@ public class SeedBasedWorldGenerator implements WorldGenerator { private class RegionGenerator { private final World world; private final Region region; - private final int size = 256; private NoiseGenerator noiseGenerator; private BlockFactory blockFactory = new BlockFactory(); @@ -111,32 +112,32 @@ public class SeedBasedWorldGenerator implements WorldGenerator { noiseGenerator.init(); File file = new File("out", region.getX() + "." + region.getZ()); file.mkdirs(); - int[][] heightMap = new int[size][size]; - int[][] grassMap = new int[size][size]; - int[][] temperatureMap = new int[size][size]; - int[][] wetMap = new int[size][size]; - Biome[][] biomes = new Biome[size][size]; - for (int x = 0; x < size; x ++) { - for (int z = 0; z < size; z ++) { - int tx = convert(x + region.getX() * 256); - int tz = convert(z + region.getZ() * 256); - double p = sigmoid(noiseGenerator.noise(tx / 53d, tz / 53d)); - double r = Math.sqrt(noiseGenerator.noise(tx / 6d, tz / 6d)); - double h = (WorldConstants.WORLD_MAX_HEIGHT - WorldConstants.WORLD_MIN_HEIGHT) * Math.min(p * r, 1); - h = Math.min(WorldConstants.WORLD_MAX_HEIGHT, h + WorldConstants.WORLD_MIN_HEIGHT); + int[][] heightMap = new int[WorldConstants.WORLD_REGION_SIZE][WorldConstants.WORLD_REGION_SIZE]; + int[][] grassMap = new int[WorldConstants.WORLD_REGION_SIZE][WorldConstants.WORLD_REGION_SIZE]; + int[][] temperatureMap = new int[WorldConstants.WORLD_REGION_SIZE][WorldConstants.WORLD_REGION_SIZE]; + int[][] wetMap = new int[WorldConstants.WORLD_REGION_SIZE][WorldConstants.WORLD_REGION_SIZE]; + Biome[][] biomes = new Biome[WorldConstants.WORLD_REGION_SIZE][WorldConstants.WORLD_REGION_SIZE]; + for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) { + for (int z = 0; z < WorldConstants.WORLD_REGION_SIZE; z ++) { + int tx = convert(x + region.getX() * WorldConstants.WORLD_REGION_SIZE); + int tz = convert(z + region.getZ() * WorldConstants.WORLD_REGION_SIZE); + double p = sigmoid(noiseGenerator.noise(tx / WORLD_LAND_SIZE, tz / WORLD_LAND_SIZE)); + double r = Math.sqrt(noiseGenerator.noise(tx / WORLD_LAKE_SIZE, tz / WORLD_LAKE_SIZE)); + double h = (WORLD_MAX_HEIGHT - WORLD_MIN_HEIGHT) * Math.min(p * r, 1); + h = Math.min(WORLD_MAX_HEIGHT, h + WORLD_MIN_HEIGHT); heightMap[x][z] = (int)(h); - grassMap[x][z] = (int) (1 + SeedRandomGenerator.random(tx, tz, world.getSeed()) * (WorldConstants.LANDFILL_GRASS_SURFACE_THIN - 1)); - double k = Math.sqrt(noiseGenerator.noise(tx * 2.99, tz * 2.99)); - double q = Math.sqrt(noiseGenerator.noise(tx / 41.0, tz / 41.0)); - temperatureMap[x][z] = (int) (100 * Math.min((k * k + q * q + k * q) * k * q, 0.99)); - if (heightMap[x][z] < WorldConstants.WORLD_SEA_LEVEL) { + grassMap[x][z] = (int) (1 + SeedRandomGenerator.random(tx, tz, world.getSeed()) * (LANDFILL_GRASS_SURFACE_THIN - 1)); + double k = Math.sqrt(noiseGenerator.noise(tx * WORLD_TEMPERATURE_GRAD_SIZE, tz * WORLD_TEMPERATURE_GRAD_SIZE)); + double q = Math.sqrt(noiseGenerator.noise(tx / WORLD_TEMPERATURE_SIZE, tz / WORLD_TEMPERATURE_SIZE)); + temperatureMap[x][z] = (int) (WORLD_MAX_TEMPERATURE * Math.min((k * k + q * q + k * q) * k * q, 0.99)); + if (heightMap[x][z] < WORLD_SEA_LEVEL) { biomes[x][z] = Biome.OCEAN; - wetMap[x][z] = 100; + wetMap[x][z] = WORLD_MAX_WETNESS; } } } - for (int x = 1; x < size - 1; x ++) { - for (int z = 1; z < size - 1; z++) { + for (int x = 1; x < WorldConstants.WORLD_REGION_SIZE - 1; x ++) { + for (int z = 1; z < WorldConstants.WORLD_REGION_SIZE - 1; z++) { int mid = 0; for (int tx = x - 1; tx <= x + 1; tx ++) { for (int tz = z - 1; tz <= z + 1; tz ++) { @@ -146,8 +147,8 @@ public class SeedBasedWorldGenerator implements WorldGenerator { wetMap[x][z] = mid / 9; } } - for (int z = 1; z < size - 1; z++) { - for (int x = 1; x < size - 1; x ++) { + for (int z = 1; z < WorldConstants.WORLD_REGION_SIZE - 1; z++) { + for (int x = 1; x < WorldConstants.WORLD_REGION_SIZE - 1; x ++) { int mid = 0; for (int tx = x - 1; tx <= x + 1; tx ++) { for (int tz = z - 1; tz <= z + 1; tz ++) { @@ -158,9 +159,9 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } } - for (int z = 1; z < size - 1; z++) { - for (int x = 1; x < size - 1; x ++) { - wetMap[x][z] = (int) Math.min(100, 60 * noiseGenerator.noise(x / 31d, z / 67d) + wetMap[x][z] * (1 + 0.2 * SeedRandomGenerator.random(x, z, world.getSeed()))); + for (int z = 1; z < WorldConstants.WORLD_REGION_SIZE - 1; z++) { + for (int x = 1; x < WorldConstants.WORLD_REGION_SIZE - 1; x ++) { + wetMap[x][z] = (int) Math.min(WORLD_MAX_WETNESS, 60 * noiseGenerator.noise(x / 31d, z / 67d) + wetMap[x][z] * (1 + 0.2 * SeedRandomGenerator.random(x, z, world.getSeed()))); } } @@ -169,10 +170,10 @@ public class SeedBasedWorldGenerator implements WorldGenerator { smooth(wetMap); //smooth(heightMap); - for (int x = 0; x < 256; x ++) { - for (int z = 0; z < 256; z ++) { - Temperature temperature = Temperature.values()[temperatureMap[x][z] / 20]; - Wetness wetness = Wetness.values()[(Math.min(wetMap[x][z], 100) - 1) / 100 * Wetness.values().length]; + for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) { + for (int z = 0; z < WorldConstants.WORLD_REGION_SIZE; z ++) { + Temperature temperature = Temperature.values()[Temperature.values().length * temperatureMap[x][z] / WORLD_MAX_TEMPERATURE]; + Wetness wetness = Wetness.values()[(Math.min(wetMap[x][z], 100) - 1) / WORLD_MAX_WETNESS * Wetness.values().length]; biomes[x][z] = selectBiome(temperature, wetness, heightMap[x][z]); } } @@ -218,11 +219,11 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } catch (Exception e) {} // ================================ DEBUG FINISH ======================================= - for (int x = 0; x < size; x ++) { - for (int z = 0; z < size; z ++) { + for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) { + for (int z = 0; z < WorldConstants.WORLD_REGION_SIZE; z ++) { region.setBiome(x, z, biomes[x][z]); - if (heightMap[x][z] < WorldConstants.WORLD_SEA_LEVEL) { - for (int y = 0; y < WorldConstants.WORLD_SEA_LEVEL; y ++) { + 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); if (y == 0) { chunk.setBlock(x % 16, y % 16, z % 16, blockFactory.create(BlockType.BEDROCK, 0)); @@ -264,25 +265,25 @@ public class SeedBasedWorldGenerator implements WorldGenerator { private Biome selectBiome (Temperature temperature, Wetness wetness, int height) { if (temperature == Temperature.FROST) { - if (height < WorldConstants.WORLD_SEA_LEVEL) { + if (height < WORLD_SEA_LEVEL) { return Biome.FROZEN_OCEAN; } else { - if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) { + if (height > (WORLD_SEA_LEVEL + WORLD_MAX_HEIGHT) / 2) { return Biome.ICE_MOUNTAINS; } else { return Biome.ICE_PLAINS; } } } - if (height < WorldConstants.WORLD_SEA_LEVEL) { - if (height < (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MIN_HEIGHT) / 2){ + if (height < WORLD_SEA_LEVEL) { + if (height < (WORLD_SEA_LEVEL + WORLD_MIN_HEIGHT) / 2){ return Biome.DEEP_OCEAN; } else { return Biome.OCEAN; } } if (temperature == Temperature.COLD) { - if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) { + if (height > (WORLD_SEA_LEVEL + WORLD_MAX_HEIGHT) / 2) { return Biome.TAIGA_HILLS; } else { return Biome.TAIGA; @@ -294,7 +295,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } else if (wetness == Wetness.WATER){ return Biome.SWAMPLAND; } else { - if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) { + if (height > (WORLD_SEA_LEVEL + WORLD_MAX_HEIGHT) / 2) { return Biome.FOREST_HILLS; } else { return Biome.FOREST; @@ -302,7 +303,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } } if (temperature == Temperature.HOTTEST && wetness.ordinal() < 2) { - if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) { + if (height > (WORLD_SEA_LEVEL + WORLD_MAX_HEIGHT) / 2) { return Biome.DESERT_HILLS; } else { return Biome.DESERT; @@ -310,7 +311,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } if (wetness.ordinal() > 2) { - if (height > (WorldConstants.WORLD_SEA_LEVEL + WorldConstants.WORLD_MAX_HEIGHT) / 2) { + if (height > (WORLD_SEA_LEVEL + WORLD_MAX_HEIGHT) / 2) { return Biome.JUNGLE_HILLS; } else { return Biome.JUNGLE; @@ -339,21 +340,20 @@ public class SeedBasedWorldGenerator implements WorldGenerator { @RequiredArgsConstructor private class NoiseGenerator { - int size = 256; - int mask = size - 1; - int[] perm = new int[size]; - double[] gradsX = new double[size]; - double[] gradsY = new double[size]; + int mask = WORLD_REGION_SIZE - 1; + int[] perm = new int[WORLD_REGION_SIZE]; + double[] gradsX = new double[WORLD_REGION_SIZE]; + double[] gradsY = new double[WORLD_REGION_SIZE]; private final int seed; void init() { - for (int i = 0; i < size; ++i) { + for (int i = 0; i < WORLD_REGION_SIZE; ++i) { int other = rand(i) % (i + 1); if (i > other) perm[i] = perm[other]; perm[other] = i; - gradsX[i] = Math.cos(2.0f * Math.PI * i / size); - gradsY[i] = Math.sin(2.0f * Math.PI * i / size); + gradsX[i] = Math.cos(2.0f * Math.PI * i / WORLD_REGION_SIZE); + gradsY[i] = Math.sin(2.0f * Math.PI * i / WORLD_REGION_SIZE); } } @@ -381,8 +381,8 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } int rand(int i) { - int x = (i * i) % 256; - int y = (i + i * x) % 256; + int x = (i * i) % WORLD_REGION_SIZE; + int y = (i + i * x) % WORLD_REGION_SIZE; return (int) (Integer.MAX_VALUE * SeedRandomGenerator.random(x, y, seed)); } } diff --git a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java index e82acb0..7abe687 100644 --- a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java +++ b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java @@ -9,6 +9,15 @@ public final class WorldConstants { public static final int WORLD_MIN_HEIGHT = 28; public static final int WORLD_SEA_LEVEL = 64; public static final int WORLD_MAX_HEIGHT = 128; + public static final int WORLD_REGION_SIZE = 256; + public static final int WORLD_MAX_TEMPERATURE = 100; + public static final int WORLD_MAX_WETNESS = 100; + + public static final double WORLD_LAND_SIZE = 53.0; + public static final double WORLD_LAKE_SIZE = 6.0; + public static final double WORLD_TEMPERATURE_SIZE = 41.0; + public static final double WORLD_TEMPERATURE_GRAD_SIZE = 2.99; + public static final int LANDFILL_GRASS_SURFACE_THIN = 5; public static final double WORLD_ROUGHNRESS = 0.35; From 1c413ceecd4a14be3e8ac54b9b97137d904c4d87 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Wed, 1 Aug 2018 11:13:05 +0300 Subject: [PATCH 17/37] Temperature drops while altitude is growing --- .../mc/world/generated_world/SeedBasedWorldGenerator.java | 8 ++++---- .../java/mc/world/generated_world/WorldConstants.java | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java index 2143bc6..cd44910 100644 --- a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java @@ -2,7 +2,6 @@ package mc.world.generated_world; import lombok.RequiredArgsConstructor; import mc.core.block.BlockFactory; -import mc.core.block.BlockType; import mc.core.world.*; import mc.world.generated_world.region.RegionImpl; import mc.world.generated_world.word.Temperature; @@ -127,7 +126,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { h = Math.min(WORLD_MAX_HEIGHT, h + WORLD_MIN_HEIGHT); heightMap[x][z] = (int)(h); grassMap[x][z] = (int) (1 + SeedRandomGenerator.random(tx, tz, world.getSeed()) * (LANDFILL_GRASS_SURFACE_THIN - 1)); - double k = Math.sqrt(noiseGenerator.noise(tx * WORLD_TEMPERATURE_GRAD_SIZE, tz * WORLD_TEMPERATURE_GRAD_SIZE)); + double k = Math.sqrt(noiseGenerator.noise(tx * WORLD_TEMPERATURE_ZONE_SIZE, tz * WORLD_TEMPERATURE_ZONE_SIZE)); double q = Math.sqrt(noiseGenerator.noise(tx / WORLD_TEMPERATURE_SIZE, tz / WORLD_TEMPERATURE_SIZE)); temperatureMap[x][z] = (int) (WORLD_MAX_TEMPERATURE * Math.min((k * k + q * q + k * q) * k * q, 0.99)); if (heightMap[x][z] < WORLD_SEA_LEVEL) { @@ -156,6 +155,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } } wetMap[x][z] = (int) (mid / 9 * (1 + 0.1 * SeedRandomGenerator.random(x, z, world.getSeed()))); + temperatureMap[x][z] = (int) Math.min(Math.max(temperatureMap[x][z] - WORLD_TEMPERATURE_HEIGHT_GRAD_SIZE * SeedRandomGenerator.random(x, z, world.getSeed()) * (heightMap[x][z] - WORLD_SEA_LEVEL), 0), WORLD_MAX_TEMPERATURE); } } @@ -219,7 +219,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } catch (Exception e) {} // ================================ DEBUG FINISH ======================================= - for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) { + /*for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) { for (int z = 0; z < WorldConstants.WORLD_REGION_SIZE; z ++) { region.setBiome(x, z, biomes[x][z]); if (heightMap[x][z] < WORLD_SEA_LEVEL) { @@ -260,7 +260,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } } } - } + }*/ } private Biome selectBiome (Temperature temperature, Wetness wetness, int height) { diff --git a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java index 7abe687..7332e2e 100644 --- a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java +++ b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java @@ -16,7 +16,8 @@ public final class WorldConstants { public static final double WORLD_LAND_SIZE = 53.0; public static final double WORLD_LAKE_SIZE = 6.0; public static final double WORLD_TEMPERATURE_SIZE = 41.0; - public static final double WORLD_TEMPERATURE_GRAD_SIZE = 2.99; + public static final double WORLD_TEMPERATURE_ZONE_SIZE = 2.99; + public static final double WORLD_TEMPERATURE_HEIGHT_GRAD_SIZE = 0.25; public static final int LANDFILL_GRASS_SURFACE_THIN = 5; From 3e889c2e7c5d7c6c65c307b944d75d27ccde176d Mon Sep 17 00:00:00 2001 From: Forwolk Date: Wed, 1 Aug 2018 12:31:49 +0300 Subject: [PATCH 18/37] Bigger mountains --- core/src/main/java/mc/core/world/Biome.java | 14 +++++++------- .../generated_world/SeedBasedWorldGenerator.java | 8 ++++++-- .../mc/world/generated_world/WorldConstants.java | 1 + 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/mc/core/world/Biome.java b/core/src/main/java/mc/core/world/Biome.java index 9826a68..a9adbc1 100644 --- a/core/src/main/java/mc/core/world/Biome.java +++ b/core/src/main/java/mc/core/world/Biome.java @@ -3,30 +3,30 @@ package mc.core.world; import lombok.Getter; public enum Biome { - OCEAN(0, "Ocean", 0x000080), + OCEAN(0, "Ocean", 0x0000cd), PLAINS(1, "Plains", 0x008000), - DESERT(2, "Desert", 0xbdb76b), + DESERT(2, "Desert", 0xffe4b5), EXTREME_HILLS(3, "Extreme hills", 0xffffff), FOREST(4, "Forest", 0x006400), TAIGA(5, "Taiga", 0xf0f8ff), SWAMPLAND(6, "Swampland", 0x808000), - RIVER(7, "River", 0xffffff), - HELL(8, "Hell", 0xffffff), + RIVER(7, "River", 0x0000cd), + HELL(8, "Hell", 0x800000), SKY(9, "Sky", 0xffffff), FROZEN_OCEAN(10, "Frozen ocean", 0xe0ffff), - FROZEN_RIVER(11, "Frozen river", 0xffffff), + FROZEN_RIVER(11, "Frozen river", 0xe0ffff), ICE_PLAINS(12, "Ice plains", 0xfffafa), ICE_MOUNTAINS(13, "Ice mountains", 0xfffafa), MUSHROOM_ISLAND(14, "Mushroom island", 0xffffff), MUSHROOM_ISLAND_SHORE(15, "Mushroom island shore", 0xffffff), BEACH(16, "Beach", 0xffffff), - DESERT_HILLS(17, "Desert hills", 0xbdb76b), + DESERT_HILLS(17, "Desert hills", 0xffe4b5), FOREST_HILLS(18, "Forest hills", 0x006400), TAIGA_HILLS(19, "Taiga hills", 0xf0f8ff), EXTREME_HILLS_EDGE(20, "Extreme hills edge", 0xffffff), JUNGLE(21, "Jungle", 0xadff2f), JUNGLE_HILLS(22, "Jungle hills", 0xadff2f), - DEEP_OCEAN(23, "Deep ocean", 0x191970); + DEEP_OCEAN(23, "Deep ocean", 0x000080); @Getter private final int id; diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java index cd44910..655c4ab 100644 --- a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java @@ -131,7 +131,11 @@ public class SeedBasedWorldGenerator implements WorldGenerator { temperatureMap[x][z] = (int) (WORLD_MAX_TEMPERATURE * Math.min((k * k + q * q + k * q) * k * q, 0.99)); if (heightMap[x][z] < WORLD_SEA_LEVEL) { biomes[x][z] = Biome.OCEAN; - wetMap[x][z] = WORLD_MAX_WETNESS; + wetMap[x][z] = (int) (WORLD_MAX_WETNESS * noiseGenerator.noise(tx, tz)); + } else { + int th = heightMap[x][z] - WORLD_SEA_LEVEL; + th = (int) (th * (1 + 1.25 * th / (WORLD_MAX_HEIGHT - WORLD_SEA_LEVEL))); + heightMap[x][z] = Math.min(WORLD_SEA_LEVEL + th, WORLD_MAX_HEIGHT); } } } @@ -161,7 +165,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { for (int z = 1; z < WorldConstants.WORLD_REGION_SIZE - 1; z++) { for (int x = 1; x < WorldConstants.WORLD_REGION_SIZE - 1; x ++) { - wetMap[x][z] = (int) Math.min(WORLD_MAX_WETNESS, 60 * noiseGenerator.noise(x / 31d, z / 67d) + wetMap[x][z] * (1 + 0.2 * SeedRandomGenerator.random(x, z, world.getSeed()))); + wetMap[x][z] = (int) Math.min(WORLD_MAX_WETNESS, WORLD_BASE_WETNESS * noiseGenerator.noise(x / 31d, z / 67d) + wetMap[x][z] * (1 + 0.2 * (0.5 - SeedRandomGenerator.random(x, z, world.getSeed())))); } } diff --git a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java index 7332e2e..b75a25f 100644 --- a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java +++ b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java @@ -12,6 +12,7 @@ public final class WorldConstants { public static final int WORLD_REGION_SIZE = 256; public static final int WORLD_MAX_TEMPERATURE = 100; public static final int WORLD_MAX_WETNESS = 100; + public static final int WORLD_BASE_WETNESS = 30; public static final double WORLD_LAND_SIZE = 53.0; public static final double WORLD_LAKE_SIZE = 6.0; From ec8e414ba135b885c05f1293cfe42d676181f522 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Wed, 1 Aug 2018 13:33:48 +0300 Subject: [PATCH 19/37] Advanced biome selector --- core/src/main/java/mc/core/world/Biome.java | 5 +- .../SeedBasedWorldGenerator.java | 130 ++++++++++++------ .../world/generated_world/WorldConstants.java | 3 +- .../world/generated_world/word/Wetness.java | 3 +- 4 files changed, 98 insertions(+), 43 deletions(-) diff --git a/core/src/main/java/mc/core/world/Biome.java b/core/src/main/java/mc/core/world/Biome.java index a9adbc1..a28aa47 100644 --- a/core/src/main/java/mc/core/world/Biome.java +++ b/core/src/main/java/mc/core/world/Biome.java @@ -26,7 +26,10 @@ public enum Biome { EXTREME_HILLS_EDGE(20, "Extreme hills edge", 0xffffff), JUNGLE(21, "Jungle", 0xadff2f), JUNGLE_HILLS(22, "Jungle hills", 0xadff2f), - DEEP_OCEAN(23, "Deep ocean", 0x000080); + DEEP_OCEAN(23, "Deep ocean", 0x000080), + TUNDRA(24, "Tundra", 0xc0c0c0), + SAVANNA(25, "Savana", 0xcd8513), + SAVANNA_FOREST(26, "Savana forest", 0x8b4513); @Getter private final int id; diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java index 655c4ab..a972154 100644 --- a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java @@ -20,7 +20,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { WorldGenerator worldGenerator = new SeedBasedWorldGenerator(); World world = new CubicWorld(UUID.fromString("00000000-0000-0000-C000-000000000046"), 123); worldGenerator.generateRegion(0, 0, world); - worldGenerator.generateRegion(1, 0, world); + /*worldGenerator.generateRegion(1, 0, world); worldGenerator.generateRegion(-1, 0, world); worldGenerator.generateRegion(0, 1, world); worldGenerator.generateRegion(0, -1, world); @@ -78,7 +78,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { image.setRGB(tx, ty, currentImage.getRGB(x, y)); } } - ImageIO.write(image, "png", new File("out", "merged.png")); + ImageIO.write(image, "png", new File("out", "merged.png"));*/ } @Override @@ -131,7 +131,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { temperatureMap[x][z] = (int) (WORLD_MAX_TEMPERATURE * Math.min((k * k + q * q + k * q) * k * q, 0.99)); if (heightMap[x][z] < WORLD_SEA_LEVEL) { biomes[x][z] = Biome.OCEAN; - wetMap[x][z] = (int) (WORLD_MAX_WETNESS * noiseGenerator.noise(tx, tz)); + wetMap[x][z] = (int) (WORLD_MAX_WETNESS * WORLD_WET_SEA_PERCENT *noiseGenerator.noise(tx, tz)); } else { int th = heightMap[x][z] - WORLD_SEA_LEVEL; th = (int) (th * (1 + 1.25 * th / (WORLD_MAX_HEIGHT - WORLD_SEA_LEVEL))); @@ -158,14 +158,14 @@ public class SeedBasedWorldGenerator implements WorldGenerator { mid += wetMap[tx][tz]; } } - wetMap[x][z] = (int) (mid / 9 * (1 + 0.1 * SeedRandomGenerator.random(x, z, world.getSeed()))); + wetMap[x][z] = (int) (mid / 9 * (1 + 0.4 * SeedRandomGenerator.random(x, z, world.getSeed()))); temperatureMap[x][z] = (int) Math.min(Math.max(temperatureMap[x][z] - WORLD_TEMPERATURE_HEIGHT_GRAD_SIZE * SeedRandomGenerator.random(x, z, world.getSeed()) * (heightMap[x][z] - WORLD_SEA_LEVEL), 0), WORLD_MAX_TEMPERATURE); } } for (int z = 1; z < WorldConstants.WORLD_REGION_SIZE - 1; z++) { for (int x = 1; x < WorldConstants.WORLD_REGION_SIZE - 1; x ++) { - wetMap[x][z] = (int) Math.min(WORLD_MAX_WETNESS, WORLD_BASE_WETNESS * noiseGenerator.noise(x / 31d, z / 67d) + wetMap[x][z] * (1 + 0.2 * (0.5 - SeedRandomGenerator.random(x, z, world.getSeed())))); + wetMap[x][z] = (int) Math.min(WORLD_MAX_WETNESS, WORLD_BASE_WETNESS * noiseGenerator.noise(x / 31d, z / 67d) + wetMap[x][z] * (1 + 0.2 * (SeedRandomGenerator.random(x, z, world.getSeed())))); } } @@ -174,16 +174,23 @@ public class SeedBasedWorldGenerator implements WorldGenerator { smooth(wetMap); //smooth(heightMap); + BufferedImage tempImg = new BufferedImage(WORLD_REGION_SIZE, WORLD_REGION_SIZE, BufferedImage.TYPE_INT_RGB); + BufferedImage wetImg = new BufferedImage(WORLD_REGION_SIZE, WORLD_REGION_SIZE, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) { for (int z = 0; z < WorldConstants.WORLD_REGION_SIZE; z ++) { Temperature temperature = Temperature.values()[Temperature.values().length * temperatureMap[x][z] / WORLD_MAX_TEMPERATURE]; - Wetness wetness = Wetness.values()[(Math.min(wetMap[x][z], 100) - 1) / WORLD_MAX_WETNESS * Wetness.values().length]; + Wetness wetness = Wetness.values()[ Wetness.values().length * (Math.min(wetMap[x][z], WORLD_MAX_WETNESS) - 1) / WORLD_MAX_WETNESS]; biomes[x][z] = selectBiome(temperature, wetness, heightMap[x][z]); + tempImg.setRGB(x, z, temperature.ordinal() * 0xff / Temperature.values().length); + wetImg.setRGB(x, z, wetness.ordinal() * 0xff / Wetness.values().length); } } // ================================ DEBUG ======================================= try { + ImageIO.write(tempImg, "png", new File("out/" + region.getX() + "." +region.getZ() +"/temp_img.png")); + ImageIO.write(wetImg, "png", new File("out/" + region.getX() + "." +region.getZ() +"/wet_img.png")); + BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); BufferedImage subImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < 256; x ++) { @@ -205,14 +212,17 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() + "/temperatureMap.png")); ImageIO.write(subImage, "png", new File("out/" + region.getX() + "." +region.getZ() + "/reg_temperatureMap.png")); + subImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < 256; x ++) { for (int z = 0; z < 256; z ++) { int wet = 0xff * wetMap[x][z] / 100; image.setRGB(x, z, wet); + subImage.setRGB(x, z, 0xff * (int) (Wetness.values().length * wetMap[x][z] / (WORLD_MAX_WETNESS))); } } ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() + "/wetMap.png")); + ImageIO.write(subImage, "png", new File("out/" + region.getX() + "." +region.getZ() + "/reg_wetMap.png")); image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < 256; x ++) { for (int z = 0; z < 256; z ++) { @@ -268,60 +278,100 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } private Biome selectBiome (Temperature temperature, Wetness wetness, int height) { - if (temperature == Temperature.FROST) { - if (height < WORLD_SEA_LEVEL) { - return Biome.FROZEN_OCEAN; + + if (wetness == Wetness.WATER || height < WORLD_SEA_LEVEL) { + if (temperature == Temperature.FROST) { + if (height < WORLD_SEA_LEVEL) { + return Biome.FROZEN_OCEAN; + } else { + return Biome.ICE_PLAINS; + } } else { - if (height > (WORLD_SEA_LEVEL + WORLD_MAX_HEIGHT) / 2) { + if (height < WORLD_SEA_LEVEL) { + if (height < WORLD_MIN_HEIGHT + (WORLD_SEA_LEVEL - WORLD_MIN_HEIGHT) / 2) { + return Biome.DEEP_OCEAN; + } else { + return Biome.OCEAN; + } + } else { + return Biome.SWAMPLAND; + } + } + } + + final int HILLS_HEIGHT = WORLD_SEA_LEVEL + (WORLD_MAX_HEIGHT - WORLD_SEA_LEVEL) / 3; + + if (temperature == Temperature.FROST) { + if (wetness == Wetness.DRIEST || wetness == Wetness.DRY) { + return Biome.TUNDRA; + } else { + if (height > HILLS_HEIGHT) { return Biome.ICE_MOUNTAINS; } else { return Biome.ICE_PLAINS; } } } - if (height < WORLD_SEA_LEVEL) { - if (height < (WORLD_SEA_LEVEL + WORLD_MIN_HEIGHT) / 2){ - return Biome.DEEP_OCEAN; - } else { - return Biome.OCEAN; - } - } - if (temperature == Temperature.COLD) { - if (height > (WORLD_SEA_LEVEL + WORLD_MAX_HEIGHT) / 2) { - return Biome.TAIGA_HILLS; - } else { - return Biome.TAIGA; - } - } - if (temperature == Temperature.WARM) { - if (wetness.ordinal() < 2) { + + if (wetness == Wetness.DRIEST) { + if (temperature == Temperature.COLD || temperature == Temperature.WARM) { return Biome.PLAINS; - } else if (wetness == Wetness.WATER){ + } else { + if (height > HILLS_HEIGHT) { + return Biome.DESERT_HILLS; + } else { + return Biome.DESERT; + } + } + } + + if (temperature == Temperature.COLD) { + if (wetness == Wetness.DRY || wetness == Wetness.WET) { + if (height > HILLS_HEIGHT) { + return Biome.TAIGA_HILLS; + } else { + return Biome.TAIGA; + } + } else { + return Biome.SWAMPLAND; + } + } + + if (wetness == Wetness.WETTEST) { + if (temperature == Temperature.WARM) { return Biome.SWAMPLAND; } else { - if (height > (WORLD_SEA_LEVEL + WORLD_MAX_HEIGHT) / 2) { + if (height > HILLS_HEIGHT) { + return Biome.JUNGLE_HILLS; + } else { + return Biome.JUNGLE; + } + } + } + + if (wetness == Wetness.WETTER) { + if (temperature == Temperature.WARM) { + if (height > HILLS_HEIGHT) { return Biome.FOREST_HILLS; } else { return Biome.FOREST; } - } - } - if (temperature == Temperature.HOTTEST && wetness.ordinal() < 2) { - if (height > (WORLD_SEA_LEVEL + WORLD_MAX_HEIGHT) / 2) { - return Biome.DESERT_HILLS; } else { - return Biome.DESERT; + return Biome.SAVANNA_FOREST; } } - if (wetness.ordinal() > 2) { - if (height > (WORLD_SEA_LEVEL + WORLD_MAX_HEIGHT) / 2) { - return Biome.JUNGLE_HILLS; - } else { - return Biome.JUNGLE; - } + if (temperature == Temperature.HOTTEST) { + return Biome.SAVANNA; } + if (wetness == Wetness.WET) { + if (height > HILLS_HEIGHT) { + return Biome.FOREST_HILLS; + } else { + return Biome.FOREST; + } + } return Biome.PLAINS; } diff --git a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java index b75a25f..e9501ab 100644 --- a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java +++ b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java @@ -12,10 +12,11 @@ public final class WorldConstants { public static final int WORLD_REGION_SIZE = 256; public static final int WORLD_MAX_TEMPERATURE = 100; public static final int WORLD_MAX_WETNESS = 100; - public static final int WORLD_BASE_WETNESS = 30; + public static final int WORLD_BASE_WETNESS = 80; public static final double WORLD_LAND_SIZE = 53.0; public static final double WORLD_LAKE_SIZE = 6.0; + public static final double WORLD_WET_SEA_PERCENT = 0.8; public static final double WORLD_TEMPERATURE_SIZE = 41.0; public static final double WORLD_TEMPERATURE_ZONE_SIZE = 2.99; public static final double WORLD_TEMPERATURE_HEIGHT_GRAD_SIZE = 0.25; diff --git a/generated_world/src/main/java/mc/world/generated_world/word/Wetness.java b/generated_world/src/main/java/mc/world/generated_world/word/Wetness.java index b0c7e49..79a872b 100644 --- a/generated_world/src/main/java/mc/world/generated_world/word/Wetness.java +++ b/generated_world/src/main/java/mc/world/generated_world/word/Wetness.java @@ -1,9 +1,10 @@ package mc.world.generated_world.word; public enum Wetness { - DRYEST, + DRIEST, DRY, WET, WETTER, + WETTEST, WATER } From 62d4ec6768032a28a13e830b3b36dedba240d3a4 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Wed, 1 Aug 2018 15:59:36 +0300 Subject: [PATCH 20/37] More frozen lands --- .../src/main/java/mc/world/generated_world/WorldConstants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java index e9501ab..acc500d 100644 --- a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java +++ b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java @@ -19,7 +19,7 @@ public final class WorldConstants { public static final double WORLD_WET_SEA_PERCENT = 0.8; public static final double WORLD_TEMPERATURE_SIZE = 41.0; public static final double WORLD_TEMPERATURE_ZONE_SIZE = 2.99; - public static final double WORLD_TEMPERATURE_HEIGHT_GRAD_SIZE = 0.25; + public static final double WORLD_TEMPERATURE_HEIGHT_GRAD_SIZE = 1.1; public static final int LANDFILL_GRASS_SURFACE_THIN = 5; From 75bec3ed93df9e8e4f47df45d590208d6b6c01a0 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Wed, 1 Aug 2018 17:49:59 +0300 Subject: [PATCH 21/37] Chunk generations & basic saving --- core/src/main/java/mc/core/block/Block.java | 24 ++++ .../main/java/mc/core/block/BlockFactory.java | 3 + .../main/java/mc/core/block/BlockType.java | 3 +- core/src/main/java/mc/core/world/Chunk.java | 3 +- core/src/main/java/mc/core/world/Region.java | 6 + .../main/java/mc/world/flat/SimpleChunk.java | 14 +- .../ChunkSerializerDeserializer.java | 41 ++++++ .../mc/world/generated_world/CubicWorld.java | 8 +- .../InMemoryCacheChunkLoader.java | 127 ++++++++++++++++++ .../RegionSerializerDeserializer.java | 17 +++ .../SeedBasedWorldGenerator.java | 10 +- .../world/generated_world/WorldConstants.java | 5 +- .../generated_world/chunk/ChunkImpl.java | 106 +++++++++++++++ .../generated_world/chunk/ChunkProxy.java | 10 +- .../generated_world/region/RegionImpl.java | 48 ++++++- generated_world/src/main/resources/log4j2.xml | 18 +++ 16 files changed, 422 insertions(+), 21 deletions(-) create mode 100644 generated_world/src/main/java/mc/world/generated_world/ChunkSerializerDeserializer.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/InMemoryCacheChunkLoader.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/RegionSerializerDeserializer.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java create mode 100644 generated_world/src/main/resources/log4j2.xml diff --git a/core/src/main/java/mc/core/block/Block.java b/core/src/main/java/mc/core/block/Block.java index ea03afb..81d662a 100644 --- a/core/src/main/java/mc/core/block/Block.java +++ b/core/src/main/java/mc/core/block/Block.java @@ -25,6 +25,30 @@ import mc.core.Location; public interface Block { + static Block airBlock (int x, int y, int z) { + return new Block() { + @Override + public int getId() { + return 0; + } + + @Override + public int getMeta() { + return 0; + } + + @Override + public BlockType getBlockType() { + return BlockType.AIR; + } + + @Override + public Location getLocation() { + return new Location(x, y, z); + } + }; + } + /** Block id */ int getId(); diff --git a/core/src/main/java/mc/core/block/BlockFactory.java b/core/src/main/java/mc/core/block/BlockFactory.java index 2007c48..8552e4c 100644 --- a/core/src/main/java/mc/core/block/BlockFactory.java +++ b/core/src/main/java/mc/core/block/BlockFactory.java @@ -1,5 +1,7 @@ package mc.core.block; +import mc.core.Location; + public class BlockFactory { public Block create(BlockType blockType, int meta) { @@ -12,6 +14,7 @@ public class BlockFactory { private class EmbeddedBlock extends AbstractBlock { EmbeddedBlock(BlockType type, int meta) { super(type, meta); + super.setLocation(new Location(0,0,0)); } } } diff --git a/core/src/main/java/mc/core/block/BlockType.java b/core/src/main/java/mc/core/block/BlockType.java index f4a8648..4b4b467 100644 --- a/core/src/main/java/mc/core/block/BlockType.java +++ b/core/src/main/java/mc/core/block/BlockType.java @@ -9,7 +9,8 @@ public enum BlockType { BEDROCK(7, "Bedrock"), WATER(8, "Water"), SAND(12, "Sand"), - SNOW(32, "Snow"); + SNOW(32, "Snow"), + AIR(0, "Air"); @Getter private final int id; diff --git a/core/src/main/java/mc/core/world/Chunk.java b/core/src/main/java/mc/core/world/Chunk.java index 4138f4d..95b49b9 100644 --- a/core/src/main/java/mc/core/world/Chunk.java +++ b/core/src/main/java/mc/core/world/Chunk.java @@ -47,6 +47,7 @@ public interface Chunk { int getY(); int getZ(); - Block[] getNotAirBlocks(); + Block[] getModifiedBlocks(); void setBlock (int x, int y, int z, Block block); + Block getBlock (int x, int y, int z); } diff --git a/core/src/main/java/mc/core/world/Region.java b/core/src/main/java/mc/core/world/Region.java index 11b197c..2d72766 100644 --- a/core/src/main/java/mc/core/world/Region.java +++ b/core/src/main/java/mc/core/world/Region.java @@ -1,5 +1,9 @@ package mc.core.world; +import mc.core.serialization.Serializer; + +import java.io.IOException; + /** * Simple world generation unit * 16x16x16 chunks @@ -23,4 +27,6 @@ public interface Region { Biome getBiomeAt (int x, int z); void setBiome (int x, int z, Biome biome); + + void save(Serializer chunkSerializer, Serializer regionSerializer) 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 09cbb5d..4e95a4d 100644 --- a/flat_world/src/main/java/mc/world/flat/SimpleChunk.java +++ b/flat_world/src/main/java/mc/world/flat/SimpleChunk.java @@ -5,6 +5,8 @@ package mc.world.flat; import mc.core.block.Block; +import mc.core.block.BlockFactory; +import mc.core.block.BlockType; import mc.core.world.Biome; import mc.core.world.Chunk; @@ -89,7 +91,7 @@ public class SimpleChunk implements Chunk { } @Override - public Block[] getNotAirBlocks() { + public Block[] getModifiedBlocks() { return new Block[0]; } @@ -97,4 +99,14 @@ public class SimpleChunk implements Chunk { public void setBlock(int x, int y, int z, Block block) { } + + @Override + public Block getBlock(int x, int y, int z) { + BlockFactory blockFactory = new BlockFactory(); + + if (y == 0) return blockFactory.create(BlockType.BEDROCK, 0); + else if (y >= 1 && y <= 2) return blockFactory.create(BlockType.DIRT, 0); + else if (y == 3) return blockFactory.create(BlockType.GRASS, 0); + else return Block.airBlock(x, y, z); + } } diff --git a/generated_world/src/main/java/mc/world/generated_world/ChunkSerializerDeserializer.java b/generated_world/src/main/java/mc/world/generated_world/ChunkSerializerDeserializer.java new file mode 100644 index 0000000..1f2df79 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/ChunkSerializerDeserializer.java @@ -0,0 +1,41 @@ +package mc.world.generated_world; + +import mc.core.block.BlockFactory; +import mc.core.serialization.BlockDeserializer; +import mc.core.serialization.BlockSerializer; +import mc.core.serialization.ChunkSerializer; +import mc.core.serialization.ChunkDeserializer; +import mc.core.world.Chunk; + +public class ChunkSerializerDeserializer implements ChunkSerializer, ChunkDeserializer { + + private BlockSerializer blockSerializer; + private BlockDeserializer blockDeserializer; + + @Override + public Chunk deserialize(byte[] bytes) { + return null; + } + + @Override + public byte[] serialize(Chunk chunk) { + BlockSerializer blockSerializer = new BlockSerializerDeserializer(new BlockFactory(), chunk); + int blocks = chunk.getModifiedBlocks().length; + byte[] bytes = new byte[6 + 3 * blocks]; + + bytes[0] = (byte) ((chunk.getX() >> 6) & 0xff); + bytes[1] = (byte) (((chunk.getX() & 0x3f) << 2) | ((chunk.getY()) >> 2) & 0x03); + bytes[2] = (byte) (((chunk.getY() & 0x03) << 6) | ((chunk.getZ() >> 8) & 0x3f)); + bytes[3] = (byte) (chunk.getZ() & 0xff); + bytes[4] = (byte) ((blocks >> 5) & 0xff); + bytes[5] = (byte) ((blocks & 0x1f) << 3); + + for (int i = 0; i < blocks; i ++) { + byte[] blockSerialized = blockSerializer.serialize(chunk.getModifiedBlocks()[i]); + for (int j = 0; j < 3; j ++) { + bytes[6 + i * 3 + j] = blockSerialized[j]; + } + } + return bytes; + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java b/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java index d22fed4..1f21785 100644 --- a/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java +++ b/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java @@ -16,25 +16,25 @@ public class CubicWorld implements World { public CubicWorld(UUID worldId, int seed) { this.worldId = worldId; - chunkLoader = new InMemoryCacheChunkLoader(worldId); + chunkLoader = new InMemoryCacheChunkLoader(this); this.seed = seed; } public CubicWorld(int seed) { this.worldId = UUID.randomUUID(); - chunkLoader = new InMemoryCacheChunkLoader(worldId); + chunkLoader = new InMemoryCacheChunkLoader(this); this.seed = seed; } public CubicWorld(UUID worldId) { this.worldId = worldId; - chunkLoader = new InMemoryCacheChunkLoader(worldId); + chunkLoader = new InMemoryCacheChunkLoader(this); this.seed = 0; } public CubicWorld () { this.worldId = UUID.randomUUID(); - chunkLoader = new InMemoryCacheChunkLoader(worldId); + chunkLoader = new InMemoryCacheChunkLoader(this); this.seed = 0; } diff --git a/generated_world/src/main/java/mc/world/generated_world/InMemoryCacheChunkLoader.java b/generated_world/src/main/java/mc/world/generated_world/InMemoryCacheChunkLoader.java new file mode 100644 index 0000000..1cef35d --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/InMemoryCacheChunkLoader.java @@ -0,0 +1,127 @@ +package mc.world.generated_world; + +import lombok.extern.slf4j.Slf4j; +import mc.core.serialization.ChunkDeserializer; +import mc.core.serialization.ChunkSerializer; +import mc.core.serialization.Deserializer; +import mc.core.serialization.Serializer; +import mc.core.world.*; +import mc.world.generated_world.region.RegionImpl; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.text.MessageFormat; +import java.util.Optional; +import java.util.UUID; + +import static mc.world.generated_world.WorldConstants.*; + +@Slf4j +public class InMemoryCacheChunkLoader implements ChunkLoader { + + private final World world; + private File worldFolder; + @Autowired + private WorldGenerator worldGenerator; + + @Autowired + private ChunkDeserializer chunkDeserializer; + @Autowired + private ChunkSerializer chunkSerializer; + @Autowired + private Serializer regionSerializer; + @Autowired + private Deserializer regionDeserializer; + + public InMemoryCacheChunkLoader(World world) { + this.world = world; + String worldPath = System.getProperty("worlds.folder", "worlds"); + worldFolder = new File(worldPath, world.getWorldId().toString()); + if (!worldFolder.exists()) { + log.info("Created folder for world with uuid '{}'", world.getWorldId()); + worldFolder.mkdirs(); + } + } + + private File getChuckFile(int x, int y, int z) { + return new File(worldFolder, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x, y, z)); + } + + @Override + public Optional loadChunk(int x, int y, int z) { + File file = getChuckFile(x, y, z); + if (!file.exists()) { + return Optional.empty(); + } else { + try { + byte[] bytes = Files.readAllBytes(Paths.get(file.toURI())); + return Optional.of(chunkDeserializer.deserialize(bytes)); + } catch (IOException e) { + log.error("Error occurred while reading chunk file: " + file.getAbsolutePath(), e); + return Optional.empty(); + } + } + } + + @Override + public Chunk loadOrGenerateChunk(int x, int y, int z) { + int regX = x / WORLD_REGION_SIZE; + int regZ = z / WORLD_REGION_SIZE; + File regionFile = new File(worldFolder, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, regX, regZ)); + Region region; + Chunk chunk; + if (!regionFile.exists()) { + log.debug("Region [{}, {}] not found. Generating!", regX, regZ); + regionFile.mkdirs(); + region = worldGenerator.generateRegion(regX, regZ, world); + File biomeMapFile = new File(regionFile, BIOME_FILE_NAME_TEMPLATE); + byte[] biomeMapBytes = regionSerializer.serialize(region); + try (FileOutputStream writer = new FileOutputStream(biomeMapFile)) { + writer.write(biomeMapBytes); + } catch (IOException e) { + log.error("Error occurred while writting biome file", e); + } + saveRegion(region); + chunk = region.getChunkAt(x % WORLD_CHUNK_SIZE, y % WORLD_CHUNK_SIZE, z % WORLD_CHUNK_SIZE); + } else { + File chunkFile = new File(regionFile, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x % WORLD_CHUNK_SIZE, y % WORLD_CHUNK_SIZE, z % WORLD_CHUNK_SIZE)); + try { + byte[] chunkBytes = Files.readAllBytes(Paths.get(chunkFile.toURI())); + byte[] regionBytes = Files.readAllBytes(Paths.get(new File(regionFile, BIOME_FILE_NAME_TEMPLATE).toURI())); + region = regionDeserializer.deserialize(regionBytes); + chunk = chunkDeserializer.deserialize(chunkBytes); + } catch (IOException e) { + log.error("Error occurred while reading chunk file", e); + return null; + } + } + for (int tx = 0; tx < WORLD_CHUNK_SIZE; tx++) { + for (int tz = 0; tz < WORLD_CHUNK_SIZE; tz ++) { + chunk.setBiome(tx, tz, region.getBiomeAt(chunk.getX() * WORLD_CHUNK_SIZE + x, chunk.getZ() * WORLD_CHUNK_SIZE + z)); + } + } + return chunk; + } + + private void saveRegion (Region region) { + File file = new File(worldFolder, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, region.getX(), region.getZ())); + for (int x = 0; x < WORLD_REGION_SIZE / WORLD_CHUNK_SIZE; x ++) { + for (int y = 0; y < WORLD_REGION_SIZE / WORLD_CHUNK_SIZE; y ++) { + for (int z = 0; z < WORLD_REGION_SIZE / WORLD_CHUNK_SIZE; z ++) { + byte[] chunkBytes = chunkSerializer.serialize(region.getChunkAt(x, y, z)); + File chunkFile = new File(file, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x, y, z)); + try (FileOutputStream writer = new FileOutputStream(chunkFile)) { + writer.write(chunkBytes); + } catch (IOException e) { + log.error("Error occurred while writting chunk to file", e); + } + } + } + } + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/RegionSerializerDeserializer.java b/generated_world/src/main/java/mc/world/generated_world/RegionSerializerDeserializer.java new file mode 100644 index 0000000..f5a1218 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/RegionSerializerDeserializer.java @@ -0,0 +1,17 @@ +package mc.world.generated_world; + +import mc.core.serialization.Deserializer; +import mc.core.serialization.Serializer; +import mc.core.world.Region; + +public class RegionSerializerDeserializer implements Serializer, Deserializer { + @Override + public Region deserialize(byte[] bytes) { + return null; + } + + @Override + public byte[] serialize(Region region) { + return new byte[0]; + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java index a972154..c1e768a 100644 --- a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java @@ -2,6 +2,7 @@ package mc.world.generated_world; import lombok.RequiredArgsConstructor; import mc.core.block.BlockFactory; +import mc.core.block.BlockType; import mc.core.world.*; import mc.world.generated_world.region.RegionImpl; import mc.world.generated_world.word.Temperature; @@ -19,7 +20,8 @@ public class SeedBasedWorldGenerator implements WorldGenerator { public static void main(String[] args) throws Exception{ WorldGenerator worldGenerator = new SeedBasedWorldGenerator(); World world = new CubicWorld(UUID.fromString("00000000-0000-0000-C000-000000000046"), 123); - worldGenerator.generateRegion(0, 0, world); + Region region = worldGenerator.generateRegion(0, 0, world); + region.save(new ChunkSerializerDeserializer(), new RegionSerializerDeserializer()); /*worldGenerator.generateRegion(1, 0, world); worldGenerator.generateRegion(-1, 0, world); worldGenerator.generateRegion(0, 1, world); @@ -83,7 +85,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { @Override public Region generateRegion(int x, int z, World world) { - Region region = new RegionImpl(x,z); + Region region = new RegionImpl(x, z, world); RegionGenerator regionGenerator = new RegionGenerator(world, region); regionGenerator.generate(); return region; @@ -233,7 +235,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } catch (Exception e) {} // ================================ DEBUG FINISH ======================================= - /*for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) { + for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) { for (int z = 0; z < WorldConstants.WORLD_REGION_SIZE; z ++) { region.setBiome(x, z, biomes[x][z]); if (heightMap[x][z] < WORLD_SEA_LEVEL) { @@ -274,7 +276,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } } } - }*/ + } } private Biome selectBiome (Temperature temperature, Wetness wetness, int height) { diff --git a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java index acc500d..7cc050c 100644 --- a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java +++ b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java @@ -3,13 +3,14 @@ package mc.world.generated_world; public final class WorldConstants { public static final String CHUNK_FILE_NAME_TEMPLATE = "chunk_{0}_{1}_{2}.dat"; - public static final String BIOME_FILE_NAME_TEMPLATE = "biome_{0}_{1}.dat"; + public static final String BIOME_FILE_NAME_TEMPLATE = "biomes.dat"; public static final String REGION_FILE_NAME_TEMPLATE = "r.{0}.{1}"; public static final int WORLD_MIN_HEIGHT = 28; public static final int WORLD_SEA_LEVEL = 64; public static final int WORLD_MAX_HEIGHT = 128; public static final int WORLD_REGION_SIZE = 256; + public static final int WORLD_CHUNK_SIZE = 16; public static final int WORLD_MAX_TEMPERATURE = 100; public static final int WORLD_MAX_WETNESS = 100; public static final int WORLD_BASE_WETNESS = 80; @@ -23,7 +24,7 @@ public final class WorldConstants { public static final int LANDFILL_GRASS_SURFACE_THIN = 5; - public static final double WORLD_ROUGHNRESS = 0.35; + public static final double WORLD_ROUGHNESS = 0.35; private WorldConstants () {} } 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..4ffcc69 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java @@ -0,0 +1,106 @@ +package mc.world.generated_world.chunk; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import mc.core.block.Block; +import mc.core.world.Biome; +import mc.core.world.Chunk; +import mc.core.world.Region; + +import java.util.LinkedList; +import java.util.List; + +import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE; + +@RequiredArgsConstructor +public class ChunkImpl implements Chunk{ + @Getter + private final int x; + @Getter + private final int y; + @Getter + private final int z; + private final Block[][][] blocks = new Block[WORLD_CHUNK_SIZE][WORLD_CHUNK_SIZE][WORLD_CHUNK_SIZE]; + private final transient List modifiedBlocks = new LinkedList<>(); + private final transient Region region; + + @Override + public int getBlockType(int x, int y, int z) { + return blocks[x][y][z].getId(); + } + + @Override + public void setBlockType(int x, int y, int z, int type) { + + } + + @Override + public int getBlockMetadata(int x, int y, int z) { + return 0; + } + + @Override + public void setBlockMetadata(int x, int y, int z, int metadata) { + + } + + @Override + public int getBlockLight(int x, int y, int z) { + return 15; + } + + @Override + public void setBlockLight(int x, int y, int z, int lightLevel) { + + } + + @Override + public int getSkyLight(int x, int y, int z) { + return 15; + } + + @Override + public void setSkyLight(int x, int y, int z, int lightLevel) { + + } + + @Override + public int getAddition(int x, int y, int z) { + return 0; + } + + @Override + public void setAddition(int x, int y, int z, int value) { + + } + + @Override + public Biome getBiome(int x, int z) { + return region.getBiomeAt(x + this.x * WORLD_CHUNK_SIZE,z + this.z * WORLD_CHUNK_SIZE); + } + + @Override + public void setBiome(int x, int z, Biome biome) { + region.setBiome(x + this.x * WORLD_CHUNK_SIZE,z + this.z * WORLD_CHUNK_SIZE, biome); + } + + @Override + public Block[] getModifiedBlocks() { + return modifiedBlocks.toArray(new Block[modifiedBlocks.size()]); + } + + @Override + public void setBlock(int x, int y, int z, Block block) { + blocks[x][y][z] = block; + modifiedBlocks.add(block); + } + + @Override + public Block getBlock(int x, int y, int z) { + Block block = blocks[x][y][z]; + if (block == null) { + return Block.airBlock(x, y, z); + } + return blocks[x][y][z]; + } +} 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 e1c1d47..d135759 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 @@ -115,9 +115,9 @@ public class ChunkProxy implements Chunk { } @Override - public Block[] getNotAirBlocks() { + public Block[] getModifiedBlocks() { use(); - return chunk.getNotAirBlocks(); + return chunk.getModifiedBlocks(); } @Override @@ -125,4 +125,10 @@ public class ChunkProxy implements Chunk { use(); chunk.setBlock(x, y, z, block); } + + @Override + public Block getBlock(int x, int y, int z) { + use(); + return chunk.getBlock(x, y, z); + } } 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 b61f053..8d73364 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 @@ -2,14 +2,21 @@ package mc.world.generated_world.region; import lombok.Getter; import lombok.RequiredArgsConstructor; -import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import mc.core.serialization.Serializer; import mc.core.world.*; +import mc.world.generated_world.InMemoryCacheChunkLoader; +import mc.world.generated_world.chunk.ChunkImpl; import mc.world.generated_world.chunk.ChunkProxy; import org.springframework.beans.factory.annotation.Autowired; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.text.MessageFormat; +import static mc.world.generated_world.WorldConstants.*; + @Slf4j @RequiredArgsConstructor public class RegionImpl implements Region{ @@ -17,10 +24,10 @@ public class RegionImpl implements Region{ private final int x; @Getter private final int z; - private final ChunkProxy[][][] chunks = new ChunkProxy[16][16][16]; - private final Biome[][] biomes = new Biome[16][16]; - @Getter@Setter - private transient World world; + private final ChunkProxy[][][] chunks = new ChunkProxy[WORLD_REGION_SIZE/WORLD_CHUNK_SIZE][WORLD_REGION_SIZE/WORLD_CHUNK_SIZE][WORLD_REGION_SIZE/WORLD_CHUNK_SIZE]; + private final Biome[][] biomes = new Biome[WORLD_REGION_SIZE][WORLD_REGION_SIZE]; + @Getter + private final transient World world; @Autowired private ChunkLoader chunkLoader; @@ -29,9 +36,12 @@ public class RegionImpl implements Region{ if (x < 0 || y < 0 || z < 0 || x >= 16 || y >= 16 || z >= 16) { throw new RuntimeException(MessageFormat.format("Invalid chunk coordinates [{0} {1} {2}]", x, y, z)); } + if (chunkLoader == null) { + chunkLoader = new InMemoryCacheChunkLoader(world); + } Chunk chunk = chunks[x][y][z]; if (chunk == null) { - chunk = chunkLoader.loadOrGenerateChunk(x, y, z); + chunk = chunkLoader.loadChunk(x + this.x * WORLD_REGION_SIZE, y, this.z * WORLD_REGION_SIZE).orElse(new ChunkImpl(x, y, z, this)); chunks[x][y][z] = new ChunkProxy(chunk); } return chunk; @@ -60,4 +70,30 @@ public class RegionImpl implements Region{ } biomes[x][z] = biome; } + + @Override + public void save(Serializer chunkSerializer, Serializer regionSerializer) throws IOException { + String worldPath = System.getProperty("worlds.folder", "worlds"); + File worldFile = new File(worldPath, world.getWorldId().toString()); + File regionFile = new File(worldFile, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, this.getX(), this.getZ())); + if (!regionFile.exists()) { + regionFile.mkdirs(); + } + File biomeMapFile = new File(regionFile, BIOME_FILE_NAME_TEMPLATE); + byte[] biomeBytes = regionSerializer.serialize(this); + try (FileOutputStream fileOutputStream = new FileOutputStream(biomeMapFile)){ + fileOutputStream.write(biomeBytes); + } + for (int x = 0; x < WORLD_CHUNK_SIZE; x ++) { + for (int z = 0; z < WORLD_CHUNK_SIZE; z ++) { + for (int y = 0; y < WORLD_CHUNK_SIZE; y++) { + File chunkFile = new File(regionFile, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x, y, z)); + byte[] chunkBytes = chunkSerializer.serialize(this.getChunkAt(x, y, z)); + try (FileOutputStream fileOutputStream = new FileOutputStream(chunkFile)){ + fileOutputStream.write(chunkBytes); + } + } + } + } + } } diff --git a/generated_world/src/main/resources/log4j2.xml b/generated_world/src/main/resources/log4j2.xml new file mode 100644 index 0000000..0ea354b --- /dev/null +++ b/generated_world/src/main/resources/log4j2.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + From 9cf3ebb55116f3f614a12a5806563e05807541fe Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 08:10:18 +0300 Subject: [PATCH 22/37] Logs --- .../SeedBasedWorldGenerator.java | 227 ++++++++++++------ 1 file changed, 148 insertions(+), 79 deletions(-) diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java index c1e768a..450d43d 100644 --- a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java @@ -1,6 +1,7 @@ package mc.world.generated_world; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import mc.core.block.BlockFactory; import mc.core.block.BlockType; import mc.core.world.*; @@ -15,17 +16,22 @@ import java.util.UUID; import static mc.world.generated_world.WorldConstants.*; +@Slf4j public class SeedBasedWorldGenerator implements WorldGenerator { public static void main(String[] args) throws Exception{ WorldGenerator worldGenerator = new SeedBasedWorldGenerator(); - World world = new CubicWorld(UUID.fromString("00000000-0000-0000-C000-000000000046"), 123); + World world = new CubicWorld(UUID.fromString("00000000-0000-0000-C000-000000000046"), 2626949); Region region = worldGenerator.generateRegion(0, 0, world); - region.save(new ChunkSerializerDeserializer(), new RegionSerializerDeserializer()); - /*worldGenerator.generateRegion(1, 0, world); + //region.save(new ChunkSerializerDeserializer(), new RegionSerializerDeserializer()); + worldGenerator.generateRegion(1, 0, world); worldGenerator.generateRegion(-1, 0, world); worldGenerator.generateRegion(0, 1, world); worldGenerator.generateRegion(0, -1, world); + worldGenerator.generateRegion(-1, -1, world); + worldGenerator.generateRegion(1, -1, world); + worldGenerator.generateRegion(-1, 1, world); + worldGenerator.generateRegion(1, 1, world); BufferedImage image = new BufferedImage(3 * 256, 3 * 256, BufferedImage.TYPE_INT_RGB); BufferedImage currentImage; int shiftX; @@ -80,14 +86,56 @@ public class SeedBasedWorldGenerator implements WorldGenerator { image.setRGB(tx, ty, currentImage.getRGB(x, y)); } } - ImageIO.write(image, "png", new File("out", "merged.png"));*/ + currentImage = ImageIO.read(new File("out/-1.-1", "biomeMap.png")); + shiftX = 0; + shiftY = 0; + for (int x = 0; x < 256; x ++){ + for (int y = 0; y < 256; y ++){ + int tx = 256 * shiftX + x; + int ty = 256 * shiftY + y; + image.setRGB(tx, ty, currentImage.getRGB(x, y)); + } + } + currentImage = ImageIO.read(new File("out/1.-1", "biomeMap.png")); + shiftX = 2; + shiftY = 0; + for (int x = 0; x < 256; x ++){ + for (int y = 0; y < 256; y ++){ + int tx = 256 * shiftX + x; + int ty = 256 * shiftY + y; + image.setRGB(tx, ty, currentImage.getRGB(x, y)); + } + } + currentImage = ImageIO.read(new File("out/1.1", "biomeMap.png")); + shiftX = 2; + shiftY = 2; + for (int x = 0; x < 256; x ++){ + for (int y = 0; y < 256; y ++){ + int tx = 256 * shiftX + x; + int ty = 256 * shiftY + y; + image.setRGB(tx, ty, currentImage.getRGB(x, y)); + } + } + currentImage = ImageIO.read(new File("out/-1.1", "biomeMap.png")); + shiftX = 0; + shiftY = 2; + for (int x = 0; x < 256; x ++){ + for (int y = 0; y < 256; y ++){ + int tx = 256 * shiftX + x; + int ty = 256 * shiftY + y; + image.setRGB(tx, ty, currentImage.getRGB(x, y)); + } + } + ImageIO.write(image, "png", new File("out", "merged.png")); } @Override public Region generateRegion(int x, int z, World world) { + log.info("Generating region [{},{}]...", x, z); Region region = new RegionImpl(x, z, world); RegionGenerator regionGenerator = new RegionGenerator(world, region); regionGenerator.generate(); + log.info("Region [{},{}] is generated", x, z); return region; } @@ -109,19 +157,21 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } public void generate() { + log.debug("Starting generating region [{}, {}] for world '{}' with seed '{}'", region.getX(), region.getZ(), world.getWorldId(), world.getSeed()); + noiseGenerator = new NoiseGenerator(world.getSeed()); noiseGenerator.init(); - File file = new File("out", region.getX() + "." + region.getZ()); - file.mkdirs(); - int[][] heightMap = new int[WorldConstants.WORLD_REGION_SIZE][WorldConstants.WORLD_REGION_SIZE]; - int[][] grassMap = new int[WorldConstants.WORLD_REGION_SIZE][WorldConstants.WORLD_REGION_SIZE]; - int[][] temperatureMap = new int[WorldConstants.WORLD_REGION_SIZE][WorldConstants.WORLD_REGION_SIZE]; - int[][] wetMap = new int[WorldConstants.WORLD_REGION_SIZE][WorldConstants.WORLD_REGION_SIZE]; - Biome[][] biomes = new Biome[WorldConstants.WORLD_REGION_SIZE][WorldConstants.WORLD_REGION_SIZE]; - for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) { - for (int z = 0; z < WorldConstants.WORLD_REGION_SIZE; z ++) { - int tx = convert(x + region.getX() * WorldConstants.WORLD_REGION_SIZE); - int tz = convert(z + region.getZ() * WorldConstants.WORLD_REGION_SIZE); + + int[][] heightMap = new int[WORLD_REGION_SIZE][WORLD_REGION_SIZE]; + int[][] grassMap = new int[WORLD_REGION_SIZE][WORLD_REGION_SIZE]; + int[][] temperatureMap = new int[WORLD_REGION_SIZE][WORLD_REGION_SIZE]; + int[][] wetMap = new int[WORLD_REGION_SIZE][WORLD_REGION_SIZE]; + Biome[][] biomes = new Biome[WORLD_REGION_SIZE][WORLD_REGION_SIZE]; + + for (int x = 0; x < WORLD_REGION_SIZE; x ++) { + for (int z = 0; z < WORLD_REGION_SIZE; z ++) { + int tx = convert(x + region.getX() * WORLD_REGION_SIZE); + int tz = convert(z + region.getZ() * WORLD_REGION_SIZE); double p = sigmoid(noiseGenerator.noise(tx / WORLD_LAND_SIZE, tz / WORLD_LAND_SIZE)); double r = Math.sqrt(noiseGenerator.noise(tx / WORLD_LAKE_SIZE, tz / WORLD_LAKE_SIZE)); double h = (WORLD_MAX_HEIGHT - WORLD_MIN_HEIGHT) * Math.min(p * r, 1); @@ -141,8 +191,9 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } } } - for (int x = 1; x < WorldConstants.WORLD_REGION_SIZE - 1; x ++) { - for (int z = 1; z < WorldConstants.WORLD_REGION_SIZE - 1; z++) { + + for (int x = 1; x < WORLD_REGION_SIZE - 1; x ++) { + for (int z = 1; z < WORLD_REGION_SIZE - 1; z++) { int mid = 0; for (int tx = x - 1; tx <= x + 1; tx ++) { for (int tz = z - 1; tz <= z + 1; tz ++) { @@ -152,8 +203,8 @@ public class SeedBasedWorldGenerator implements WorldGenerator { wetMap[x][z] = mid / 9; } } - for (int z = 1; z < WorldConstants.WORLD_REGION_SIZE - 1; z++) { - for (int x = 1; x < WorldConstants.WORLD_REGION_SIZE - 1; x ++) { + for (int z = 1; z < WORLD_REGION_SIZE - 1; z++) { + for (int x = 1; x < WORLD_REGION_SIZE - 1; x ++) { int mid = 0; for (int tx = x - 1; tx <= x + 1; tx ++) { for (int tz = z - 1; tz <= z + 1; tz ++) { @@ -165,9 +216,9 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } } - for (int z = 1; z < WorldConstants.WORLD_REGION_SIZE - 1; z++) { - for (int x = 1; x < WorldConstants.WORLD_REGION_SIZE - 1; x ++) { - wetMap[x][z] = (int) Math.min(WORLD_MAX_WETNESS, WORLD_BASE_WETNESS * noiseGenerator.noise(x / 31d, z / 67d) + wetMap[x][z] * (1 + 0.2 * (SeedRandomGenerator.random(x, z, world.getSeed())))); + for (int z = 1; z < WORLD_REGION_SIZE - 1; z++) { + for (int x = 1; x < WORLD_REGION_SIZE - 1; x ++) { + wetMap[x][z] = (int) Math.min(WORLD_MAX_WETNESS, WORLD_BASE_WETNESS * noiseGenerator.noise(x / 31d, z / 31d) + wetMap[x][z] * (1 + 0.2 * (SeedRandomGenerator.random(x, z, world.getSeed())))); } } @@ -176,67 +227,77 @@ public class SeedBasedWorldGenerator implements WorldGenerator { smooth(wetMap); //smooth(heightMap); - BufferedImage tempImg = new BufferedImage(WORLD_REGION_SIZE, WORLD_REGION_SIZE, BufferedImage.TYPE_INT_RGB); - BufferedImage wetImg = new BufferedImage(WORLD_REGION_SIZE, WORLD_REGION_SIZE, BufferedImage.TYPE_INT_RGB); - for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) { - for (int z = 0; z < WorldConstants.WORLD_REGION_SIZE; z ++) { - Temperature temperature = Temperature.values()[Temperature.values().length * temperatureMap[x][z] / WORLD_MAX_TEMPERATURE]; - Wetness wetness = Wetness.values()[ Wetness.values().length * (Math.min(wetMap[x][z], WORLD_MAX_WETNESS) - 1) / WORLD_MAX_WETNESS]; - biomes[x][z] = selectBiome(temperature, wetness, heightMap[x][z]); - tempImg.setRGB(x, z, temperature.ordinal() * 0xff / Temperature.values().length); - wetImg.setRGB(x, z, wetness.ordinal() * 0xff / Wetness.values().length); + // ================================ DEBUG ======================================= + if (DEBUG_ENABLED) { + log.debug("Creating debug images"); + File outFile; + outFile = new File("out", region.getX() + "." + region.getZ()); + outFile.mkdirs(); + BufferedImage tempImg = new BufferedImage(WORLD_REGION_SIZE, WORLD_REGION_SIZE, BufferedImage.TYPE_INT_RGB); + BufferedImage wetImg = new BufferedImage(WORLD_REGION_SIZE, WORLD_REGION_SIZE, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < WORLD_REGION_SIZE; x ++) { + for (int z = 0; z < WORLD_REGION_SIZE; z ++) { + Temperature temperature = Temperature.values()[Temperature.values().length * temperatureMap[x][z] / WORLD_MAX_TEMPERATURE]; + Wetness wetness = Wetness.values()[ Wetness.values().length * (Math.min(wetMap[x][z], WORLD_MAX_WETNESS) - 1) / WORLD_MAX_WETNESS]; + biomes[x][z] = selectBiome(temperature, wetness, heightMap[x][z]); + tempImg.setRGB(x, z, temperature.ordinal() * 0xff / Temperature.values().length); + wetImg.setRGB(x, z, wetness.ordinal() * 0xff / Wetness.values().length); + } + } + + try { + ImageIO.write(tempImg, "png", new File(outFile, "temp_img.png")); + ImageIO.write(wetImg, "png", new File(outFile, "wet_img.png")); + + BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); + BufferedImage subImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < 256; x++) { + for (int z = 0; z < 256; z++) { + int h = heightMap[x][z]; + h = h << 16 | h << 8 | h; + image.setRGB(x, z, h); + } + } + ImageIO.write(image, "png", new File(outFile, "heightmap.png")); + image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < 256; x++) { + for (int z = 0; z < 256; z++) { + int temp = 0xff * temperatureMap[x][z] / 100; + temp = temp << 16; + image.setRGB(x, z, temp); + subImage.setRGB(x, z, (0xff * (int) (temperatureMap[x][z] / 20) / 5) << 16); + } + } + ImageIO.write(image, "png", new File(outFile, "temperatureMap.png")); + ImageIO.write(subImage, "png", new File(outFile, "reg_temperatureMap.png")); + subImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); + image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < 256; x++) { + for (int z = 0; z < 256; z++) { + int wet = 0xff * wetMap[x][z] / 100; + image.setRGB(x, z, wet); + subImage.setRGB(x, z, 0xff * (int) (Wetness.values().length * wetMap[x][z] / (WORLD_MAX_WETNESS))); + } + } + ImageIO.write(image, "png", new File(outFile, "wetMap.png")); + ImageIO.write(subImage, "png", new File(outFile, "reg_wetMap.png")); + image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < 256; x++) { + for (int z = 0; z < 256; z++) { + image.setRGB(x, z, biomes[x][z].getColor()); + } + } + ImageIO.write(image, "png", new File(outFile, "biomeMap.png")); + } catch (Exception e) { + log.error("Error occurred while creating debug images", e); } } - - // ================================ DEBUG ======================================= - try { - ImageIO.write(tempImg, "png", new File("out/" + region.getX() + "." +region.getZ() +"/temp_img.png")); - ImageIO.write(wetImg, "png", new File("out/" + region.getX() + "." +region.getZ() +"/wet_img.png")); - - BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); - BufferedImage subImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); - for (int x = 0; x < 256; x ++) { - for (int z = 0; z < 256; z ++) { - int h = heightMap[x][z]; - h = h << 16 | h << 8 | h; - image.setRGB(x, z, h); - } - } - ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() +"/hightmap.png")); - image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); - for (int x = 0; x < 256; x ++) { - for (int z = 0; z < 256; z ++) { - int temp = 0xff * temperatureMap[x][z] / 100; - temp = temp << 16; - image.setRGB(x, z, temp); - subImage.setRGB(x, z, (0xff * (int) (temperatureMap[x][z] / 20) / 5) << 16); - } - } - ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() + "/temperatureMap.png")); - ImageIO.write(subImage, "png", new File("out/" + region.getX() + "." +region.getZ() + "/reg_temperatureMap.png")); - subImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); - image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); - for (int x = 0; x < 256; x ++) { - for (int z = 0; z < 256; z ++) { - int wet = 0xff * wetMap[x][z] / 100; - image.setRGB(x, z, wet); - subImage.setRGB(x, z, 0xff * (int) (Wetness.values().length * wetMap[x][z] / (WORLD_MAX_WETNESS))); - } - } - ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() + "/wetMap.png")); - ImageIO.write(subImage, "png", new File("out/" + region.getX() + "." +region.getZ() + "/reg_wetMap.png")); - image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB); - for (int x = 0; x < 256; x ++) { - for (int z = 0; z < 256; z ++) { - image.setRGB(x, z, biomes[x][z].getColor()); - } - } - ImageIO.write(image, "png", new File("out/" + region.getX() + "." +region.getZ() + "/biomeMap.png")); - } catch (Exception e) {} // ================================ DEBUG FINISH ======================================= - for (int x = 0; x < WorldConstants.WORLD_REGION_SIZE; x ++) { - for (int z = 0; z < WorldConstants.WORLD_REGION_SIZE; z ++) { + log.debug("Creating chunks..."); + + for (int x = 0; x < WORLD_REGION_SIZE; x ++) { + for (int z = 0; z < WORLD_REGION_SIZE; z ++) { region.setBiome(x, z, biomes[x][z]); if (heightMap[x][z] < WORLD_SEA_LEVEL) { for (int y = 0; y < WORLD_SEA_LEVEL; y ++) { @@ -277,6 +338,13 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } } } + + /* TODO + log.debug("Creating rivers..."); + log.debug("Creating caves..."); + log.debug("Planting trees..."); + log.debug("Spawning animals..."); + */ } private Biome selectBiome (Temperature temperature, Wetness wetness, int height) { @@ -411,6 +479,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { gradsX[i] = Math.cos(2.0f * Math.PI * i / WORLD_REGION_SIZE); gradsY[i] = Math.sin(2.0f * Math.PI * i / WORLD_REGION_SIZE); } + log.debug("Noise generator is initialized"); } double f(double t) { From 0301448a79bda78c6e52cfd7db70880a82164cc7 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 08:10:44 +0300 Subject: [PATCH 23/37] Constants changed to better world generation --- .../java/mc/world/generated_world/WorldConstants.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java index 7cc050c..5a59209 100644 --- a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java +++ b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java @@ -2,11 +2,13 @@ package mc.world.generated_world; public final class WorldConstants { + public static final boolean DEBUG_ENABLED = true; + public static final String CHUNK_FILE_NAME_TEMPLATE = "chunk_{0}_{1}_{2}.dat"; public static final String BIOME_FILE_NAME_TEMPLATE = "biomes.dat"; public static final String REGION_FILE_NAME_TEMPLATE = "r.{0}.{1}"; - public static final int WORLD_MIN_HEIGHT = 28; + public static final int WORLD_MIN_HEIGHT = 36; public static final int WORLD_SEA_LEVEL = 64; public static final int WORLD_MAX_HEIGHT = 128; public static final int WORLD_REGION_SIZE = 256; @@ -15,8 +17,8 @@ public final class WorldConstants { public static final int WORLD_MAX_WETNESS = 100; public static final int WORLD_BASE_WETNESS = 80; - public static final double WORLD_LAND_SIZE = 53.0; - public static final double WORLD_LAKE_SIZE = 6.0; + public static final double WORLD_LAND_SIZE = 63.03; + public static final double WORLD_LAKE_SIZE = 9.3; public static final double WORLD_WET_SEA_PERCENT = 0.8; public static final double WORLD_TEMPERATURE_SIZE = 41.0; public static final double WORLD_TEMPERATURE_ZONE_SIZE = 2.99; From 2e84f2e4603e82dae91dbb0d8153d3007d206c29 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 08:36:49 +0300 Subject: [PATCH 24/37] NBT dependency --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 74a7f0e..f9a8ef5 100644 --- a/build.gradle +++ b/build.gradle @@ -33,6 +33,7 @@ subprojects { /* Components */ compile (group: 'org.projectlombok', name: 'lombok', version: '1.16.16') + compile 'com.flowpowered:flow-nbt:1.0.1-SNAPSHOT' //Named Binary Tags } task copyDep(type: Copy) { From 93edc88114ae7e7467a83b17a82851b06c274ffa Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 08:37:04 +0300 Subject: [PATCH 25/37] ReadWriteLock --- .../java/mc/world/generated_world/chunk/ChunkProxy.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 d135759..292f886 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 @@ -4,9 +4,13 @@ import mc.core.block.Block; import mc.core.world.Biome; import mc.core.world.Chunk; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + public class ChunkProxy implements Chunk { private final Chunk chunk; - private volatile long lastUsage = System.currentTimeMillis(); + private volatile transient long lastUsage = System.currentTimeMillis(); + private final transient ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public ChunkProxy(Chunk chunk) { this.chunk = chunk; @@ -18,7 +22,7 @@ public class ChunkProxy implements Chunk { } } - private void use () { + private final void use () { synchronized (chunk) { lastUsage = System.currentTimeMillis(); } From 827c13f9b851784cdfbf482e87e398b1cd80ea69 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 08:38:00 +0300 Subject: [PATCH 26/37] More generation stages --- .../java/mc/world/generated_world/SeedBasedWorldGenerator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java index 450d43d..50dfec9 100644 --- a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java @@ -342,6 +342,8 @@ public class SeedBasedWorldGenerator implements WorldGenerator { /* TODO log.debug("Creating rivers..."); log.debug("Creating caves..."); + log.debug("Generating ores..."); + log.debug("Creating structures..."); log.debug("Planting trees..."); log.debug("Spawning animals..."); */ From ad4a0889494d20426b1d588da672d10cc1cda8f8 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 09:15:59 +0300 Subject: [PATCH 27/37] Interfaces --- .../java/mc/core/block/AbstractBlock.java | 21 ++++++++++++++++++ core/src/main/java/mc/core/block/Block.java | 22 +++++++------------ core/src/main/java/mc/core/nbt/Taggable.java | 11 ++++++++++ core/src/main/java/mc/core/world/Chunk.java | 4 +++- core/src/main/java/mc/core/world/Region.java | 3 ++- core/src/main/java/mc/core/world/World.java | 4 +++- 6 files changed, 48 insertions(+), 17 deletions(-) create mode 100644 core/src/main/java/mc/core/nbt/Taggable.java diff --git a/core/src/main/java/mc/core/block/AbstractBlock.java b/core/src/main/java/mc/core/block/AbstractBlock.java index 11f3f7f..126e605 100644 --- a/core/src/main/java/mc/core/block/AbstractBlock.java +++ b/core/src/main/java/mc/core/block/AbstractBlock.java @@ -1,9 +1,14 @@ package mc.core.block; +import com.flowpowered.nbt.Tag; import lombok.Getter; import lombok.Setter; import mc.core.Location; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + public abstract class AbstractBlock implements Block { @Getter@Setter private Location location; @@ -11,6 +16,7 @@ public abstract class AbstractBlock implements Block { private int meta; @Getter private final BlockType blockType; + private final Map> nbtTagsMap = new HashMap<>(); protected AbstractBlock(BlockType type) { this.blockType = type; @@ -25,4 +31,19 @@ public abstract class AbstractBlock implements Block { public int getId() { return blockType.getId(); } + + @Override + public Tag getTag(String name) { + return nbtTagsMap.get(name); + } + + @Override + public void setTag(Tag tag) { + nbtTagsMap.put(tag.getName(), tag); + } + + @Override + public Stream> tagStream() { + return nbtTagsMap.values().stream(); + } } diff --git a/core/src/main/java/mc/core/block/Block.java b/core/src/main/java/mc/core/block/Block.java index 81d662a..fd67fa8 100644 --- a/core/src/main/java/mc/core/block/Block.java +++ b/core/src/main/java/mc/core/block/Block.java @@ -1,6 +1,10 @@ package mc.core.block; +import com.flowpowered.nbt.Tag; import mc.core.Location; +import mc.core.nbt.Taggable; + +import java.io.Serializable; /** * Serialization block info @@ -23,23 +27,13 @@ import mc.core.Location; * */ -public interface Block { +public interface Block extends Taggable, Serializable{ static Block airBlock (int x, int y, int z) { - return new Block() { + return new AbstractBlock(BlockType.AIR) { @Override - public int getId() { - return 0; - } - - @Override - public int getMeta() { - return 0; - } - - @Override - public BlockType getBlockType() { - return BlockType.AIR; + public Tag getTag(String name) { + return null; } @Override diff --git a/core/src/main/java/mc/core/nbt/Taggable.java b/core/src/main/java/mc/core/nbt/Taggable.java new file mode 100644 index 0000000..0e3a46c --- /dev/null +++ b/core/src/main/java/mc/core/nbt/Taggable.java @@ -0,0 +1,11 @@ +package mc.core.nbt; + +import com.flowpowered.nbt.Tag; + +import java.util.stream.Stream; + +public interface Taggable { + Tag getTag(String name); + void setTag(Tag tag); + Stream> tagStream(); +} diff --git a/core/src/main/java/mc/core/world/Chunk.java b/core/src/main/java/mc/core/world/Chunk.java index 95b49b9..a8c09cf 100644 --- a/core/src/main/java/mc/core/world/Chunk.java +++ b/core/src/main/java/mc/core/world/Chunk.java @@ -6,6 +6,8 @@ package mc.core.world; import mc.core.block.Block; +import java.io.Serializable; + /** * Serialization chunk info * @@ -24,7 +26,7 @@ import mc.core.block.Block; * */ /* 16x16x16 */ -public interface Chunk { +public interface Chunk 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 2d72766..ebf921e 100644 --- a/core/src/main/java/mc/core/world/Region.java +++ b/core/src/main/java/mc/core/world/Region.java @@ -3,6 +3,7 @@ package mc.core.world; import mc.core.serialization.Serializer; import java.io.IOException; +import java.io.Serializable; /** * Simple world generation unit @@ -18,7 +19,7 @@ import java.io.IOException; * Total: 2097152 bits (256 Kb) * */ -public interface Region { +public interface Region extends Serializable{ Chunk getChunkAt(int x, int y, int z); void setChunk(int x, int y, int z, Chunk chunk); diff --git a/core/src/main/java/mc/core/world/World.java b/core/src/main/java/mc/core/world/World.java index aafdc2e..86184e4 100644 --- a/core/src/main/java/mc/core/world/World.java +++ b/core/src/main/java/mc/core/world/World.java @@ -5,7 +5,9 @@ package mc.core.world; import mc.core.Location; +import mc.core.nbt.Taggable; +import java.io.Serializable; import java.util.UUID; /** @@ -39,7 +41,7 @@ import java.util.UUID; * --> []player_uuid.dat */ -public interface World { +public interface World extends Taggable, Serializable{ UUID getWorldId(); IWorldType getWorldType(); From f55c9bfb3390b1a308aaa065949ba5f1d4fc904e Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 09:22:38 +0300 Subject: [PATCH 28/37] Serializers refactoring --- build.gradle | 2 +- .../mc/core/serialization/BlockDeserializer.java | 6 ------ .../mc/core/serialization/BlockSerializer.java | 6 ------ .../mc/core/serialization/ChunkDeserializer.java | 6 ------ .../mc/core/serialization/ChunkSerializer.java | 6 ------ .../BlockSerializerDeserializer.java | 6 +++--- .../ChunkSerializerDeserializer.java | 15 +++++++-------- .../generated_world/InMemoryCacheChunkLoader.java | 9 ++------- 8 files changed, 13 insertions(+), 43 deletions(-) delete mode 100644 core/src/main/java/mc/core/serialization/BlockDeserializer.java delete mode 100644 core/src/main/java/mc/core/serialization/BlockSerializer.java delete mode 100644 core/src/main/java/mc/core/serialization/ChunkDeserializer.java delete mode 100644 core/src/main/java/mc/core/serialization/ChunkSerializer.java diff --git a/build.gradle b/build.gradle index f9a8ef5..13d4052 100644 --- a/build.gradle +++ b/build.gradle @@ -33,7 +33,7 @@ subprojects { /* Components */ compile (group: 'org.projectlombok', name: 'lombok', version: '1.16.16') - compile 'com.flowpowered:flow-nbt:1.0.1-SNAPSHOT' //Named Binary Tags + compile 'com.flowpowered:flow-nbt:1.0.0' //Named Binary Tags } task copyDep(type: Copy) { diff --git a/core/src/main/java/mc/core/serialization/BlockDeserializer.java b/core/src/main/java/mc/core/serialization/BlockDeserializer.java deleted file mode 100644 index dfdbc89..0000000 --- a/core/src/main/java/mc/core/serialization/BlockDeserializer.java +++ /dev/null @@ -1,6 +0,0 @@ -package mc.core.serialization; - -import mc.core.block.Block; - -public interface BlockDeserializer extends Deserializer { -} diff --git a/core/src/main/java/mc/core/serialization/BlockSerializer.java b/core/src/main/java/mc/core/serialization/BlockSerializer.java deleted file mode 100644 index 1e5730d..0000000 --- a/core/src/main/java/mc/core/serialization/BlockSerializer.java +++ /dev/null @@ -1,6 +0,0 @@ -package mc.core.serialization; - -import mc.core.block.Block; - -public interface BlockSerializer extends Serializer { -} diff --git a/core/src/main/java/mc/core/serialization/ChunkDeserializer.java b/core/src/main/java/mc/core/serialization/ChunkDeserializer.java deleted file mode 100644 index edff066..0000000 --- a/core/src/main/java/mc/core/serialization/ChunkDeserializer.java +++ /dev/null @@ -1,6 +0,0 @@ -package mc.core.serialization; - -import mc.core.world.Chunk; - -public interface ChunkDeserializer extends Deserializer{ -} diff --git a/core/src/main/java/mc/core/serialization/ChunkSerializer.java b/core/src/main/java/mc/core/serialization/ChunkSerializer.java deleted file mode 100644 index 3614951..0000000 --- a/core/src/main/java/mc/core/serialization/ChunkSerializer.java +++ /dev/null @@ -1,6 +0,0 @@ -package mc.core.serialization; - -import mc.core.world.Chunk; - -public interface ChunkSerializer extends Serializer{ -} diff --git a/generated_world/src/main/java/mc/world/generated_world/BlockSerializerDeserializer.java b/generated_world/src/main/java/mc/world/generated_world/BlockSerializerDeserializer.java index 718a420..c8fe07c 100644 --- a/generated_world/src/main/java/mc/world/generated_world/BlockSerializerDeserializer.java +++ b/generated_world/src/main/java/mc/world/generated_world/BlockSerializerDeserializer.java @@ -3,14 +3,14 @@ package mc.world.generated_world; import mc.core.block.Block; import mc.core.block.BlockFactory; import mc.core.block.BlockType; -import mc.core.serialization.BlockDeserializer; -import mc.core.serialization.BlockSerializer; +import mc.core.serialization.Deserializer; +import mc.core.serialization.Serializer; import mc.core.world.Chunk; /** * Prototype */ -public class BlockSerializerDeserializer implements BlockSerializer, BlockDeserializer { +public class BlockSerializerDeserializer implements Serializer, Deserializer { private BlockFactory blockFactory; private Chunk chunk; diff --git a/generated_world/src/main/java/mc/world/generated_world/ChunkSerializerDeserializer.java b/generated_world/src/main/java/mc/world/generated_world/ChunkSerializerDeserializer.java index 1f2df79..a31e25d 100644 --- a/generated_world/src/main/java/mc/world/generated_world/ChunkSerializerDeserializer.java +++ b/generated_world/src/main/java/mc/world/generated_world/ChunkSerializerDeserializer.java @@ -1,16 +1,15 @@ package mc.world.generated_world; +import mc.core.block.Block; import mc.core.block.BlockFactory; -import mc.core.serialization.BlockDeserializer; -import mc.core.serialization.BlockSerializer; -import mc.core.serialization.ChunkSerializer; -import mc.core.serialization.ChunkDeserializer; +import mc.core.serialization.Deserializer; +import mc.core.serialization.Serializer; import mc.core.world.Chunk; -public class ChunkSerializerDeserializer implements ChunkSerializer, ChunkDeserializer { +public class ChunkSerializerDeserializer implements Serializer, Deserializer { - private BlockSerializer blockSerializer; - private BlockDeserializer blockDeserializer; + private Serializer blockSerializer; + private Deserializer blockDeserializer; @Override public Chunk deserialize(byte[] bytes) { @@ -19,7 +18,7 @@ public class ChunkSerializerDeserializer implements ChunkSerializer, ChunkDeseri @Override public byte[] serialize(Chunk chunk) { - BlockSerializer blockSerializer = new BlockSerializerDeserializer(new BlockFactory(), chunk); + Serializer blockSerializer = new BlockSerializerDeserializer(new BlockFactory(), chunk); int blocks = chunk.getModifiedBlocks().length; byte[] bytes = new byte[6 + 3 * blocks]; diff --git a/generated_world/src/main/java/mc/world/generated_world/InMemoryCacheChunkLoader.java b/generated_world/src/main/java/mc/world/generated_world/InMemoryCacheChunkLoader.java index 1cef35d..be00010 100644 --- a/generated_world/src/main/java/mc/world/generated_world/InMemoryCacheChunkLoader.java +++ b/generated_world/src/main/java/mc/world/generated_world/InMemoryCacheChunkLoader.java @@ -1,23 +1,18 @@ package mc.world.generated_world; import lombok.extern.slf4j.Slf4j; -import mc.core.serialization.ChunkDeserializer; -import mc.core.serialization.ChunkSerializer; import mc.core.serialization.Deserializer; import mc.core.serialization.Serializer; import mc.core.world.*; -import mc.world.generated_world.region.RegionImpl; import org.springframework.beans.factory.annotation.Autowired; import java.io.File; import java.io.FileOutputStream; -import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.text.MessageFormat; import java.util.Optional; -import java.util.UUID; import static mc.world.generated_world.WorldConstants.*; @@ -30,9 +25,9 @@ public class InMemoryCacheChunkLoader implements ChunkLoader { private WorldGenerator worldGenerator; @Autowired - private ChunkDeserializer chunkDeserializer; + private Deserializer chunkDeserializer; @Autowired - private ChunkSerializer chunkSerializer; + private Serializer chunkSerializer; @Autowired private Serializer regionSerializer; @Autowired From ef383b6e134b94572892b80f7e637c457e627dcd Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 09:25:47 +0300 Subject: [PATCH 29/37] Interfaces implementations --- .../main/java/mc/world/flat/FlatWorld.java | 17 ++++++++++++++++ .../mc/world/generated_world/CubicWorld.java | 20 +++++++++++++++++++ 2 files changed, 37 insertions(+) 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 418fbab..0671c31 100644 --- a/flat_world/src/main/java/mc/world/flat/FlatWorld.java +++ b/flat_world/src/main/java/mc/world/flat/FlatWorld.java @@ -4,12 +4,14 @@ */ package mc.world.flat; +import com.flowpowered.nbt.Tag; import lombok.Getter; import lombok.Setter; import mc.core.Location; import mc.core.world.*; import java.util.UUID; +import java.util.stream.Stream; public class FlatWorld implements World { @@ -50,4 +52,19 @@ public class FlatWorld implements World { public int getSeed() { return 0; } + + @Override + public Tag getTag(String name) { + throw new UnsupportedOperationException(); + } + + @Override + public void setTag(Tag tag) { + throw new UnsupportedOperationException(); + } + + @Override + public Stream> tagStream() { + throw new UnsupportedOperationException(); + } } diff --git a/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java b/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java index 1f21785..2d785aa 100644 --- a/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java +++ b/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java @@ -1,10 +1,14 @@ package mc.world.generated_world; +import com.flowpowered.nbt.Tag; import lombok.Getter; import mc.core.Location; import mc.core.world.*; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; +import java.util.stream.Stream; public class CubicWorld implements World { @Getter @@ -13,6 +17,7 @@ public class CubicWorld implements World { private volatile Location spawnLocation; private final transient Object spawnLocationLock = new Object(); private final transient ChunkLoader chunkLoader; + private final Map> nbtTagMap = new HashMap<>(); public CubicWorld(UUID worldId, int seed) { this.worldId = worldId; @@ -86,4 +91,19 @@ public class CubicWorld implements World { public int getSeed() { return seed; } + + @Override + public Tag getTag(String name) { + return nbtTagMap.get(name); + } + + @Override + public void setTag(Tag tag) { + nbtTagMap.put(tag.getName(), tag); + } + + @Override + public Stream> tagStream() { + return nbtTagMap.values().stream(); + } } From 7115da905bea92a1350589cba2fece4f723ae87b Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 09:43:05 +0300 Subject: [PATCH 30/37] World generator refactoring --- .../main/java/mc/world/generated_world/WorldConstants.java | 1 - .../{ => chunk}/InMemoryCacheChunkLoader.java | 2 +- .../{ => generator}/SeedBasedWorldGenerator.java | 7 ++++--- .../{ => generator}/SeedRandomGenerator.java | 2 +- .../java/mc/world/generated_world/region/RegionImpl.java | 2 +- .../{ => serialization}/BlockSerializerDeserializer.java | 2 +- .../{ => serialization}/ChunkSerializerDeserializer.java | 2 +- .../{ => serialization}/RegionSerializerDeserializer.java | 2 +- .../mc/world/generated_world/{ => world}/CubicWorld.java | 3 ++- .../world/generated_world/{word => world}/Temperature.java | 2 +- .../mc/world/generated_world/{word => world}/Wetness.java | 2 +- .../mc/world/generated_world/SeedRandomGeneratorTest.java | 1 + 12 files changed, 15 insertions(+), 13 deletions(-) rename generated_world/src/main/java/mc/world/generated_world/{ => chunk}/InMemoryCacheChunkLoader.java (99%) rename generated_world/src/main/java/mc/world/generated_world/{ => generator}/SeedBasedWorldGenerator.java (99%) rename generated_world/src/main/java/mc/world/generated_world/{ => generator}/SeedRandomGenerator.java (93%) rename generated_world/src/main/java/mc/world/generated_world/{ => serialization}/BlockSerializerDeserializer.java (96%) rename generated_world/src/main/java/mc/world/generated_world/{ => serialization}/ChunkSerializerDeserializer.java (96%) rename generated_world/src/main/java/mc/world/generated_world/{ => serialization}/RegionSerializerDeserializer.java (89%) rename generated_world/src/main/java/mc/world/generated_world/{ => world}/CubicWorld.java (95%) rename generated_world/src/main/java/mc/world/generated_world/{word => world}/Temperature.java (66%) rename generated_world/src/main/java/mc/world/generated_world/{word => world}/Wetness.java (69%) diff --git a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java index 5a59209..728a825 100644 --- a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java +++ b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java @@ -24,7 +24,6 @@ public final class WorldConstants { public static final double WORLD_TEMPERATURE_ZONE_SIZE = 2.99; public static final double WORLD_TEMPERATURE_HEIGHT_GRAD_SIZE = 1.1; - public static final int LANDFILL_GRASS_SURFACE_THIN = 5; public static final double WORLD_ROUGHNESS = 0.35; diff --git a/generated_world/src/main/java/mc/world/generated_world/InMemoryCacheChunkLoader.java b/generated_world/src/main/java/mc/world/generated_world/chunk/InMemoryCacheChunkLoader.java similarity index 99% rename from generated_world/src/main/java/mc/world/generated_world/InMemoryCacheChunkLoader.java rename to generated_world/src/main/java/mc/world/generated_world/chunk/InMemoryCacheChunkLoader.java index be00010..dc36e0e 100644 --- a/generated_world/src/main/java/mc/world/generated_world/InMemoryCacheChunkLoader.java +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/InMemoryCacheChunkLoader.java @@ -1,4 +1,4 @@ -package mc.world.generated_world; +package mc.world.generated_world.chunk; import lombok.extern.slf4j.Slf4j; import mc.core.serialization.Deserializer; diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java similarity index 99% rename from generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java rename to generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java index 50dfec9..2a7ab64 100644 --- a/generated_world/src/main/java/mc/world/generated_world/SeedBasedWorldGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java @@ -1,4 +1,4 @@ -package mc.world.generated_world; +package mc.world.generated_world.generator; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -6,8 +6,9 @@ import mc.core.block.BlockFactory; import mc.core.block.BlockType; import mc.core.world.*; import mc.world.generated_world.region.RegionImpl; -import mc.world.generated_world.word.Temperature; -import mc.world.generated_world.word.Wetness; +import mc.world.generated_world.world.CubicWorld; +import mc.world.generated_world.world.Temperature; +import mc.world.generated_world.world.Wetness; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; diff --git a/generated_world/src/main/java/mc/world/generated_world/SeedRandomGenerator.java b/generated_world/src/main/java/mc/world/generated_world/generator/SeedRandomGenerator.java similarity index 93% rename from generated_world/src/main/java/mc/world/generated_world/SeedRandomGenerator.java rename to generated_world/src/main/java/mc/world/generated_world/generator/SeedRandomGenerator.java index b4af1ab..c2ff8e7 100644 --- a/generated_world/src/main/java/mc/world/generated_world/SeedRandomGenerator.java +++ b/generated_world/src/main/java/mc/world/generated_world/generator/SeedRandomGenerator.java @@ -1,4 +1,4 @@ -package mc.world.generated_world; +package mc.world.generated_world.generator; public final class SeedRandomGenerator { 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 8d73364..0750ecd 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 @@ -5,7 +5,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import mc.core.serialization.Serializer; import mc.core.world.*; -import mc.world.generated_world.InMemoryCacheChunkLoader; +import mc.world.generated_world.chunk.InMemoryCacheChunkLoader; import mc.world.generated_world.chunk.ChunkImpl; import mc.world.generated_world.chunk.ChunkProxy; import org.springframework.beans.factory.annotation.Autowired; diff --git a/generated_world/src/main/java/mc/world/generated_world/BlockSerializerDeserializer.java b/generated_world/src/main/java/mc/world/generated_world/serialization/BlockSerializerDeserializer.java similarity index 96% rename from generated_world/src/main/java/mc/world/generated_world/BlockSerializerDeserializer.java rename to generated_world/src/main/java/mc/world/generated_world/serialization/BlockSerializerDeserializer.java index c8fe07c..a176afe 100644 --- a/generated_world/src/main/java/mc/world/generated_world/BlockSerializerDeserializer.java +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/BlockSerializerDeserializer.java @@ -1,4 +1,4 @@ -package mc.world.generated_world; +package mc.world.generated_world.serialization; import mc.core.block.Block; import mc.core.block.BlockFactory; diff --git a/generated_world/src/main/java/mc/world/generated_world/ChunkSerializerDeserializer.java b/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializerDeserializer.java similarity index 96% rename from generated_world/src/main/java/mc/world/generated_world/ChunkSerializerDeserializer.java rename to generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializerDeserializer.java index a31e25d..b0b3feb 100644 --- a/generated_world/src/main/java/mc/world/generated_world/ChunkSerializerDeserializer.java +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializerDeserializer.java @@ -1,4 +1,4 @@ -package mc.world.generated_world; +package mc.world.generated_world.serialization; import mc.core.block.Block; import mc.core.block.BlockFactory; diff --git a/generated_world/src/main/java/mc/world/generated_world/RegionSerializerDeserializer.java b/generated_world/src/main/java/mc/world/generated_world/serialization/RegionSerializerDeserializer.java similarity index 89% rename from generated_world/src/main/java/mc/world/generated_world/RegionSerializerDeserializer.java rename to generated_world/src/main/java/mc/world/generated_world/serialization/RegionSerializerDeserializer.java index f5a1218..11e8a53 100644 --- a/generated_world/src/main/java/mc/world/generated_world/RegionSerializerDeserializer.java +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/RegionSerializerDeserializer.java @@ -1,4 +1,4 @@ -package mc.world.generated_world; +package mc.world.generated_world.serialization; import mc.core.serialization.Deserializer; import mc.core.serialization.Serializer; diff --git a/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java b/generated_world/src/main/java/mc/world/generated_world/world/CubicWorld.java similarity index 95% rename from generated_world/src/main/java/mc/world/generated_world/CubicWorld.java rename to generated_world/src/main/java/mc/world/generated_world/world/CubicWorld.java index 2d785aa..8442528 100644 --- a/generated_world/src/main/java/mc/world/generated_world/CubicWorld.java +++ b/generated_world/src/main/java/mc/world/generated_world/world/CubicWorld.java @@ -1,9 +1,10 @@ -package mc.world.generated_world; +package mc.world.generated_world.world; import com.flowpowered.nbt.Tag; import lombok.Getter; import mc.core.Location; import mc.core.world.*; +import mc.world.generated_world.chunk.InMemoryCacheChunkLoader; import java.util.HashMap; import java.util.Map; diff --git a/generated_world/src/main/java/mc/world/generated_world/word/Temperature.java b/generated_world/src/main/java/mc/world/generated_world/world/Temperature.java similarity index 66% rename from generated_world/src/main/java/mc/world/generated_world/word/Temperature.java rename to generated_world/src/main/java/mc/world/generated_world/world/Temperature.java index 1c2cb80..52b48c3 100644 --- a/generated_world/src/main/java/mc/world/generated_world/word/Temperature.java +++ b/generated_world/src/main/java/mc/world/generated_world/world/Temperature.java @@ -1,4 +1,4 @@ -package mc.world.generated_world.word; +package mc.world.generated_world.world; public enum Temperature { FROST, diff --git a/generated_world/src/main/java/mc/world/generated_world/word/Wetness.java b/generated_world/src/main/java/mc/world/generated_world/world/Wetness.java similarity index 69% rename from generated_world/src/main/java/mc/world/generated_world/word/Wetness.java rename to generated_world/src/main/java/mc/world/generated_world/world/Wetness.java index 79a872b..a1ed1ce 100644 --- a/generated_world/src/main/java/mc/world/generated_world/word/Wetness.java +++ b/generated_world/src/main/java/mc/world/generated_world/world/Wetness.java @@ -1,4 +1,4 @@ -package mc.world.generated_world.word; +package mc.world.generated_world.world; public enum Wetness { DRIEST, diff --git a/generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java b/generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java index 4b4b2a7..a99a251 100644 --- a/generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java +++ b/generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java @@ -1,5 +1,6 @@ package mc.world.generated_world; +import mc.world.generated_world.generator.SeedRandomGenerator; import org.junit.Test; import javax.imageio.ImageIO; From aa44d70897e4b6f4322b298721133d0fd04c507d Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 10:34:55 +0300 Subject: [PATCH 31/37] Serialization/Deserialization of world --- .../mc/core/serialization/IChunkReader.java | 10 ++++ .../serialization/IRegionReaderWriter.java | 12 +++++ core/src/main/java/mc/core/world/Biome.java | 4 ++ core/src/main/java/mc/core/world/Chunk.java | 8 +-- core/src/main/java/mc/core/world/Region.java | 3 +- .../chunk/InMemoryCacheChunkLoader.java | 38 +++++-------- .../generator/SeedBasedWorldGenerator.java | 2 +- .../generated_world/region/RegionImpl.java | 9 ++-- .../serialization/ChunkReader.java | 49 +++++++++++++++++ .../serialization/ChunkSerializer.java | 26 +++++++++ .../ChunkSerializerDeserializer.java | 40 -------------- .../serialization/RegionReaderWriter.java | 53 +++++++++++++++++++ .../RegionSerializerDeserializer.java | 17 ------ 13 files changed, 174 insertions(+), 97 deletions(-) create mode 100644 core/src/main/java/mc/core/serialization/IChunkReader.java create mode 100644 core/src/main/java/mc/core/serialization/IRegionReaderWriter.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/serialization/ChunkReader.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializer.java delete mode 100644 generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializerDeserializer.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/serialization/RegionReaderWriter.java delete mode 100644 generated_world/src/main/java/mc/world/generated_world/serialization/RegionSerializerDeserializer.java diff --git a/core/src/main/java/mc/core/serialization/IChunkReader.java b/core/src/main/java/mc/core/serialization/IChunkReader.java new file mode 100644 index 0000000..0ecf126 --- /dev/null +++ b/core/src/main/java/mc/core/serialization/IChunkReader.java @@ -0,0 +1,10 @@ +package mc.core.serialization; + +import mc.core.world.Chunk; +import mc.core.world.Region; + +import java.io.IOException; + +public interface IChunkReader { + Chunk read (Region region, int x, int y, int z) throws IOException; +} diff --git a/core/src/main/java/mc/core/serialization/IRegionReaderWriter.java b/core/src/main/java/mc/core/serialization/IRegionReaderWriter.java new file mode 100644 index 0000000..76a7023 --- /dev/null +++ b/core/src/main/java/mc/core/serialization/IRegionReaderWriter.java @@ -0,0 +1,12 @@ +package mc.core.serialization; + +import mc.core.world.Region; +import mc.core.world.World; + +import java.io.IOException; + +public interface IRegionReaderWriter { + + Region read (int x, int z, World world) throws IOException; + void write (Region region) throws IOException; +} diff --git a/core/src/main/java/mc/core/world/Biome.java b/core/src/main/java/mc/core/world/Biome.java index a28aa47..5a60047 100644 --- a/core/src/main/java/mc/core/world/Biome.java +++ b/core/src/main/java/mc/core/world/Biome.java @@ -43,4 +43,8 @@ public enum Biome { this.name = name; this.color = color; } + + public static Biome getById(int id) { + return Biome.values()[id]; + } } diff --git a/core/src/main/java/mc/core/world/Chunk.java b/core/src/main/java/mc/core/world/Chunk.java index a8c09cf..1300d42 100644 --- a/core/src/main/java/mc/core/world/Chunk.java +++ b/core/src/main/java/mc/core/world/Chunk.java @@ -14,15 +14,11 @@ import java.io.Serializable; * +-------------+----------------+------------+ * | param | range | bits | * +-------------+----------------+------------+ - * | | | 3 | - * +-------------+----------------+------------+ - * | block_count | 0:4096 | 13 | - * +-------------+----------------+------------+ * | blocks | array | 24*count | * +-------------+----------------+------------+ * - * Total: 16 bits header (2 bytes) + 24 * block_count bits (3 * block_count bytes) - * Max size: 12290 bytes (~12 Kb per chunk) + * Total: 24 * block_count bits (3 * block_count bytes) + * Max size: 12288 bytes (~12 Kb per chunk) * */ /* 16x16x16 */ diff --git a/core/src/main/java/mc/core/world/Region.java b/core/src/main/java/mc/core/world/Region.java index ebf921e..6791088 100644 --- a/core/src/main/java/mc/core/world/Region.java +++ b/core/src/main/java/mc/core/world/Region.java @@ -1,5 +1,6 @@ package mc.core.world; +import mc.core.serialization.IRegionReaderWriter; import mc.core.serialization.Serializer; import java.io.IOException; @@ -29,5 +30,5 @@ public interface Region extends Serializable{ Biome getBiomeAt (int x, int z); void setBiome (int x, int z, Biome biome); - void save(Serializer chunkSerializer, Serializer regionSerializer) throws IOException; + void save(Serializer chunkSerializer, IRegionReaderWriter regionReaderWritter) throws IOException; } 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 dc36e0e..2724497 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 @@ -1,16 +1,15 @@ package mc.world.generated_world.chunk; import lombok.extern.slf4j.Slf4j; -import mc.core.serialization.Deserializer; import mc.core.serialization.Serializer; import mc.core.world.*; +import mc.world.generated_world.serialization.ChunkReader; +import mc.world.generated_world.serialization.RegionReaderWriter; import org.springframework.beans.factory.annotation.Autowired; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; import java.text.MessageFormat; import java.util.Optional; @@ -23,15 +22,12 @@ public class InMemoryCacheChunkLoader implements ChunkLoader { private File worldFolder; @Autowired private WorldGenerator worldGenerator; - @Autowired - private Deserializer chunkDeserializer; + private ChunkReader chunkReader; @Autowired private Serializer chunkSerializer; @Autowired - private Serializer regionSerializer; - @Autowired - private Deserializer regionDeserializer; + private RegionReaderWriter regionReaderWritter; public InMemoryCacheChunkLoader(World world) { this.world = world; @@ -54,8 +50,8 @@ public class InMemoryCacheChunkLoader implements ChunkLoader { return Optional.empty(); } else { try { - byte[] bytes = Files.readAllBytes(Paths.get(file.toURI())); - return Optional.of(chunkDeserializer.deserialize(bytes)); + Chunk chunk = chunkReader.read(world.getRegion(x / WORLD_CHUNK_SIZE, z / WORLD_CHUNK_SIZE), x, y, z); + return Optional.of(chunk); } catch (IOException e) { log.error("Error occurred while reading chunk file: " + file.getAbsolutePath(), e); return Optional.empty(); @@ -65,8 +61,8 @@ public class InMemoryCacheChunkLoader implements ChunkLoader { @Override public Chunk loadOrGenerateChunk(int x, int y, int z) { - int regX = x / WORLD_REGION_SIZE; - int regZ = z / WORLD_REGION_SIZE; + 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; @@ -74,32 +70,22 @@ public class InMemoryCacheChunkLoader implements ChunkLoader { log.debug("Region [{}, {}] not found. Generating!", regX, regZ); regionFile.mkdirs(); region = worldGenerator.generateRegion(regX, regZ, world); - File biomeMapFile = new File(regionFile, BIOME_FILE_NAME_TEMPLATE); - byte[] biomeMapBytes = regionSerializer.serialize(region); - try (FileOutputStream writer = new FileOutputStream(biomeMapFile)) { - writer.write(biomeMapBytes); + try { + regionReaderWritter.write(region); } catch (IOException e) { log.error("Error occurred while writting biome file", e); } saveRegion(region); chunk = region.getChunkAt(x % WORLD_CHUNK_SIZE, y % WORLD_CHUNK_SIZE, z % WORLD_CHUNK_SIZE); } else { - File chunkFile = new File(regionFile, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x % WORLD_CHUNK_SIZE, y % WORLD_CHUNK_SIZE, z % WORLD_CHUNK_SIZE)); try { - byte[] chunkBytes = Files.readAllBytes(Paths.get(chunkFile.toURI())); - byte[] regionBytes = Files.readAllBytes(Paths.get(new File(regionFile, BIOME_FILE_NAME_TEMPLATE).toURI())); - region = regionDeserializer.deserialize(regionBytes); - chunk = chunkDeserializer.deserialize(chunkBytes); + region = regionReaderWritter.read(regX, regZ, world); + chunk = chunkReader.read(region, x, y, z); } catch (IOException e) { log.error("Error occurred while reading chunk file", e); return null; } } - for (int tx = 0; tx < WORLD_CHUNK_SIZE; tx++) { - for (int tz = 0; tz < WORLD_CHUNK_SIZE; tz ++) { - chunk.setBiome(tx, tz, region.getBiomeAt(chunk.getX() * WORLD_CHUNK_SIZE + x, chunk.getZ() * WORLD_CHUNK_SIZE + z)); - } - } return chunk; } 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 2a7ab64..3ede02c 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 @@ -24,7 +24,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { WorldGenerator worldGenerator = new SeedBasedWorldGenerator(); World world = new CubicWorld(UUID.fromString("00000000-0000-0000-C000-000000000046"), 2626949); Region region = worldGenerator.generateRegion(0, 0, world); - //region.save(new ChunkSerializerDeserializer(), new RegionSerializerDeserializer()); + //region.save(new ChunkSerializer(), new RegionSerializerDeserializer()); worldGenerator.generateRegion(1, 0, world); worldGenerator.generateRegion(-1, 0, world); worldGenerator.generateRegion(0, 1, world); 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 0750ecd..8637f47 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.serialization.IRegionReaderWriter; import mc.core.serialization.Serializer; import mc.core.world.*; import mc.world.generated_world.chunk.InMemoryCacheChunkLoader; @@ -72,18 +73,14 @@ public class RegionImpl implements Region{ } @Override - public void save(Serializer chunkSerializer, Serializer regionSerializer) throws IOException { + 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 regionFile = new File(worldFile, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, this.getX(), this.getZ())); if (!regionFile.exists()) { regionFile.mkdirs(); } - File biomeMapFile = new File(regionFile, BIOME_FILE_NAME_TEMPLATE); - byte[] biomeBytes = regionSerializer.serialize(this); - try (FileOutputStream fileOutputStream = new FileOutputStream(biomeMapFile)){ - fileOutputStream.write(biomeBytes); - } + regionReaderWriter.write(this); 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++) { 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 new file mode 100644 index 0000000..8b77dde --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkReader.java @@ -0,0 +1,49 @@ +package mc.world.generated_world.serialization; + +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.Region; +import mc.world.generated_world.chunk.ChunkImpl; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.text.MessageFormat; + +import static mc.world.generated_world.WorldConstants.*; + +public class ChunkReader implements IChunkReader{ + private final File worldFolder; + @Autowired + private Deserializer blockDeserializer; + + public ChunkReader (File worldFolder) { + this.worldFolder = worldFolder; + } + + @Override + public Chunk 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); + for (int i = 0; i < blocks; i ++) { + byte[] blockBytes = new byte[3]; + blockBytes[0] = chunkBytes[3 * i]; + blockBytes[1] = chunkBytes[1 + 3 * i]; + blockBytes[2] = chunkBytes[2 + 3 * i]; + Block block = blockDeserializer.deserialize(blockBytes); + Location blockLocation = block.getLocation(); + chunk.setBlock(blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ(), block); + } + return chunk; + } +} 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 new file mode 100644 index 0000000..b854c64 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializer.java @@ -0,0 +1,26 @@ +package mc.world.generated_world.serialization; + +import mc.core.block.Block; +import mc.core.serialization.Serializer; +import mc.core.world.Chunk; +import org.springframework.beans.factory.annotation.Autowired; + +public class ChunkSerializer implements Serializer { + + @Autowired + private Serializer blockSerializer; + + @Override + public byte[] serialize(Chunk chunk) { + int blocks = chunk.getModifiedBlocks().length; + byte[] bytes = new byte[3 * blocks]; + + for (int i = 0; i < blocks; i ++) { + byte[] blockSerialized = blockSerializer.serialize(chunk.getModifiedBlocks()[i]); + for (int j = 0; j < 3; j ++) { + bytes[i * 3 + j] = blockSerialized[j]; + } + } + return bytes; + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializerDeserializer.java b/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializerDeserializer.java deleted file mode 100644 index b0b3feb..0000000 --- a/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializerDeserializer.java +++ /dev/null @@ -1,40 +0,0 @@ -package mc.world.generated_world.serialization; - -import mc.core.block.Block; -import mc.core.block.BlockFactory; -import mc.core.serialization.Deserializer; -import mc.core.serialization.Serializer; -import mc.core.world.Chunk; - -public class ChunkSerializerDeserializer implements Serializer, Deserializer { - - private Serializer blockSerializer; - private Deserializer blockDeserializer; - - @Override - public Chunk deserialize(byte[] bytes) { - return null; - } - - @Override - public byte[] serialize(Chunk chunk) { - Serializer blockSerializer = new BlockSerializerDeserializer(new BlockFactory(), chunk); - int blocks = chunk.getModifiedBlocks().length; - byte[] bytes = new byte[6 + 3 * blocks]; - - bytes[0] = (byte) ((chunk.getX() >> 6) & 0xff); - bytes[1] = (byte) (((chunk.getX() & 0x3f) << 2) | ((chunk.getY()) >> 2) & 0x03); - bytes[2] = (byte) (((chunk.getY() & 0x03) << 6) | ((chunk.getZ() >> 8) & 0x3f)); - bytes[3] = (byte) (chunk.getZ() & 0xff); - bytes[4] = (byte) ((blocks >> 5) & 0xff); - bytes[5] = (byte) ((blocks & 0x1f) << 3); - - for (int i = 0; i < blocks; i ++) { - byte[] blockSerialized = blockSerializer.serialize(chunk.getModifiedBlocks()[i]); - for (int j = 0; j < 3; j ++) { - bytes[6 + i * 3 + j] = blockSerialized[j]; - } - } - return bytes; - } -} diff --git a/generated_world/src/main/java/mc/world/generated_world/serialization/RegionReaderWriter.java b/generated_world/src/main/java/mc/world/generated_world/serialization/RegionReaderWriter.java new file mode 100644 index 0000000..2a44fda --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/RegionReaderWriter.java @@ -0,0 +1,53 @@ +package mc.world.generated_world.serialization; + +import mc.core.serialization.IRegionReaderWriter; +import mc.core.world.Biome; +import mc.core.world.Region; +import mc.core.world.World; +import mc.world.generated_world.region.RegionImpl; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.text.MessageFormat; + +import static mc.world.generated_world.WorldConstants.*; + +public class RegionReaderWriter implements IRegionReaderWriter { + private final File worldFolder; + + public RegionReaderWriter(File worldFolder) { + this.worldFolder = worldFolder; + } + + @Override + public Region read (int x, int z, World world) throws IOException{ + File regionFolder = new File(worldFolder, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, x, z)); + File biomesFile = new File(regionFolder, BIOME_FILE_NAME_TEMPLATE); + byte[] biomesBytes = Files.readAllBytes(Paths.get(biomesFile.toURI())); + Region region = new RegionImpl(x, z, world); + for (int tx = 0; tx < WORLD_REGION_SIZE; tx ++) { + for (int tz = 0; tz < WORLD_REGION_SIZE; tz ++) { + region.setBiome(tx, tz, Biome.getById(biomesBytes[tx * WORLD_REGION_SIZE + tz])); + } + } + return region; + } + + @Override + public void write (Region region) throws IOException{ + File regionFolder = new File(worldFolder, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, region.getX(), region.getZ())); + File biomesFile = new File(regionFolder, BIOME_FILE_NAME_TEMPLATE); + byte[] biomesBytes = new byte[WORLD_REGION_SIZE * WORLD_REGION_SIZE]; + for (int x = 0; x < WORLD_REGION_SIZE; x ++) { + for (int z = 0; z < WORLD_REGION_SIZE; z ++) { + biomesBytes[x * WORLD_REGION_SIZE + z] = (byte) region.getBiomeAt(x, z).getId(); + } + } + try (FileOutputStream fos = new FileOutputStream(biomesFile)) { + fos.write(biomesBytes); + } + } +} diff --git a/generated_world/src/main/java/mc/world/generated_world/serialization/RegionSerializerDeserializer.java b/generated_world/src/main/java/mc/world/generated_world/serialization/RegionSerializerDeserializer.java deleted file mode 100644 index 11e8a53..0000000 --- a/generated_world/src/main/java/mc/world/generated_world/serialization/RegionSerializerDeserializer.java +++ /dev/null @@ -1,17 +0,0 @@ -package mc.world.generated_world.serialization; - -import mc.core.serialization.Deserializer; -import mc.core.serialization.Serializer; -import mc.core.world.Region; - -public class RegionSerializerDeserializer implements Serializer, Deserializer { - @Override - public Region deserialize(byte[] bytes) { - return null; - } - - @Override - public byte[] serialize(Region region) { - return new byte[0]; - } -} From 476b3624fe445111f593ba035d25fffbcf2ed019 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 11:06:56 +0300 Subject: [PATCH 32/37] - unused class --- .../world/generated_world/chunk/ProxiedChunkLoader.java | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 generated_world/src/main/java/mc/world/generated_world/chunk/ProxiedChunkLoader.java diff --git a/generated_world/src/main/java/mc/world/generated_world/chunk/ProxiedChunkLoader.java b/generated_world/src/main/java/mc/world/generated_world/chunk/ProxiedChunkLoader.java deleted file mode 100644 index f5aa630..0000000 --- a/generated_world/src/main/java/mc/world/generated_world/chunk/ProxiedChunkLoader.java +++ /dev/null @@ -1,9 +0,0 @@ -package mc.world.generated_world.chunk; - -import mc.core.world.Chunk; -import mc.core.world.ChunkLoader; - -public interface ProxiedChunkLoader extends ChunkLoader { - @Override - Chunk loadOrGenerateChunk(int x, int y, int z); -} From a9e637810162faa20f1861bdf3d7004a0258eaf4 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 11:41:09 +0300 Subject: [PATCH 33/37] More compact serialization --- core/src/main/java/mc/core/world/Chunk.java | 1 - core/src/main/java/mc/core/world/Region.java | 4 +-- .../main/java/mc/world/flat/SimpleChunk.java | 5 --- .../generated_world/chunk/ChunkImpl.java | 14 +++----- .../generated_world/chunk/ChunkProxy.java | 6 ---- .../generator/SeedBasedWorldGenerator.java | 8 +++-- .../generated_world/region/RegionImpl.java | 11 ++++--- .../serialization/ChunkSerializer.java | 33 ++++++++++++++----- .../serialization/RegionReaderWriter.java | 3 ++ 9 files changed, 46 insertions(+), 39 deletions(-) diff --git a/core/src/main/java/mc/core/world/Chunk.java b/core/src/main/java/mc/core/world/Chunk.java index 1300d42..0b712b0 100644 --- a/core/src/main/java/mc/core/world/Chunk.java +++ b/core/src/main/java/mc/core/world/Chunk.java @@ -45,7 +45,6 @@ public interface Chunk extends Serializable{ int getY(); int getZ(); - Block[] getModifiedBlocks(); void setBlock (int x, int y, int z, Block block); Block getBlock (int x, int y, int z); } diff --git a/core/src/main/java/mc/core/world/Region.java b/core/src/main/java/mc/core/world/Region.java index 6791088..dec2730 100644 --- a/core/src/main/java/mc/core/world/Region.java +++ b/core/src/main/java/mc/core/world/Region.java @@ -14,10 +14,10 @@ import java.io.Serializable; * +-------------+----------------+------------+ * | param | range | bits | * +-------------+----------------+------------+ - * | biome_map | 256x256 0-32 | 2097152 | + * | biome_map | 256x256 0-128 | 524288 | * +-------------+----------------+------------+ * - * Total: 2097152 bits (256 Kb) + * Total: 524288 bits (64 Kb) * */ public interface Region extends Serializable{ 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 4e95a4d..03ad6ad 100644 --- a/flat_world/src/main/java/mc/world/flat/SimpleChunk.java +++ b/flat_world/src/main/java/mc/world/flat/SimpleChunk.java @@ -90,11 +90,6 @@ public class SimpleChunk implements Chunk { return 0; } - @Override - public Block[] getModifiedBlocks() { - return new Block[0]; - } - @Override public void setBlock(int x, int y, int z, Block block) { 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 4ffcc69..464b980 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,13 +3,11 @@ 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 java.util.LinkedList; -import java.util.List; - import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE; @RequiredArgsConstructor @@ -21,7 +19,6 @@ 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 List modifiedBlocks = new LinkedList<>(); private final transient Region region; @Override @@ -84,15 +81,12 @@ public class ChunkImpl implements Chunk{ region.setBiome(x + this.x * WORLD_CHUNK_SIZE,z + this.z * WORLD_CHUNK_SIZE, biome); } - @Override - public Block[] getModifiedBlocks() { - return modifiedBlocks.toArray(new Block[modifiedBlocks.size()]); - } - @Override public void setBlock(int x, int y, int z, Block block) { + if (block.getBlockType() == BlockType.AIR) { + blocks[x][y][z] = null; + } blocks[x][y][z] = block; - modifiedBlocks.add(block); } @Override 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 292f886..4490001 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 @@ -118,12 +118,6 @@ public class ChunkProxy implements Chunk { return chunk.getZ(); } - @Override - public Block[] getModifiedBlocks() { - use(); - return chunk.getModifiedBlocks(); - } - @Override public void setBlock(int x, int y, int z, Block block) { use(); 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 3ede02c..edcbe21 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 @@ -6,6 +6,8 @@ import mc.core.block.BlockFactory; import mc.core.block.BlockType; import mc.core.world.*; import mc.world.generated_world.region.RegionImpl; +import mc.world.generated_world.serialization.ChunkSerializer; +import mc.world.generated_world.serialization.RegionReaderWriter; import mc.world.generated_world.world.CubicWorld; import mc.world.generated_world.world.Temperature; import mc.world.generated_world.world.Wetness; @@ -24,8 +26,8 @@ public class SeedBasedWorldGenerator implements WorldGenerator { WorldGenerator worldGenerator = new SeedBasedWorldGenerator(); World world = new CubicWorld(UUID.fromString("00000000-0000-0000-C000-000000000046"), 2626949); Region region = worldGenerator.generateRegion(0, 0, world); - //region.save(new ChunkSerializer(), new RegionSerializerDeserializer()); - worldGenerator.generateRegion(1, 0, world); + region.save(new ChunkSerializer(), new RegionReaderWriter(new File("worlds", world.getWorldId().toString()))); + /*worldGenerator.generateRegion(1, 0, world); worldGenerator.generateRegion(-1, 0, world); worldGenerator.generateRegion(0, 1, world); worldGenerator.generateRegion(0, -1, world); @@ -127,7 +129,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { image.setRGB(tx, ty, currentImage.getRGB(x, y)); } } - ImageIO.write(image, "png", new File("out", "merged.png")); + ImageIO.write(image, "png", new File("out", "merged.png"));*/ } @Override 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 8637f47..812512f 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 @@ -84,10 +84,13 @@ 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++) { - File chunkFile = new File(regionFile, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x, y, z)); - byte[] chunkBytes = chunkSerializer.serialize(this.getChunkAt(x, y, z)); - try (FileOutputStream fileOutputStream = new FileOutputStream(chunkFile)){ - fileOutputStream.write(chunkBytes); + Chunk chunk = this.getChunkAt(x, y, z); + byte[] chunkBytes = chunkSerializer.serialize(chunk); + if (chunkBytes.length > 0) { + File chunkFile = new File(regionFile, MessageFormat.format(CHUNK_FILE_NAME_TEMPLATE, x, y, z)); + try (FileOutputStream fileOutputStream = new FileOutputStream(chunkFile)) { + fileOutputStream.write(chunkBytes); + } } } } 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 b854c64..aae910b 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 @@ -1,10 +1,19 @@ package mc.world.generated_world.serialization; +import lombok.extern.slf4j.Slf4j; import mc.core.block.Block; +import mc.core.block.BlockFactory; +import mc.core.block.BlockType; import mc.core.serialization.Serializer; import mc.core.world.Chunk; import org.springframework.beans.factory.annotation.Autowired; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE; + +@Slf4j public class ChunkSerializer implements Serializer { @Autowired @@ -12,15 +21,23 @@ public class ChunkSerializer implements Serializer { @Override public byte[] serialize(Chunk chunk) { - int blocks = chunk.getModifiedBlocks().length; - byte[] bytes = new byte[3 * blocks]; - - for (int i = 0; i < blocks; i ++) { - byte[] blockSerialized = blockSerializer.serialize(chunk.getModifiedBlocks()[i]); - for (int j = 0; j < 3; j ++) { - bytes[i * 3 + j] = blockSerialized[j]; + Serializer blockSerializer = new BlockSerializerDeserializer(new BlockFactory(), chunk); + 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); + if (current != null && current.getBlockType() != BlockType.AIR) { + try { + baos.write(blockSerializer.serialize(current)); + } catch (IOException e) { + log.error("Error occurred while writing serialized block to byte array", e); + } + } + } } } - return bytes; + return baos.toByteArray(); } } diff --git a/generated_world/src/main/java/mc/world/generated_world/serialization/RegionReaderWriter.java b/generated_world/src/main/java/mc/world/generated_world/serialization/RegionReaderWriter.java index 2a44fda..20595a4 100644 --- a/generated_world/src/main/java/mc/world/generated_world/serialization/RegionReaderWriter.java +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/RegionReaderWriter.java @@ -39,6 +39,9 @@ public class RegionReaderWriter implements IRegionReaderWriter { @Override public void write (Region region) throws IOException{ File regionFolder = new File(worldFolder, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, region.getX(), region.getZ())); + if (!regionFolder.exists()) { + regionFolder.mkdirs(); + } File biomesFile = new File(regionFolder, BIOME_FILE_NAME_TEMPLATE); byte[] biomesBytes = new byte[WORLD_REGION_SIZE * WORLD_REGION_SIZE]; for (int x = 0; x < WORLD_REGION_SIZE; x ++) { From 94e32a69215afa49a18fac93223ec8b8f11eded7 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 13:14:59 +0300 Subject: [PATCH 34/37] World info saving --- core/src/main/java/mc/core/Location.java | 4 +- core/src/main/java/mc/core/WarpPosition.java | 14 +++++ core/src/main/java/mc/core/player/Look.java | 4 +- core/src/main/java/mc/core/world/World.java | 14 +++-- .../main/java/mc/world/flat/FlatWorld.java | 6 +- .../world/generated_world/WorldConstants.java | 1 + .../generator/SeedBasedWorldGenerator.java | 2 + .../serialization/WorldReaderWriter.java | 62 +++++++++++++++++++ .../generated_world/world/CubicWorld.java | 21 ++++--- 9 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 core/src/main/java/mc/core/WarpPosition.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/serialization/WorldReaderWriter.java diff --git a/core/src/main/java/mc/core/Location.java b/core/src/main/java/mc/core/Location.java index 78b25c8..7240e7c 100644 --- a/core/src/main/java/mc/core/Location.java +++ b/core/src/main/java/mc/core/Location.java @@ -7,9 +7,11 @@ package mc.core; import lombok.AllArgsConstructor; import lombok.Data; +import java.io.Serializable; + @AllArgsConstructor @Data -public class Location { +public class Location implements Serializable{ private double x, y, z; public static Location copyOf(Location location) { diff --git a/core/src/main/java/mc/core/WarpPosition.java b/core/src/main/java/mc/core/WarpPosition.java new file mode 100644 index 0000000..6e1aacf --- /dev/null +++ b/core/src/main/java/mc/core/WarpPosition.java @@ -0,0 +1,14 @@ +package mc.core; + +import lombok.AllArgsConstructor; +import lombok.Data; +import mc.core.player.Look; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +public class WarpPosition implements Serializable { + private Location location; + private Look look; +} diff --git a/core/src/main/java/mc/core/player/Look.java b/core/src/main/java/mc/core/player/Look.java index 9335111..1c0f7f4 100644 --- a/core/src/main/java/mc/core/player/Look.java +++ b/core/src/main/java/mc/core/player/Look.java @@ -7,9 +7,11 @@ package mc.core.player; import lombok.AllArgsConstructor; import lombok.Data; +import java.io.Serializable; + @Data @AllArgsConstructor -public class Look { +public class Look implements Serializable{ private float yaw, pitch; public void set(Look look) { diff --git a/core/src/main/java/mc/core/world/World.java b/core/src/main/java/mc/core/world/World.java index 86184e4..bc18bf8 100644 --- a/core/src/main/java/mc/core/world/World.java +++ b/core/src/main/java/mc/core/world/World.java @@ -5,6 +5,7 @@ package mc.core.world; import mc.core.Location; +import mc.core.WarpPosition; import mc.core.nbt.Taggable; import java.io.Serializable; @@ -45,14 +46,17 @@ public interface World extends Taggable, Serializable{ UUID getWorldId(); IWorldType getWorldType(); - Location getSpawn(); - void setSpawn(Location location); + WarpPosition getSpawn(); + void setSpawn(WarpPosition location); Chunk getChunk(int x, int y, int z); void setChunk(int x, int y, int z, Chunk chunk); - Region getRegion (int x, int z); - void setRegion (int x, int z, Region region); + Region getRegion(int x, int z); + void setRegion(int x, int z, Region region); - int getSeed (); + int getSeed(); + + String getName(); + void setName(String name); } 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 0671c31..4f7ef22 100644 --- a/flat_world/src/main/java/mc/world/flat/FlatWorld.java +++ b/flat_world/src/main/java/mc/world/flat/FlatWorld.java @@ -8,6 +8,8 @@ import com.flowpowered.nbt.Tag; import lombok.Getter; import lombok.Setter; import mc.core.Location; +import mc.core.WarpPosition; +import mc.core.player.Look; import mc.core.world.*; import java.util.UUID; @@ -17,10 +19,12 @@ public class FlatWorld implements World { @Getter@Setter private UUID worldId = UUID.fromString("00000000-0000-0000-C000-000000000046"); + @Getter@Setter + private String name; @Getter @Setter - private Location spawn = new Location(0, 6, 0); + private WarpPosition spawn = new WarpPosition(new Location(0, 6, 0), new Look(0, 0)); private Chunk chunk = new SimpleChunk(); @Override diff --git a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java index 728a825..a635084 100644 --- a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java +++ b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java @@ -6,6 +6,7 @@ public final class WorldConstants { public static final String CHUNK_FILE_NAME_TEMPLATE = "chunk_{0}_{1}_{2}.dat"; public static final String BIOME_FILE_NAME_TEMPLATE = "biomes.dat"; + public static final String WORLD_INFO_FILE_NAME_TEMPLATE = "world.dat"; public static final String REGION_FILE_NAME_TEMPLATE = "r.{0}.{1}"; public static final int WORLD_MIN_HEIGHT = 36; 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 edcbe21..78f2d67 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,6 +8,7 @@ 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; @@ -27,6 +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); /*worldGenerator.generateRegion(1, 0, world); worldGenerator.generateRegion(-1, 0, world); worldGenerator.generateRegion(0, 1, world); diff --git a/generated_world/src/main/java/mc/world/generated_world/serialization/WorldReaderWriter.java b/generated_world/src/main/java/mc/world/generated_world/serialization/WorldReaderWriter.java new file mode 100644 index 0000000..485c98f --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/WorldReaderWriter.java @@ -0,0 +1,62 @@ +package mc.world.generated_world.serialization; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import mc.core.WarpPosition; +import mc.core.world.World; +import mc.world.generated_world.world.CubicWorld; + +import java.io.*; +import java.util.UUID; + +import static mc.world.generated_world.WorldConstants.WORLD_INFO_FILE_NAME_TEMPLATE; + +@Slf4j +public class WorldReaderWriter { + private final File worldsFolder; + + public WorldReaderWriter(File worldsFolder) { + this.worldsFolder = worldsFolder; + } + + public World readWorld (UUID uuid) throws IOException { + World world = null; + File worldFolder = new File(worldsFolder, uuid.toString()); + if (!worldFolder.exists()) { + throw new FileNotFoundException("World folder is not exist"); + } + File worldInfoFile = new File(worldFolder, WORLD_INFO_FILE_NAME_TEMPLATE); + WorldInfo worldInfo; + try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(worldInfoFile))) { + worldInfo = (WorldInfo) ois.readObject(); + } catch (ClassNotFoundException e) { + log.error("Error occurred while reading world info file", e); + return null; + } + world = new CubicWorld(uuid, worldInfo.getSeed()); + world.setSpawn(worldInfo.getSpawn()); + world.setName(worldInfo.getName()); + return world; + } + + public void writeWorldInfo (World world) throws IOException { + File worldFolder = new File(worldsFolder, world.getWorldId().toString()); + worldFolder.mkdirs(); + File worldInfoFile = new File(worldFolder, WORLD_INFO_FILE_NAME_TEMPLATE); + WorldInfo worldInfo = new WorldInfo(); + worldInfo.setName(world.getName()); + worldInfo.setSeed(world.getSeed()); + worldInfo.setSpawn(world.getSpawn()); + try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(worldInfoFile))) { + oos.writeObject(worldInfo); + oos.flush(); + } + } + + @Data + public static class WorldInfo implements Serializable { + private WarpPosition spawn; + private String name; + private int seed; + } +} 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 8442528..b419717 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 @@ -2,7 +2,10 @@ package mc.world.generated_world.world; import com.flowpowered.nbt.Tag; import lombok.Getter; +import lombok.Setter; import mc.core.Location; +import mc.core.WarpPosition; +import mc.core.player.Look; import mc.core.world.*; import mc.world.generated_world.chunk.InMemoryCacheChunkLoader; @@ -15,10 +18,12 @@ public class CubicWorld implements World { @Getter private final UUID worldId; private final int seed; - private volatile Location spawnLocation; + private volatile WarpPosition warpPosition; private final transient Object spawnLocationLock = new Object(); private final transient ChunkLoader chunkLoader; private final Map> nbtTagMap = new HashMap<>(); + @Getter@Setter + private String name; public CubicWorld(UUID worldId, int seed) { this.worldId = worldId; @@ -50,21 +55,21 @@ public class CubicWorld implements World { } @Override - public Location getSpawn() { - if (spawnLocation == null) { + public WarpPosition getSpawn() { + if (warpPosition == null) { synchronized (spawnLocationLock) { - if (spawnLocation == null) { - spawnLocation = Location.startPointLocation(); + if (warpPosition == null) { + warpPosition = new WarpPosition(Location.startPointLocation(), new Look(0,0)); } } } - return spawnLocation; + return warpPosition; } @Override - public void setSpawn(Location location) { + public void setSpawn(WarpPosition warpPosition) { synchronized (spawnLocationLock) { - this.spawnLocation = location; + this.warpPosition = warpPosition; } } From 7ec05c4e246ce60699db303ff0fd278ed184cfd6 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 14:03:04 +0300 Subject: [PATCH 35/37] RegionManager --- core/src/main/java/mc/core/Direction.java | 8 + .../generated_world/world/RegionManager.java | 143 ++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 core/src/main/java/mc/core/Direction.java create mode 100644 generated_world/src/main/java/mc/world/generated_world/world/RegionManager.java diff --git a/core/src/main/java/mc/core/Direction.java b/core/src/main/java/mc/core/Direction.java new file mode 100644 index 0000000..74e4630 --- /dev/null +++ b/core/src/main/java/mc/core/Direction.java @@ -0,0 +1,8 @@ +package mc.core; + +public enum Direction { + NORTH, + EAST, + WEST, + SOUTH +} diff --git a/generated_world/src/main/java/mc/world/generated_world/world/RegionManager.java b/generated_world/src/main/java/mc/world/generated_world/world/RegionManager.java new file mode 100644 index 0000000..0cc0ef4 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/world/RegionManager.java @@ -0,0 +1,143 @@ +package mc.world.generated_world.world; + +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import mc.core.Direction; +import mc.core.world.Region; +import mc.core.world.World; +import mc.core.world.WorldGenerator; +import mc.world.generated_world.serialization.RegionReaderWriter; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.File; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import static mc.world.generated_world.WorldConstants.REGION_FILE_NAME_TEMPLATE; + +/* +* NORTH +* +* EAST WEST +* +* SOUTH +* +* + ----> X +* | +* | +* | +* V Z +*/ +@Slf4j +public class RegionManager { + private final World world; + private int pointX = -1; + private int pointZ = -1; + private int sizeX = 2; + private int sizeZ = 2; + private Region[][] regions = new Region[sizeX][sizeZ]; + private final Lock regionSaveLock = new ReentrantLock(); + @Autowired + private RegionReaderWriter regionReaderWriter; + @Autowired + private WorldGenerator worldGenerator; + @Setter + private boolean autoSaveRegionAfterGenerating = true; + + + public RegionManager(World world) { + this.world = world; + } + + public void setRegion (Region region) { + int x = region.getX(); + int z = region.getZ(); + + try { + regionSaveLock.lock(); + regions[x - pointX][z - pointZ] = region; + } finally { + regionSaveLock.unlock(); + } + } + + private void checkCoordsInCache (int x, int z) { + if (x < pointX) { + addLines(Direction.EAST, pointX - x); + } else if (x > pointX + sizeX) { + addLines(Direction.WEST, x - (pointX + sizeX)); + } else if (z < pointZ) { + addLines(Direction.NORTH, pointZ - z); + } else if (z > pointZ + sizeZ) { + addLines(Direction.SOUTH, z - (pointZ + sizeZ)); + } + } + + public Region getRegion (int x, int z) { + checkCoordsInCache(x, z); + Region region; + if (regions[x - pointX][z - pointZ] == null) { + File file = new File(new File("worlds", world.getWorldId().toString()), MessageFormat.format(REGION_FILE_NAME_TEMPLATE, x, z)); + if (!file.exists()) { + region = worldGenerator.generateRegion(x, z, world); + if (autoSaveRegionAfterGenerating) { + try { + regionReaderWriter.write(region); + } catch (IOException e) { + log.error("Error occurred while saving region data"); + } + } + } else { + try { + region = regionReaderWriter.read(x, z, world); + } catch (IOException e) { + log.error("Error occurred while loading region"); + region = null; + } + } + setRegion(region); + } else { + region = regions[x - pointX][z - pointZ]; + } + return region; + } + + private void addLines (Direction direction, int amount) { + int addBeforeX = 0; + int addAfterX = 0; + int addBeforeZ = 0; + int addAfterZ = 0; + switch (direction) { + case NORTH: + addBeforeZ = amount; + break; + case EAST: + addBeforeX = amount; + break; + case WEST: + addAfterX = amount; + break; + case SOUTH: + addAfterZ = amount; + break; + } + try { + int tempSizeX = sizeX + addAfterX + addBeforeX; + int tempSizeZ = sizeZ + addAfterZ + addBeforeZ; + Region[][] temp = new Region[tempSizeX][tempSizeZ]; + for (int x = 0; x < sizeX; x ++) { + System.arraycopy(regions[x], 0, temp[x + addBeforeX], addBeforeZ, sizeZ); + } + + this.sizeX = tempSizeX; + this.sizeZ = tempSizeZ; + this.pointX = pointX - addBeforeX; + this.pointZ = pointZ - addBeforeZ; + } finally { + regionSaveLock.unlock(); + } + } + +} From 1abe2208641a01e0efdfc2d69580a744073f1c53 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 14:07:05 +0300 Subject: [PATCH 36/37] WORLD --[RegionManager]--> REGION --[ChunkLoader]--> CHUNK --- .../mc/world/generated_world/world/CubicWorld.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 b419717..643cf30 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 @@ -6,8 +6,11 @@ import lombok.Setter; import mc.core.Location; import mc.core.WarpPosition; import mc.core.player.Look; -import mc.core.world.*; -import mc.world.generated_world.chunk.InMemoryCacheChunkLoader; +import mc.core.world.Chunk; +import mc.core.world.IWorldType; +import mc.core.world.Region; +import mc.core.world.World; +import org.springframework.beans.factory.annotation.Autowired; import java.util.HashMap; import java.util.Map; @@ -20,32 +23,29 @@ public class CubicWorld implements World { private final int seed; private volatile WarpPosition warpPosition; private final transient Object spawnLocationLock = new Object(); - private final transient ChunkLoader chunkLoader; private final Map> nbtTagMap = new HashMap<>(); + @Autowired + private RegionManager regionManager; @Getter@Setter private String name; public CubicWorld(UUID worldId, int seed) { this.worldId = worldId; - chunkLoader = new InMemoryCacheChunkLoader(this); this.seed = seed; } public CubicWorld(int seed) { this.worldId = UUID.randomUUID(); - chunkLoader = new InMemoryCacheChunkLoader(this); this.seed = seed; } public CubicWorld(UUID worldId) { this.worldId = worldId; - chunkLoader = new InMemoryCacheChunkLoader(this); this.seed = 0; } public CubicWorld () { this.worldId = UUID.randomUUID(); - chunkLoader = new InMemoryCacheChunkLoader(this); this.seed = 0; } From f5057d5a92ae04b3ba113b93eae45af24a1674f3 Mon Sep 17 00:00:00 2001 From: Forwolk Date: Thu, 2 Aug 2018 16:23:12 +0300 Subject: [PATCH 37/37] Selecting best spawn location if it wasn't defined --- .../mc/world/generated_world/WorldConstants.java | 5 +++-- .../generator/SeedBasedWorldGenerator.java | 12 ++++++------ .../world/generated_world/world/CubicWorld.java | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java index a635084..cd33fde 100644 --- a/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java +++ b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java @@ -9,9 +9,10 @@ public final class WorldConstants { public static final String WORLD_INFO_FILE_NAME_TEMPLATE = "world.dat"; public static final String REGION_FILE_NAME_TEMPLATE = "r.{0}.{1}"; - public static final int WORLD_MIN_HEIGHT = 36; + public static final int WORLD_MAX_HEIGHT = 256; public static final int WORLD_SEA_LEVEL = 64; - public static final int WORLD_MAX_HEIGHT = 128; + public static final int WORLD_MIN_GENERATION_HEIGHT = 36; + public static final int WORLD_MAX_GENERATION_HEIGHT = 128; public static final int WORLD_REGION_SIZE = 256; public static final int WORLD_CHUNK_SIZE = 16; public static final int WORLD_MAX_TEMPERATURE = 100; 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 78f2d67..8253165 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 @@ -179,8 +179,8 @@ public class SeedBasedWorldGenerator implements WorldGenerator { int tz = convert(z + region.getZ() * WORLD_REGION_SIZE); double p = sigmoid(noiseGenerator.noise(tx / WORLD_LAND_SIZE, tz / WORLD_LAND_SIZE)); double r = Math.sqrt(noiseGenerator.noise(tx / WORLD_LAKE_SIZE, tz / WORLD_LAKE_SIZE)); - double h = (WORLD_MAX_HEIGHT - WORLD_MIN_HEIGHT) * Math.min(p * r, 1); - h = Math.min(WORLD_MAX_HEIGHT, h + WORLD_MIN_HEIGHT); + double h = (WORLD_MAX_GENERATION_HEIGHT - WORLD_MIN_GENERATION_HEIGHT) * Math.min(p * r, 1); + h = Math.min(WORLD_MAX_GENERATION_HEIGHT, h + WORLD_MIN_GENERATION_HEIGHT); heightMap[x][z] = (int)(h); grassMap[x][z] = (int) (1 + SeedRandomGenerator.random(tx, tz, world.getSeed()) * (LANDFILL_GRASS_SURFACE_THIN - 1)); double k = Math.sqrt(noiseGenerator.noise(tx * WORLD_TEMPERATURE_ZONE_SIZE, tz * WORLD_TEMPERATURE_ZONE_SIZE)); @@ -191,8 +191,8 @@ public class SeedBasedWorldGenerator implements WorldGenerator { wetMap[x][z] = (int) (WORLD_MAX_WETNESS * WORLD_WET_SEA_PERCENT *noiseGenerator.noise(tx, tz)); } else { int th = heightMap[x][z] - WORLD_SEA_LEVEL; - th = (int) (th * (1 + 1.25 * th / (WORLD_MAX_HEIGHT - WORLD_SEA_LEVEL))); - heightMap[x][z] = Math.min(WORLD_SEA_LEVEL + th, WORLD_MAX_HEIGHT); + th = (int) (th * (1 + 1.25 * th / (WORLD_MAX_GENERATION_HEIGHT - WORLD_SEA_LEVEL))); + heightMap[x][z] = Math.min(WORLD_SEA_LEVEL + th, WORLD_MAX_GENERATION_HEIGHT); } } } @@ -365,7 +365,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } } else { if (height < WORLD_SEA_LEVEL) { - if (height < WORLD_MIN_HEIGHT + (WORLD_SEA_LEVEL - WORLD_MIN_HEIGHT) / 2) { + if (height < WORLD_MIN_GENERATION_HEIGHT + (WORLD_SEA_LEVEL - WORLD_MIN_GENERATION_HEIGHT) / 2) { return Biome.DEEP_OCEAN; } else { return Biome.OCEAN; @@ -376,7 +376,7 @@ public class SeedBasedWorldGenerator implements WorldGenerator { } } - final int HILLS_HEIGHT = WORLD_SEA_LEVEL + (WORLD_MAX_HEIGHT - WORLD_SEA_LEVEL) / 3; + final int HILLS_HEIGHT = WORLD_SEA_LEVEL + (WORLD_MAX_GENERATION_HEIGHT - WORLD_SEA_LEVEL) / 3; if (temperature == Temperature.FROST) { if (wetness == Wetness.DRIEST || wetness == Wetness.DRY) { 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 643cf30..6c39781 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 @@ -3,8 +3,10 @@ package mc.world.generated_world.world; import com.flowpowered.nbt.Tag; import lombok.Getter; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; 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.IWorldType; @@ -17,6 +19,10 @@ import java.util.Map; import java.util.UUID; import java.util.stream.Stream; +import static mc.world.generated_world.WorldConstants.WORLD_CHUNK_SIZE; +import static mc.world.generated_world.WorldConstants.WORLD_MAX_HEIGHT; + +@Slf4j public class CubicWorld implements World { @Getter private final UUID worldId; @@ -59,6 +65,15 @@ public class CubicWorld implements World { if (warpPosition == null) { synchronized (spawnLocationLock) { if (warpPosition == null) { + log.warn("Spawn location is not defined. Trying to select best location"); + warpPosition = new WarpPosition(Location.startPointLocation(), new Look(0, 0)); + for (int y = WORLD_MAX_HEIGHT; y > 0; y --) { + Chunk chunk = getChunk(0,y / WORLD_CHUNK_SIZE, 0); + if (chunk.getBlock(0, y, 0).getBlockType() != BlockType.AIR) { + warpPosition = new WarpPosition(new Location(0, y + 1, 0), new Look(0, 0)); + break; + } + } warpPosition = new WarpPosition(Location.startPointLocation(), new Look(0,0)); } }