mirror of
https://github.com/Minestom/Minestom.git
synced 2024-11-17 16:15:32 +01:00
add support for static chunks
This commit is contained in:
parent
284613a1a8
commit
448a26a7d8
@ -1,14 +1,11 @@
|
||||
package net.minestom.server.instance;
|
||||
|
||||
import com.extollit.gaming.ai.path.model.ColumnarOcclusionFieldList;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import it.unimi.dsi.fastutil.ints.*;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.Viewable;
|
||||
import net.minestom.server.data.Data;
|
||||
import net.minestom.server.data.SerializableData;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.entity.pathfinding.PFBlockDescription;
|
||||
import net.minestom.server.entity.pathfinding.PFColumnarSpace;
|
||||
import net.minestom.server.event.player.PlayerChunkLoadEvent;
|
||||
import net.minestom.server.event.player.PlayerChunkUnloadEvent;
|
||||
@ -19,7 +16,6 @@ import net.minestom.server.instance.block.UpdateConsumer;
|
||||
import net.minestom.server.network.PacketWriterUtils;
|
||||
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.utils.PacketUtils;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
import net.minestom.server.utils.time.CooldownUtils;
|
||||
@ -27,17 +23,15 @@ import net.minestom.server.utils.time.UpdateOption;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import net.minestom.server.world.biomes.Biome;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
// TODO light data & API
|
||||
public final class Chunk implements Viewable {
|
||||
public abstract class Chunk implements Viewable {
|
||||
|
||||
private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
||||
protected static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
||||
|
||||
public static final int CHUNK_SIZE_X = 16;
|
||||
public static final int CHUNK_SIZE_Y = 256;
|
||||
@ -46,34 +40,34 @@ public final class Chunk implements Viewable {
|
||||
|
||||
public static final int BIOME_COUNT = 1024; // 4x4x4 blocks
|
||||
|
||||
private Biome[] biomes;
|
||||
private int chunkX, chunkZ;
|
||||
protected Biome[] biomes;
|
||||
protected int chunkX, chunkZ;
|
||||
|
||||
// blocks id based on coord, see Chunk#getBlockIndex
|
||||
public short[] blocksStateId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
|
||||
private short[] customBlocksId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
|
||||
//public short[] blocksStateId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
|
||||
//protected short[] customBlocksId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
|
||||
|
||||
// Used to get all blocks with data (no null)
|
||||
// Key is still chunk coord
|
||||
private Int2ObjectMap<Data> blocksData = new Int2ObjectOpenHashMap<>(16 * 16); // Start with the size of a single row
|
||||
protected Int2ObjectMap<Data> blocksData = new Int2ObjectOpenHashMap<>(16 * 16); // Start with the size of a single row
|
||||
|
||||
// Contains CustomBlocks' index which are updatable
|
||||
private IntSet updatableBlocks = new IntOpenHashSet();
|
||||
protected IntSet updatableBlocks = new IntOpenHashSet();
|
||||
// (block index)/(last update in ms)
|
||||
private Int2LongMap updatableBlocksLastUpdate = new Int2LongOpenHashMap();
|
||||
protected Int2LongMap updatableBlocksLastUpdate = new Int2LongOpenHashMap();
|
||||
|
||||
protected volatile boolean packetUpdated;
|
||||
|
||||
// Block entities
|
||||
private Set<Integer> blockEntities = new CopyOnWriteArraySet<>();
|
||||
protected Set<Integer> blockEntities = new CopyOnWriteArraySet<>();
|
||||
|
||||
// Path finding
|
||||
private PFColumnarSpace columnarSpace;
|
||||
protected PFColumnarSpace columnarSpace;
|
||||
|
||||
// Cache
|
||||
private volatile boolean loaded = true;
|
||||
private Set<Player> viewers = new CopyOnWriteArraySet<>();
|
||||
private ByteBuf fullDataPacket;
|
||||
protected volatile boolean loaded = true;
|
||||
protected Set<Player> viewers = new CopyOnWriteArraySet<>();
|
||||
protected ByteBuf fullDataPacket;
|
||||
|
||||
public Chunk(Biome[] biomes, int chunkX, int chunkZ) {
|
||||
this.biomes = biomes;
|
||||
@ -97,69 +91,9 @@ public final class Chunk implements Viewable {
|
||||
setBlock(x, y, z, blockStateId, customBlock.getCustomBlockId(), data, updateConsumer);
|
||||
}
|
||||
|
||||
public void UNSAFE_removeCustomBlock(int x, int y, int z) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
this.customBlocksId[index] = 0; // Set to none
|
||||
this.blocksData.remove(index);
|
||||
public abstract void UNSAFE_removeCustomBlock(int x, int y, int z);
|
||||
|
||||
this.updatableBlocks.remove(index);
|
||||
this.updatableBlocksLastUpdate.remove(index);
|
||||
|
||||
this.blockEntities.remove(index);
|
||||
}
|
||||
|
||||
private void setBlock(int x, int y, int z, short blockStateId, short customId, Data data, UpdateConsumer updateConsumer) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
if (blockStateId != 0
|
||||
|| (blockStateId == 0 && customId != 0 && updateConsumer != null)) { // Allow custom air block for update purpose, refused if no update consumer has been found
|
||||
this.blocksStateId[index] = blockStateId;
|
||||
this.customBlocksId[index] = customId;
|
||||
} else {
|
||||
// Block has been deleted, clear cache and return
|
||||
|
||||
this.blocksStateId[index] = 0; // Set to air
|
||||
|
||||
this.blocksData.remove(index);
|
||||
|
||||
this.updatableBlocks.remove(index);
|
||||
this.updatableBlocksLastUpdate.remove(index);
|
||||
|
||||
this.blockEntities.remove(index);
|
||||
|
||||
this.packetUpdated = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the new data (or remove from the map if is null)
|
||||
if (data != null) {
|
||||
this.blocksData.put(index, data);
|
||||
} else {
|
||||
this.blocksData.remove(index);
|
||||
}
|
||||
|
||||
// Set update consumer
|
||||
if (updateConsumer != null) {
|
||||
this.updatableBlocks.add(index);
|
||||
this.updatableBlocksLastUpdate.put(index, System.currentTimeMillis());
|
||||
} else {
|
||||
this.updatableBlocks.remove(index);
|
||||
this.updatableBlocksLastUpdate.remove(index);
|
||||
}
|
||||
|
||||
if (isBlockEntity(blockStateId)) {
|
||||
this.blockEntities.add(index);
|
||||
} else {
|
||||
this.blockEntities.remove(index);
|
||||
}
|
||||
|
||||
this.packetUpdated = false;
|
||||
|
||||
if (columnarSpace != null) {
|
||||
final ColumnarOcclusionFieldList columnarOcclusionFieldList = columnarSpace.occlusionFields();
|
||||
final PFBlockDescription blockDescription = new PFBlockDescription(Block.fromStateId(blockStateId));
|
||||
columnarOcclusionFieldList.onBlockChanged(x, y, z, blockDescription, 0);
|
||||
}
|
||||
}
|
||||
protected abstract void setBlock(int x, int y, int z, short blockStateId, short customId, Data data, UpdateConsumer updateConsumer);
|
||||
|
||||
public void setBlockData(int x, int y, int z, Data data) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
@ -170,56 +104,20 @@ public final class Chunk implements Viewable {
|
||||
}
|
||||
}
|
||||
|
||||
public short getBlockStateId(int x, int y, int z) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
if (!MathUtils.isBetween(index, 0, blocksStateId.length)) {
|
||||
return 0; // TODO: custom invalid block
|
||||
}
|
||||
final short id = blocksStateId[index];
|
||||
return id;
|
||||
}
|
||||
public abstract short getBlockStateId(int x, int y, int z);
|
||||
|
||||
public short getCustomBlockId(int x, int y, int z) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
if (!MathUtils.isBetween(index, 0, blocksStateId.length)) {
|
||||
return 0; // TODO: custom invalid block
|
||||
}
|
||||
final short id = customBlocksId[index];
|
||||
return id;
|
||||
}
|
||||
public abstract short getCustomBlockId(int x, int y, int z);
|
||||
|
||||
public CustomBlock getCustomBlock(int x, int y, int z) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
if (!MathUtils.isBetween(index, 0, blocksStateId.length)) {
|
||||
return null; // TODO: custom invalid block
|
||||
}
|
||||
final short id = customBlocksId[index];
|
||||
return id != 0 ? BLOCK_MANAGER.getCustomBlock(id) : null;
|
||||
}
|
||||
public abstract CustomBlock getCustomBlock(int x, int y, int z);
|
||||
|
||||
protected CustomBlock getCustomBlock(int index) {
|
||||
final int[] pos = ChunkUtils.indexToChunkPosition(index);
|
||||
return getCustomBlock(pos[0], pos[1], pos[2]);
|
||||
}
|
||||
|
||||
protected void refreshBlockValue(int x, int y, int z, short blockStateId, short customId) {
|
||||
final int blockIndex = getBlockIndex(x, y, z);
|
||||
if (!MathUtils.isBetween(blockIndex, 0, blocksStateId.length)) {
|
||||
return;
|
||||
}
|
||||
protected abstract void refreshBlockValue(int x, int y, int z, short blockStateId, short customId);
|
||||
|
||||
this.blocksStateId[blockIndex] = blockStateId;
|
||||
this.customBlocksId[blockIndex] = customId;
|
||||
}
|
||||
|
||||
protected void refreshBlockStateId(int x, int y, int z, short blockStateId) {
|
||||
final int blockIndex = getBlockIndex(x, y, z);
|
||||
if (!MathUtils.isBetween(blockIndex, 0, blocksStateId.length)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.blocksStateId[blockIndex] = blockStateId;
|
||||
}
|
||||
protected abstract void refreshBlockStateId(int x, int y, int z, short blockStateId);
|
||||
|
||||
protected void refreshBlockValue(int x, int y, int z, short blockStateId) {
|
||||
final CustomBlock customBlock = getCustomBlock(x, y, z);
|
||||
@ -282,7 +180,7 @@ public final class Chunk implements Viewable {
|
||||
return fullDataPacket;
|
||||
}
|
||||
|
||||
private boolean isBlockEntity(short blockStateId) {
|
||||
protected boolean isBlockEntity(short blockStateId) {
|
||||
final Block block = Block.fromStateId(blockStateId);
|
||||
return block.hasBlockEntity();
|
||||
}
|
||||
@ -316,51 +214,7 @@ public final class Chunk implements Viewable {
|
||||
this.packetUpdated = true;
|
||||
}
|
||||
|
||||
protected byte[] getSerializedData() throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(output);
|
||||
|
||||
for (int i = 0; i < BIOME_COUNT; i++) {
|
||||
dos.writeByte(biomes[i].getId());
|
||||
}
|
||||
|
||||
for (byte x = 0; x < CHUNK_SIZE_X; x++) {
|
||||
for (short y = 0; y < CHUNK_SIZE_Y; y++) {
|
||||
for (byte z = 0; z < CHUNK_SIZE_Z; z++) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
|
||||
final short blockStateId = blocksStateId[index];
|
||||
final short customBlockId = customBlocksId[index];
|
||||
|
||||
if (blockStateId == 0 && customBlockId == 0)
|
||||
continue;
|
||||
|
||||
final Data data = blocksData.get(index);
|
||||
|
||||
// Chunk coordinates
|
||||
dos.writeInt(x);
|
||||
dos.writeInt(y);
|
||||
dos.writeInt(z);
|
||||
|
||||
// Id
|
||||
dos.writeShort(blockStateId);
|
||||
dos.writeShort(customBlockId);
|
||||
|
||||
// Data
|
||||
final boolean hasData = (data != null && (data instanceof SerializableData));
|
||||
dos.writeBoolean(hasData);
|
||||
if (hasData) {
|
||||
final byte[] d = ((SerializableData) data).getSerializedData();
|
||||
dos.writeInt(d.length);
|
||||
dos.write(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final byte[] result = output.toByteArray();
|
||||
return result;
|
||||
}
|
||||
protected abstract byte[] getSerializedData() throws IOException;
|
||||
|
||||
public ChunkDataPacket getFreshFullDataPacket() {
|
||||
ChunkDataPacket fullDataPacket = getFreshPacket();
|
||||
@ -377,17 +231,7 @@ public final class Chunk implements Viewable {
|
||||
/**
|
||||
* @return a {@link ChunkDataPacket} containing a copy this chunk data
|
||||
*/
|
||||
private ChunkDataPacket getFreshPacket() {
|
||||
ChunkDataPacket fullDataPacket = new ChunkDataPacket();
|
||||
fullDataPacket.biomes = biomes.clone();
|
||||
fullDataPacket.chunkX = chunkX;
|
||||
fullDataPacket.chunkZ = chunkZ;
|
||||
fullDataPacket.blocksStateId = blocksStateId.clone();
|
||||
fullDataPacket.customBlocksId = customBlocksId.clone();
|
||||
fullDataPacket.blockEntities = new CopyOnWriteArraySet<>(blockEntities);
|
||||
fullDataPacket.blocksData = new Int2ObjectOpenHashMap<>(blocksData);
|
||||
return fullDataPacket;
|
||||
}
|
||||
protected abstract ChunkDataPacket getFreshPacket();
|
||||
|
||||
// Write the packet in the current thread
|
||||
public void refreshDataPacket() {
|
||||
@ -449,7 +293,7 @@ public final class Chunk implements Viewable {
|
||||
this.loaded = false;
|
||||
}
|
||||
|
||||
private int getBlockIndex(int x, int y, int z) {
|
||||
protected int getBlockIndex(int x, int y, int z) {
|
||||
return ChunkUtils.getBlockIndex(x, y, z);
|
||||
}
|
||||
}
|
206
src/main/java/net/minestom/server/instance/DynamicChunk.java
Normal file
206
src/main/java/net/minestom/server/instance/DynamicChunk.java
Normal file
@ -0,0 +1,206 @@
|
||||
package net.minestom.server.instance;
|
||||
|
||||
import com.extollit.gaming.ai.path.model.ColumnarOcclusionFieldList;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import net.minestom.server.data.Data;
|
||||
import net.minestom.server.data.SerializableData;
|
||||
import net.minestom.server.entity.pathfinding.PFBlockDescription;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.CustomBlock;
|
||||
import net.minestom.server.instance.block.UpdateConsumer;
|
||||
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.world.biomes.Biome;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public class DynamicChunk extends Chunk {
|
||||
|
||||
public short[] blocksStateId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
|
||||
private short[] customBlocksId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
|
||||
|
||||
public DynamicChunk(Biome[] biomes, int chunkX, int chunkZ) {
|
||||
super(biomes, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void UNSAFE_removeCustomBlock(int x, int y, int z) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
this.customBlocksId[index] = 0; // Set to none
|
||||
this.blocksData.remove(index);
|
||||
|
||||
this.updatableBlocks.remove(index);
|
||||
this.updatableBlocksLastUpdate.remove(index);
|
||||
|
||||
this.blockEntities.remove(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setBlock(int x, int y, int z, short blockStateId, short customId, Data data, UpdateConsumer updateConsumer) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
if (blockStateId != 0
|
||||
|| (blockStateId == 0 && customId != 0 && updateConsumer != null)) { // Allow custom air block for update purpose, refused if no update consumer has been found
|
||||
this.blocksStateId[index] = blockStateId;
|
||||
this.customBlocksId[index] = customId;
|
||||
} else {
|
||||
// Block has been deleted, clear cache and return
|
||||
|
||||
this.blocksStateId[index] = 0; // Set to air
|
||||
|
||||
this.blocksData.remove(index);
|
||||
|
||||
this.updatableBlocks.remove(index);
|
||||
this.updatableBlocksLastUpdate.remove(index);
|
||||
|
||||
this.blockEntities.remove(index);
|
||||
|
||||
this.packetUpdated = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the new data (or remove from the map if is null)
|
||||
if (data != null) {
|
||||
this.blocksData.put(index, data);
|
||||
} else {
|
||||
this.blocksData.remove(index);
|
||||
}
|
||||
|
||||
// Set update consumer
|
||||
if (updateConsumer != null) {
|
||||
this.updatableBlocks.add(index);
|
||||
this.updatableBlocksLastUpdate.put(index, System.currentTimeMillis());
|
||||
} else {
|
||||
this.updatableBlocks.remove(index);
|
||||
this.updatableBlocksLastUpdate.remove(index);
|
||||
}
|
||||
|
||||
if (isBlockEntity(blockStateId)) {
|
||||
this.blockEntities.add(index);
|
||||
} else {
|
||||
this.blockEntities.remove(index);
|
||||
}
|
||||
|
||||
this.packetUpdated = false;
|
||||
|
||||
if (columnarSpace != null) {
|
||||
final ColumnarOcclusionFieldList columnarOcclusionFieldList = columnarSpace.occlusionFields();
|
||||
final PFBlockDescription blockDescription = new PFBlockDescription(Block.fromStateId(blockStateId));
|
||||
columnarOcclusionFieldList.onBlockChanged(x, y, z, blockDescription, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBlockStateId(int x, int y, int z) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
if (!MathUtils.isBetween(index, 0, blocksStateId.length)) {
|
||||
return 0; // TODO: custom invalid block
|
||||
}
|
||||
final short id = blocksStateId[index];
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getCustomBlockId(int x, int y, int z) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
if (!MathUtils.isBetween(index, 0, blocksStateId.length)) {
|
||||
return 0; // TODO: custom invalid block
|
||||
}
|
||||
final short id = customBlocksId[index];
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomBlock getCustomBlock(int x, int y, int z) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
if (!MathUtils.isBetween(index, 0, blocksStateId.length)) {
|
||||
return null; // TODO: custom invalid block
|
||||
}
|
||||
final short id = customBlocksId[index];
|
||||
return id != 0 ? BLOCK_MANAGER.getCustomBlock(id) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refreshBlockValue(int x, int y, int z, short blockStateId, short customId) {
|
||||
final int blockIndex = getBlockIndex(x, y, z);
|
||||
if (!MathUtils.isBetween(blockIndex, 0, blocksStateId.length)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.blocksStateId[blockIndex] = blockStateId;
|
||||
this.customBlocksId[blockIndex] = customId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refreshBlockStateId(int x, int y, int z, short blockStateId) {
|
||||
final int blockIndex = getBlockIndex(x, y, z);
|
||||
if (!MathUtils.isBetween(blockIndex, 0, blocksStateId.length)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.blocksStateId[blockIndex] = blockStateId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] getSerializedData() throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(output);
|
||||
|
||||
for (int i = 0; i < BIOME_COUNT; i++) {
|
||||
dos.writeByte(biomes[i].getId());
|
||||
}
|
||||
|
||||
for (byte x = 0; x < CHUNK_SIZE_X; x++) {
|
||||
for (short y = 0; y < CHUNK_SIZE_Y; y++) {
|
||||
for (byte z = 0; z < CHUNK_SIZE_Z; z++) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
|
||||
final short blockStateId = blocksStateId[index];
|
||||
final short customBlockId = customBlocksId[index];
|
||||
|
||||
if (blockStateId == 0 && customBlockId == 0)
|
||||
continue;
|
||||
|
||||
final Data data = blocksData.get(index);
|
||||
|
||||
// Chunk coordinates
|
||||
dos.writeInt(x);
|
||||
dos.writeInt(y);
|
||||
dos.writeInt(z);
|
||||
|
||||
// Id
|
||||
dos.writeShort(blockStateId);
|
||||
dos.writeShort(customBlockId);
|
||||
|
||||
// Data
|
||||
final boolean hasData = (data != null && (data instanceof SerializableData));
|
||||
dos.writeBoolean(hasData);
|
||||
if (hasData) {
|
||||
final byte[] d = ((SerializableData) data).getSerializedData();
|
||||
dos.writeInt(d.length);
|
||||
dos.write(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final byte[] result = output.toByteArray();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChunkDataPacket getFreshPacket() {
|
||||
ChunkDataPacket fullDataPacket = new ChunkDataPacket();
|
||||
fullDataPacket.biomes = biomes.clone();
|
||||
fullDataPacket.chunkX = chunkX;
|
||||
fullDataPacket.chunkZ = chunkZ;
|
||||
fullDataPacket.blocksStateId = blocksStateId.clone();
|
||||
fullDataPacket.customBlocksId = customBlocksId.clone();
|
||||
fullDataPacket.blockEntities = new CopyOnWriteArraySet<>(blockEntities);
|
||||
fullDataPacket.blocksData = new Int2ObjectOpenHashMap<>(blocksData);
|
||||
return fullDataPacket;
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package net.minestom.server.instance;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.Setter;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.data.Data;
|
||||
import net.minestom.server.data.SerializableData;
|
||||
@ -38,7 +39,9 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* InstanceContainer is an instance that contains chunks in contrary to SharedInstance.
|
||||
@ -62,6 +65,9 @@ public class InstanceContainer extends Instance {
|
||||
|
||||
private boolean autoChunkLoad;
|
||||
|
||||
@Setter
|
||||
private BiFunction<Integer, Integer, Function<BlockPosition, Short>> chunkDecider;
|
||||
|
||||
public InstanceContainer(UUID uniqueId, DimensionType dimensionType, StorageFolder storageFolder) {
|
||||
super(uniqueId, dimensionType);
|
||||
|
||||
@ -431,9 +437,11 @@ public class InstanceContainer extends Instance {
|
||||
chunkGenerator.fillBiomes(biomes, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
final Chunk chunk = new Chunk(biomes, chunkX, chunkZ);
|
||||
Function<BlockPosition, Short> chunkSuppler = chunkDecider.apply(chunkX, chunkZ);
|
||||
final Chunk chunk = chunkSuppler == null ? new DynamicChunk(biomes, chunkX, chunkZ) : new StaticChunk(biomes, chunkX, chunkZ, chunkSuppler) ;
|
||||
cacheChunk(chunk);
|
||||
if (chunkGenerator != null) {
|
||||
|
||||
if (chunkGenerator != null && chunkSuppler == null) {
|
||||
final ChunkBatch chunkBatch = createChunkBatch(chunk);
|
||||
|
||||
chunkBatch.flushChunkGenerator(chunkGenerator, callback);
|
||||
|
@ -29,6 +29,8 @@ public class MinestomBasicChunkLoader implements IChunkLoader {
|
||||
|
||||
try {
|
||||
final byte[] data = chunk.getSerializedData();
|
||||
if (data == null)
|
||||
return;
|
||||
storageFolder.set(getChunkKey(chunkX, chunkZ), data);
|
||||
|
||||
if (callback != null)
|
||||
|
83
src/main/java/net/minestom/server/instance/StaticChunk.java
Normal file
83
src/main/java/net/minestom/server/instance/StaticChunk.java
Normal file
@ -0,0 +1,83 @@
|
||||
package net.minestom.server.instance;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import net.minestom.server.data.Data;
|
||||
import net.minestom.server.instance.block.CustomBlock;
|
||||
import net.minestom.server.instance.block.UpdateConsumer;
|
||||
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
import net.minestom.server.world.biomes.Biome;
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class StaticChunk extends Chunk {
|
||||
|
||||
final Function<BlockPosition, Short> blockProvider;
|
||||
|
||||
public StaticChunk(Biome[] biomes, int chunkX, int chunkZ, Function<BlockPosition, Short> blockProvider) {
|
||||
super(biomes, chunkX, chunkZ);
|
||||
this.blockProvider = blockProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void UNSAFE_removeCustomBlock(int x, int y, int z) {
|
||||
//noop
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setBlock(int x, int y, int z, short blockStateId, short customId, Data data, UpdateConsumer updateConsumer) {
|
||||
//noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBlockStateId(int x, int y, int z) {
|
||||
return blockProvider.apply(new BlockPosition(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getCustomBlockId(int x, int y, int z) {
|
||||
//noop
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomBlock getCustomBlock(int x, int y, int z) {
|
||||
//noop
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refreshBlockValue(int x, int y, int z, short blockStateId, short customId) {
|
||||
//noop
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refreshBlockStateId(int x, int y, int z, short blockStateId) {
|
||||
//noop
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] getSerializedData(){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChunkDataPacket getFreshPacket() {
|
||||
ChunkDataPacket fullDataPacket = new ChunkDataPacket();
|
||||
fullDataPacket.biomes = biomes.clone();
|
||||
fullDataPacket.chunkX = chunkX;
|
||||
fullDataPacket.chunkZ = chunkZ;
|
||||
short[] blocksStateId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
|
||||
for (int i = 0; i < blocksStateId.length; i++) {
|
||||
blocksStateId[i] = blockProvider.apply(ChunkUtils.getBlockPosition(i, 0, 0));
|
||||
}
|
||||
fullDataPacket.blocksStateId = blocksStateId;
|
||||
fullDataPacket.customBlocksId = new short[0];
|
||||
fullDataPacket.blockEntities = new CopyOnWriteArraySet<>(blockEntities);
|
||||
fullDataPacket.blocksData = new Int2ObjectOpenHashMap<>(blocksData);
|
||||
return fullDataPacket;
|
||||
}
|
||||
|
||||
}
|
@ -3,6 +3,7 @@ package net.minestom.server.reader;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.data.Data;
|
||||
import net.minestom.server.instance.DynamicChunk;
|
||||
import net.minestom.server.world.biomes.Biome;
|
||||
import net.minestom.server.instance.Chunk;
|
||||
import net.minestom.server.instance.Instance;
|
||||
@ -27,7 +28,7 @@ public class ChunkReader {
|
||||
biomes[i] = MinecraftServer.getBiomeManager().getById(stream.readByte());
|
||||
}
|
||||
|
||||
final Chunk chunk = new Chunk(biomes, chunkX, chunkZ);
|
||||
final Chunk chunk = new DynamicChunk(biomes, chunkX, chunkZ);
|
||||
|
||||
chunkBatch = instance.createChunkBatch(chunk);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user