Archived
0

Merge branch 'develop' into anarok/loop-3-merge

# Conflicts:
#	build.gradle
#	settings.gradle
This commit is contained in:
Daniil
2018-08-05 00:11:17 +07:00
85 changed files with 2520 additions and 287 deletions

View File

@@ -0,0 +1,8 @@
package mc.core;
public enum Direction {
NORTH,
EAST,
WEST,
SOUTH
}

View File

@@ -7,11 +7,18 @@ package mc.core;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import java.io.Serializable;
@AllArgsConstructor @AllArgsConstructor
@Data @Data
public class Location { public class Location implements Serializable{
private double x, y, z; 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) { public static Location copyOf(Location location) {
return new Location( return new Location(
location.x, 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) { public void set(Location location) {
this.x = location.x; this.x = location.x;
this.y = location.y; this.y = location.y;
this.z = location.z; this.z = location.z;
} }
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) { public Location diff(Location location) {
return new Location( return new Location(
this.x - location.x, this.x - location.x,
@@ -45,4 +66,10 @@ public class Location {
public int getBlockZ() { public int getBlockZ() {
return (int) z; return (int) z;
} }
public long toLong() {
return ((floor_double(x) & 0x3FFFFFF) << 38)
| ((floor_double(y) & 0xFFF) << 26)
| (floor_double(z) & 0x3FFFFFF);
}
} }

View File

@@ -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;
}

View File

@@ -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<String, Tag<?>> 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<Tag<?>> tagStream() {
return nbtTagsMap.values().stream();
}
}

View File

@@ -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();
}

View File

@@ -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));
}
}
}

View File

@@ -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;
}
}

View File

@@ -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<Tag<?>> tagStream();
}

View File

@@ -8,5 +8,5 @@ package mc.core.network;
* Пакеты Client->Server * Пакеты Client->Server
*/ */
public interface CSPacket { public interface CSPacket {
void readSelf(NetStream netStream); void readSelf(NetInputStream netStream);
} }

View File

@@ -1,6 +1,6 @@
/* /*
* DmitriyMX <dimon550@gmail.com> * DmitriyMX <dimon550@gmail.com>
* 2018-03-28 * 2018-07-25
*/ */
package mc.core.network; package mc.core.network;
@@ -9,7 +9,7 @@ import lombok.Setter;
import java.util.UUID; import java.util.UUID;
public abstract class NetStream { public abstract class NetInputStream {
@Getter @Getter
@Setter @Setter
private int dataSize; private int dataSize;
@@ -28,18 +28,5 @@ public abstract class NetStream {
public abstract String readString(); public abstract String readString();
public abstract UUID readUUID(); 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); public abstract void skipBytes(int count);
} }

View File

@@ -0,0 +1,22 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 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);
}

View File

@@ -8,5 +8,5 @@ package mc.core.network;
* Пакеты Server->Client * Пакеты Server->Client
*/ */
public interface SCPacket { public interface SCPacket {
void writeSelf(NetStream netStream); void writeSelf(NetOutputStream netStream);
} }

View File

@@ -7,9 +7,11 @@ package mc.core.player;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import java.io.Serializable;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
public class Look { public class Look implements Serializable{
private float yaw, pitch; private float yaw, pitch;
public void set(Look look) { public void set(Look look) {

View File

@@ -0,0 +1,5 @@
package mc.core.serialization;
public interface Deserializer<T> {
T deserialize (byte[] bytes);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,5 @@
package mc.core.serialization;
public interface Serializer<T> {
byte[] serialize (T t);
}

View File

@@ -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();
}
}

View File

@@ -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];
}
}

View File

@@ -4,8 +4,25 @@
*/ */
package mc.core.world; 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 */ /* 16x16x16 */
public interface Chunk { public interface Chunk extends Serializable{
int getBlockType(int x, int y, int z); int getBlockType(int x, int y, int z);
void setBlockType(int x, int y, int z, int type); 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); int getAddition(int x, int y, int z);
void setAddition(int x, int y, int z, int value); void setAddition(int x, int y, int z, int value);
int getBiome(int x, int z); Biome getBiome(int x, int z);
void setBiome(int x, int z, int value); 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);
} }

View File

@@ -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<Chunk> 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);
}

View File

@@ -0,0 +1,6 @@
package mc.core.world;
public interface IWorldType {
String name();
String description();
}

View File

@@ -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<Chunk> chunkSerializer, IRegionReaderWriter regionReaderWritter) throws IOException;
}

View File

@@ -5,11 +5,58 @@
package mc.core.world; package mc.core.world;
import mc.core.Location; import mc.core.Location;
import mc.core.WarpPosition;
import mc.core.nbt.Taggable;
public interface World { import java.io.Serializable;
Location getSpawn(); import java.util.UUID;
void setSpawn(Location location);
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);
} }

View File

@@ -0,0 +1,6 @@
package mc.core.world;
public interface WorldGenerator {
Region generateRegion (int x, int z, World world);
}

View File

@@ -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;
}
}

View File

@@ -4,25 +4,71 @@
*/ */
package mc.world.flat; package mc.world.flat;
import com.flowpowered.nbt.Tag;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import mc.core.Location; import mc.core.Location;
import mc.core.world.Chunk; import mc.core.WarpPosition;
import mc.core.world.World; import mc.core.player.Look;
import mc.core.world.*;
import java.util.UUID;
import java.util.stream.Stream;
public class FlatWorld implements World { public class FlatWorld implements World {
@Getter@Setter
private UUID worldId = UUID.fromString("00000000-0000-0000-C000-000000000046");
@Getter@Setter
private String name;
@Getter @Getter
@Setter @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(); private Chunk chunk = new SimpleChunk();
@Override @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; return chunk;
} }
@Override @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<Tag<?>> tagStream() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
} }

View File

@@ -4,6 +4,10 @@
*/ */
package mc.world.flat; package mc.world.flat;
import mc.core.block.Block;
import mc.core.block.BlockFactory;
import mc.core.block.BlockType;
import mc.core.world.Biome;
import mc.core.world.Chunk; import mc.core.world.Chunk;
public class SimpleChunk implements Chunk { public class SimpleChunk implements Chunk {
@@ -62,12 +66,42 @@ public class SimpleChunk implements Chunk {
} }
@Override @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; return 0;
} }
@Override @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);
}
} }

View File

@@ -0,0 +1,3 @@
### System properties:
* `worlds.folder` -- folder where worlds will be located

View File

@@ -0,0 +1,7 @@
group 'mc'
version '1.0-SNAPSHOT'
dependencies {
compile_excludeCopy project(':core')
testCompile group: 'junit', name: 'junit', version: '4.12'
}

View File

@@ -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 () {}
}

View File

@@ -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];
}
}

View File

@@ -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);
}
}

View File

@@ -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<Chunk> 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<Chunk> 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);
}
}
}
}
}
}

View File

@@ -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));
}
}
}

View File

@@ -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;
}
}

View File

@@ -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<Chunk> 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);
}
}
}
}
}
}
}

View File

@@ -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<Block>, Deserializer<Block> {
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;
}
}

View File

@@ -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<Block> 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;
}
}

View File

@@ -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<Chunk> {
@Autowired
private Serializer<Block> blockSerializer;
@Override
public byte[] serialize(Chunk chunk) {
Serializer<Block> 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();
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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<String, Tag<?>> 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<Tag<?>> tagStream() {
return nbtTagMap.values().stream();
}
}

View File

@@ -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();
}
}
}

View File

@@ -0,0 +1,9 @@
package mc.world.generated_world.world;
public enum Temperature {
FROST,
COLD,
WARM,
HOT,
HOTTEST
}

View File

@@ -0,0 +1,10 @@
package mc.world.generated_world.world;
public enum Wetness {
DRIEST,
DRY,
WET,
WETTER,
WETTEST,
WATER
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{HH:mm:ss}] [%-5p] %m%n"/>
</Console>
<RollingFile name="File" fileName="log/log_file.log" filePattern="log/log_file-%d{MM-dd-yyyy}.log.gz">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
<TimeBasedTriggeringPolicy />
</RollingFile>
</Appenders>
<Loggers>
<Root level="Trace">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>

View File

@@ -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"));
}
}

View File

@@ -2,65 +2,13 @@
* DmitriyMX <dimon550@gmail.com> * DmitriyMX <dimon550@gmail.com>
* 2018-06-10 * 2018-06-10
*/ */
package mc.core.network.proto_1_12_2.netty.wrappers; package mc.core.network.proto_1_12_2;
import mc.core.network.proto_1_12_2.NetStream_p340;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
public class ByteArrayOutputNetStream extends NetStream_p340 { public class ByteArrayOutputNetStream extends NetOutputStream_p340 {
private ByteArrayOutputStream baos = new ByteArrayOutputStream(); 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 @Override
public void writeBoolean(boolean value) { public void writeBoolean(boolean value) {
baos.write(value ? 1 : 0); baos.write(value ? 1 : 0);
@@ -117,11 +65,6 @@ public class ByteArrayOutputNetStream extends NetStream_p340 {
writeLong(Double.doubleToLongBits(value)); writeLong(Double.doubleToLongBits(value));
} }
@Override
public void skipBytes(int count) {
throw new UnsupportedOperationException();
}
public byte[] toByteArray() { public byte[] toByteArray() {
return baos.toByteArray(); return baos.toByteArray();
} }

View File

@@ -0,0 +1,52 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 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());
}
}

View File

@@ -1,37 +1,17 @@
/* /*
* DmitriyMX <dimon550@gmail.com> * DmitriyMX <dimon550@gmail.com>
* 2018-06-10 * 2018-07-25
*/ */
package mc.core.network.proto_1_12_2; package mc.core.network.proto_1_12_2;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.UUID; import java.util.UUID;
@Slf4j @Slf4j
public abstract class NetStream_p340 extends NetStream { public abstract class NetOutputStream_p340 extends NetOutputStream {
@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 @Override
public void writeVarInt(int value) { public void writeVarInt(int value) {
do { do {
@@ -45,19 +25,6 @@ public abstract class NetStream_p340 extends NetStream {
} while (value != 0); } 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 @Override
public void writeString(String value) { public void writeString(String value) {
if (value.length() > Short.MAX_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 @Override
public void writeUUID(UUID uuid) { public void writeUUID(UUID uuid) {
writeLong(uuid.getMostSignificantBits()); writeLong(uuid.getMostSignificantBits());

View File

@@ -85,6 +85,7 @@ public enum State {
.put(BossBarPacket.class, 0x0C) .put(BossBarPacket.class, 0x0C)
.put(ChatMessageServerPacket.class, 0x0F) .put(ChatMessageServerPacket.class, 0x0F)
.put(PluginMessagePacket.class, 0x18) .put(PluginMessagePacket.class, 0x18)
.put(ChangeGameState.class, 0x1E)
.put(KeepAlivePacket.class, 0x1F) .put(KeepAlivePacket.class, 0x1F)
.put(JoinGamePacket.class, 0x23) .put(JoinGamePacket.class, 0x23)
.put(PlayerAbilitiesPacket.class, 0x2C) .put(PlayerAbilitiesPacket.class, 0x2C)

View File

@@ -5,13 +5,13 @@
package mc.core.network.proto_1_12_2.packets; package mc.core.network.proto_1_12_2.packets;
import mc.core.network.CSPacket; import mc.core.network.CSPacket;
import mc.core.network.NetStream; import mc.core.network.NetInputStream;
public class AnimationPacket implements CSPacket { public class AnimationPacket implements CSPacket {
private int handAnimation; private int handAnimation;
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
this.handAnimation = netStream.readVarInt(); this.handAnimation = netStream.readVarInt();
} }
} }

View File

@@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets;
import lombok.Data; import lombok.Data;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
import mc.core.network.proto_1_12_2.serializers.TextSerializer; import mc.core.network.proto_1_12_2.serializers.TextSerializer;
import mc.core.text.Text; import mc.core.text.Text;
@@ -63,7 +63,7 @@ public class BossBarPacket implements SCPacket {
private BarData barData; private BarData barData;
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeUUID(uuid); netStream.writeUUID(uuid);
netStream.writeVarInt(action); netStream.writeVarInt(action);

View File

@@ -0,0 +1,36 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 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);
}
}

View File

@@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets;
import lombok.Getter; import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import mc.core.network.CSPacket; import mc.core.network.CSPacket;
import mc.core.network.NetStream; import mc.core.network.NetInputStream;
@Getter @Getter
@ToString @ToString
@@ -15,7 +15,7 @@ public class ChatMessageClientPacket implements CSPacket {
private String message; private String message;
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
this.message = netStream.readString(); this.message = netStream.readString();
} }
} }

View File

@@ -9,7 +9,7 @@ import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import mc.core.chat.MessageType; import mc.core.chat.MessageType;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
import mc.core.network.proto_1_12_2.serializers.TextSerializer; import mc.core.network.proto_1_12_2.serializers.TextSerializer;
import mc.core.text.Text; import mc.core.text.Text;
@@ -23,7 +23,7 @@ public class ChatMessageServerPacket implements SCPacket {
private MessageType type; private MessageType type;
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeString(TextSerializer.serialize(text).toString()); netStream.writeString(TextSerializer.serialize(text).toString());
netStream.writeByte(type.getId()); netStream.writeByte(type.getId());
} }

View File

@@ -8,7 +8,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.ToString; import lombok.ToString;
import mc.core.network.CSPacket; import mc.core.network.CSPacket;
import mc.core.network.NetStream; import mc.core.network.NetInputStream;
@NoArgsConstructor @NoArgsConstructor
@Getter @Getter
@@ -28,7 +28,7 @@ public class ClientSettingsPacket implements CSPacket {
private int mainHand; private int mainHand;
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
locale = netStream.readString(); locale = netStream.readString();
viewDistance = netStream.readByte(); viewDistance = netStream.readByte();
chatMode = netStream.readVarInt(); chatMode = netStream.readVarInt();

View File

@@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
import mc.core.network.proto_1_12_2.serializers.TextSerializer; import mc.core.network.proto_1_12_2.serializers.TextSerializer;
import mc.core.text.Text; import mc.core.text.Text;
@@ -19,7 +19,7 @@ public class DisconnectPacket implements SCPacket {
private Text reason; private Text reason;
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeString(TextSerializer.serialize(reason).toString()); netStream.writeString(TextSerializer.serialize(reason).toString());
} }
} }

View File

@@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
import java.security.PublicKey; import java.security.PublicKey;
@@ -21,7 +21,7 @@ public class EncryptionRequestPacket implements SCPacket {
private byte[] verifyToken; private byte[] verifyToken;
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeString(serverId); netStream.writeString(serverId);
byte[] bytes = publicKey.getEncoded(); byte[] bytes = publicKey.getEncoded();
netStream.writeVarInt(bytes.length); netStream.writeVarInt(bytes.length);

View File

@@ -8,7 +8,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.ToString; import lombok.ToString;
import mc.core.network.CSPacket; 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.State;
@NoArgsConstructor @NoArgsConstructor
@@ -21,7 +21,7 @@ public class HandshakePacket implements CSPacket {
private State nextState; private State nextState;
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
this.protocolVersion = netStream.readVarInt(); this.protocolVersion = netStream.readVarInt();
this.address = netStream.readString(); this.address = netStream.readString();
this.serverPort = netStream.readUnsignedShort(); this.serverPort = netStream.readUnsignedShort();

View File

@@ -5,13 +5,13 @@
package mc.core.network.proto_1_12_2.packets; package mc.core.network.proto_1_12_2.packets;
import mc.core.network.CSPacket; import mc.core.network.CSPacket;
import mc.core.network.NetStream; import mc.core.network.NetInputStream;
public class HeldItemChangePacket implements CSPacket { public class HeldItemChangePacket implements CSPacket {
private int slot; private int slot;
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
this.slot = netStream.readShort(); this.slot = netStream.readShort();
} }
} }

View File

@@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
import mc.core.player.PlayerMode; import mc.core.player.PlayerMode;
@@ -22,7 +22,7 @@ public class JoinGamePacket implements SCPacket {
private String levelType; private String levelType;
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeInt(entityId); netStream.writeInt(entityId);
netStream.writeUnsignedByte(mode.getId()); netStream.writeUnsignedByte(mode.getId());
netStream.writeInt(dimension); netStream.writeInt(dimension);

View File

@@ -8,9 +8,7 @@ import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import mc.core.network.CSPacket; import mc.core.network.*;
import mc.core.network.NetStream;
import mc.core.network.SCPacket;
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@@ -20,12 +18,12 @@ public class KeepAlivePacket implements CSPacket, SCPacket {
private long payload; private long payload;
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
this.payload = netStream.readLong(); this.payload = netStream.readLong();
} }
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeLong(this.payload); netStream.writeLong(this.payload);
} }
} }

View File

@@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets;
import lombok.Getter; import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import mc.core.network.CSPacket; import mc.core.network.CSPacket;
import mc.core.network.NetStream; import mc.core.network.NetInputStream;
@Getter @Getter
@ToString @ToString
@@ -15,7 +15,7 @@ public class LoginStartPacket implements CSPacket {
private String playerName; private String playerName;
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
this.playerName = netStream.readString(); this.playerName = netStream.readString();
} }
} }

View File

@@ -8,7 +8,7 @@ import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
import java.util.UUID; import java.util.UUID;
@@ -22,7 +22,7 @@ public class LoginSuccessPacket implements SCPacket {
private String playerName; private String playerName;
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeString(uuid.toString()); netStream.writeString(uuid.toString());
netStream.writeString(playerName); netStream.writeString(playerName);
} }

View File

@@ -5,21 +5,19 @@
package mc.core.network.proto_1_12_2.packets; package mc.core.network.proto_1_12_2.packets;
import lombok.ToString; import lombok.ToString;
import mc.core.network.CSPacket; import mc.core.network.*;
import mc.core.network.NetStream;
import mc.core.network.SCPacket;
@ToString @ToString
public class PingPacket implements CSPacket, SCPacket { public class PingPacket implements CSPacket, SCPacket {
private long payload; private long payload;
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
this.payload = netStream.readLong(); this.payload = netStream.readLong();
} }
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeLong(payload); netStream.writeLong(payload);
} }
} }

View File

@@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
@NoArgsConstructor @NoArgsConstructor
@@ -22,7 +22,7 @@ public class PlayerAbilitiesPacket implements SCPacket {
private float fieldOfView = flyingSpeed; private float fieldOfView = flyingSpeed;
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
byte flag = 0; byte flag = 0;
if (godMode) flag = (byte)(flag | 0x01); if (godMode) flag = (byte)(flag | 0x01);
if (flying) flag = (byte)(flag | 0x02); if (flying) flag = (byte)(flag | 0x02);

View File

@@ -6,7 +6,7 @@ package mc.core.network.proto_1_12_2.packets;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
import mc.core.network.proto_1_12_2.serializers.TextSerializer; import mc.core.network.proto_1_12_2.serializers.TextSerializer;
import mc.core.text.Text; import mc.core.text.Text;
@@ -19,7 +19,7 @@ public class PlayerListHeaderAndFooterPacket implements SCPacket {
private Text footer; private Text footer;
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
if (header == null) { if (header == null) {
netStream.writeString("{\"translate\":\"\"}"); netStream.writeString("{\"translate\":\"\"}");
} else { } else {

View File

@@ -9,7 +9,7 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
import mc.core.network.proto_1_12_2.serializers.TextSerializer; import mc.core.network.proto_1_12_2.serializers.TextSerializer;
import mc.core.player.PlayerMode; import mc.core.player.PlayerMode;
@@ -44,7 +44,7 @@ public class PlayerListItemPacket implements SCPacket {
private List<PlayerData> listPlayers = new ArrayList<>(); private List<PlayerData> listPlayers = new ArrayList<>();
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeVarInt(action); netStream.writeVarInt(action);
netStream.writeVarInt(listPlayers.size()); netStream.writeVarInt(listPlayers.size());

View File

@@ -9,9 +9,7 @@ import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import mc.core.Location; import mc.core.Location;
import mc.core.network.CSPacket; import mc.core.network.*;
import mc.core.network.NetStream;
import mc.core.network.SCPacket;
import mc.core.player.Look; import mc.core.player.Look;
@NoArgsConstructor @NoArgsConstructor
@@ -25,7 +23,7 @@ public class PlayerPositionAndLookPacket implements SCPacket, CSPacket {
private boolean onGround = false; private boolean onGround = false;
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeDouble(location.getX()); netStream.writeDouble(location.getX());
netStream.writeDouble(location.getY()); netStream.writeDouble(location.getY());
netStream.writeDouble(location.getZ()); netStream.writeDouble(location.getZ());
@@ -42,7 +40,7 @@ public class PlayerPositionAndLookPacket implements SCPacket, CSPacket {
} }
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
this.location = new Location( this.location = new Location(
netStream.readDouble(), netStream.readDouble(),
netStream.readDouble(), netStream.readDouble(),

View File

@@ -5,9 +5,7 @@
package mc.core.network.proto_1_12_2.packets; package mc.core.network.proto_1_12_2.packets;
import lombok.*; import lombok.*;
import mc.core.network.CSPacket; import mc.core.network.*;
import mc.core.network.NetStream;
import mc.core.network.SCPacket;
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@@ -19,14 +17,14 @@ public class PluginMessagePacket implements SCPacket, CSPacket {
private byte[] data; private byte[] data;
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
channelName = netStream.readString(); channelName = netStream.readString();
data = new byte[netStream.getDataSize() - channelName.getBytes().length - 1]; data = new byte[netStream.getDataSize() - channelName.getBytes().length - 1];
netStream.readBytes(data); netStream.readBytes(data);
} }
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeString(channelName); netStream.writeString(channelName);
netStream.writeBytes(data); netStream.writeBytes(data);
} }

View File

@@ -9,9 +9,8 @@ import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import mc.core.Location; import mc.core.Location;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
import mc.core.network.proto_1_12_2.serializers.LocationSerializer;
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@@ -21,7 +20,7 @@ public class SpawnPositionPacket implements SCPacket {
private Location location; private Location location;
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeLong(LocationSerializer.serialize(location)); netStream.writeLong(location.toLong());
} }
} }

View File

@@ -6,11 +6,11 @@ package mc.core.network.proto_1_12_2.packets;
import lombok.ToString; import lombok.ToString;
import mc.core.network.CSPacket; import mc.core.network.CSPacket;
import mc.core.network.NetStream; import mc.core.network.NetInputStream;
@ToString @ToString
public class StatusRequestPacket implements CSPacket { public class StatusRequestPacket implements CSPacket {
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
} }
} }

View File

@@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
@Setter @Setter
@@ -29,7 +29,7 @@ public class StatusResponsePacket implements SCPacket {
private byte[] faviconBase64; private byte[] faviconBase64;
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
JsonObject playersObj = new JsonObject(); JsonObject playersObj = new JsonObject();
playersObj.addProperty("max", maxOnline); playersObj.addProperty("max", maxOnline);
playersObj.addProperty("online", online); playersObj.addProperty("online", online);

View File

@@ -6,8 +6,7 @@ package mc.core.network.proto_1_12_2.packets;
import mc.core.Location; import mc.core.Location;
import mc.core.network.CSPacket; import mc.core.network.CSPacket;
import mc.core.network.NetStream; import mc.core.network.NetInputStream;
import mc.core.network.proto_1_12_2.serializers.LocationSerializer;
public class TabCompletePacket implements CSPacket { public class TabCompletePacket implements CSPacket {
private String text; private String text;
@@ -16,13 +15,13 @@ public class TabCompletePacket implements CSPacket {
private Location location; private Location location;
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
this.text = netStream.readString(); this.text = netStream.readString();
this.assumeCommand = netStream.readBoolean(); this.assumeCommand = netStream.readBoolean();
this.hasPosition = netStream.readBoolean(); this.hasPosition = netStream.readBoolean();
if (this.hasPosition) { if (this.hasPosition) {
this.location = LocationSerializer.deserialize(netStream.readLong()); this.location = new Location(netStream.readLong());
} }
} }
} }

View File

@@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets;
import lombok.Getter; import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import mc.core.network.CSPacket; import mc.core.network.CSPacket;
import mc.core.network.NetStream; import mc.core.network.NetInputStream;
@Getter @Getter
@ToString @ToString
@@ -15,7 +15,7 @@ public class TeleportConfirmPacket implements CSPacket {
private int teleportId; private int teleportId;
@Override @Override
public void readSelf(NetStream netStream) { public void readSelf(NetInputStream netStream) {
teleportId = netStream.readVarInt(); teleportId = netStream.readVarInt();
} }
} }

View File

@@ -8,7 +8,7 @@ import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
@AllArgsConstructor @AllArgsConstructor
@@ -20,7 +20,7 @@ public class TimeUpdatePacket implements SCPacket {
private long worldage; private long worldage;
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeLong(worldage); netStream.writeLong(worldage);
netStream.writeLong(time); netStream.writeLong(time);
} }

View File

@@ -7,7 +7,7 @@ package mc.core.network.proto_1_12_2.packets;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
import mc.core.network.proto_1_12_2.serializers.TextSerializer; import mc.core.network.proto_1_12_2.serializers.TextSerializer;
import mc.core.text.Text; import mc.core.text.Text;
@@ -91,7 +91,7 @@ public class TitlePacket implements SCPacket {
} }
@Override @Override
public void writeSelf(NetStream netStream) { public void writeSelf(NetOutputStream netStream) {
netStream.writeVarInt(this.action); netStream.writeVarInt(this.action);
switch (this.action) { switch (this.action) {

View File

@@ -1,27 +0,0 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 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);
}
}

View File

@@ -9,9 +9,9 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import mc.core.network.CSPacket; 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.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; import java.util.List;
@@ -36,7 +36,7 @@ public class PacketDecoder extends ByteToMessageDecoder {
log.debug("ByteBuf readableBytes: {}", in.readableBytes()); log.debug("ByteBuf readableBytes: {}", in.readableBytes());
State state = ctx.channel().attr(ATTR_STATE).get(); State state = ctx.channel().attr(ATTR_STATE).get();
NetStream netStream = new WrapperNetStream(in); NetInputStream netStream = new WrapperNetInputStream(in);
int packetSize = netStream.readVarInt(); int packetSize = netStream.readVarInt();
log.debug("Packet size: {}", packetSize); log.debug("Packet size: {}", packetSize);

View File

@@ -8,11 +8,11 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.MessageToByteEncoder;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import mc.core.network.NetStream; import mc.core.network.NetOutputStream;
import mc.core.network.SCPacket; import mc.core.network.SCPacket;
import mc.core.network.proto_1_12_2.State; 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.ByteArrayOutputNetStream;
import mc.core.network.proto_1_12_2.netty.wrappers.WrapperNetStream; import mc.core.network.proto_1_12_2.netty.wrappers.WrapperNetOutputStream;
import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE; import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE;
@@ -41,10 +41,10 @@ public class PacketEncoder extends MessageToByteEncoder<SCPacket> {
log.debug("Send {}:{}", state, packet); log.debug("Send {}:{}", state, packet);
NetStream netStream = new ByteArrayOutputNetStream(); NetOutputStream netStream = new ByteArrayOutputNetStream();
packet.writeSelf(netStream); packet.writeSelf(netStream);
byte[] bytes = ((ByteArrayOutputNetStream) netStream).toByteArray(); byte[] bytes = ((ByteArrayOutputNetStream) netStream).toByteArray();
netStream = new WrapperNetStream(out); netStream = new WrapperNetOutputStream(out);
netStream.writeVarInt(bytes.length + sizeVarInt(id)); netStream.writeVarInt(bytes.length + sizeVarInt(id));
netStream.writeVarInt(id); netStream.writeVarInt(id);

View File

@@ -1,17 +1,17 @@
/* /*
* DmitriyMX <dimon550@gmail.com> * DmitriyMX <dimon550@gmail.com>
* 2018-04-08 * 2018-07-25
*/ */
package mc.core.network.proto_1_12_2.netty.wrappers; package mc.core.network.proto_1_12_2.netty.wrappers;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; 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 @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
public class WrapperNetStream extends NetStream_p340 { public class WrapperNetInputStream extends NetInputStream_p340 {
private final ByteBuf byteBuf; private final ByteBuf byteBuf;
@Override @Override
@@ -64,51 +64,6 @@ public class WrapperNetStream extends NetStream_p340 {
return byteBuf.readDouble(); 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 @Override
public void skipBytes(int count) { public void skipBytes(int count) {
byteBuf.skipBytes(count); byteBuf.skipBytes(count);

View File

@@ -0,0 +1,61 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 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);
}
}

View File

@@ -5,5 +5,5 @@ include('flat_world')
include('vanilla_commands') include('vanilla_commands')
include('proto_1.12.2') // Protocol 1.12.2 include('proto_1.12.2') // Protocol 1.12.2
include('proto_1.12.2_netty') // Protocol 1.12.2 (Netty impl.) include('proto_1.12.2_netty') // Protocol 1.12.2 (Netty impl.)
include('event-loop') include('generated_world')
include('event-loop')