World tinkering

This commit is contained in:
mcrcortex
2024-07-15 12:24:50 +10:00
parent 91e93dea2b
commit 5b5939855f
11 changed files with 78 additions and 47 deletions

View File

@@ -234,16 +234,16 @@ public class VoxelCore {
//this.world.getMapper().forceResaveStates(); //this.world.getMapper().forceResaveStates();
if (this.importer != null) { if (this.importer != null) {
System.out.println("Shutting down importer"); System.out.println("Shutting down importer");
try {this.importer.shutdown();this.importer = null;} catch (Exception e) {System.err.println(e);} try {this.importer.shutdown();this.importer = null;} catch (Exception e) {e.printStackTrace();}
} }
System.out.println("Shutting down voxel core"); System.out.println("Shutting down voxel core");
try {this.renderGen.shutdown();} catch (Exception e) {System.err.println(e);} try {this.renderGen.shutdown();} catch (Exception e) {e.printStackTrace();}
System.out.println("Render gen shut down"); System.out.println("Render gen shut down");
try {this.world.shutdown();} catch (Exception e) {System.err.println(e);} try {this.world.shutdown();} catch (Exception e) {e.printStackTrace();}
System.out.println("World engine shut down"); System.out.println("World engine shut down");
try {this.renderer.shutdown(); this.viewportSelector.free(); this.modelManager.free();} catch (Exception e) {System.err.println(e);} try {this.renderer.shutdown(); this.viewportSelector.free(); this.modelManager.free();} catch (Exception e) {e.printStackTrace();}
System.out.println("Renderer shut down"); System.out.println("Renderer shut down");
if (this.postProcessing!=null){try {this.postProcessing.shutdown();} catch (Exception e) {System.err.println(e);}} if (this.postProcessing!=null){try {this.postProcessing.shutdown();} catch (Exception e) {e.printStackTrace();}}
System.out.println("Voxel core shut down"); System.out.println("Voxel core shut down");
} }

View File

@@ -87,7 +87,7 @@ public class RenderGenerationService {
} }
} }
} catch (Exception e) { } catch (Exception e) {
System.err.println(e); e.printStackTrace();
MinecraftClient.getInstance().executeSync(()->MinecraftClient.getInstance().player.sendMessage(Text.literal("Voxy render service had an exception while executing please check logs and report error"))); MinecraftClient.getInstance().executeSync(()->MinecraftClient.getInstance().player.sendMessage(Text.literal("Voxy render service had an exception while executing please check logs and report error")));
} }
} }

View File

@@ -237,6 +237,8 @@ public class WorldImporter {
} }
private static final ThreadLocal<VoxelizedSection> SECTION_CACHE = ThreadLocal.withInitial(VoxelizedSection::createEmpty);
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.createPalettedContainerCodec(Block.STATE_IDS, BlockState.CODEC, PalettedContainer.PaletteProvider.BLOCK_STATE, Blocks.AIR.getDefaultState()); private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.createPalettedContainerCodec(Block.STATE_IDS, BlockState.CODEC, PalettedContainer.PaletteProvider.BLOCK_STATE, Blocks.AIR.getDefaultState());
private void importSectionNBT(int x, int y, int z, NbtCompound section) { private void importSectionNBT(int x, int y, int z, NbtCompound section) {
if (section.getCompound("block_states").isEmpty()) { if (section.getCompound("block_states").isEmpty()) {
@@ -260,9 +262,15 @@ public class WorldImporter {
skyLight = null; skyLight = null;
} }
var blockStates = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, section.getCompound("block_states")).result().get(); var blockStatesRes = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, section.getCompound("block_states"));
if (!blockStatesRes.hasResultOrPartial()) {
//TODO: if its only partial, it means should try to upgrade the nbt format with datafixerupper probably
return;
}
var blockStates = blockStatesRes.getPartialOrThrow();
var biomes = this.biomeCodec.parse(NbtOps.INSTANCE, section.getCompound("biomes")).result().orElse(this.defaultBiomeProvider); var biomes = this.biomeCodec.parse(NbtOps.INSTANCE, section.getCompound("biomes")).result().orElse(this.defaultBiomeProvider);
VoxelizedSection csec = WorldConversionFactory.convert( VoxelizedSection csec = WorldConversionFactory.convert(
SECTION_CACHE.get().setPosition(x, y, z),
this.world.getMapper(), this.world.getMapper(),
blockStates, blockStates,
biomes, biomes,
@@ -277,10 +285,7 @@ public class WorldImporter {
} }
sky = 15-sky; sky = 15-sky;
return (byte) (sky|(block<<4)); return (byte) (sky|(block<<4));
}, }
x,
y,
z
); );
WorldConversionFactory.mipSection(csec, this.world.getMapper()); WorldConversionFactory.mipSection(csec, this.world.getMapper());

View File

@@ -24,6 +24,7 @@ public class RocksDBStorageBackend extends StorageBackend {
private final List<AbstractImmutableNativeReference> closeList = new ArrayList<>(); private final List<AbstractImmutableNativeReference> closeList = new ArrayList<>();
public RocksDBStorageBackend(String path) { public RocksDBStorageBackend(String path) {
/*
var lockPath = new File(path).toPath().resolve("LOCK"); var lockPath = new File(path).toPath().resolve("LOCK");
if (Files.exists(lockPath)) { if (Files.exists(lockPath)) {
System.err.println("WARNING, deleting rocksdb LOCK file"); System.err.println("WARNING, deleting rocksdb LOCK file");
@@ -44,6 +45,7 @@ public class RocksDBStorageBackend extends StorageBackend {
throw new RuntimeException("Unable to delete rocksdb lock file"); throw new RuntimeException("Unable to delete rocksdb lock file");
} }
} }
*/
final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions().optimizeUniversalStyleCompaction(); final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions().optimizeUniversalStyleCompaction();
@@ -71,6 +73,8 @@ public class RocksDBStorageBackend extends StorageBackend {
this.worldSections = handles.get(1); this.worldSections = handles.get(1);
this.idMappings = handles.get(2); this.idMappings = handles.get(2);
this.db.flushWal(true);
} catch (RocksDBException e) { } catch (RocksDBException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@@ -5,15 +5,19 @@ import me.cortex.voxy.common.world.other.Mapper;
//16x16x16 block section //16x16x16 block section
public class VoxelizedSection { public class VoxelizedSection {
public final int x; public int x;
public final int y; public int y;
public final int z; public int z;
final long[] section; final long[] section;
public VoxelizedSection(long[] section, int x, int y, int z) { public VoxelizedSection(long[] section) {
this.section = section; this.section = section;
}
public VoxelizedSection setPosition(int x, int y, int z) {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.z = z; this.z = z;
return this;
} }
private static int getIdx(int x, int y, int z, int shiftBy, int size) { private static int getIdx(int x, int y, int z, int shiftBy, int size) {
@@ -32,7 +36,7 @@ public class VoxelizedSection {
return this.section[getIdx(x, y, z, 0, 4-lvl) + offset]; return this.section[getIdx(x, y, z, 0, 4-lvl) + offset];
} }
public static VoxelizedSection createEmpty(int x, int y, int z) { public static VoxelizedSection createEmpty() {
return new VoxelizedSection(new long[16*16*16 + 8*8*8 + 4*4*4 + 2*2*2 + 1], x, y, z); return new VoxelizedSection(new long[16*16*16 + 8*8*8 + 4*4*4 + 2*2*2 + 1]);
} }
} }

View File

@@ -13,16 +13,12 @@ public class WorldConversionFactory {
private static final ThreadLocal<Reference2IntOpenHashMap<BlockState>> BLOCK_CACHE = ThreadLocal.withInitial(Reference2IntOpenHashMap::new); private static final ThreadLocal<Reference2IntOpenHashMap<BlockState>> BLOCK_CACHE = ThreadLocal.withInitial(Reference2IntOpenHashMap::new);
//TODO: add a local mapper cache since it should be smaller and faster //TODO: add a local mapper cache since it should be smaller and faster
public static VoxelizedSection convert(Mapper stateMapper, public static VoxelizedSection convert(VoxelizedSection section,
Mapper stateMapper,
PalettedContainer<BlockState> blockContainer, PalettedContainer<BlockState> blockContainer,
ReadableContainer<RegistryEntry<Biome>> biomeContainer, ReadableContainer<RegistryEntry<Biome>> biomeContainer,
ILightingSupplier lightSupplier, ILightingSupplier lightSupplier) {
int sx,
int sy,
int sz) {
var blockCache = BLOCK_CACHE.get(); var blockCache = BLOCK_CACHE.get();
var section = VoxelizedSection.createEmpty(sx, sy, sz);
var data = section.section; var data = section.section;
int blockId = -1; int blockId = -1;

View File

@@ -10,19 +10,38 @@ import static org.lwjgl.util.zstd.Zstd.*;
public class SaveLoadSystem { public class SaveLoadSystem {
public static int lin2z(int i) {
int x = i&0x1F;
int y = (i>>10)&0x1F;
int z = (i>>5)&0x1F;
return Integer.expand(x,0b1001001001001)|Integer.expand(y,0b10010010010010)|Integer.expand(z,0b100100100100100);
}
public static int z2lin(int i) {
int x = Integer.compress(i, 0b1001001001001);
int y = Integer.compress(i, 0b10010010010010);
int z = Integer.compress(i, 0b100100100100100);
return x|(y<<10)|(z<<5);
}
//TODO: Cache like long2short and the short and other data to stop allocs //TODO: Cache like long2short and the short and other data to stop allocs
public static ByteBuffer serialize(WorldSection section) { public static ByteBuffer serialize(WorldSection section) {
var data = section.copyData(); var data = section.copyData();
var compressed = new short[data.length]; var compressed = new short[data.length];
Long2ShortOpenHashMap LUT = new Long2ShortOpenHashMap(data.length); Long2ShortOpenHashMap LUT = new Long2ShortOpenHashMap(data.length);
LongArrayList LUTVAL = new LongArrayList(); LongArrayList LUTVAL = new LongArrayList();
long pHash = 99;
for (int i = 0; i < data.length; i++) { for (int i = 0; i < data.length; i++) {
long block = data[i]; long block = data[i];
short mapping = LUT.computeIfAbsent(block, id->{ short mapping = LUT.computeIfAbsent(block, id->{
LUTVAL.add(id); LUTVAL.add(id);
return (short)(LUTVAL.size()-1); return (short)(LUTVAL.size()-1);
}); });
compressed[i] = mapping; compressed[lin2z(i)] = mapping;
pHash *= 127817112311121L;
pHash ^= pHash>>31;
pHash += 9918322711L;
pHash ^= block;
} }
long[] lut = LUTVAL.toLongArray(); long[] lut = LUTVAL.toLongArray();
ByteBuffer raw = MemoryUtil.memAlloc(compressed.length*2+lut.length*8+512); ByteBuffer raw = MemoryUtil.memAlloc(compressed.length*2+lut.length*8+512);
@@ -36,13 +55,10 @@ public class SaveLoadSystem {
hash += 12831; hash += 12831;
hash ^= id; hash ^= id;
} }
hash ^= pHash;
for (int i = 0; i < compressed.length; i++) { for (short block : compressed) {
short block = compressed[i];
raw.putShort(block); raw.putShort(block);
hash *= 1230987149811L;
hash += 12831;
hash ^= (block*1827631L) ^ data[i];
} }
raw.putLong(hash); raw.putLong(hash);
@@ -73,13 +89,18 @@ public class SaveLoadSystem {
} }
for (int i = 0; i < section.data.length; i++) { for (int i = 0; i < section.data.length; i++) {
short lutId = data.getShort(); section.data[z2lin(i)] = lut[data.getShort()];
section.data[i] = lut[lutId];
hash *= 1230987149811L;
hash += 12831;
hash ^= (lutId*1827631L) ^ section.data[i];
} }
long pHash = 99;
for (long block : section.data) {
pHash *= 127817112311121L;
pHash ^= pHash>>31;
pHash += 9918322711L;
pHash ^= block;
}
hash ^= pHash;
long expectedHash = data.getLong(); long expectedHash = data.getLong();
if (expectedHash != hash) { if (expectedHash != hash) {
//throw new IllegalStateException("Hash mismatch got: " + hash + " expected: " + expectedHash); //throw new IllegalStateException("Hash mismatch got: " + hash + " expected: " + expectedHash);

View File

@@ -109,6 +109,8 @@ public class WorldEngine {
//TODO: move this to auxilery class so that it can take into account larger than 4 mip levels //TODO: move this to auxilery class so that it can take into account larger than 4 mip levels
//Executes an update to the world and automatically updates all the parent mip layers up to level 4 (e.g. where 1 chunk section is 1 block big) //Executes an update to the world and automatically updates all the parent mip layers up to level 4 (e.g. where 1 chunk section is 1 block big)
//NOTE: THIS RUNS ON THE THREAD IT WAS EXECUTED ON, when this method exits, the calling method may assume that VoxelizedSection is no longer needed
public void insertUpdate(VoxelizedSection section) {//TODO: add a bitset of levels to update and if it should force update public void insertUpdate(VoxelizedSection section) {//TODO: add a bitset of levels to update and if it should force update
//The >>1 is cause the world sections size is 32x32x32 vs the 16x16x16 of the voxelized section //The >>1 is cause the world sections size is 32x32x32 vs the 16x16x16 of the voxelized section
for (int lvl = 0; lvl < this.maxMipLevels; lvl++) { for (int lvl = 0; lvl < this.maxMipLevels; lvl++) {
@@ -146,10 +148,10 @@ public class WorldEngine {
} }
public void shutdown() { public void shutdown() {
try {this.storage.flush();} catch (Exception e) {System.err.println(e);} try {this.storage.flush();} catch (Exception e) {e.printStackTrace();}
//Shutdown in this order to preserve as much data as possible //Shutdown in this order to preserve as much data as possible
try {this.ingestService.shutdown();} catch (Exception e) {System.err.println(e);} try {this.ingestService.shutdown();} catch (Exception e) {e.printStackTrace();}
try {this.savingService.shutdown();} catch (Exception e) {System.err.println(e);} try {this.savingService.shutdown();} catch (Exception e) {e.printStackTrace();}
try {this.storage.close();} catch (Exception e) {System.err.println(e);} try {this.storage.close();} catch (Exception e) {e.printStackTrace();}
} }
} }

View File

@@ -48,7 +48,7 @@ public class SectionSavingService {
this.world.storage.setSectionData(section.key, saveData); this.world.storage.setSectionData(section.key, saveData);
MemoryUtil.memFree(saveData); MemoryUtil.memFree(saveData);
} catch (Exception e) { } catch (Exception e) {
System.err.println(e); e.printStackTrace();
MinecraftClient.getInstance().executeSync(()->MinecraftClient.getInstance().player.sendMessage(Text.literal("Voxy saver had an exception while executing please check logs and report error"))); MinecraftClient.getInstance().executeSync(()->MinecraftClient.getInstance().player.sendMessage(Text.literal("Voxy saver had an exception while executing please check logs and report error")));
} }
section.release(); section.release();

View File

@@ -42,7 +42,7 @@ public class ServiceThreadPool {
try { try {
job.run(); job.run();
} catch (Exception e) { } catch (Exception e) {
System.err.println(e); e.printStackTrace();
MinecraftClient.getInstance().executeSync(()-> MinecraftClient.getInstance().executeSync(()->
MinecraftClient.getInstance().player.sendMessage( MinecraftClient.getInstance().player.sendMessage(
Text.literal( Text.literal(

View File

@@ -51,9 +51,11 @@ public class VoxelIngestService {
i++; i++;
var lighting = this.captureLightMap.remove(ChunkSectionPos.from(chunk.getPos(), i).asLong()); var lighting = this.captureLightMap.remove(ChunkSectionPos.from(chunk.getPos(), i).asLong());
if (section.isEmpty()) { if (section.isEmpty()) {
this.world.insertUpdate(VoxelizedSection.createEmpty(chunk.getPos().x, i, chunk.getPos().z)); //TODO: add local cache so that it doesnt constantly create new sections
this.world.insertUpdate(VoxelizedSection.createEmpty().setPosition(chunk.getPos().x, i, chunk.getPos().z));
} else { } else {
VoxelizedSection csec = WorldConversionFactory.convert( VoxelizedSection csec = WorldConversionFactory.convert(
VoxelizedSection.createEmpty().setPosition(chunk.getPos().x, i, chunk.getPos().z),
this.world.getMapper(), this.world.getMapper(),
section.getBlockStateContainer(), section.getBlockStateContainer(),
section.getBiomeContainer(), section.getBiomeContainer(),
@@ -70,17 +72,14 @@ public class VoxelIngestService {
sky = 15-sky;//This is cause sky light is inverted which saves memory when saving empty sections sky = 15-sky;//This is cause sky light is inverted which saves memory when saving empty sections
return (byte) (sky|(block<<4)); return (byte) (sky|(block<<4));
} }
}, }
chunk.getPos().x,
i,
chunk.getPos().z
); );
WorldConversionFactory.mipSection(csec, this.world.getMapper()); WorldConversionFactory.mipSection(csec, this.world.getMapper());
this.world.insertUpdate(csec); this.world.insertUpdate(csec);
} }
} }
} catch (Exception e) { } catch (Exception e) {
System.err.println(e); e.printStackTrace();
MinecraftClient.getInstance().executeSync(()->MinecraftClient.getInstance().player.sendMessage(Text.literal("Voxy ingester had an exception while executing please check logs and report error"))); MinecraftClient.getInstance().executeSync(()->MinecraftClient.getInstance().player.sendMessage(Text.literal("Voxy ingester had an exception while executing please check logs and report error")));
} }
} }