From ee829304260ccfbcec8465610b7390172d922533 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Sun, 18 Jul 2021 12:15:10 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D0=BE=D1=80=20=D0=BF=D0=BB=D0=BE=D1=81=D0=BA=D0=BE=D0=B9=20?= =?UTF-8?q?=D0=BA=D0=B0=D1=80=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mc/protocol/utils/ChunkSerializeUtil.java | 13 +++- .../main/java/mc/protocol/world/Block.java | 4 +- .../main/java/mc/protocol/world/Chunk.java | 2 +- .../java/mc/protocol/world/ChunkSection.java | 5 ++ server/src/main/java/mc/server/Main.java | 2 +- .../java/mc/server/di/FlatWorldModule.java | 61 +++++++++++++++++++ .../main/java/mc/server/di/WorldModule.java | 2 +- .../main/java/mc/server/world/FlatChunk.java | 33 ++++++++++ .../mc/server/world/FlatChunkSection.java | 61 +++++++++++++++++++ .../main/java/mc/server/world/FlatWorld.java | 46 ++++++++++++++ .../main/java/mc/server/world/SomeBlock.java | 4 +- .../mc/server/world/SomeChunkSection.java | 14 ++++- server/src/main/resources/config-default.conf | 2 + .../utils/pool/PassivableMultiObjectPool.java | 6 +- 14 files changed, 241 insertions(+), 14 deletions(-) create mode 100644 server/src/main/java/mc/server/di/FlatWorldModule.java create mode 100644 server/src/main/java/mc/server/world/FlatChunk.java create mode 100644 server/src/main/java/mc/server/world/FlatChunkSection.java create mode 100644 server/src/main/java/mc/server/world/FlatWorld.java diff --git a/protocol/src/main/java/mc/protocol/utils/ChunkSerializeUtil.java b/protocol/src/main/java/mc/protocol/utils/ChunkSerializeUtil.java index e0645f5..fe49109 100644 --- a/protocol/src/main/java/mc/protocol/utils/ChunkSerializeUtil.java +++ b/protocol/src/main/java/mc/protocol/utils/ChunkSerializeUtil.java @@ -26,7 +26,7 @@ public final class ChunkSerializeUtil { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { Block block = section.getBlock(x, y, z); - int blockState = (block.getId() << 4) | block.getMeta(); + int blockState = blockIdMetaSerialize(block.getId(), block.getMeta()); blockArray.put(blockState); blockLight.put(block.getLight()); @@ -45,4 +45,15 @@ public final class ChunkSerializeUtil { return result; } + + public static int blockIdMetaSerialize(int id, int meta) { + return (id << 4) | meta; + } + + public static int[] blockIdMetaDeserialize(int blockState) { + return new int[]{ + blockState >> 4, + blockState & 0b1111 + }; + } } diff --git a/protocol/src/main/java/mc/protocol/world/Block.java b/protocol/src/main/java/mc/protocol/world/Block.java index 91717cc..219f2c4 100644 --- a/protocol/src/main/java/mc/protocol/world/Block.java +++ b/protocol/src/main/java/mc/protocol/world/Block.java @@ -1,13 +1,13 @@ package mc.protocol.world; -import mc.protocol.model.Location; +import mc.protocol.model.BlockLocation; public interface Block { int getId(); int getMeta(); - Location getLocation(); + BlockLocation getLocation(); int getLight(); void setLight(int value); diff --git a/protocol/src/main/java/mc/protocol/world/Chunk.java b/protocol/src/main/java/mc/protocol/world/Chunk.java index 10eff95..21eadef 100644 --- a/protocol/src/main/java/mc/protocol/world/Chunk.java +++ b/protocol/src/main/java/mc/protocol/world/Chunk.java @@ -5,6 +5,6 @@ public interface Chunk { int getX(); int getZ(); - ChunkSection getSection(int index); + ChunkSection getSection(int height); byte getBiome(int x, int z); } diff --git a/protocol/src/main/java/mc/protocol/world/ChunkSection.java b/protocol/src/main/java/mc/protocol/world/ChunkSection.java index 8b04966..cbc6a00 100644 --- a/protocol/src/main/java/mc/protocol/world/ChunkSection.java +++ b/protocol/src/main/java/mc/protocol/world/ChunkSection.java @@ -1,9 +1,14 @@ package mc.protocol.world; +import mc.protocol.model.BlockLocation; + public interface ChunkSection { int getY(); Block getBlock(int x, int y, int z); + Block getBlock(BlockLocation blockLocation); + int getSkyLight(int x, int y, int z); + int getSkyLight(BlockLocation blockLocation); } diff --git a/server/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java index 0cf877a..60a1182 100644 --- a/server/src/main/java/mc/server/Main.java +++ b/server/src/main/java/mc/server/Main.java @@ -68,7 +68,7 @@ public class Main { ServerComponent serverComponent = DaggerServerComponent.builder() .scenarioModule(new ScenarioModule(configComponent.getConfig())) - .worldModule(new WorldModule(configComponent.getConfig())) + .worldModule(new FlatWorldModule(configComponent.getConfig())) .build(); serverComponent.getPacketScenarios().forEach(scenario -> scenario.setup(serverComponent.getProtocolHandlersBus())); diff --git a/server/src/main/java/mc/server/di/FlatWorldModule.java b/server/src/main/java/mc/server/di/FlatWorldModule.java new file mode 100644 index 0000000..ffb538f --- /dev/null +++ b/server/src/main/java/mc/server/di/FlatWorldModule.java @@ -0,0 +1,61 @@ +package mc.server.di; + +import com.typesafe.config.Config; +import mc.protocol.model.Location; +import mc.protocol.utils.ChunkSerializeUtil; +import mc.protocol.world.World; +import mc.server.world.FlatWorld; +import mc.utils.array.BitArray; +import mc.utils.array.BitLongArray; + +public class FlatWorldModule extends WorldModule { + + public FlatWorldModule(Config config) { + super(config); + } + + @Override + World provideWorld() { + String[] rawConfigParts = this.config.getString("world.flat-generator").split(";"); + byte biome = Byte.parseByte(rawConfigParts[0]); + + return new FlatWorld(spawn(), flatConfig(rawConfigParts), biome); + } + + private Location spawn() { + Location spawn = new Location(); + spawn.set( + config.getDouble("world.spawn.x"), + config.getDouble("world.spawn.y"), + config.getDouble("world.spawn.z") + ); + + return spawn; + } + + private BitArray flatConfig(String[] rawConfigParts) { + BitArray flatConfig = new BitLongArray(13, 256); + int k = 0; + for (int i = 1; i < rawConfigParts.length; i++) { + String[] part1 = rawConfigParts[i].split(","); + String[] part2 = part1[1].split(":"); + + int count = Integer.parseInt(part1[0]); + int blockId = Integer.parseInt(part2[0]); + int blockMeta = Integer.parseInt(part2[1]); + + k += count; + for (int j = 0; j < count; j++) { + flatConfig.put(ChunkSerializeUtil.blockIdMetaSerialize(blockId, blockMeta)); + } + } + + if (k < 256) { + for (int i = 0; i < (256 - k); i++) { + flatConfig.put(0); + } + } + + return flatConfig; + } +} diff --git a/server/src/main/java/mc/server/di/WorldModule.java b/server/src/main/java/mc/server/di/WorldModule.java index fca7fa9..872a104 100644 --- a/server/src/main/java/mc/server/di/WorldModule.java +++ b/server/src/main/java/mc/server/di/WorldModule.java @@ -14,7 +14,7 @@ import javax.inject.Singleton; @RequiredArgsConstructor public class WorldModule { - private final Config config; + protected final Config config; @Provides @Singleton diff --git a/server/src/main/java/mc/server/world/FlatChunk.java b/server/src/main/java/mc/server/world/FlatChunk.java new file mode 100644 index 0000000..a682fe6 --- /dev/null +++ b/server/src/main/java/mc/server/world/FlatChunk.java @@ -0,0 +1,33 @@ +package mc.server.world; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import mc.protocol.world.Chunk; +import mc.protocol.world.ChunkSection; +import mc.utils.array.BitArray; + +import java.util.HashMap; +import java.util.Map; + +@RequiredArgsConstructor +@Getter +public class FlatChunk implements Chunk { + + private final Map sections = new HashMap<>(); + + private final BitArray chunkConfig; + + private final int x; + private final int z; + private final byte biome; + + @Override + public ChunkSection getSection(int height) { + return sections.computeIfAbsent(height, h -> new FlatChunkSection(chunkConfig, h)); + } + + @Override + public byte getBiome(int x, int z) { + return biome; + } +} diff --git a/server/src/main/java/mc/server/world/FlatChunkSection.java b/server/src/main/java/mc/server/world/FlatChunkSection.java new file mode 100644 index 0000000..e767cb8 --- /dev/null +++ b/server/src/main/java/mc/server/world/FlatChunkSection.java @@ -0,0 +1,61 @@ +package mc.server.world; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import mc.protocol.model.BlockLocation; +import mc.protocol.utils.ChunkSerializeUtil; +import mc.protocol.world.Block; +import mc.protocol.world.ChunkSection; +import mc.utils.array.BitArray; + +import java.util.HashMap; +import java.util.Map; + +@RequiredArgsConstructor +public class FlatChunkSection implements ChunkSection { + + private final Map blocks = new HashMap<>(); + private final Map sky = new HashMap<>(); + + private final BitArray chunkConfig; + + @Getter + private final int y; + + @Override + public Block getBlock(int x, int y, int z) { + return blocks.computeIfAbsent(y, y0 -> { + int blockState = chunkConfig.get((this.y << 4) + y); + int[] blockIdMeta = ChunkSerializeUtil.blockIdMetaDeserialize(blockState); + + SomeBlock block = new SomeBlock(); + block.setId(blockIdMeta[0]); + block.setMeta(blockIdMeta[1]); + return block; + }); + } + + @Override + public Block getBlock(BlockLocation blockLocation) { + return getBlock(blockLocation.getX(), blockLocation.getY(), blockLocation.getZ()); + } + + @Override + public int getSkyLight(int x, int y, int z) { + return sky.computeIfAbsent(y, y0 -> { + int blockState = chunkConfig.get((this.y << 4) + y); + int[] blockIdMeta = ChunkSerializeUtil.blockIdMetaDeserialize(blockState); + + if (blockIdMeta[0] != 0/*AIR*/) { + return 0; + } else { + return 15; + } + }); + } + + @Override + public int getSkyLight(BlockLocation blockLocation) { + return getSkyLight(blockLocation.getX(), blockLocation.getY(), blockLocation.getZ()); + } +} diff --git a/server/src/main/java/mc/server/world/FlatWorld.java b/server/src/main/java/mc/server/world/FlatWorld.java new file mode 100644 index 0000000..4ee8eae --- /dev/null +++ b/server/src/main/java/mc/server/world/FlatWorld.java @@ -0,0 +1,46 @@ +package mc.server.world; + +import lombok.RequiredArgsConstructor; +import mc.protocol.model.ChunkSectionLocation; +import mc.protocol.model.Location; +import mc.protocol.utils.LevelType; +import mc.protocol.world.Chunk; +import mc.protocol.world.World; +import mc.utils.Table; +import mc.utils.array.BitArray; + +@RequiredArgsConstructor +public class FlatWorld implements World { + + private final Table chunkTable = new Table<>(); + + private final Location spawn; + private final BitArray flatConfig; + private final byte biome; + + @Override + public LevelType getLevelType() { + return LevelType.FLAT; + } + + @Override + public Location getSpawn() { + return this.spawn; + } + + @Override + public Chunk getChunk(int x, int z) { + Chunk chunk = chunkTable.getColumnAndRow(x, z); + if (chunk == null) { + chunk = new FlatChunk(flatConfig, x, z, biome); + chunkTable.put(x, z, chunk); + } + + return chunk; + } + + @Override + public Chunk getChunk(ChunkSectionLocation chunkSectionLocation) { + return getChunk(chunkSectionLocation.getX(), chunkSectionLocation.getZ()); + } +} diff --git a/server/src/main/java/mc/server/world/SomeBlock.java b/server/src/main/java/mc/server/world/SomeBlock.java index 4c282a3..6d11a80 100644 --- a/server/src/main/java/mc/server/world/SomeBlock.java +++ b/server/src/main/java/mc/server/world/SomeBlock.java @@ -1,7 +1,7 @@ package mc.server.world; import lombok.Data; -import mc.protocol.model.Location; +import mc.protocol.model.BlockLocation; import mc.protocol.world.Block; @Data @@ -10,5 +10,5 @@ public class SomeBlock implements Block { private int id; private int meta; private int light; - private Location location; + private BlockLocation location; } diff --git a/server/src/main/java/mc/server/world/SomeChunkSection.java b/server/src/main/java/mc/server/world/SomeChunkSection.java index 6e45ba7..d0790be 100644 --- a/server/src/main/java/mc/server/world/SomeChunkSection.java +++ b/server/src/main/java/mc/server/world/SomeChunkSection.java @@ -2,6 +2,7 @@ package mc.server.world; import lombok.Getter; import lombok.RequiredArgsConstructor; +import mc.protocol.model.BlockLocation; import mc.protocol.model.Location; import mc.protocol.world.Block; import mc.protocol.world.ChunkSection; @@ -24,7 +25,6 @@ public class SomeChunkSection implements ChunkSection { location1.set(x, y, z); return blocks.computeIfAbsent(location1, location -> { SomeBlock block = new SomeBlock(); - block.setLocation(location); block.setId(3); return block; }); @@ -33,7 +33,6 @@ public class SomeChunkSection implements ChunkSection { location1.set(x, y, z); return blocks.computeIfAbsent(location1, location -> { SomeBlock block = new SomeBlock(); - block.setLocation(location); block.setId(0); return block; }); @@ -43,13 +42,17 @@ public class SomeChunkSection implements ChunkSection { location1.set(x, y, z); return blocks.computeIfAbsent(location1, location -> { SomeBlock block = new SomeBlock(); - block.setLocation(location); block.setId(1); return block; }); } } + @Override + public Block getBlock(BlockLocation blockLocation) { + return getBlock(blockLocation.getX(), blockLocation.getY(), blockLocation.getZ()); + } + @Override public int getSkyLight(int x, int y, int z) { if (this.y == 15 && y != 0) { @@ -59,4 +62,9 @@ public class SomeChunkSection implements ChunkSection { } } + @Override + public int getSkyLight(BlockLocation blockLocation) { + return getSkyLight(blockLocation.getX(), blockLocation.getY(), blockLocation.getZ()); + } + } \ No newline at end of file diff --git a/server/src/main/resources/config-default.conf b/server/src/main/resources/config-default.conf index deaca56..7974b29 100644 --- a/server/src/main/resources/config-default.conf +++ b/server/src/main/resources/config-default.conf @@ -29,4 +29,6 @@ world { y: 256 z: -247 } + // biome_id;count,id:meta;count,id:meta;... + flat-generator: "1;240,1:0;1,2:0" } diff --git a/utils/src/main/java/mc/utils/pool/PassivableMultiObjectPool.java b/utils/src/main/java/mc/utils/pool/PassivableMultiObjectPool.java index f428881..cd3cae8 100644 --- a/utils/src/main/java/mc/utils/pool/PassivableMultiObjectPool.java +++ b/utils/src/main/java/mc/utils/pool/PassivableMultiObjectPool.java @@ -1,12 +1,12 @@ package mc.utils.pool; -import java.util.HashMap; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; public class PassivableMultiObjectPool implements MultiObjectPool { @SuppressWarnings("rawtypes") - private final Map mapPool = new HashMap<>(); + private final ConcurrentMap mapPool = new ConcurrentHashMap<>(); @SuppressWarnings("unchecked") @Override