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/core/src/main/java/mc/core/Location.java b/core/src/main/java/mc/core/Location.java index fa1e00b..7e560f3 100644 --- a/core/src/main/java/mc/core/Location.java +++ b/core/src/main/java/mc/core/Location.java @@ -7,11 +7,18 @@ 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; + private static int floor_double(double value) { + int i = (int)value; + return value < (double)i ? i - 1 : i; + } + public static Location copyOf(Location location) { return new Location( location.x, @@ -20,12 +27,26 @@ public class Location { ); } + public static Location startPointLocation () { + return new Location(0,10,0); + } + + public Location(long compactValue) { + set(compactValue); + } + public void set(Location location) { this.x = location.x; this.y = location.y; this.z = location.z; } + public void set(long compactValue) { + this.x = compactValue >> 38; + this.y = (compactValue >> 26) & 0xFFF; + this.z = compactValue << 38 >> 38; // is normal? + } + public Location diff(Location location) { return new Location( this.x - location.x, @@ -45,4 +66,10 @@ public class Location { public int getBlockZ() { return (int) z; } + + public long toLong() { + return ((floor_double(x) & 0x3FFFFFF) << 38) + | ((floor_double(y) & 0xFFF) << 26) + | (floor_double(z) & 0x3FFFFFF); + } } 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/block/AbstractBlock.java b/core/src/main/java/mc/core/block/AbstractBlock.java new file mode 100644 index 0000000..126e605 --- /dev/null +++ b/core/src/main/java/mc/core/block/AbstractBlock.java @@ -0,0 +1,49 @@ +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; + @Getter + private int meta; + @Getter + private final BlockType blockType; + private final Map> nbtTagsMap = new HashMap<>(); + + protected AbstractBlock(BlockType type) { + this.blockType = type; + } + + protected AbstractBlock(BlockType type, int meta) { + this.blockType = type; + this.meta = meta; + } + + @Override + 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 new file mode 100644 index 0000000..fd67fa8 --- /dev/null +++ b/core/src/main/java/mc/core/block/Block.java @@ -0,0 +1,64 @@ +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 + * + * +------------+--------+------------+ + * | 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 extends Taggable, Serializable{ + + static Block airBlock (int x, int y, int z) { + return new AbstractBlock(BlockType.AIR) { + @Override + public Tag getTag(String name) { + return null; + } + + @Override + public Location getLocation() { + return new Location(x, y, z); + } + }; + } + + /** 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/BlockFactory.java b/core/src/main/java/mc/core/block/BlockFactory.java new file mode 100644 index 0000000..8552e4c --- /dev/null +++ b/core/src/main/java/mc/core/block/BlockFactory.java @@ -0,0 +1,20 @@ +package mc.core.block; + +import mc.core.Location; + +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); + 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 new file mode 100644 index 0000000..4b4b467 --- /dev/null +++ b/core/src/main/java/mc/core/block/BlockType.java @@ -0,0 +1,25 @@ +package mc.core.block; + +import lombok.Getter; + +public enum BlockType { + STONE(1, "Stone"), + GRASS(2, "Grass"), + DIRT(3, "Dirt"), + BEDROCK(7, "Bedrock"), + WATER(8, "Water"), + SAND(12, "Sand"), + SNOW(32, "Snow"), + AIR(0, "Air"); + + @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/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/network/CSPacket.java b/core/src/main/java/mc/core/network/CSPacket.java index 7ed00aa..4e8bb79 100644 --- a/core/src/main/java/mc/core/network/CSPacket.java +++ b/core/src/main/java/mc/core/network/CSPacket.java @@ -8,5 +8,5 @@ package mc.core.network; * Пакеты Client->Server */ public interface CSPacket { - void readSelf(NetStream netStream); + void readSelf(NetInputStream netStream); } diff --git a/core/src/main/java/mc/core/network/NetStream.java b/core/src/main/java/mc/core/network/NetInputStream.java similarity index 54% rename from core/src/main/java/mc/core/network/NetStream.java rename to core/src/main/java/mc/core/network/NetInputStream.java index e82d53c..a2e7b54 100644 --- a/core/src/main/java/mc/core/network/NetStream.java +++ b/core/src/main/java/mc/core/network/NetInputStream.java @@ -1,6 +1,6 @@ /* * DmitriyMX - * 2018-03-28 + * 2018-07-25 */ package mc.core.network; @@ -9,7 +9,7 @@ import lombok.Setter; import java.util.UUID; -public abstract class NetStream { +public abstract class NetInputStream { @Getter @Setter private int dataSize; @@ -28,18 +28,5 @@ public abstract class NetStream { public abstract String readString(); public abstract UUID readUUID(); - public abstract void writeBoolean(boolean value); - public abstract void writeByte(int value); - public abstract void writeUnsignedByte(int value); - public abstract void writeBytes(byte[] buffer); - public abstract void writeShort(int value); - public abstract void writeInt(int value); - public abstract void writeVarInt(int value); - public abstract void writeLong(long value); - public abstract void writeFloat(float value); - public abstract void writeDouble(double value); - public abstract void writeString(String value); - public abstract void writeUUID(UUID uuid); - public abstract void skipBytes(int count); } diff --git a/core/src/main/java/mc/core/network/NetOutputStream.java b/core/src/main/java/mc/core/network/NetOutputStream.java new file mode 100644 index 0000000..86c6f19 --- /dev/null +++ b/core/src/main/java/mc/core/network/NetOutputStream.java @@ -0,0 +1,22 @@ +/* + * DmitriyMX + * 2018-07-25 + */ +package mc.core.network; + +import java.util.UUID; + +public abstract class NetOutputStream { + public abstract void writeBoolean(boolean value); + public abstract void writeByte(int value); + public abstract void writeUnsignedByte(int value); + public abstract void writeBytes(byte[] buffer); + public abstract void writeShort(int value); + public abstract void writeInt(int value); + public abstract void writeVarInt(int value); + public abstract void writeLong(long value); + public abstract void writeFloat(float value); + public abstract void writeDouble(double value); + public abstract void writeString(String value); + public abstract void writeUUID(UUID uuid); +} diff --git a/core/src/main/java/mc/core/network/SCPacket.java b/core/src/main/java/mc/core/network/SCPacket.java index 9abba0e..2265331 100644 --- a/core/src/main/java/mc/core/network/SCPacket.java +++ b/core/src/main/java/mc/core/network/SCPacket.java @@ -8,5 +8,5 @@ package mc.core.network; * Пакеты Server->Client */ public interface SCPacket { - void writeSelf(NetStream netStream); + void writeSelf(NetOutputStream netStream); } 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/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/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/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/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(); + } +} 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..5a60047 --- /dev/null +++ b/core/src/main/java/mc/core/world/Biome.java @@ -0,0 +1,50 @@ +package mc.core.world; + +import lombok.Getter; + +public enum Biome { + OCEAN(0, "Ocean", 0x0000cd), + PLAINS(1, "Plains", 0x008000), + 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", 0x0000cd), + HELL(8, "Hell", 0x800000), + SKY(9, "Sky", 0xffffff), + FROZEN_OCEAN(10, "Frozen ocean", 0xe0ffff), + 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", 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", 0x000080), + TUNDRA(24, "Tundra", 0xc0c0c0), + SAVANNA(25, "Savana", 0xcd8513), + SAVANNA_FOREST(26, "Savana forest", 0x8b4513); + + @Getter + private final int id; + @Getter + private final String name; + @Getter + private final int color; + + Biome(int id, String name, int color) { + this.id = id; + 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 15ee0fa..0b712b0 100644 --- a/core/src/main/java/mc/core/world/Chunk.java +++ b/core/src/main/java/mc/core/world/Chunk.java @@ -4,8 +4,25 @@ */ package mc.core.world; +import mc.core.block.Block; + +import java.io.Serializable; + +/** + * Serialization chunk info + * + * +-------------+----------------+------------+ + * | param | range | bits | + * +-------------+----------------+------------+ + * | blocks | array | 24*count | + * +-------------+----------------+------------+ + * + * Total: 24 * block_count bits (3 * block_count bytes) + * Max size: 12288 bytes (~12 Kb per chunk) + * + */ /* 16x16x16 */ -public interface Chunk { +public interface Chunk extends Serializable{ int getBlockType(int x, int y, int z); void setBlockType(int x, int y, int z, int type); @@ -21,6 +38,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(); + + 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/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/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/Region.java b/core/src/main/java/mc/core/world/Region.java new file mode 100644 index 0000000..dec2730 --- /dev/null +++ b/core/src/main/java/mc/core/world/Region.java @@ -0,0 +1,34 @@ +package mc.core.world; + +import mc.core.serialization.IRegionReaderWriter; +import mc.core.serialization.Serializer; + +import java.io.IOException; +import java.io.Serializable; + +/** + * Simple world generation unit + * 16x16x16 chunks + * + * + * +-------------+----------------+------------+ + * | param | range | bits | + * +-------------+----------------+------------+ + * | biome_map | 256x256 0-128 | 524288 | + * +-------------+----------------+------------+ + * + * Total: 524288 bits (64 Kb) + * + */ +public interface Region extends Serializable{ + Chunk getChunkAt(int x, int y, int z); + void setChunk(int x, int y, int z, Chunk chunk); + + int getX(); + int getZ(); + + Biome getBiomeAt (int x, int z); + void setBiome (int x, int z, Biome biome); + + void save(Serializer chunkSerializer, IRegionReaderWriter regionReaderWritter) throws IOException; +} diff --git a/core/src/main/java/mc/core/world/World.java b/core/src/main/java/mc/core/world/World.java index be5002b..bc18bf8 100644 --- a/core/src/main/java/mc/core/world/World.java +++ b/core/src/main/java/mc/core/world/World.java @@ -5,11 +5,58 @@ package mc.core.world; import mc.core.Location; +import mc.core.WarpPosition; +import mc.core.nbt.Taggable; -public interface World { - Location getSpawn(); - void setSpawn(Location location); +import java.io.Serializable; +import java.util.UUID; - Chunk getChunk(int x, int z); - void setChunk(int x, int z, Chunk chunk); +/** + * 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 | + * +-------------+----------------+------------+ + * | 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 extends Taggable, Serializable{ + UUID getWorldId(); + IWorldType getWorldType(); + + 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); + + int getSeed(); + + String getName(); + void setName(String name); } 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..817012c --- /dev/null +++ b/core/src/main/java/mc/core/world/WorldGenerator.java @@ -0,0 +1,6 @@ +package mc.core.world; + +public interface WorldGenerator { + + Region generateRegion (int x, int z, World world); +} 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..73533fa --- /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 8340979..4f7ef22 100644 --- a/flat_world/src/main/java/mc/world/flat/FlatWorld.java +++ b/flat_world/src/main/java/mc/world/flat/FlatWorld.java @@ -4,25 +4,71 @@ */ package mc.world.flat; +import com.flowpowered.nbt.Tag; import lombok.Getter; import lombok.Setter; import mc.core.Location; -import mc.core.world.Chunk; -import mc.core.world.World; +import mc.core.WarpPosition; +import mc.core.player.Look; +import mc.core.world.*; + +import java.util.UUID; +import java.util.stream.Stream; 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 - public Chunk getChunk(int x, int z) { + public IWorldType getWorldType() { + return WorldType.GENERAL; + } + + @Override + 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(); + } + + @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 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/flat_world/src/main/java/mc/world/flat/SimpleChunk.java b/flat_world/src/main/java/mc/world/flat/SimpleChunk.java index 5186615..03ad6ad 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,10 @@ */ 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; public class SimpleChunk implements Chunk { @@ -62,12 +66,42 @@ public class SimpleChunk implements Chunk { } @Override - public int getBiome(int x, int z) { + public Biome getBiome(int x, int z) { + return Biome.PLAINS; + } + + @Override + public void setBiome(int x, int z, Biome biome) { + + } + + @Override + public int getX() { return 0; } @Override - public void setBiome(int x, int z, int value) { + public int getY() { + return 0; + } + + @Override + public int getZ() { + return 0; + } + + @Override + public void setBlock(int x, int y, int z, Block block) { } + + @Override + public Block getBlock(int x, int y, int z) { + BlockFactory blockFactory = new BlockFactory(); + + if (y == 0) return blockFactory.create(BlockType.BEDROCK, 0); + else if (y >= 1 && y <= 2) return blockFactory.create(BlockType.DIRT, 0); + else if (y == 3) return blockFactory.create(BlockType.GRASS, 0); + else return Block.airBlock(x, y, z); + } } 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 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/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..cd33fde --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/WorldConstants.java @@ -0,0 +1,33 @@ +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 WORLD_INFO_FILE_NAME_TEMPLATE = "world.dat"; + public static final String REGION_FILE_NAME_TEMPLATE = "r.{0}.{1}"; + + public static final int WORLD_MAX_HEIGHT = 256; + public static final int WORLD_SEA_LEVEL = 64; + 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; + public static final int WORLD_MAX_WETNESS = 100; + public static final int WORLD_BASE_WETNESS = 80; + + 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; + 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; + + 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..464b980 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkImpl.java @@ -0,0 +1,100 @@ +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 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 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 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; + } + + @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 new file mode 100644 index 0000000..4490001 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/ChunkProxy.java @@ -0,0 +1,132 @@ +package mc.world.generated_world.chunk; + +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 transient long lastUsage = System.currentTimeMillis(); + private final transient ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + + public ChunkProxy(Chunk chunk) { + this.chunk = chunk; + } + + public long getLastUsage() { + synchronized (chunk) { + return lastUsage; + } + } + + private final void use () { + synchronized (chunk) { + lastUsage = System.currentTimeMillis(); + } + } + + @Override + public int getBlockType(int x, int y, int z) { + use(); + return chunk.getBlockType(x, y, z); + } + + @Override + public void setBlockType(int x, int y, int z, int type) { + use(); + chunk.setBlockType(x, y, z, type); + } + + @Override + public int getBlockMetadata(int x, int y, int z) { + use(); + return chunk.getBlockMetadata(x, y, z); + } + + @Override + public void setBlockMetadata(int x, int y, int z, int metadata) { + use(); + chunk.setBlockMetadata(x, y, z, metadata); + } + + @Override + public int getBlockLight(int x, int y, int z) { + use(); + return chunk.getBlockLight(x, y, z); + } + + @Override + public void setBlockLight(int x, int y, int z, int lightLevel) { + use(); + chunk.setBlockLight(x, y, z, lightLevel); + } + + @Override + public int getSkyLight(int x, int y, int z) { + use(); + return chunk.getSkyLight(x, y, z); + } + + @Override + public void setSkyLight(int x, int y, int z, int lightLevel) { + use(); + chunk.setSkyLight(x, y, z, lightLevel); + } + + @Override + public int getAddition(int x, int y, int z) { + use(); + return chunk.getAddition(x, y, z); + } + + @Override + public void setAddition(int x, int y, int z, int value) { + use(); + chunk.setAddition(x, y, z, value); + } + + @Override + public Biome getBiome(int x, int z) { + use(); + return chunk.getBiome(x, z); + } + + @Override + public void setBiome(int x, int z, Biome biome) { + use(); + chunk.setBiome(x, z, biome); + } + + @Override + public int getX() { + use(); + return chunk.getX(); + } + + @Override + public int getY() { + use(); + return chunk.getY(); + } + + @Override + public int getZ() { + use(); + return chunk.getZ(); + } + + @Override + public void setBlock(int x, int y, int z, Block block) { + use(); + chunk.setBlock(x, y, z, block); + } + + @Override + public Block getBlock(int x, int y, int z) { + use(); + return chunk.getBlock(x, y, z); + } +} 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 new file mode 100644 index 0000000..2724497 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/chunk/InMemoryCacheChunkLoader.java @@ -0,0 +1,108 @@ +package mc.world.generated_world.chunk; + +import lombok.extern.slf4j.Slf4j; +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.text.MessageFormat; +import java.util.Optional; + +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 ChunkReader chunkReader; + @Autowired + private Serializer chunkSerializer; + @Autowired + private RegionReaderWriter regionReaderWritter; + + 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 { + 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(); + } + } + } + + @Override + public Chunk loadOrGenerateChunk(int x, int y, int z) { + int regX = x / WORLD_CHUNK_SIZE; + int regZ = z / WORLD_CHUNK_SIZE; + File regionFile = new File(worldFolder, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, regX, regZ)); + Region region; + Chunk chunk; + if (!regionFile.exists()) { + log.debug("Region [{}, {}] not found. Generating!", regX, regZ); + regionFile.mkdirs(); + region = worldGenerator.generateRegion(regX, regZ, world); + 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 { + try { + 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; + } + } + 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/generator/SeedBasedWorldGenerator.java b/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java new file mode 100644 index 0000000..8253165 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/generator/SeedBasedWorldGenerator.java @@ -0,0 +1,522 @@ +package mc.world.generated_world.generator; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +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.serialization.WorldReaderWriter; +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; +import java.io.File; +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"), 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); + 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; + 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)); + } + } + 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; + } + + @RequiredArgsConstructor + private class RegionGenerator { + private final World world; + private final Region region; + private NoiseGenerator noiseGenerator; + private BlockFactory blockFactory = new 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() { + log.debug("Starting generating region [{}, {}] for world '{}' with seed '{}'", region.getX(), region.getZ(), world.getWorldId(), world.getSeed()); + + noiseGenerator = new NoiseGenerator(world.getSeed()); + noiseGenerator.init(); + + 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_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)); + 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] = (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_GENERATION_HEIGHT - WORLD_SEA_LEVEL))); + heightMap[x][z] = Math.min(WORLD_SEA_LEVEL + th, WORLD_MAX_GENERATION_HEIGHT); + } + } + } + + 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 ++) { + mid += wetMap[tx][tz]; + } + } + wetMap[x][z] = mid / 9; + } + } + 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 ++) { + mid += wetMap[tx][tz]; + } + } + 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 < 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())))); + } + } + + smooth(grassMap); + smooth(temperatureMap); + smooth(wetMap); + //smooth(heightMap); + + // ================================ 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 FINISH ======================================= + + 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 ++) { + 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)); + } + } + } + } + } + } + + /* 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..."); + */ + } + + private Biome selectBiome (Temperature temperature, Wetness wetness, int height) { + + 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) { + if (height < WORLD_MIN_GENERATION_HEIGHT + (WORLD_SEA_LEVEL - WORLD_MIN_GENERATION_HEIGHT) / 2) { + return Biome.DEEP_OCEAN; + } else { + return Biome.OCEAN; + } + } else { + return Biome.SWAMPLAND; + } + } + } + + 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) { + return Biome.TUNDRA; + } else { + if (height > HILLS_HEIGHT) { + return Biome.ICE_MOUNTAINS; + } else { + return Biome.ICE_PLAINS; + } + } + } + + if (wetness == Wetness.DRIEST) { + if (temperature == Temperature.COLD || temperature == Temperature.WARM) { + return Biome.PLAINS; + } 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 > 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; + } + } else { + return Biome.SAVANNA_FOREST; + } + } + + 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; + } + + 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 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 < 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 / 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) { + 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) % WORLD_REGION_SIZE; + int y = (i + i * x) % WORLD_REGION_SIZE; + 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/generator/SeedRandomGenerator.java b/generated_world/src/main/java/mc/world/generated_world/generator/SeedRandomGenerator.java new file mode 100644 index 0000000..c2ff8e7 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/generator/SeedRandomGenerator.java @@ -0,0 +1,23 @@ +package mc.world.generated_world.generator; + +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 < 20; 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/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..812512f --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/region/RegionImpl.java @@ -0,0 +1,99 @@ +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; +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{ + @Getter + private final int x; + @Getter + private final int z; + private final ChunkProxy[][][] chunks = new ChunkProxy[WORLD_REGION_SIZE/WORLD_CHUNK_SIZE][WORLD_REGION_SIZE/WORLD_CHUNK_SIZE][WORLD_REGION_SIZE/WORLD_CHUNK_SIZE]; + private final Biome[][] biomes = new Biome[WORLD_REGION_SIZE][WORLD_REGION_SIZE]; + @Getter + private final 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)); + } + if (chunkLoader == null) { + chunkLoader = new InMemoryCacheChunkLoader(world); + } + Chunk chunk = chunks[x][y][z]; + if (chunk == null) { + chunk = chunkLoader.loadChunk(x + this.x * WORLD_REGION_SIZE, y, this.z * WORLD_REGION_SIZE).orElse(new ChunkImpl(x, y, z, this)); + chunks[x][y][z] = new ChunkProxy(chunk); + } + 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 >= 256 || z >= 256) { + 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 >= 256 || z >= 256) { + throw new RuntimeException(MessageFormat.format("Invalid biome coordinates [{0} {1}]", x, z)); + } + biomes[x][z] = biome; + } + + @Override + public void save(Serializer chunkSerializer, IRegionReaderWriter regionReaderWriter) throws IOException { + String worldPath = System.getProperty("worlds.folder", "worlds"); + File worldFile = new File(worldPath, world.getWorldId().toString()); + File regionFile = new File(worldFile, MessageFormat.format(REGION_FILE_NAME_TEMPLATE, this.getX(), this.getZ())); + if (!regionFile.exists()) { + regionFile.mkdirs(); + } + 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++) { + 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/BlockSerializerDeserializer.java b/generated_world/src/main/java/mc/world/generated_world/serialization/BlockSerializerDeserializer.java new file mode 100644 index 0000000..a176afe --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/BlockSerializerDeserializer.java @@ -0,0 +1,46 @@ +package mc.world.generated_world.serialization; + +import mc.core.block.Block; +import mc.core.block.BlockFactory; +import mc.core.block.BlockType; +import mc.core.serialization.Deserializer; +import mc.core.serialization.Serializer; +import mc.core.world.Chunk; + +/** + * Prototype + */ +public class BlockSerializerDeserializer implements Serializer, Deserializer { + + 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; + } +} 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..aae910b --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/ChunkSerializer.java @@ -0,0 +1,43 @@ +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 + private Serializer blockSerializer; + + @Override + public byte[] serialize(Chunk chunk) { + 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 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 new file mode 100644 index 0000000..20595a4 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/serialization/RegionReaderWriter.java @@ -0,0 +1,56 @@ +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())); + 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 ++) { + 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/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 new file mode 100644 index 0000000..6c39781 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/world/CubicWorld.java @@ -0,0 +1,130 @@ +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; +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; +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; + private final int seed; + private volatile WarpPosition warpPosition; + private final transient Object spawnLocationLock = new Object(); + private final Map> nbtTagMap = new HashMap<>(); + @Autowired + private RegionManager regionManager; + @Getter@Setter + private String name; + + public CubicWorld(UUID worldId, int seed) { + this.worldId = worldId; + this.seed = seed; + } + + public CubicWorld(int seed) { + this.worldId = UUID.randomUUID(); + this.seed = seed; + } + + public CubicWorld(UUID worldId) { + this.worldId = worldId; + this.seed = 0; + } + + public CubicWorld () { + this.worldId = UUID.randomUUID(); + this.seed = 0; + } + + @Override + public IWorldType getWorldType() { + return null; + } + + @Override + public WarpPosition getSpawn() { + 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)); + } + } + } + return warpPosition; + } + + @Override + public void setSpawn(WarpPosition warpPosition) { + synchronized (spawnLocationLock) { + this.warpPosition = warpPosition; + } + } + + @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; + } + + @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(); + } +} 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(); + } + } + +} diff --git a/generated_world/src/main/java/mc/world/generated_world/world/Temperature.java b/generated_world/src/main/java/mc/world/generated_world/world/Temperature.java new file mode 100644 index 0000000..52b48c3 --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/world/Temperature.java @@ -0,0 +1,9 @@ +package mc.world.generated_world.world; + +public enum Temperature { + FROST, + COLD, + WARM, + HOT, + HOTTEST +} diff --git a/generated_world/src/main/java/mc/world/generated_world/world/Wetness.java b/generated_world/src/main/java/mc/world/generated_world/world/Wetness.java new file mode 100644 index 0000000..a1ed1ce --- /dev/null +++ b/generated_world/src/main/java/mc/world/generated_world/world/Wetness.java @@ -0,0 +1,10 @@ +package mc.world.generated_world.world; + +public enum Wetness { + DRIEST, + DRY, + WET, + WETTER, + WETTEST, + WATER +} 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 @@ + + + + + + + + + + + + + + + + + + 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..a99a251 --- /dev/null +++ b/generated_world/src/test/java/mc/world/generated_world/SeedRandomGeneratorTest.java @@ -0,0 +1,93 @@ +package mc.world.generated_world; + +import mc.world.generated_world.generator.SeedRandomGenerator; +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 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; + 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); + 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); + } + + @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 diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/ByteArrayOutputNetStream.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/ByteArrayOutputNetStream.java similarity index 56% rename from proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/ByteArrayOutputNetStream.java rename to proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/ByteArrayOutputNetStream.java index e3248d6..15810b7 100644 --- a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/ByteArrayOutputNetStream.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/ByteArrayOutputNetStream.java @@ -2,65 +2,13 @@ * DmitriyMX * 2018-06-10 */ -package mc.core.network.proto_1_12_2.netty.wrappers; - -import mc.core.network.proto_1_12_2.NetStream_p340; +package mc.core.network.proto_1_12_2; import java.io.ByteArrayOutputStream; -public class ByteArrayOutputNetStream extends NetStream_p340 { +public class ByteArrayOutputNetStream extends NetOutputStream_p340 { private ByteArrayOutputStream baos = new ByteArrayOutputStream(); - @Override - public boolean readBoolean() { - throw new UnsupportedOperationException(); - } - - @Override - public byte readByte() { - throw new UnsupportedOperationException(); - } - - @Override - public void readBytes(byte[] buffer) { - throw new UnsupportedOperationException(); - } - - @Override - public int readUnsignedByte() { - throw new UnsupportedOperationException(); - } - - @Override - public int readUnsignedShort() { - throw new UnsupportedOperationException(); - } - - @Override - public short readShort() { - throw new UnsupportedOperationException(); - } - - @Override - public int readInt() { - throw new UnsupportedOperationException(); - } - - @Override - public long readLong() { - throw new UnsupportedOperationException(); - } - - @Override - public float readFloat() { - throw new UnsupportedOperationException(); - } - - @Override - public double readDouble() { - throw new UnsupportedOperationException(); - } - @Override public void writeBoolean(boolean value) { baos.write(value ? 1 : 0); @@ -117,11 +65,6 @@ public class ByteArrayOutputNetStream extends NetStream_p340 { writeLong(Double.doubleToLongBits(value)); } - @Override - public void skipBytes(int count) { - throw new UnsupportedOperationException(); - } - public byte[] toByteArray() { return baos.toByteArray(); } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetInputStream_p340.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetInputStream_p340.java new file mode 100644 index 0000000..418f9aa --- /dev/null +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetInputStream_p340.java @@ -0,0 +1,52 @@ +/* + * DmitriyMX + * 2018-07-25 + */ +package mc.core.network.proto_1_12_2; + +import lombok.extern.slf4j.Slf4j; +import mc.core.network.NetInputStream; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +@Slf4j +public abstract class NetInputStream_p340 extends NetInputStream { + @Override + public int readVarInt() { + int numRead = 0; + int result = 0; + byte read; + do { + read = readByte(); + int value = (read & 0b01111111); + result |= (value << (7 * numRead)); + + numRead++; + if (numRead > 5) { + log.warn("VarInt is too big"); + break; + } + } while ((read & 0b10000000) != 0); + + return result; + } + + @Override + public String readString() { + int size = readVarInt(); + if (size == 0) { + log.warn("String zero length??"); + return ""; + } + + byte[] bytes = new byte[size]; + readBytes(bytes); + return new String(bytes, StandardCharsets.UTF_8); + } + + @Override + public UUID readUUID() { + return new UUID(readLong(), readLong()); + } +} diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetStream_p340.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetOutputStream_p340.java similarity index 56% rename from proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetStream_p340.java rename to proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetOutputStream_p340.java index b1ebdc9..ea609cf 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetStream_p340.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/NetOutputStream_p340.java @@ -1,37 +1,17 @@ /* * DmitriyMX - * 2018-06-10 + * 2018-07-25 */ package mc.core.network.proto_1_12_2; import lombok.extern.slf4j.Slf4j; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import java.nio.charset.StandardCharsets; import java.util.UUID; @Slf4j -public abstract class NetStream_p340 extends NetStream { - @Override - public int readVarInt() { - int numRead = 0; - int result = 0; - byte read; - do { - read = readByte(); - int value = (read & 0b01111111); - result |= (value << (7 * numRead)); - - numRead++; - if (numRead > 5) { - log.warn("VarInt is too big"); - break; - } - } while ((read & 0b10000000) != 0); - - return result; - } - +public abstract class NetOutputStream_p340 extends NetOutputStream { @Override public void writeVarInt(int value) { do { @@ -45,19 +25,6 @@ public abstract class NetStream_p340 extends NetStream { } while (value != 0); } - @Override - public String readString() { - int size = readVarInt(); - if (size == 0) { - log.warn("String zero length??"); - return ""; - } - - byte[] bytes = new byte[size]; - readBytes(bytes); - return new String(bytes, StandardCharsets.UTF_8); - } - @Override public void writeString(String value) { if (value.length() > Short.MAX_VALUE) { @@ -72,11 +39,6 @@ public abstract class NetStream_p340 extends NetStream { } } - @Override - public UUID readUUID() { - return new UUID(readLong(), readLong()); - } - @Override public void writeUUID(UUID uuid) { writeLong(uuid.getMostSignificantBits()); diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/State.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/State.java index 9c32f60..237aa4f 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/State.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/State.java @@ -85,6 +85,7 @@ public enum State { .put(BossBarPacket.class, 0x0C) .put(ChatMessageServerPacket.class, 0x0F) .put(PluginMessagePacket.class, 0x18) + .put(ChangeGameState.class, 0x1E) .put(KeepAlivePacket.class, 0x1F) .put(JoinGamePacket.class, 0x23) .put(PlayerAbilitiesPacket.class, 0x2C) diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/AnimationPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/AnimationPacket.java index b333bc5..be82f07 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/AnimationPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/AnimationPacket.java @@ -5,13 +5,13 @@ package mc.core.network.proto_1_12_2.packets; import mc.core.network.CSPacket; -import mc.core.network.NetStream; +import mc.core.network.NetInputStream; public class AnimationPacket implements CSPacket { private int handAnimation; @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { this.handAnimation = netStream.readVarInt(); } } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/BossBarPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/BossBarPacket.java index 6b1cfdc..127f124 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/BossBarPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/BossBarPacket.java @@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets; import lombok.Data; import lombok.Setter; import lombok.ToString; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; import mc.core.network.proto_1_12_2.serializers.TextSerializer; import mc.core.text.Text; @@ -63,7 +63,7 @@ public class BossBarPacket implements SCPacket { private BarData barData; @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeUUID(uuid); netStream.writeVarInt(action); diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ChangeGameState.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ChangeGameState.java new file mode 100644 index 0000000..e4d1169 --- /dev/null +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ChangeGameState.java @@ -0,0 +1,36 @@ +/* + * DmitriyMX + * 2018-07-27 + */ +package mc.core.network.proto_1_12_2.packets; + +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import mc.core.network.NetOutputStream; +import mc.core.network.SCPacket; + +@Setter +public class ChangeGameState implements SCPacket { + @RequiredArgsConstructor + public enum Reason { + INVALID_BED(0), // Would be used to switch between messages, but the only used message is 0 for invalid bed (wat?) + RAINING_END(1), + RAINING_BEGIN(2), + CHANGE_GAMEMODE(3), // 0: Survival, 1: Creative, 2: Adventure, 3: Spectator + ARROW_HITTING_PLAYER(6), // Appears to be played when an arrow strikes another player in Multiplayer + FADE_VALUE(7), // The current darkness value. 1 = Dark, 0 = Bright, Setting the value higher causes the game to change color and freeze + FADE_TIME(8), // Time in ticks for the sky to fade + GUARDIAN_APPEARANCE(10); // Play elder guardian mob appearance (effect and sound) + + private final int id; + } + + private Reason reason; + private float value; + + @Override + public void writeSelf(NetOutputStream netStream) { + netStream.writeUnsignedByte(reason.id); + netStream.writeFloat(value); + } +} diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ChatMessageClientPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ChatMessageClientPacket.java index 9e84224..70aa84a 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ChatMessageClientPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ChatMessageClientPacket.java @@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets; import lombok.Getter; import lombok.ToString; import mc.core.network.CSPacket; -import mc.core.network.NetStream; +import mc.core.network.NetInputStream; @Getter @ToString @@ -15,7 +15,7 @@ public class ChatMessageClientPacket implements CSPacket { private String message; @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { this.message = netStream.readString(); } } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ChatMessageServerPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ChatMessageServerPacket.java index 03ae3b4..0f20c2e 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ChatMessageServerPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ChatMessageServerPacket.java @@ -9,7 +9,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; import mc.core.chat.MessageType; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; import mc.core.network.proto_1_12_2.serializers.TextSerializer; import mc.core.text.Text; @@ -23,7 +23,7 @@ public class ChatMessageServerPacket implements SCPacket { private MessageType type; @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeString(TextSerializer.serialize(text).toString()); netStream.writeByte(type.getId()); } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ClientSettingsPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ClientSettingsPacket.java index 8a2072d..6cb98bd 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ClientSettingsPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/ClientSettingsPacket.java @@ -8,7 +8,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; import mc.core.network.CSPacket; -import mc.core.network.NetStream; +import mc.core.network.NetInputStream; @NoArgsConstructor @Getter @@ -28,7 +28,7 @@ public class ClientSettingsPacket implements CSPacket { private int mainHand; @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { locale = netStream.readString(); viewDistance = netStream.readByte(); chatMode = netStream.readVarInt(); diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/DisconnectPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/DisconnectPacket.java index aaf9df4..00568ad 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/DisconnectPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/DisconnectPacket.java @@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.Setter; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; import mc.core.network.proto_1_12_2.serializers.TextSerializer; import mc.core.text.Text; @@ -19,7 +19,7 @@ public class DisconnectPacket implements SCPacket { private Text reason; @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeString(TextSerializer.serialize(reason).toString()); } } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/EncryptionRequestPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/EncryptionRequestPacket.java index dd7b8d8..33a2f54 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/EncryptionRequestPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/EncryptionRequestPacket.java @@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.Setter; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; import java.security.PublicKey; @@ -21,7 +21,7 @@ public class EncryptionRequestPacket implements SCPacket { private byte[] verifyToken; @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeString(serverId); byte[] bytes = publicKey.getEncoded(); netStream.writeVarInt(bytes.length); diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/HandshakePacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/HandshakePacket.java index 8933818..a0a2ab2 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/HandshakePacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/HandshakePacket.java @@ -8,7 +8,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; import mc.core.network.CSPacket; -import mc.core.network.NetStream; +import mc.core.network.NetInputStream; import mc.core.network.proto_1_12_2.State; @NoArgsConstructor @@ -21,7 +21,7 @@ public class HandshakePacket implements CSPacket { private State nextState; @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { this.protocolVersion = netStream.readVarInt(); this.address = netStream.readString(); this.serverPort = netStream.readUnsignedShort(); diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/HeldItemChangePacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/HeldItemChangePacket.java index 3ae989a..ca9f073 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/HeldItemChangePacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/HeldItemChangePacket.java @@ -5,13 +5,13 @@ package mc.core.network.proto_1_12_2.packets; import mc.core.network.CSPacket; -import mc.core.network.NetStream; +import mc.core.network.NetInputStream; public class HeldItemChangePacket implements CSPacket { private int slot; @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { this.slot = netStream.readShort(); } } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/JoinGamePacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/JoinGamePacket.java index c1592c1..6000085 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/JoinGamePacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/JoinGamePacket.java @@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; import mc.core.player.PlayerMode; @@ -22,7 +22,7 @@ public class JoinGamePacket implements SCPacket { private String levelType; @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeInt(entityId); netStream.writeUnsignedByte(mode.getId()); netStream.writeInt(dimension); diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/KeepAlivePacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/KeepAlivePacket.java index 7a8fa44..c41ae76 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/KeepAlivePacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/KeepAlivePacket.java @@ -8,9 +8,7 @@ import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; -import mc.core.network.CSPacket; -import mc.core.network.NetStream; -import mc.core.network.SCPacket; +import mc.core.network.*; @AllArgsConstructor @NoArgsConstructor @@ -20,12 +18,12 @@ public class KeepAlivePacket implements CSPacket, SCPacket { private long payload; @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { this.payload = netStream.readLong(); } @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeLong(this.payload); } } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/LoginStartPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/LoginStartPacket.java index a25627a..e3654c7 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/LoginStartPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/LoginStartPacket.java @@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets; import lombok.Getter; import lombok.ToString; import mc.core.network.CSPacket; -import mc.core.network.NetStream; +import mc.core.network.NetInputStream; @Getter @ToString @@ -15,7 +15,7 @@ public class LoginStartPacket implements CSPacket { private String playerName; @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { this.playerName = netStream.readString(); } } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/LoginSuccessPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/LoginSuccessPacket.java index af059ce..376d7a1 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/LoginSuccessPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/LoginSuccessPacket.java @@ -8,7 +8,7 @@ import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; import java.util.UUID; @@ -22,7 +22,7 @@ public class LoginSuccessPacket implements SCPacket { private String playerName; @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeString(uuid.toString()); netStream.writeString(playerName); } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PingPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PingPacket.java index 0d03f72..5bd0c25 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PingPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PingPacket.java @@ -5,21 +5,19 @@ package mc.core.network.proto_1_12_2.packets; import lombok.ToString; -import mc.core.network.CSPacket; -import mc.core.network.NetStream; -import mc.core.network.SCPacket; +import mc.core.network.*; @ToString public class PingPacket implements CSPacket, SCPacket { private long payload; @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { this.payload = netStream.readLong(); } @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeLong(payload); } } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerAbilitiesPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerAbilitiesPacket.java index f6355b0..d0397c5 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerAbilitiesPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerAbilitiesPacket.java @@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; @NoArgsConstructor @@ -22,7 +22,7 @@ public class PlayerAbilitiesPacket implements SCPacket { private float fieldOfView = flyingSpeed; @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { byte flag = 0; if (godMode) flag = (byte)(flag | 0x01); if (flying) flag = (byte)(flag | 0x02); diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListHeaderAndFooterPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListHeaderAndFooterPacket.java index 91ae687..8579a1b 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListHeaderAndFooterPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListHeaderAndFooterPacket.java @@ -6,7 +6,7 @@ package mc.core.network.proto_1_12_2.packets; import lombok.Setter; import lombok.ToString; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; import mc.core.network.proto_1_12_2.serializers.TextSerializer; import mc.core.text.Text; @@ -19,7 +19,7 @@ public class PlayerListHeaderAndFooterPacket implements SCPacket { private Text footer; @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { if (header == null) { netStream.writeString("{\"translate\":\"\"}"); } else { diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListItemPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListItemPacket.java index f5f72c4..b8a651d 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListItemPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerListItemPacket.java @@ -9,7 +9,7 @@ import lombok.Getter; import lombok.Setter; import lombok.ToString; import lombok.extern.slf4j.Slf4j; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; import mc.core.network.proto_1_12_2.serializers.TextSerializer; import mc.core.player.PlayerMode; @@ -44,7 +44,7 @@ public class PlayerListItemPacket implements SCPacket { private List listPlayers = new ArrayList<>(); @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeVarInt(action); netStream.writeVarInt(listPlayers.size()); diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerPositionAndLookPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerPositionAndLookPacket.java index ddc0dd2..4133bbe 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerPositionAndLookPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PlayerPositionAndLookPacket.java @@ -9,9 +9,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; import mc.core.Location; -import mc.core.network.CSPacket; -import mc.core.network.NetStream; -import mc.core.network.SCPacket; +import mc.core.network.*; import mc.core.player.Look; @NoArgsConstructor @@ -25,7 +23,7 @@ public class PlayerPositionAndLookPacket implements SCPacket, CSPacket { private boolean onGround = false; @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeDouble(location.getX()); netStream.writeDouble(location.getY()); netStream.writeDouble(location.getZ()); @@ -42,7 +40,7 @@ public class PlayerPositionAndLookPacket implements SCPacket, CSPacket { } @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { this.location = new Location( netStream.readDouble(), netStream.readDouble(), diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PluginMessagePacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PluginMessagePacket.java index 9af5f84..b10208d 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PluginMessagePacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/PluginMessagePacket.java @@ -5,9 +5,7 @@ package mc.core.network.proto_1_12_2.packets; import lombok.*; -import mc.core.network.CSPacket; -import mc.core.network.NetStream; -import mc.core.network.SCPacket; +import mc.core.network.*; @AllArgsConstructor @NoArgsConstructor @@ -19,14 +17,14 @@ public class PluginMessagePacket implements SCPacket, CSPacket { private byte[] data; @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { channelName = netStream.readString(); data = new byte[netStream.getDataSize() - channelName.getBytes().length - 1]; netStream.readBytes(data); } @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeString(channelName); netStream.writeBytes(data); } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/SpawnPositionPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/SpawnPositionPacket.java index 488d126..8b11502 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/SpawnPositionPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/SpawnPositionPacket.java @@ -9,9 +9,8 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; import mc.core.Location; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; -import mc.core.network.proto_1_12_2.serializers.LocationSerializer; @AllArgsConstructor @NoArgsConstructor @@ -21,7 +20,7 @@ public class SpawnPositionPacket implements SCPacket { private Location location; @Override - public void writeSelf(NetStream netStream) { - netStream.writeLong(LocationSerializer.serialize(location)); + public void writeSelf(NetOutputStream netStream) { + netStream.writeLong(location.toLong()); } } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusRequestPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusRequestPacket.java index 0d3cb2f..b57c56a 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusRequestPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusRequestPacket.java @@ -6,11 +6,11 @@ package mc.core.network.proto_1_12_2.packets; import lombok.ToString; import mc.core.network.CSPacket; -import mc.core.network.NetStream; +import mc.core.network.NetInputStream; @ToString public class StatusRequestPacket implements CSPacket { @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { } } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusResponsePacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusResponsePacket.java index 959575d..3505581 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusResponsePacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/StatusResponsePacket.java @@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets; import com.google.gson.JsonObject; import lombok.Setter; import lombok.ToString; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; @Setter @@ -29,7 +29,7 @@ public class StatusResponsePacket implements SCPacket { private byte[] faviconBase64; @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { JsonObject playersObj = new JsonObject(); playersObj.addProperty("max", maxOnline); playersObj.addProperty("online", online); diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TabCompletePacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TabCompletePacket.java index f3a202e..3251bbb 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TabCompletePacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TabCompletePacket.java @@ -6,8 +6,7 @@ package mc.core.network.proto_1_12_2.packets; import mc.core.Location; import mc.core.network.CSPacket; -import mc.core.network.NetStream; -import mc.core.network.proto_1_12_2.serializers.LocationSerializer; +import mc.core.network.NetInputStream; public class TabCompletePacket implements CSPacket { private String text; @@ -16,13 +15,13 @@ public class TabCompletePacket implements CSPacket { private Location location; @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { this.text = netStream.readString(); this.assumeCommand = netStream.readBoolean(); this.hasPosition = netStream.readBoolean(); if (this.hasPosition) { - this.location = LocationSerializer.deserialize(netStream.readLong()); + this.location = new Location(netStream.readLong()); } } } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TeleportConfirmPacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TeleportConfirmPacket.java index a1fe944..356b6a3 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TeleportConfirmPacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TeleportConfirmPacket.java @@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets; import lombok.Getter; import lombok.ToString; import mc.core.network.CSPacket; -import mc.core.network.NetStream; +import mc.core.network.NetInputStream; @Getter @ToString @@ -15,7 +15,7 @@ public class TeleportConfirmPacket implements CSPacket { private int teleportId; @Override - public void readSelf(NetStream netStream) { + public void readSelf(NetInputStream netStream) { teleportId = netStream.readVarInt(); } } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TimeUpdatePacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TimeUpdatePacket.java index 1a95d8c..e17160e 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TimeUpdatePacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TimeUpdatePacket.java @@ -8,7 +8,7 @@ import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; @AllArgsConstructor @@ -20,7 +20,7 @@ public class TimeUpdatePacket implements SCPacket { private long worldage; @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeLong(worldage); netStream.writeLong(time); } diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TitlePacket.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TitlePacket.java index 3cd4256..3b426f1 100644 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TitlePacket.java +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/packets/TitlePacket.java @@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets; import lombok.RequiredArgsConstructor; import lombok.Setter; import lombok.ToString; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; import mc.core.network.proto_1_12_2.serializers.TextSerializer; import mc.core.text.Text; @@ -91,7 +91,7 @@ public class TitlePacket implements SCPacket { } @Override - public void writeSelf(NetStream netStream) { + public void writeSelf(NetOutputStream netStream) { netStream.writeVarInt(this.action); switch (this.action) { diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/serializers/LocationSerializer.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/serializers/LocationSerializer.java deleted file mode 100644 index 3fd1318..0000000 --- a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/serializers/LocationSerializer.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * DmitriyMX - * 2018-06-11 - */ -package mc.core.network.proto_1_12_2.serializers; - -import mc.core.Location; - -public class LocationSerializer { - private static int floor_double(double value) { - int i = (int)value; - return value < (double)i ? i - 1 : i; - } - - public static long serialize(Location location) { - return ((floor_double(location.getX()) & 0x3FFFFFF) << 38) - | ((floor_double(location.getY()) & 0xFFF) << 26) - | (floor_double(location.getZ()) & 0x3FFFFFF); - } - - public static Location deserialize(long location) { - return new Location( - location >> 38, - (location >> 26) & 0xFFF, - location << 38 >> 38); - } -} diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketDecoder.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketDecoder.java index 561a058..dc1090b 100644 --- a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketDecoder.java +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketDecoder.java @@ -9,9 +9,9 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; import mc.core.network.CSPacket; -import mc.core.network.NetStream; +import mc.core.network.NetInputStream; import mc.core.network.proto_1_12_2.State; -import mc.core.network.proto_1_12_2.netty.wrappers.WrapperNetStream; +import mc.core.network.proto_1_12_2.netty.wrappers.WrapperNetInputStream; import java.util.List; @@ -36,7 +36,7 @@ public class PacketDecoder extends ByteToMessageDecoder { log.debug("ByteBuf readableBytes: {}", in.readableBytes()); State state = ctx.channel().attr(ATTR_STATE).get(); - NetStream netStream = new WrapperNetStream(in); + NetInputStream netStream = new WrapperNetInputStream(in); int packetSize = netStream.readVarInt(); log.debug("Packet size: {}", packetSize); diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketEncoder.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketEncoder.java index 4a9b9ed..f2a9a9d 100644 --- a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketEncoder.java +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PacketEncoder.java @@ -8,11 +8,11 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import lombok.extern.slf4j.Slf4j; -import mc.core.network.NetStream; +import mc.core.network.NetOutputStream; import mc.core.network.SCPacket; import mc.core.network.proto_1_12_2.State; -import mc.core.network.proto_1_12_2.netty.wrappers.ByteArrayOutputNetStream; -import mc.core.network.proto_1_12_2.netty.wrappers.WrapperNetStream; +import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream; +import mc.core.network.proto_1_12_2.netty.wrappers.WrapperNetOutputStream; import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE; @@ -41,10 +41,10 @@ public class PacketEncoder extends MessageToByteEncoder { log.debug("Send {}:{}", state, packet); - NetStream netStream = new ByteArrayOutputNetStream(); + NetOutputStream netStream = new ByteArrayOutputNetStream(); packet.writeSelf(netStream); byte[] bytes = ((ByteArrayOutputNetStream) netStream).toByteArray(); - netStream = new WrapperNetStream(out); + netStream = new WrapperNetOutputStream(out); netStream.writeVarInt(bytes.length + sizeVarInt(id)); netStream.writeVarInt(id); diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetStream.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetInputStream.java similarity index 55% rename from proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetStream.java rename to proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetInputStream.java index 19d688c..215fc68 100644 --- a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetStream.java +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetInputStream.java @@ -1,17 +1,17 @@ /* * DmitriyMX - * 2018-04-08 + * 2018-07-25 */ package mc.core.network.proto_1_12_2.netty.wrappers; import io.netty.buffer.ByteBuf; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import mc.core.network.proto_1_12_2.NetStream_p340; +import mc.core.network.proto_1_12_2.NetInputStream_p340; @Slf4j @RequiredArgsConstructor -public class WrapperNetStream extends NetStream_p340 { +public class WrapperNetInputStream extends NetInputStream_p340 { private final ByteBuf byteBuf; @Override @@ -64,51 +64,6 @@ public class WrapperNetStream extends NetStream_p340 { return byteBuf.readDouble(); } - @Override - public void writeBoolean(boolean value) { - byteBuf.writeBoolean(value); - } - - @Override - public void writeByte(int value) { - byteBuf.writeByte(value); - } - - @Override - public void writeUnsignedByte(int value) { - byteBuf.writeByte((byte)(value & 0xFF)); - } - - @Override - public void writeBytes(byte[] buffer) { - byteBuf.writeBytes(buffer); - } - - @Override - public void writeShort(int value) { - byteBuf.writeShort(value); - } - - @Override - public void writeInt(int value) { - byteBuf.writeInt(value); - } - - @Override - public void writeLong(long value) { - byteBuf.writeLong(value); - } - - @Override - public void writeFloat(float value) { - byteBuf.writeFloat(value); - } - - @Override - public void writeDouble(double value) { - byteBuf.writeDouble(value); - } - @Override public void skipBytes(int count) { byteBuf.skipBytes(count); diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetOutputStream.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetOutputStream.java new file mode 100644 index 0000000..539dc2c --- /dev/null +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/wrappers/WrapperNetOutputStream.java @@ -0,0 +1,61 @@ +/* + * DmitriyMX + * 2018-07-25 + */ +package mc.core.network.proto_1_12_2.netty.wrappers; + +import io.netty.buffer.ByteBuf; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import mc.core.network.proto_1_12_2.NetOutputStream_p340; + +@Slf4j +@RequiredArgsConstructor +public class WrapperNetOutputStream extends NetOutputStream_p340 { + private final ByteBuf byteBuf; + + @Override + public void writeBoolean(boolean value) { + byteBuf.writeBoolean(value); + } + + @Override + public void writeByte(int value) { + byteBuf.writeByte(value); + } + + @Override + public void writeUnsignedByte(int value) { + byteBuf.writeByte((byte)(value & 0xFF)); + } + + @Override + public void writeBytes(byte[] buffer) { + byteBuf.writeBytes(buffer); + } + + @Override + public void writeShort(int value) { + byteBuf.writeShort(value); + } + + @Override + public void writeInt(int value) { + byteBuf.writeInt(value); + } + + @Override + public void writeLong(long value) { + byteBuf.writeLong(value); + } + + @Override + public void writeFloat(float value) { + byteBuf.writeFloat(value); + } + + @Override + public void writeDouble(double value) { + byteBuf.writeDouble(value); + } +} diff --git a/settings.gradle b/settings.gradle index 5f84ba5..bc4f7bf 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,5 +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('event-loop') - +include('generated_world') +include('event-loop') \ No newline at end of file