Skip to content

Commit

Permalink
feat: improve lighting storage
Browse files Browse the repository at this point in the history
  • Loading branch information
mworzala committed Jul 13, 2024
1 parent 3449457 commit 203f1f0
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 39 deletions.
8 changes: 4 additions & 4 deletions FORMAT.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ Entities or some other extra data field needs to be added to chunks in the futur
| Biome Palette | array[string] | |
| Biome Palette Data Length | varint | Only present if `Biome Palette Size > 1` |
| Biome Palette Data | array[long] | See the anvil format for more information about this type |
| Has Block Light Data | bool | If unset, block light is ommitted |
| Block Light | bytes | A 2048 byte long nibble array |
| Has Sky Light Data | bool | If unset, sky light is ommitted |
| Sky Light | bytes | A 2048 byte long nibble array |
| Block Light Data Content | byte | 0 = no lighting, 1 = all zero, 2 = all max, 3 = present after |
| Block Light | bytes | A 2048 byte long nibble array, only present if above = 3 |
| Sky Light Data Content | byte | 0 = no lighting, 1 = all zero, 2 = all max, 3 = present after |
| Sky Light | bytes | A 2048 byte long nibble array, only present if above = 3 |

### Block Entity

Expand Down
48 changes: 31 additions & 17 deletions src/main/java/net/hollowcube/polar/PolarLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@

import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
import net.hollowcube.polar.PolarSection.LightContent;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.builder.arguments.minecraft.ArgumentBlockState;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.exception.ExceptionManager;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.IChunkLoader;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.Section;
import net.minestom.server.instance.*;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.light.LightCompute;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.world.biome.Biome;
Expand All @@ -27,10 +26,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ForkJoinPool;
Expand Down Expand Up @@ -227,10 +223,19 @@ private void loadSection(@NotNull PolarSection sectionData, @NotNull Section sec
}

// Light
if (loadLighting && sectionData.hasBlockLightData())
section.setBlockLight(sectionData.blockLight());
if (loadLighting && sectionData.hasSkyLightData())
section.setSkyLight(sectionData.skyLight());
if (loadLighting && sectionData.blockLightContent() != LightContent.MISSING)
section.setBlockLight(getLightArray(sectionData.blockLightContent(), sectionData.blockLight()));
if (loadLighting && sectionData.skyLightContent() != LightContent.MISSING)
section.setSkyLight(getLightArray(sectionData.skyLightContent(), sectionData.skyLight()));
}

private byte[] getLightArray(@NotNull LightContent content, byte @Nullable [] data) {
return switch (content) {
case MISSING -> null;
case EMPTY -> LightCompute.emptyContent;
case FULL -> LightCompute.contentFullyLit;
case PRESENT -> data;
};
}

private void loadBlockEntity(@NotNull PolarChunk.BlockEntity blockEntity, @NotNull Chunk chunk) {
Expand Down Expand Up @@ -360,15 +365,17 @@ private void updateChunkData(@NotNull Short2ObjectMap<String> blockCache, @NotNu
biomeData[x + z * 4 + y * 4 * 4] = paletteId;
});

byte[] blockLight = section.blockLight().array();
if (blockLight.length != 2048) blockLight = null;
byte[] skyLight = section.skyLight().array();
if (skyLight.length != 2048) skyLight = null;
byte[] blockLight = null, skyLight = null;
if (chunk instanceof LightingChunk) {
blockLight = section.blockLight().array();
skyLight = section.skyLight().array();
}

sections[i] = new PolarSection(
blockPalette.toArray(new String[0]), blockData,
biomePalette.toArray(new String[0]), biomeData,
blockLight, skyLight
getLightContent(blockLight), blockLight,
getLightContent(skyLight), skyLight
);
}

Expand All @@ -393,6 +400,13 @@ private void updateChunkData(@NotNull Short2ObjectMap<String> blockCache, @NotNu
worldDataLock.writeLock().unlock();
}

private @NotNull LightContent getLightContent(byte @Nullable [] data) {
if (data == null) return LightContent.MISSING;
if (data.length == 0 || Arrays.equals(data, LightCompute.emptyContent)) return LightContent.EMPTY;
if (Arrays.equals(data, LightCompute.contentFullyLit)) return LightContent.FULL;
return LightContent.PRESENT;
}

@Override
public @NotNull CompletableFuture<Void> saveChunk(@NotNull Chunk chunk) {
return saveChunks(List.of(chunk));
Expand Down
22 changes: 18 additions & 4 deletions src/main/java/net/hollowcube/polar/PolarReader.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.hollowcube.polar;

import com.github.luben.zstd.Zstd;
import net.hollowcube.polar.PolarSection.LightContent;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.network.NetworkBuffer;
Expand Down Expand Up @@ -143,19 +144,32 @@ private PolarReader() {
PaletteUtil.unpack(biomeData, rawBiomeData, bitsPerEntry);
}

LightContent blockLightContent = LightContent.MISSING, skyLightContent = LightContent.MISSING;
byte[] blockLight = null, skyLight = null;

if (version > PolarWorld.VERSION_UNIFIED_LIGHT) {
if (buffer.read(BOOLEAN))
blockLightContent = version >= PolarWorld.VERSION_IMPROVED_LIGHT
? LightContent.VALUES[buffer.read(BYTE)]
: (buffer.read(BOOLEAN) ? LightContent.PRESENT : LightContent.MISSING);
if (blockLightContent == LightContent.PRESENT)
blockLight = buffer.readBytes(2048);
if (buffer.read(BOOLEAN))
skyLightContent = version >= PolarWorld.VERSION_IMPROVED_LIGHT
? LightContent.VALUES[buffer.read(BYTE)]
: (buffer.read(BOOLEAN) ? LightContent.PRESENT : LightContent.MISSING);
if (skyLightContent == LightContent.PRESENT)
skyLight = buffer.readBytes(2048);
} else if (buffer.read(BOOLEAN)) {
blockLightContent = LightContent.PRESENT;
blockLight = buffer.readBytes(2048);
skyLightContent = LightContent.PRESENT;
skyLight = buffer.readBytes(2048);
}

return new PolarSection(blockPalette, blockData, biomePalette, biomeData, blockLight, skyLight);
return new PolarSection(
blockPalette, blockData,
biomePalette, biomeData,
blockLightContent, blockLight,
skyLightContent, skyLight
);
}

private static @NotNull PolarChunk.BlockEntity readBlockEntity(@NotNull PolarDataConverter dataConverter, int version, int dataVersion, @NotNull NetworkBuffer buffer) {
Expand Down
28 changes: 20 additions & 8 deletions src/main/java/net/hollowcube/polar/PolarSection.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ public class PolarSection {
public static final int BLOCK_PALETTE_SIZE = 4096;
public static final int BIOME_PALETTE_SIZE = 64;

public enum LightContent {
MISSING, EMPTY, FULL, PRESENT;

public static final LightContent[] VALUES = values();
}

private final boolean empty;

private final String @NotNull [] blockPalette;
Expand All @@ -23,8 +29,9 @@ public class PolarSection {
private final String @NotNull [] biomePalette;
private final int @Nullable [] biomeData;

// Both light arrays are present/missing together. you cannot have one without the other.
private final LightContent blockLightContent;
private final byte @Nullable [] blockLight;
private final LightContent skyLightContent;
private final byte @Nullable [] skyLight;

public PolarSection() {
Expand All @@ -35,14 +42,17 @@ public PolarSection() {
this.biomePalette = new String[]{"minecraft:plains"};
this.biomeData = null;

this.blockLightContent = LightContent.MISSING;
this.blockLight = null;
this.skyLightContent = LightContent.MISSING;
this.skyLight = null;
}

public PolarSection(
String @NotNull [] blockPalette, int @Nullable [] blockData,
String @NotNull [] biomePalette, int @Nullable [] biomeData,
byte @Nullable [] blockLight, byte @Nullable [] skyLight
@NotNull LightContent blockLightContent, byte @Nullable [] blockLight,
@NotNull LightContent skyLightContent, byte @Nullable [] skyLight
) {
this.empty = false;

Expand All @@ -51,7 +61,9 @@ public PolarSection(
this.biomePalette = biomePalette;
this.biomeData = biomeData;

this.blockLightContent = blockLightContent;
this.blockLight = blockLight;
this.skyLightContent = skyLightContent;
this.skyLight = skyLight;
}

Expand Down Expand Up @@ -85,19 +97,19 @@ public int[] biomeData() {
return biomeData;
}

public boolean hasBlockLightData() {
return blockLight != null;
}

public boolean hasSkyLightData() {
return skyLight != null;
public @NotNull LightContent blockLightContent() {
return blockLightContent;
}

public byte[] blockLight() {
assert blockLight != null : "must check hasBlockLightData() before calling blockLight()";
return blockLight;
}

public @NotNull LightContent skyLightContent() {
return skyLightContent;
}

public byte[] skyLight() {
assert skyLight != null : "must check hasSkyLightData() before calling skyLight()";
return skyLight;
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/net/hollowcube/polar/PolarWorld.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
@SuppressWarnings("UnstableApiUsage")
public class PolarWorld {
public static final int MAGIC_NUMBER = 0x506F6C72; // `Polr`
public static final short LATEST_VERSION = 6;
public static final short LATEST_VERSION = 7;

static final short VERSION_UNIFIED_LIGHT = 1;
static final short VERSION_USERDATA_OPT_BLOCK_ENT_NBT = 2;
static final short VERSION_MINESTOM_NBT_READ_BREAK = 3;
static final short VERSION_WORLD_USERDATA = 4;
static final short VERSION_SHORT_GRASS = 5; // >:(
static final short VERSION_DATA_CONVERTER = 6;
static final short VERSION_IMPROVED_LIGHT = 7;

public static CompressionType DEFAULT_COMPRESSION = CompressionType.ZSTD;

Expand Down
10 changes: 5 additions & 5 deletions src/main/java/net/hollowcube/polar/PolarWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static byte[] write(@NotNull PolarWorld world, @NotNull PolarDataConverte
// Create final buffer
return NetworkBuffer.makeArray(buffer -> {
buffer.write(INT, PolarWorld.MAGIC_NUMBER);
buffer.write(SHORT, PolarWorld.LATEST_VERSION);
buffer.write(SHORT, PolarWorld.VERSION_IMPROVED_LIGHT);
buffer.write(VAR_INT, dataConverter.dataVersion());
buffer.write(BYTE, (byte) world.compression().ordinal());
switch (world.compression()) {
Expand Down Expand Up @@ -100,11 +100,11 @@ private static void writeSection(@NotNull NetworkBuffer buffer, @NotNull PolarSe
}

// Light
buffer.write(BOOLEAN, section.hasBlockLightData());
if (section.hasBlockLightData())
buffer.write(BYTE, (byte) section.blockLightContent().ordinal());
if (section.blockLightContent() == PolarSection.LightContent.PRESENT)
buffer.write(RAW_BYTES, section.blockLight());
buffer.write(BOOLEAN, section.hasSkyLightData());
if (section.hasSkyLightData())
buffer.write(BYTE, (byte) section.skyLightContent().ordinal());
if (section.skyLightContent() == PolarSection.LightContent.PRESENT)
buffer.write(RAW_BYTES, section.skyLight());
}

Expand Down

0 comments on commit 203f1f0

Please sign in to comment.