World tinkering
This commit is contained in:
@@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user