Add basic tests for Palette

Signed-off-by: TheMode <themode@outlook.fr>
This commit is contained in:
TheMode 2021-12-18 16:30:24 +01:00
parent 6a204135bd
commit 41a52c993e
3 changed files with 93 additions and 9 deletions

View File

@ -10,11 +10,15 @@ import org.jetbrains.annotations.NotNull;
*/
public sealed interface Palette extends Writeable permits PaletteImpl {
static Palette blocks() {
return new PaletteImpl(16 * 16 * 16, 8, 6, 1);
return newPalette(16, 8, 6, 1);
}
static Palette biomes() {
return new PaletteImpl(4 * 4 * 4, 2, 2, 1);
return newPalette(4, 2, 2, 1);
}
static Palette newPalette(int dimension, int maxBitsPerEntry, int bitsPerEntry, int bitIncrement) {
return new PaletteImpl(dimension, maxBitsPerEntry, bitsPerEntry, bitIncrement);
}
int get(int x, int y, int z);
@ -47,5 +51,7 @@ public sealed interface Palette extends Writeable permits PaletteImpl {
*/
int maxSize();
int dimension();
@NotNull Palette clone();
}

View File

@ -7,8 +7,6 @@ import net.minestom.server.instance.Chunk;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import static net.minestom.server.instance.Chunk.CHUNK_SECTION_SIZE;
final class PaletteImpl implements Palette, Cloneable {
// Magic values generated with "Integer.MAX_VALUE >> (31 - bitsPerIndex)" for bitsPerIndex between 1 and 16
private static final int[] MAGIC_MASKS =
@ -18,6 +16,7 @@ final class PaletteImpl implements Palette, Cloneable {
8191, 16383, 32767};
// Specific to this palette type
private final int dimension;
private final int size;
private final int maxBitsPerEntry;
@ -36,8 +35,9 @@ final class PaletteImpl implements Palette, Cloneable {
// value = palette index
private Int2IntOpenHashMap valueToPaletteMap;
PaletteImpl(int size, int maxBitsPerEntry, int bitsPerEntry, int bitsIncrement) {
this.size = size;
PaletteImpl(int dimension, int maxBitsPerEntry, int bitsPerEntry, int bitsIncrement) {
this.dimension = dimension;
this.size = dimension * dimension * dimension;
this.maxBitsPerEntry = maxBitsPerEntry;
this.bitsPerEntry = bitsPerEntry;
@ -55,10 +55,16 @@ final class PaletteImpl implements Palette, Cloneable {
@Override
public int get(int x, int y, int z) {
if (x < 0 || y < 0 || z < 0) {
throw new IllegalArgumentException("Coordinates must be positive");
}
if (values.length == 0) {
// Section is not loaded, can only be air
return -1;
}
x %= dimension;
y %= dimension;
z %= dimension;
final int sectionIdentifier = getSectionIndex(x, y, z);
final int index = sectionIdentifier / valuesPerLong;
final int bitIndex = sectionIdentifier % valuesPerLong * bitsPerEntry;
@ -69,6 +75,9 @@ final class PaletteImpl implements Palette, Cloneable {
@Override
public void set(int x, int y, int z, int value) {
if (x < 0 || y < 0 || z < 0) {
throw new IllegalArgumentException("Coordinates must be positive");
}
final boolean placedAir = value == 0;
if (values.length == 0) {
if (placedAir) {
@ -78,6 +87,9 @@ final class PaletteImpl implements Palette, Cloneable {
// Initialize the section
this.values = new long[(size + valuesPerLong - 1) / valuesPerLong];
}
x %= dimension;
y %= dimension;
z %= dimension;
// Change to palette value
value = getPaletteIndex(value);
final int sectionIndex = getSectionIndex(x, y, z);
@ -126,6 +138,11 @@ final class PaletteImpl implements Palette, Cloneable {
return size;
}
@Override
public int dimension() {
return dimension;
}
@Override
public long[] data() {
return values;
@ -201,9 +218,9 @@ final class PaletteImpl implements Palette, Cloneable {
return paletteIndex;
}
static int getSectionIndex(int x, int y, int z) {
y = Math.floorMod(y, CHUNK_SECTION_SIZE);
return y << 8 | z << 4 | x;
int getSectionIndex(int x, int y, int z) {
y = Math.floorMod(y, dimension);
return y << (dimension / 2) | z << (dimension / 4) | x;
}
static int maxPaletteSize(int bitsPerEntry) {

View File

@ -0,0 +1,61 @@
package instance;
import net.minestom.server.instance.palette.Palette;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class PaletteTest {
private List<Palette> palettes = new ArrayList<>();
@BeforeEach
public void reset() {
for (int i = 4; i < 16; i++) {
palettes.add(Palette.newPalette(i, 5, 3, 1));
}
}
@Test
public void testPlacement() {
for (Palette palette : palettes) {
final int dimension = palette.dimension();
assertEquals(-1, palette.get(0, 0, 0), "Empty section should return -1");
palette.set(0, 0, 0, 64);
assertEquals(64, palette.get(0, 0, 0));
assertEquals(64, palette.get(dimension, 0, 0), "Coordinate must be rounded to the palette dimension");
palette.set(1, 0, 0, 65);
assertEquals(64, palette.get(0, 0, 0));
assertEquals(65, palette.get(1, 0, 0));
palette.set(0, 1, 0, 66);
assertEquals(64, palette.get(0, 0, 0));
assertEquals(65, palette.get(1, 0, 0));
assertEquals(66, palette.get(0, 1, 0));
palette.set(0, 0, 1, 67);
assertEquals(64, palette.get(0, 0, 0));
assertEquals(65, palette.get(1, 0, 0));
assertEquals(66, palette.get(0, 1, 0));
assertEquals(67, palette.get(0, 0, 1));
}
}
@Test
public void testPlacementNeg() {
for (Palette palette : palettes) {
assertThrows(IllegalArgumentException.class, () -> palette.set(-1, 0, 0, 64));
assertThrows(IllegalArgumentException.class, () -> palette.set(0, -1, 0, 64));
assertThrows(IllegalArgumentException.class, () -> palette.set(0, 0, -1, 64));
assertThrows(IllegalArgumentException.class, () -> palette.get(-1, 0, 0));
assertThrows(IllegalArgumentException.class, () -> palette.get(0, -1, 0));
assertThrows(IllegalArgumentException.class, () -> palette.get(0, 0, -1));
}
}
}