Implemented TestChunkCodec and removed chunk generation from client

This commit is contained in:
OLEGSHA 2020-12-30 14:22:34 +03:00
parent c9087e7215
commit ef928b382f
4 changed files with 230 additions and 10 deletions

View File

@ -25,7 +25,7 @@ public class DataBuffer {
@Override
public int read() throws IOException {
if (DataBuffer.this.position >= buffer.size()) return -1;
int result = buffer.getQuick(DataBuffer.this.position);
int result = buffer.getQuick(DataBuffer.this.position) & 0xFF;
++DataBuffer.this.position;
return result;
}

View File

@ -394,6 +394,24 @@ implements GenericChunk<
report(null, tile);
}
@Override
public void load(TileData tile, int tag) {
addFarthest(tile);
int assignedTag = getIndexByTag(tag);
if (assignedTag == tag) return;
if (assignedTag == -1) {
throw new IllegalArgumentException("Tag " + tag + " already used by tile at index " + getIndexByTag(tag));
}
indicesByTag[tagsByIndex[size() - 1]] = -1;
tagsByIndex[size() - 1] = tag;
indicesByTag[tag] = size() - 1;
assert checkConsistency();
}
@Override
public TileData remove(int index) {
TileData previous = get(index); // checks index

View File

@ -26,6 +26,16 @@ extends GenericTileStack<
@Override
public abstract void add(int index, TileData tile);
/**
* Adds the specified tile at the end of this stack assigning it the provided tag.
* This method is useful for copying stacks when preserving tags is necessary.
* @param tile the tile to add
* @param tag the tag to assign the new tile
* @throws IllegalArgumentException if this stack already contains a tile with the
* provided tag
*/
public abstract void load(TileData tile, int tag);
/**
* Replaces the tile at the specified position in this stack with the specified tile.
* @param index index of the tile to replace

View File

@ -1,26 +1,59 @@
package ru.windcorp.progressia.test;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import glm.vec._3.i.Vec3i;
import gnu.trove.map.TObjectIntMap;
import gnu.trove.map.hash.TObjectIntHashMap;
import ru.windcorp.jputil.functions.ThrowingConsumer;
import ru.windcorp.progressia.common.io.ChunkCodec;
import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.DecodingException;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.common.world.block.BlockFace;
import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
public class TestChunkCodec extends ChunkCodec {
public TestChunkCodec() {
super("Test:TestCodec", 0x00);
private static class Palette<E> {
private final List<E> nidToElement = new ArrayList<>();
private final TObjectIntMap<E> elementToNid = new TObjectIntHashMap<>();
public void add(E element) {
if (elementToNid.containsKey(element)) return;
nidToElement.add(element);
elementToNid.put(element, elementToNid.size());
}
public E getByNid(int nid) {
return nidToElement.get(nid);
}
public int getNid(E element) {
return elementToNid.get(element);
}
public int size() {
return nidToElement.size();
}
}
@Override
public ChunkData decode(WorldData world, Vec3i position, InputStream data) throws DecodingException, IOException {
ChunkData chunk = new ChunkData(position, world);
TestContent.generateChunk(chunk);
return chunk;
public TestChunkCodec() {
super("Test:TestCodec", 0x00);
}
@Override
@ -28,9 +61,168 @@ public class TestChunkCodec extends ChunkCodec {
return true;
}
/*
* Decoding
*/
@Override
public void encode(ChunkData chunk, OutputStream output) throws IOException {
// Do nothing. Heh.
public ChunkData decode(WorldData world, Vec3i position, InputStream inputStream) throws DecodingException, IOException {
DataInput input = new DataInputStream(inputStream);
BlockData[] blockPalette = readBlockPalette(input);
TileData[] tilePalette = readTilePalette(input);
ChunkData chunk = new ChunkData(position, world);
readBlocks(input, blockPalette, chunk);
readTiles(input, tilePalette, chunk);
return chunk;
}
private BlockData[] readBlockPalette(DataInput input) throws IOException {
BlockData[] palette = new BlockData[input.readInt()];
for (int nid = 0; nid < palette.length; ++nid) {
String id = input.readUTF();
palette[nid] = BlockDataRegistry.getInstance().get(id);
}
return palette;
}
private TileData[] readTilePalette(DataInput input) throws IOException {
TileData[] palette = new TileData[input.readInt()];
for (int nid = 0; nid < palette.length; ++nid) {
String id = input.readUTF();
palette[nid] = TileDataRegistry.getInstance().get(id);
}
return palette;
}
private void readBlocks(DataInput input, BlockData[] blockPalette, ChunkData chunk) throws IOException {
try {
chunk.forEachBiC(guard(v -> {
chunk.setBlock(v, blockPalette[input.readInt()], false);
}));
} catch (UncheckedIOException e) {
throw e.getCause();
}
}
private void readTiles(DataInput input, TileData[] tilePalette, ChunkData chunk) throws IOException {
Vec3i bic = new Vec3i();
while (true) {
int xOrEndMarker = input.readByte() & 0xFF;
if (xOrEndMarker == 0xFF) break;
bic.set(xOrEndMarker, input.readByte() & 0xFF, input.readByte() & 0xFF);
BlockFace face = BlockFace.getFaces().get(input.readByte() & 0xFF);
int tiles = input.readByte() & 0xFF;
for (int i = 0; i < tiles; ++i) {
TileData tile = tilePalette[input.readInt()];
int tag = input.readInt();
chunk.getTiles(bic, face).load(tile, tag);
}
}
}
/*
* Encoding
*/
@Override
public void encode(ChunkData chunk, OutputStream outputStream) throws IOException {
DataOutput output = new DataOutputStream(outputStream);
Palette<BlockData> blockPalette = createBlockPalette(chunk);
Palette<TileData> tilePalette = createTilePalette(chunk);
writeBlockPalette(blockPalette, output);
writeTilePalette(tilePalette, output);
writeBlocks(chunk, blockPalette, output);
writeTiles(chunk, tilePalette, output);
}
private Palette<BlockData> createBlockPalette(ChunkData chunk) {
Palette<BlockData> blockPalette = new Palette<>();
chunk.forEachBiC(v -> blockPalette.add(chunk.getBlock(v)));
return blockPalette;
}
private Palette<TileData> createTilePalette(ChunkData chunk) {
Palette<TileData> tilePalette = new Palette<>();
chunk.forEachTile((ts, t) -> tilePalette.add(t));
return tilePalette;
}
private void writeBlockPalette(Palette<BlockData> blockPalette, DataOutput output) throws IOException {
output.writeInt(blockPalette.size());
for (int nid = 0; nid < blockPalette.size(); ++nid) {
BlockData block = blockPalette.getByNid(nid);
output.writeUTF(block.getId());
}
}
private void writeTilePalette(Palette<TileData> tilePalette, DataOutput output) throws IOException {
output.writeInt(tilePalette.size());
for (int nid = 0; nid < tilePalette.size(); ++nid) {
TileData tile = tilePalette.getByNid(nid);
output.writeUTF(tile.getId());
}
}
private void writeBlocks(ChunkData chunk, Palette<BlockData> blockPalette, DataOutput output) throws IOException {
try {
chunk.forEachBiC(guard(v -> {
output.writeInt(blockPalette.getNid(chunk.getBlock(v)));
}));
} catch (UncheckedIOException e) {
throw e.getCause();
}
}
private void writeTiles(ChunkData chunk, Palette<TileData> tilePalette, DataOutput output) throws IOException {
Vec3i bic = new Vec3i();
try {
chunk.forEachTileStack(guard(ts -> {
if (ts.isEmpty()) return;
ts.getBlockInChunk(bic);
output.writeByte(bic.x);
output.writeByte(bic.y);
output.writeByte(bic.z);
output.writeByte(ts.getFace().getId());
output.writeByte(ts.size());
for (int index = 0; index < ts.size(); ++index) {
output.writeInt(tilePalette.getNid(ts.get(index)));
output.writeInt(ts.getTagByIndex(index));
}
}));
} catch (UncheckedIOException e) {
throw e.getCause();
}
output.writeByte(0xFF);
}
private static <V> Consumer<V> guard(ThrowingConsumer<? super V, IOException> action) {
return v -> {
try {
action.accept(v);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
};
}
}