Cleanup Palette interface and read/write

This commit is contained in:
Nassim Jahnke 2021-09-16 13:03:31 +02:00
parent eaa18f569a
commit c565f2c9c7
No known key found for this signature in database
GPG Key ID: 6BE3B555EBC5982B
8 changed files with 227 additions and 220 deletions

View File

@ -37,7 +37,7 @@ public interface ChunkSection {
@Deprecated/*(forRemoval = true)*/
default int getFlatBlock(int idx) {
return palette(PaletteType.BLOCKS).value(idx);
return palette(PaletteType.BLOCKS).idAt(idx);
}
@Deprecated/*(forRemoval = true)*/
@ -47,7 +47,7 @@ public interface ChunkSection {
@Deprecated/*(forRemoval = true)*/
default void setFlatBlock(int idx, int id) {
palette(PaletteType.BLOCKS).setValue(idx, id);
palette(PaletteType.BLOCKS).setIdAt(idx, id);
}
@Deprecated/*(forRemoval = true)*/
@ -77,12 +77,12 @@ public interface ChunkSection {
@Deprecated/*(forRemoval = true)*/
default void setPaletteIndex(int idx, int index) {
palette(PaletteType.BLOCKS).setIndex(idx, index);
palette(PaletteType.BLOCKS).setPaletteIndexAt(idx, index);
}
@Deprecated/*(forRemoval = true)*/
default int getPaletteIndex(int idx) {
return palette(PaletteType.BLOCKS).index(idx);
return palette(PaletteType.BLOCKS).paletteIndexAt(idx);
}
@Deprecated/*(forRemoval = true)*/
@ -92,22 +92,22 @@ public interface ChunkSection {
@Deprecated/*(forRemoval = true)*/
default int getPaletteEntry(int index) {
return palette(PaletteType.BLOCKS).entry(index);
return palette(PaletteType.BLOCKS).idByIndex(index);
}
@Deprecated/*(forRemoval = true)*/
default void setPaletteEntry(int index, int id) {
palette(PaletteType.BLOCKS).setEntry(index, id);
palette(PaletteType.BLOCKS).setIdByIndex(index, id);
}
@Deprecated/*(forRemoval = true)*/
default void replacePaletteEntry(int oldId, int newId) {
palette(PaletteType.BLOCKS).replaceEntry(oldId, newId);
palette(PaletteType.BLOCKS).replaceId(oldId, newId);
}
@Deprecated/*(forRemoval = true)*/
default void addPaletteEntry(int id) {
palette(PaletteType.BLOCKS).addEntry(id);
palette(PaletteType.BLOCKS).addId(id);
}
@Deprecated/*(forRemoval = true)*/
@ -152,7 +152,7 @@ public interface ChunkSection {
*/
@Nullable DataPalette palette(PaletteType type);
void addPalette(DataPalette blockPalette);
void addPalette(PaletteType type, DataPalette blockPalette);
void removePalette(PaletteType type);
}

View File

@ -36,14 +36,14 @@ public class ChunkSectionImpl implements ChunkSection {
}
public ChunkSectionImpl(final boolean holdsLight) {
addPalette(new DataPaletteImpl(PaletteType.BLOCKS));
addPalette(PaletteType.BLOCKS, new DataPaletteImpl());
if (holdsLight) {
this.light = new ChunkSectionLightImpl();
}
}
public ChunkSectionImpl(final boolean holdsLight, final int expectedPaletteLength) {
addPalette(new DataPaletteImpl(PaletteType.BLOCKS, expectedPaletteLength));
addPalette(PaletteType.BLOCKS, new DataPaletteImpl(expectedPaletteLength));
if (holdsLight) {
this.light = new ChunkSectionLightImpl();
}
@ -75,8 +75,8 @@ public class ChunkSectionImpl implements ChunkSection {
}
@Override
public void addPalette(final DataPalette palette) {
palettes.put(palette.type(), palette);
public void addPalette(final PaletteType type, final DataPalette palette) {
palettes.put(type, palette);
}
@Override

View File

@ -25,82 +25,93 @@ package com.viaversion.viaversion.api.minecraft.chunks;
public interface DataPalette {
/**
* Returns the block state of the given index.
* Returns the value of the given chunk coordinate.
*
* @param idx block index within the section
* @param sectionCoordinate block index within the section
* @return block state of the given index
*/
int value(int idx);
int idAt(int sectionCoordinate);
/**
* Returns the block state of the section coordinate.
* Returns the value of the section coordinate.
*
* @param x section x
* @param y section y
* @param z section z
* @param sectionX section x
* @param sectionY section y
* @param sectionZ section z
* @return block state of the given section coordinate
*/
default int value(final int x, final int y, final int z) {
return value(ChunkSection.index(x, y, z));
default int idAt(final int sectionX, final int sectionY, final int sectionZ) {
return idAt(ChunkSection.index(sectionX, sectionY, sectionZ));
}
/**
* Set a block state in the chunk section.
* This method will not update non-air blocks count.
* Set a value in the chunk section.
* This method does not update non-air blocks count.
*
* @param idx block index within the section
* @param id raw or flat id of the block state
* @param sectionCoordinate block index within the section
* @param id id value
*/
void setValue(int idx, int id);
void setIdAt(int sectionCoordinate, int id);
/**
* Set a block state in the chunk section.
* This method will not update non-air blocks count.
* Set a value in the chunk section.
* This method does not update non-air blocks count.
*
* @param x section x
* @param y section y
* @param z section z
* @param id raw or flat id of the block state
* @param sectionX section x
* @param sectionY section y
* @param sectionZ section z
* @param id id value
*/
default void setValue(final int x, final int y, final int z, final int id) {
setValue(ChunkSection.index(x, y, z), id);
default void setIdAt(final int sectionX, final int sectionY, final int sectionZ, final int id) {
setIdAt(ChunkSection.index(sectionX, sectionY, sectionZ), id);
}
// ----------------------------------------------------------------------------
default int rawDataBlock(final int x, final int y, final int z) {
return value(x, y, z) >> 4;
}
default int dataBlock(final int x, final int y, final int z) {
return value(x, y, z) & 0xF;
}
default void setDataBlock(final int x, final int y, final int z, final int type, final int data) {
setValue(ChunkSection.index(x, y, z), type << 4 | (data & 0xF));
}
default void setDataBlock(final int idx, final int type, final int data) {
setValue(idx, type << 4 | (data & 0xF));
}
// ----------------------------------------------------------------------------
/**
* Sets a block to the given palette index.
* Returns the id assigned to the given palette index.
*
* @param idx block index
* @param index palette index
* @return id assigned to the given palette index
*/
void setIndex(int idx, int index);
int idByIndex(int index);
/**
* Assigns an id assigned to the given palette index.
*
* @param index palette index
* @param id id value
*/
void setIdByIndex(int index, int id);
/**
* Returns the palette index of the given block index.
*
* @param idx block index
* @param packedCoordinate block index
* @return palette index of the given block index
*/
int index(int idx);
int paletteIndexAt(int packedCoordinate);
/**
* Sets the index of the given section coordinate.
*
* @param sectionCoordinate block index
* @param index palette index
*/
void setPaletteIndexAt(int sectionCoordinate, int index);
/**
* Adds a new id to the palette.
*
* @param id id value
*/
void addId(int id);
/**
* Replaces an id in the palette.
*
* @param oldId old id
* @param newId new id
*/
void replaceId(int oldId, int newId);
/**
* Returns the size of the palette.
@ -109,46 +120,8 @@ public interface DataPalette {
*/
int size();
/**
* Returns the block state assigned to the given palette index.
*
* @param index palette index
* @return block state assigned to the given palette index
*/
int entry(int index);
/**
* Assigns a block state assigned to the given palette index.
*
* @param index palette index
* @param id block state
*/
void setEntry(int index, int id);
/**
* Replaces a block state in the palette.
*
* @param oldId old block state
* @param newId new block state
*/
void replaceEntry(int oldId, int newId);
/**
* Adds a new block state to the palette.
*
* @param id block state
*/
void addEntry(int id);
/**
* Clears the palette.
*/
void clear();
/**
* Returns the type of data this palette holds.
*
* @return type of data this palette holds
*/
PaletteType type();
}

View File

@ -32,18 +32,15 @@ public final class DataPaletteImpl implements DataPalette {
private final IntList palette;
private final Int2IntMap inversePalette;
private final int[] values;
private final PaletteType type;
public DataPaletteImpl(final PaletteType type) {
this.type = type;
public DataPaletteImpl() {
this.values = new int[ChunkSection.SIZE];
palette = new IntArrayList();
inversePalette = new Int2IntOpenHashMap();
inversePalette.defaultReturnValue(-1);
}
public DataPaletteImpl(final PaletteType type, final int expectedPaletteLength) {
this.type = type;
public DataPaletteImpl(final int expectedPaletteLength) {
this.values = new int[ChunkSection.SIZE];
// Pre-size the palette array/map
palette = new IntArrayList(expectedPaletteLength);
@ -52,13 +49,13 @@ public final class DataPaletteImpl implements DataPalette {
}
@Override
public int value(final int idx) {
final int index = values[idx];
public int idAt(final int sectionCoordinate) {
final int index = values[sectionCoordinate];
return palette.getInt(index);
}
@Override
public void setValue(final int idx, final int id) {
public void setIdAt(final int sectionCoordinate, final int id) {
int index = inversePalette.get(id);
if (index == -1) {
index = palette.size();
@ -66,17 +63,17 @@ public final class DataPaletteImpl implements DataPalette {
inversePalette.put(id, index);
}
values[idx] = index;
values[sectionCoordinate] = index;
}
@Override
public int index(final int idx) {
return values[idx];
public int paletteIndexAt(final int packedCoordinate) {
return values[packedCoordinate];
}
@Override
public void setIndex(final int idx, final int index) {
values[idx] = index;
public void setPaletteIndexAt(final int sectionCoordinate, final int index) {
values[sectionCoordinate] = index;
}
@Override
@ -85,12 +82,12 @@ public final class DataPaletteImpl implements DataPalette {
}
@Override
public int entry(final int index) {
public int idByIndex(final int index) {
return palette.getInt(index);
}
@Override
public void setEntry(final int index, final int id) {
public void setIdByIndex(final int index, final int id) {
final int oldId = palette.set(index, id);
if (oldId == id) return;
@ -107,7 +104,7 @@ public final class DataPaletteImpl implements DataPalette {
}
@Override
public void replaceEntry(final int oldId, final int newId) {
public void replaceId(final int oldId, final int newId) {
final int index = inversePalette.remove(oldId);
if (index == -1) return;
@ -120,7 +117,7 @@ public final class DataPaletteImpl implements DataPalette {
}
@Override
public void addEntry(final int id) {
public void addId(final int id) {
inversePalette.put(id, palette.size());
palette.add(id);
}
@ -130,9 +127,4 @@ public final class DataPaletteImpl implements DataPalette {
palette.clear();
inversePalette.clear();
}
@Override
public PaletteType type() {
return type;
}
}

View File

@ -24,15 +24,11 @@ package com.viaversion.viaversion.api.type.types.version;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSectionImpl;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.DataPaletteImpl;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.CompactArrayUtil;
import io.netty.buffer.ByteBuf;
public class ChunkSectionType1_18 extends Type<ChunkSection> {
private static final int GLOBAL_PALETTE = 15;
public final class ChunkSectionType1_18 extends Type<ChunkSection> {
public ChunkSectionType1_18() {
super("Chunk Section Type", ChunkSection.class);
@ -42,100 +38,15 @@ public class ChunkSectionType1_18 extends Type<ChunkSection> {
public ChunkSection read(final ByteBuf buffer) throws Exception {
final ChunkSection chunkSection = new ChunkSectionImpl();
chunkSection.setNonAirBlocksCount(buffer.readShort());
chunkSection.addPalette(readPalette(buffer, PaletteType.BLOCKS));
chunkSection.addPalette(readPalette(buffer, PaletteType.BIOMES));
chunkSection.addPalette(PaletteType.BLOCKS, Types1_18.BLOCK_PALETTE_TYPE.read(buffer));
chunkSection.addPalette(PaletteType.BIOMES, Types1_18.BIOME_PALETTE_TYPE.read(buffer));
return chunkSection;
}
@Override
public void write(final ByteBuf buffer, final ChunkSection section) throws Exception {
buffer.writeShort(section.getNonAirBlocksCount());
writePalette(buffer, section.palette(PaletteType.BLOCKS));
writePalette(buffer, section.palette(PaletteType.BIOMES));
}
private DataPalette readPalette(final ByteBuf buffer, final PaletteType type) {
int bitsPerValue = buffer.readByte();
final int originalBitsPerValue = bitsPerValue;
if (bitsPerValue > type.highestBitsPerValue()) {
bitsPerValue = GLOBAL_PALETTE;
}
// Read palette
final DataPaletteImpl palette;
if (bitsPerValue == 0) {
//TODO Create proper singleton palette Object
palette = new DataPaletteImpl(type, 1);
palette.addEntry(Type.VAR_INT.readPrimitive(buffer));
Type.VAR_INT.readPrimitive(buffer); // 0 values length
return palette;
}
if (bitsPerValue != GLOBAL_PALETTE) {
final int paletteLength = Type.VAR_INT.readPrimitive(buffer);
palette = new DataPaletteImpl(type, paletteLength);
for (int i = 0; i < paletteLength; i++) {
palette.addEntry(Type.VAR_INT.readPrimitive(buffer));
}
} else {
palette = new DataPaletteImpl(type);
}
// Read values
final long[] values = new long[Type.VAR_INT.readPrimitive(buffer)];
if (values.length > 0) {
final char valuesPerLong = (char) (64 / bitsPerValue);
final int expectedLength = (ChunkSection.SIZE + valuesPerLong - 1) / valuesPerLong;
if (values.length != expectedLength) {
throw new IllegalStateException("Palette data length (" + values.length + ") does not match expected length (" + expectedLength + ")! bitsPerValue=" + bitsPerValue + ", originalBitsPerValue=" + originalBitsPerValue);
}
for (int i = 0; i < values.length; i++) {
values[i] = buffer.readLong();
}
CompactArrayUtil.iterateCompactArrayWithPadding(bitsPerValue, ChunkSection.SIZE, values,
bitsPerValue == GLOBAL_PALETTE ? palette::setValue : palette::setIndex);
}
return palette;
}
private void writePalette(final ByteBuf buffer, final DataPalette palette) {
int bitsPerValue;
if (palette.size() > 1) {
bitsPerValue = palette.type() == PaletteType.BLOCKS ? 4 : 2; //TODO implement linear palette
while (palette.size() > 1 << bitsPerValue) {
bitsPerValue += 1;
}
if (bitsPerValue > palette.type().highestBitsPerValue()) {
bitsPerValue = GLOBAL_PALETTE;
}
} else {
bitsPerValue = 0;
}
buffer.writeByte(bitsPerValue);
if (bitsPerValue == 0) {
// Write single value
Type.VAR_INT.writePrimitive(buffer, palette.entry(0));
Type.VAR_INT.writePrimitive(buffer, 0); // Empty values length
return;
}
if (bitsPerValue != GLOBAL_PALETTE) {
// Write pallete
Type.VAR_INT.writePrimitive(buffer, palette.size());
for (int i = 0; i < palette.size(); i++) {
Type.VAR_INT.writePrimitive(buffer, palette.entry(i));
}
}
final long[] data = CompactArrayUtil.createCompactArrayWithPadding(bitsPerValue, ChunkSection.SIZE, bitsPerValue == GLOBAL_PALETTE ? palette::value : palette::index);
Type.VAR_INT.writePrimitive(buffer, data.length);
for (final long l : data) {
buffer.writeLong(l);
}
Types1_18.BLOCK_PALETTE_TYPE.write(buffer, section.palette(PaletteType.BLOCKS));
Types1_18.BIOME_PALETTE_TYPE.write(buffer, section.palette(PaletteType.BIOMES));
}
}

View File

@ -0,0 +1,127 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2021 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.version;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.DataPaletteImpl;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.type.PartialType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.CompactArrayUtil;
import io.netty.buffer.ByteBuf;
public final class PaletteType1_18 extends PartialType<DataPalette, PaletteType> {
private static final int GLOBAL_PALETTE = 15;
public PaletteType1_18(final PaletteType type) {
super(type, DataPalette.class);
}
@Override
public DataPalette read(final ByteBuf buffer, final PaletteType type) throws Exception {
int bitsPerValue = buffer.readByte();
final int originalBitsPerValue = bitsPerValue;
if (bitsPerValue > type.highestBitsPerValue()) {
bitsPerValue = GLOBAL_PALETTE;
}
// Read palette
final DataPaletteImpl palette;
if (bitsPerValue == 0) {
//TODO Create proper singleton palette Object
palette = new DataPaletteImpl(1);
palette.addId(Type.VAR_INT.readPrimitive(buffer));
Type.VAR_INT.readPrimitive(buffer); // 0 values length
return palette;
}
if (bitsPerValue != GLOBAL_PALETTE) {
final int paletteLength = Type.VAR_INT.readPrimitive(buffer);
palette = new DataPaletteImpl(paletteLength);
for (int i = 0; i < paletteLength; i++) {
palette.addId(Type.VAR_INT.readPrimitive(buffer));
}
} else {
palette = new DataPaletteImpl();
}
// Read values
final long[] values = new long[Type.VAR_INT.readPrimitive(buffer)];
if (values.length > 0) {
final char valuesPerLong = (char) (64 / bitsPerValue);
final int expectedLength = (ChunkSection.SIZE + valuesPerLong - 1) / valuesPerLong;
if (values.length != expectedLength) {
throw new IllegalStateException("Palette data length (" + values.length + ") does not match expected length (" + expectedLength + ")! bitsPerValue=" + bitsPerValue + ", originalBitsPerValue=" + originalBitsPerValue);
}
for (int i = 0; i < values.length; i++) {
values[i] = buffer.readLong();
}
CompactArrayUtil.iterateCompactArrayWithPadding(bitsPerValue, ChunkSection.SIZE, values,
bitsPerValue == GLOBAL_PALETTE ? palette::setIdAt : palette::setPaletteIndexAt);
}
return palette;
}
@Override
public void write(final ByteBuf buffer, final PaletteType type, final DataPalette palette) throws Exception {
int bitsPerValue;
if (palette.size() > 1) {
bitsPerValue = type == PaletteType.BLOCKS ? 4 : 2; //TODO implement linear palette
while (palette.size() > 1 << bitsPerValue) {
bitsPerValue += 1;
}
if (bitsPerValue > type.highestBitsPerValue()) {
bitsPerValue = GLOBAL_PALETTE;
}
} else {
bitsPerValue = 0;
}
buffer.writeByte(bitsPerValue);
if (bitsPerValue == 0) {
// Write single value
Type.VAR_INT.writePrimitive(buffer, palette.idByIndex(0));
Type.VAR_INT.writePrimitive(buffer, 0); // Empty values length
return;
}
if (bitsPerValue != GLOBAL_PALETTE) {
// Write pallete
Type.VAR_INT.writePrimitive(buffer, palette.size());
for (int i = 0; i < palette.size(); i++) {
Type.VAR_INT.writePrimitive(buffer, palette.idByIndex(i));
}
}
final long[] data = CompactArrayUtil.createCompactArrayWithPadding(bitsPerValue, ChunkSection.SIZE, bitsPerValue == GLOBAL_PALETTE ? palette::idAt : palette::paletteIndexAt);
Type.VAR_INT.writePrimitive(buffer, data.length);
for (final long l : data) {
buffer.writeLong(l);
}
}
}

View File

@ -24,10 +24,14 @@ package com.viaversion.viaversion.api.type.types.version;
import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.type.Type;
public final class Types1_18 {
public static final Type<ChunkSection> CHUNK_SECTION = new ChunkSectionType1_18();
public static final Type<BlockEntity> BLOCK_ENTITY = new BlockEntityType1_18();
public static final Type<DataPalette> BLOCK_PALETTE_TYPE = new PaletteType1_18(PaletteType.BLOCKS);
public static final Type<DataPalette> BIOME_PALETTE_TYPE = new PaletteType1_18(PaletteType.BIOMES);
}

View File

@ -132,9 +132,9 @@ public final class WorldPackets {
sections[i] = section;
section.setNonAirBlocksCount(0);
final DataPaletteImpl blockPalette = new DataPaletteImpl(PaletteType.BLOCKS);
blockPalette.addEntry(0);
section.addPalette(blockPalette);
final DataPaletteImpl blockPalette = new DataPaletteImpl();
blockPalette.addId(0);
section.addPalette(PaletteType.BLOCKS, blockPalette);
} else {
/*final DataPalette blockpalette = section.palette(PaletteType.BLOCKS);
for (int j = 0; j < blockpalette.size(); j++) {
@ -145,8 +145,8 @@ public final class WorldPackets {
// Fill biome palette
//TODO Use single value palette if given the possibility
final DataPaletteImpl biomePalette = new DataPaletteImpl(PaletteType.BIOMES);
section.addPalette(biomePalette);
final DataPaletteImpl biomePalette = new DataPaletteImpl();
section.addPalette(PaletteType.BIOMES, biomePalette);
for (int biomeIndex = i * BIOMES_PER_CHUNK; biomeIndex < (i * BIOMES_PER_CHUNK) + BIOMES_PER_CHUNK; biomeIndex++) {
final int biome = biomeData[biomeIndex];
final int minX = (biomeIndex & HORIZONTAL_MASK) << 2;
@ -155,7 +155,7 @@ public final class WorldPackets {
for (int x = minX; x < minX + 4; x++) {
for (int y = minY; y < minY + 4; y++) {
for (int z = minZ; z < minZ + 4; z++) {
biomePalette.setValue(x, y, z, biome);
biomePalette.setIdAt(x, y, z, biome);
}
}
}