Added experimental TranslocatingStorageAdaptor
This commit is contained in:
@@ -2,6 +2,7 @@ package me.cortex.voxy.client;
|
|||||||
|
|
||||||
import me.cortex.voxy.client.config.VoxyConfig;
|
import me.cortex.voxy.client.config.VoxyConfig;
|
||||||
import me.cortex.voxy.client.core.VoxelCore;
|
import me.cortex.voxy.client.core.VoxelCore;
|
||||||
|
import me.cortex.voxy.client.saver.WorldSelectionSystem;
|
||||||
import me.cortex.voxy.client.terrain.WorldImportCommand;
|
import me.cortex.voxy.client.terrain.WorldImportCommand;
|
||||||
import me.cortex.voxy.common.storage.config.Serialization;
|
import me.cortex.voxy.common.storage.config.Serialization;
|
||||||
import me.cortex.voxy.common.storage.other.CompressionStorageAdaptor;
|
import me.cortex.voxy.common.storage.other.CompressionStorageAdaptor;
|
||||||
@@ -14,27 +15,21 @@ import net.fabricmc.api.ClientModInitializer;
|
|||||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class Voxy implements ClientModInitializer {
|
public class Voxy implements ClientModInitializer {
|
||||||
@Override
|
@Override
|
||||||
public void onInitializeClient() {
|
public void onInitializeClient() {
|
||||||
//var cfg = new CompressionStorageAdaptor.Config();
|
Serialization.init();
|
||||||
//cfg.compressor = new ZSTDCompressor.Config();
|
|
||||||
//cfg.backend = new FragmentedStorageBackendAdaptor.Config();
|
|
||||||
//((FragmentedStorageBackendAdaptor.Config)cfg.backend).backends.add(new RocksDBStorageBackend.Config());
|
|
||||||
//System.out.println(Serialization.GSON.toJson(cfg));
|
|
||||||
|
|
||||||
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
|
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
|
||||||
dispatcher.register(WorldImportCommand.register());
|
dispatcher.register(WorldImportCommand.register());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static final WorldSelectionSystem selector = new WorldSelectionSystem();
|
||||||
|
|
||||||
public static VoxelCore createVoxelCore(ClientWorld world) {
|
public static VoxelCore createVoxelCore(ClientWorld world) {
|
||||||
StorageBackend storage = new RocksDBStorageBackend(VoxyConfig.CONFIG.storagePath);
|
var selection = selector.getBestSelectionOrCreate(world);
|
||||||
//StorageBackend storage = new FragmentedStorageBackendAdaptor(new File(VoxyConfig.CONFIG.storagePath));
|
return new VoxelCore(selection);
|
||||||
storage = new CompressionStorageAdaptor(new ZSTDCompressor(VoxyConfig.CONFIG.savingCompressionLevel), storage);
|
|
||||||
var engine = new WorldEngine(storage, VoxyConfig.CONFIG.ingestThreads, VoxyConfig.CONFIG.savingThreads, 5);
|
|
||||||
return new VoxelCore(engine);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public class DistanceTracker {
|
|||||||
|
|
||||||
public void init(int x, int z) {
|
public void init(int x, int z) {
|
||||||
//Radius of chunks to enqueue
|
//Radius of chunks to enqueue
|
||||||
int SIZE = 64;
|
int SIZE = 128;
|
||||||
//Insert highest LOD level
|
//Insert highest LOD level
|
||||||
for (int ox = -SIZE; ox <= SIZE; ox++) {
|
for (int ox = -SIZE; ox <= SIZE; ox++) {
|
||||||
for (int oz = -SIZE; oz <= SIZE; oz++) {
|
for (int oz = -SIZE; oz <= SIZE; oz++) {
|
||||||
@@ -265,8 +265,8 @@ public class DistanceTracker {
|
|||||||
|
|
||||||
this.currentX = cx;
|
this.currentX = cx;
|
||||||
this.currentZ = cz;
|
this.currentZ = cz;
|
||||||
this.lastUpdateX = x;
|
this.lastUpdateX = x + (((int)(Math.random()*4))<<(this.shiftSize-4));
|
||||||
this.lastUpdateZ = z;
|
this.lastUpdateZ = z + (((int)(Math.random()*4))<<(this.shiftSize-4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import me.cortex.voxy.client.core.rendering.*;
|
|||||||
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
|
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
|
||||||
import me.cortex.voxy.client.core.rendering.post.PostProcessing;
|
import me.cortex.voxy.client.core.rendering.post.PostProcessing;
|
||||||
import me.cortex.voxy.client.core.util.DebugUtil;
|
import me.cortex.voxy.client.core.util.DebugUtil;
|
||||||
|
import me.cortex.voxy.client.saver.WorldSelectionSystem;
|
||||||
import me.cortex.voxy.common.world.WorldEngine;
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
import me.cortex.voxy.client.importers.WorldImporter;
|
import me.cortex.voxy.client.importers.WorldImporter;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
@@ -46,8 +47,8 @@ public class VoxelCore {
|
|||||||
|
|
||||||
//private final Thread shutdownThread = new Thread(this::shutdown);
|
//private final Thread shutdownThread = new Thread(this::shutdown);
|
||||||
|
|
||||||
public VoxelCore(WorldEngine engine) {
|
public VoxelCore(WorldSelectionSystem.Selection worldSelection) {
|
||||||
this.world = engine;
|
this.world = worldSelection.createEngine();
|
||||||
System.out.println("Initializing voxy core");
|
System.out.println("Initializing voxy core");
|
||||||
|
|
||||||
//Trigger the shared index buffer loading
|
//Trigger the shared index buffer loading
|
||||||
@@ -106,6 +107,7 @@ public class VoxelCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Matrix4f getProjectionMatrix() {
|
private Matrix4f getProjectionMatrix() {
|
||||||
|
//TODO: use the existing projection matrix use mulLocal by the inverse of the projection and then mulLocal our projection
|
||||||
|
|
||||||
var projection = new Matrix4f();
|
var projection = new Matrix4f();
|
||||||
var client = MinecraftClient.getInstance();
|
var client = MinecraftClient.getInstance();
|
||||||
@@ -115,7 +117,7 @@ public class VoxelCore {
|
|||||||
|
|
||||||
projection.setPerspective(fov * 0.01745329238474369f,
|
projection.setPerspective(fov * 0.01745329238474369f,
|
||||||
(float) client.getWindow().getFramebufferWidth() / (float)client.getWindow().getFramebufferHeight(),
|
(float) client.getWindow().getFramebufferWidth() / (float)client.getWindow().getFramebufferHeight(),
|
||||||
64F, 16 * 3000f);
|
16F, 16 * 3000f);
|
||||||
var transform = new Matrix4f().identity();
|
var transform = new Matrix4f().identity();
|
||||||
transform.translate(gameRenderer.zoomX, -gameRenderer.zoomY, 0.0F);
|
transform.translate(gameRenderer.zoomX, -gameRenderer.zoomY, 0.0F);
|
||||||
transform.scale(gameRenderer.zoom, gameRenderer.zoom, 1.0F);
|
transform.scale(gameRenderer.zoom, gameRenderer.zoom, 1.0F);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package me.cortex.voxy.client.core.rendering;
|
package me.cortex.voxy.client.core.rendering;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
||||||
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
|
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
|
||||||
import me.cortex.voxy.common.world.WorldEngine;
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
@@ -14,45 +16,77 @@ public class RenderTracker {
|
|||||||
private final WorldEngine world;
|
private final WorldEngine world;
|
||||||
private RenderGenerationService renderGen;
|
private RenderGenerationService renderGen;
|
||||||
private final AbstractFarWorldRenderer renderer;
|
private final AbstractFarWorldRenderer renderer;
|
||||||
|
private final LongSet[] sets;
|
||||||
|
|
||||||
//private final Long2ObjectOpenHashMap<Object> activeSections = new Long2ObjectOpenHashMap<>();
|
|
||||||
private final ConcurrentHashMap<Long,Object> activeSections = new ConcurrentHashMap<>(50000,0.75f, 16);
|
|
||||||
private static final Object O = new Object();
|
|
||||||
|
|
||||||
|
public RenderTracker(WorldEngine world, AbstractFarWorldRenderer renderer) {
|
||||||
|
this.world = world;
|
||||||
|
this.renderer = renderer;
|
||||||
|
this.sets = new LongSet[1<<4];
|
||||||
|
for (int i = 0; i < this.sets.length; i++) {
|
||||||
|
this.sets[i] = new LongOpenHashSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setRenderGen(RenderGenerationService renderGen) {
|
public void setRenderGen(RenderGenerationService renderGen) {
|
||||||
this.renderGen = renderGen;
|
this.renderGen = renderGen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RenderTracker(WorldEngine world, AbstractFarWorldRenderer renderer) {
|
public static long mixStafford13(long seed) {
|
||||||
this.world = world;
|
seed = (seed ^ seed >>> 30) * -4658895280553007687L;
|
||||||
this.renderer = renderer;
|
seed = (seed ^ seed >>> 27) * -7723592293110705685L;
|
||||||
|
return seed ^ seed >>> 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LongSet getSet(long key) {
|
||||||
|
return this.sets[(int) (mixStafford13(key) & (this.sets.length-1))];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void put(long key) {
|
||||||
|
var set = this.getSet(key);
|
||||||
|
synchronized (set) {
|
||||||
|
set.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void remove(long key) {
|
||||||
|
var set = this.getSet(key);
|
||||||
|
synchronized (set) {
|
||||||
|
set.remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean contains(long key) {
|
||||||
|
var set = this.getSet(key);
|
||||||
|
synchronized (set) {
|
||||||
|
return set.contains(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Adds a lvl 0 section into the world renderer
|
//Adds a lvl 0 section into the world renderer
|
||||||
public void addLvl0(int x, int y, int z) {
|
public void addLvl0(int x, int y, int z) {
|
||||||
this.activeSections.put(WorldEngine.getWorldSectionId(0, x, y, z), O);
|
this.put(WorldEngine.getWorldSectionId(0, x, y, z));
|
||||||
this.renderGen.enqueueTask(0, x, y, z, this::shouldStillBuild);
|
this.renderGen.enqueueTask(0, x, y, z, this::shouldStillBuild);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Removes a lvl 0 section from the world renderer
|
//Removes a lvl 0 section from the world renderer
|
||||||
public void remLvl0(int x, int y, int z) {
|
public void remLvl0(int x, int y, int z) {
|
||||||
this.activeSections.remove(WorldEngine.getWorldSectionId(0, x, y, z));
|
this.remove(WorldEngine.getWorldSectionId(0, x, y, z));
|
||||||
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(0, x, y, z)));
|
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(0, x, y, z)));
|
||||||
this.renderGen.removeTask(0, x, y, z);
|
this.renderGen.removeTask(0, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Increases from lvl-1 to lvl at the coordinates (which are in lvl space)
|
//Increases from lvl-1 to lvl at the coordinates (which are in lvl space)
|
||||||
public void inc(int lvl, int x, int y, int z) {
|
public void inc(int lvl, int x, int y, int z) {
|
||||||
this.activeSections.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)));
|
this.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)));
|
||||||
this.activeSections.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)+1));
|
this.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)+1));
|
||||||
this.activeSections.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)));
|
this.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)));
|
||||||
this.activeSections.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)+1));
|
this.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)+1));
|
||||||
this.activeSections.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)));
|
this.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)));
|
||||||
this.activeSections.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)+1));
|
this.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)+1));
|
||||||
this.activeSections.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)));
|
this.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)));
|
||||||
this.activeSections.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)+1));
|
this.remove(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)+1));
|
||||||
this.activeSections.put(WorldEngine.getWorldSectionId(lvl, x, y, z), O);
|
this.put(WorldEngine.getWorldSectionId(lvl, x, y, z));
|
||||||
|
|
||||||
//TODO: make a seperate object to hold the build data and link it with the location in a
|
//TODO: make a seperate object to hold the build data and link it with the location in a
|
||||||
// concurrent hashmap or something, this is so that e.g. the build data position
|
// concurrent hashmap or something, this is so that e.g. the build data position
|
||||||
@@ -82,15 +116,15 @@ public class RenderTracker {
|
|||||||
|
|
||||||
//Decreases from lvl to lvl-1 at the coordinates (which are in lvl space)
|
//Decreases from lvl to lvl-1 at the coordinates (which are in lvl space)
|
||||||
public void dec(int lvl, int x, int y, int z) {
|
public void dec(int lvl, int x, int y, int z) {
|
||||||
this.activeSections.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)), O);
|
this.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)));
|
||||||
this.activeSections.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)+1), O);
|
this.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)+1));
|
||||||
this.activeSections.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)), O);
|
this.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)));
|
||||||
this.activeSections.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)+1), O);
|
this.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)+1));
|
||||||
this.activeSections.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)), O);
|
this.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)));
|
||||||
this.activeSections.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)+1), O);
|
this.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)+1));
|
||||||
this.activeSections.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)), O);
|
this.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)));
|
||||||
this.activeSections.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)+1), O);
|
this.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)+1));
|
||||||
this.activeSections.remove(WorldEngine.getWorldSectionId(lvl, x, y, z));
|
this.remove(WorldEngine.getWorldSectionId(lvl, x, y, z));
|
||||||
|
|
||||||
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl, x, y, z)));
|
this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl, x, y, z)));
|
||||||
this.renderGen.removeTask(lvl, x, y, z);
|
this.renderGen.removeTask(lvl, x, y, z);
|
||||||
@@ -120,7 +154,7 @@ public class RenderTracker {
|
|||||||
|
|
||||||
//Called by the world engine when a section gets dirtied
|
//Called by the world engine when a section gets dirtied
|
||||||
public void sectionUpdated(WorldSection section) {
|
public void sectionUpdated(WorldSection section) {
|
||||||
if (this.activeSections.containsKey(section.key)) {
|
if (this.contains(section.key)) {
|
||||||
//TODO:FIXME: if the section gets updated, that means that its neighbors might need to be updated aswell
|
//TODO:FIXME: if the section gets updated, that means that its neighbors might need to be updated aswell
|
||||||
// (due to block occlusion)
|
// (due to block occlusion)
|
||||||
|
|
||||||
@@ -144,7 +178,7 @@ public class RenderTracker {
|
|||||||
// it also batch collects the geometry sections until all the geometry for an operation is collected, then it executes the operation, its removes flickering
|
// it also batch collects the geometry sections until all the geometry for an operation is collected, then it executes the operation, its removes flickering
|
||||||
public void processBuildResult(BuiltSection section) {
|
public void processBuildResult(BuiltSection section) {
|
||||||
//Check that we still want the section
|
//Check that we still want the section
|
||||||
if (this.activeSections.containsKey(section.position)) {
|
if (this.contains(section.position)) {
|
||||||
this.renderer.enqueueResult(section);
|
this.renderer.enqueueResult(section);
|
||||||
} else {
|
} else {
|
||||||
section.free();
|
section.free();
|
||||||
@@ -152,6 +186,6 @@ public class RenderTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean shouldStillBuild(int lvl, int x, int y, int z) {
|
public boolean shouldStillBuild(int lvl, int x, int y, int z) {
|
||||||
return this.activeSections.containsKey(WorldEngine.getWorldSectionId(lvl, x, y, z));
|
return this.contains(WorldEngine.getWorldSectionId(lvl, x, y, z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
package me.cortex.voxy.client.saver;
|
|
||||||
|
|
||||||
import me.cortex.voxy.client.config.VoxyConfig;
|
|
||||||
import me.cortex.voxy.common.storage.other.CompressionStorageAdaptor;
|
|
||||||
import me.cortex.voxy.common.storage.other.FragmentedStorageBackendAdaptor;
|
|
||||||
import me.cortex.voxy.common.storage.compressors.ZSTDCompressor;
|
|
||||||
import me.cortex.voxy.common.world.WorldEngine;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
//Sets up a world engine with respect to the world the client is currently loaded into
|
|
||||||
// this is a bit tricky as each world has its own config, e.g. storage configuration
|
|
||||||
public class SaveSelectionSystem {
|
|
||||||
|
|
||||||
//The way this works is saves are segmented into base worlds, e.g. server ip, local save etc
|
|
||||||
// these are then segmented into subsaves for different worlds within the parent
|
|
||||||
public SaveSelectionSystem(List<Path> storagePaths) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorldEngine createWorldEngine() {
|
|
||||||
//TODO: have basicly a recursive config tree for StorageBackend
|
|
||||||
// with a .build() method
|
|
||||||
// also have a way for the config to specify and create a config "screen"
|
|
||||||
|
|
||||||
// e.g. CompressionStorageAdaptorConfig(StorageCompressorConfig, StorageBackendConfig)
|
|
||||||
// FragmentedStorageBackendAdaptorConfig(File)
|
|
||||||
// RocksDBStorageBackendConfig(File)
|
|
||||||
// RedisStorageBackendConfig(String, int, String)
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package me.cortex.voxy.client.saver;
|
||||||
|
|
||||||
|
import me.cortex.voxy.client.config.VoxyConfig;
|
||||||
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
|
import me.cortex.voxy.common.storage.compressors.ZSTDCompressor;
|
||||||
|
import me.cortex.voxy.common.storage.config.ConfigBuildCtx;
|
||||||
|
import me.cortex.voxy.common.storage.other.CompressionStorageAdaptor;
|
||||||
|
import me.cortex.voxy.common.storage.other.TranslocatingStorageAdaptor;
|
||||||
|
import me.cortex.voxy.common.storage.rocksdb.RocksDBStorageBackend;
|
||||||
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
|
import net.minecraft.client.world.ClientWorld;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
//Sets up a world engine with respect to the world the client is currently loaded into
|
||||||
|
// this is a bit tricky as each world has its own config, e.g. storage configuration
|
||||||
|
public class WorldSelectionSystem {
|
||||||
|
public static class Selection {
|
||||||
|
public WorldEngine createEngine() {
|
||||||
|
var baseDB = new RocksDBStorageBackend.Config();
|
||||||
|
baseDB.path = VoxyConfig.CONFIG.storagePath;
|
||||||
|
|
||||||
|
var compressor = new ZSTDCompressor.Config();
|
||||||
|
compressor.compressionLevel = VoxyConfig.CONFIG.savingCompressionLevel;
|
||||||
|
|
||||||
|
var compression = new CompressionStorageAdaptor.Config();
|
||||||
|
compression.delegate = baseDB;
|
||||||
|
compression.compressor = compressor;
|
||||||
|
|
||||||
|
var translocator = new TranslocatingStorageAdaptor.Config();
|
||||||
|
translocator.delegate = compression;
|
||||||
|
translocator.transforms.add(new TranslocatingStorageAdaptor.BoxTransform(0,5,0, 200, 64, 200, 0, -5, 0));
|
||||||
|
|
||||||
|
var ctx = new ConfigBuildCtx();
|
||||||
|
var storage = translocator.build(ctx);
|
||||||
|
return new WorldEngine(storage, VoxyConfig.CONFIG.ingestThreads, VoxyConfig.CONFIG.savingThreads, 5);
|
||||||
|
|
||||||
|
//StorageBackend storage = new RocksDBStorageBackend(VoxyConfig.CONFIG.storagePath);
|
||||||
|
////StorageBackend storage = new FragmentedStorageBackendAdaptor(new File(VoxyConfig.CONFIG.storagePath));
|
||||||
|
//storage = new CompressionStorageAdaptor(new ZSTDCompressor(VoxyConfig.CONFIG.savingCompressionLevel), storage);
|
||||||
|
//return new WorldEngine(storage, VoxyConfig.CONFIG.ingestThreads, VoxyConfig.CONFIG.savingThreads, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Saves the config for the world selection or something, need to figure out how to make it work with dimensional configs maybe?
|
||||||
|
// or just have per world config, cause when creating the world engine doing the string substitution would
|
||||||
|
// make it automatically select the right id
|
||||||
|
public void save() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//The way this works is saves are segmented into base worlds, e.g. server ip, local save etc
|
||||||
|
// these are then segmented into subsaves for different worlds within the parent
|
||||||
|
public WorldSelectionSystem() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Selection getBestSelectionOrCreate(ClientWorld world) {
|
||||||
|
return new Selection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ package me.cortex.voxy.common.storage;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class StorageBackend {
|
public abstract class StorageBackend {
|
||||||
|
|
||||||
@@ -19,4 +21,17 @@ public abstract class StorageBackend {
|
|||||||
public abstract void flush();
|
public abstract void flush();
|
||||||
|
|
||||||
public abstract void close();
|
public abstract void close();
|
||||||
|
|
||||||
|
public List<StorageBackend> getChildBackends() {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final List<StorageBackend> collectAllBackends() {
|
||||||
|
List<StorageBackend> backends = new ArrayList<>();
|
||||||
|
backends.add(this);
|
||||||
|
for (var child : this.getChildBackends()) {
|
||||||
|
backends.addAll(child.collectAllBackends());
|
||||||
|
}
|
||||||
|
return backends;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,27 +3,71 @@ package me.cortex.voxy.common.storage.config;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
public class ConfigBuildCtx {
|
public class ConfigBuildCtx {
|
||||||
//List of tokens
|
//List of tokens
|
||||||
public static final String BASE_LEVEL_PATH = "{base_level_path}";
|
public static final String BASE_LEVEL_PATH = "{base_level_path}";
|
||||||
|
|
||||||
//Pushes a path to the BuildCtx path stack so that when resolving with resolvePath it uses the entire path stack
|
private final Stack<String> pathStack = new Stack<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes a path to the build context so that when resolvePath is called it is with respect to the added path
|
||||||
|
* @param path the path to add to the stack
|
||||||
|
* @return the build context
|
||||||
|
*/
|
||||||
public ConfigBuildCtx pushPath(String path) {
|
public ConfigBuildCtx pushPath(String path) {
|
||||||
|
this.pathStack.push(path);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pops a path from the build context path stack
|
||||||
|
* @return the build context
|
||||||
|
*/
|
||||||
public ConfigBuildCtx popPath() {
|
public ConfigBuildCtx popPath() {
|
||||||
|
this.pathStack.pop();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: FINISH THIS and check and test
|
||||||
|
private static String concatPath(String a, String b) {
|
||||||
|
if (b.contains("..")) {
|
||||||
|
throw new IllegalStateException("Relative resolving not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!a.isBlank()) && !a.endsWith("/")) {
|
||||||
|
a += "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.startsWith("/")) {//Absolute path
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.startsWith("./")) {
|
||||||
|
b = b.substring(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.startsWith(":", 1)) {//Drive path
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a+b;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a path with the current build context path
|
* Resolves a path with the current build context path
|
||||||
* @param other path to resolve against
|
* @param other path to resolve against
|
||||||
* @return resolved path
|
* @return resolved path
|
||||||
*/
|
*/
|
||||||
public String resolvePath(String other) {
|
public String resolvePath(String other) {
|
||||||
return null;
|
this.pathStack.push(other);
|
||||||
|
String path = "";
|
||||||
|
for (var part : this.pathStack) {
|
||||||
|
path = concatPath(path, part);
|
||||||
|
}
|
||||||
|
this.pathStack.pop();
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,8 +76,8 @@ public class ConfigBuildCtx {
|
|||||||
* @return substituted string
|
* @return substituted string
|
||||||
*/
|
*/
|
||||||
public String substituteString(String string) {
|
public String substituteString(String string) {
|
||||||
//This is e.g. so you can have dbs spread across multiple disks if you want
|
//TODO: this
|
||||||
return null;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -98,4 +98,6 @@ public class Serialization {
|
|||||||
}
|
}
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void init() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,26 @@ package me.cortex.voxy.common.storage.config;
|
|||||||
|
|
||||||
import me.cortex.voxy.common.storage.StorageBackend;
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class StorageConfig {
|
public abstract class StorageConfig {
|
||||||
static {
|
static {
|
||||||
Serialization.CONFIG_TYPES.add(StorageConfig.class);
|
Serialization.CONFIG_TYPES.add(StorageConfig.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract StorageBackend build(ConfigBuildCtx ctx);
|
public abstract StorageBackend build(ConfigBuildCtx ctx);
|
||||||
|
|
||||||
|
public List<StorageConfig> getChildStorageConfigs() {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final List<StorageConfig> collectStorageConfigs() {
|
||||||
|
List<StorageConfig> configs = new ArrayList<>();
|
||||||
|
configs.add(this);
|
||||||
|
for (var child : this.getChildStorageConfigs()) {
|
||||||
|
configs.addAll(child.collectStorageConfigs());
|
||||||
|
}
|
||||||
|
return configs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,19 +9,19 @@ import me.cortex.voxy.common.storage.config.StorageConfig;
|
|||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
//Compresses the section data
|
//Compresses the section data
|
||||||
public class CompressionStorageAdaptor extends StorageBackend {
|
public class CompressionStorageAdaptor extends DelegatingStorageAdaptor {
|
||||||
private final StorageCompressor compressor;
|
private final StorageCompressor compressor;
|
||||||
private final StorageBackend child;
|
public CompressionStorageAdaptor(StorageCompressor compressor, StorageBackend delegate) {
|
||||||
public CompressionStorageAdaptor(StorageCompressor compressor, StorageBackend child) {
|
super(delegate);
|
||||||
this.compressor = compressor;
|
this.compressor = compressor;
|
||||||
this.child = child;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer getSectionData(long key) {
|
public ByteBuffer getSectionData(long key) {
|
||||||
var data = this.child.getSectionData(key);
|
var data = this.delegate.getSectionData(key);
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -33,43 +33,28 @@ public class CompressionStorageAdaptor extends StorageBackend {
|
|||||||
@Override
|
@Override
|
||||||
public void setSectionData(long key, ByteBuffer data) {
|
public void setSectionData(long key, ByteBuffer data) {
|
||||||
var cdata = this.compressor.compress(data);
|
var cdata = this.compressor.compress(data);
|
||||||
this.child.setSectionData(key, cdata);
|
this.delegate.setSectionData(key, cdata);
|
||||||
MemoryUtil.memFree(cdata);
|
MemoryUtil.memFree(cdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteSectionData(long key) {
|
|
||||||
this.child.deleteSectionData(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putIdMapping(int id, ByteBuffer data) {
|
|
||||||
this.child.putIdMapping(id, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Int2ObjectOpenHashMap<byte[]> getIdMappingsData() {
|
|
||||||
return this.child.getIdMappingsData();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
this.child.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
this.compressor.close();
|
this.compressor.close();
|
||||||
this.child.close();
|
super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Config extends StorageConfig {
|
public static class Config extends StorageConfig {
|
||||||
public CompressorConfig compressor;
|
public CompressorConfig compressor;
|
||||||
public StorageConfig backend;
|
public StorageConfig delegate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StorageBackend build(ConfigBuildCtx ctx) {
|
public StorageBackend build(ConfigBuildCtx ctx) {
|
||||||
return new CompressionStorageAdaptor(this.compressor.build(ctx), this.backend.build(ctx));
|
return new CompressionStorageAdaptor(this.compressor.build(ctx), this.delegate.build(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StorageConfig> getChildStorageConfigs() {
|
||||||
|
return List.of(this.delegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getConfigTypeName() {
|
public static String getConfigTypeName() {
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package me.cortex.voxy.common.storage.other;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
|
import me.cortex.voxy.common.storage.StorageCompressor;
|
||||||
|
import me.cortex.voxy.common.storage.config.CompressorConfig;
|
||||||
|
import me.cortex.voxy.common.storage.config.ConfigBuildCtx;
|
||||||
|
import me.cortex.voxy.common.storage.config.StorageConfig;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DelegatingStorageAdaptor extends StorageBackend {
|
||||||
|
protected final StorageBackend delegate;
|
||||||
|
public DelegatingStorageAdaptor(StorageBackend delegate) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer getSectionData(long key) {
|
||||||
|
return this.delegate.getSectionData(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSectionData(long key, ByteBuffer data) {
|
||||||
|
this.delegate.setSectionData(key, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteSectionData(long key) {
|
||||||
|
this.delegate.deleteSectionData(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putIdMapping(int id, ByteBuffer data) {
|
||||||
|
this.delegate.putIdMapping(id, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Int2ObjectOpenHashMap<byte[]> getIdMappingsData() {
|
||||||
|
return this.delegate.getIdMappingsData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() {
|
||||||
|
this.delegate.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
this.delegate.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StorageBackend> getChildBackends() {
|
||||||
|
return List.of(this.delegate);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -131,9 +131,19 @@ public class FragmentedStorageBackendAdaptor extends StorageBackend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StorageBackend> getChildBackends() {
|
||||||
|
return List.of(this.backends);
|
||||||
|
}
|
||||||
|
|
||||||
public static class Config extends StorageConfig {
|
public static class Config extends StorageConfig {
|
||||||
public List<StorageConfig> backends = new ArrayList<>();
|
public List<StorageConfig> backends = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StorageConfig> getChildStorageConfigs() {
|
||||||
|
return new ArrayList<>(this.backends);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StorageBackend build(ConfigBuildCtx ctx) {
|
public StorageBackend build(ConfigBuildCtx ctx) {
|
||||||
StorageBackend[] builtBackends = new StorageBackend[this.backends.size()];
|
StorageBackend[] builtBackends = new StorageBackend[this.backends.size()];
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package me.cortex.voxy.common.storage.other;
|
||||||
|
|
||||||
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
|
import me.cortex.voxy.common.storage.config.ConfigBuildCtx;
|
||||||
|
import me.cortex.voxy.common.storage.config.StorageConfig;
|
||||||
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TranslocatingStorageAdaptor extends DelegatingStorageAdaptor {
|
||||||
|
public record BoxTransform(int x1, int y1, int z1, int x2, int y2, int z2, int dx, int dy, int dz) {
|
||||||
|
public long transformIfInBox(long pos) {
|
||||||
|
int lvl = WorldEngine.getLevel(pos);
|
||||||
|
int x = WorldEngine.getX(pos);
|
||||||
|
int y = WorldEngine.getY(pos);
|
||||||
|
int z = WorldEngine.getZ(pos);
|
||||||
|
|
||||||
|
//TODO: FIXME this might need to be the other way around, as in shift x,y,z instead of x1 etc
|
||||||
|
if (!((this.x1>>lvl) <= x && x <= (this.x2>>lvl) &&
|
||||||
|
(this.y1>>lvl) <= y && y <= (this.y2>>lvl) &&
|
||||||
|
(this.z1>>lvl) <= z && z <= (this.z2>>lvl))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return WorldEngine.getWorldSectionId(lvl,
|
||||||
|
x + (this.dx>>lvl),
|
||||||
|
y + (this.dy>>lvl),
|
||||||
|
z + (this.dz>>lvl)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final BoxTransform[] transforms;
|
||||||
|
|
||||||
|
public TranslocatingStorageAdaptor(StorageBackend delegate, BoxTransform... transforms) {
|
||||||
|
super(delegate);
|
||||||
|
this.transforms = transforms;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long transformPosition(long pos) {
|
||||||
|
for (var transform : this.transforms) {
|
||||||
|
long tpos = transform.transformIfInBox(pos);
|
||||||
|
if (tpos != -1) {
|
||||||
|
return tpos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteBuffer getSectionData(long key) {
|
||||||
|
return super.getSectionData(this.transformPosition(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSectionData(long key, ByteBuffer data) {
|
||||||
|
super.setSectionData(this.transformPosition(key), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteSectionData(long key) {
|
||||||
|
super.deleteSectionData(this.transformPosition(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Config extends StorageConfig {
|
||||||
|
public StorageConfig delegate;
|
||||||
|
public List<BoxTransform> transforms = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StorageBackend build(ConfigBuildCtx ctx) {
|
||||||
|
return new TranslocatingStorageAdaptor(this.delegate.build(ctx), this.transforms.toArray(BoxTransform[]::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StorageConfig> getChildStorageConfigs() {
|
||||||
|
return List.of(this.delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getConfigTypeName() {
|
||||||
|
return "TranslocatingAdaptor";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,11 +66,11 @@ public class SaveLoadSystem {
|
|||||||
hash ^= lut[i];
|
hash ^= lut[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (section.key != key) {
|
//if (section.key != key) {
|
||||||
//throw new IllegalStateException("Decompressed section not the same as requested. got: " + key + " expected: " + section.key);
|
// //throw new IllegalStateException("Decompressed section not the same as requested. got: " + key + " expected: " + section.key);
|
||||||
System.err.println("Decompressed section not the same as requested. got: " + key + " expected: " + section.key);
|
// System.err.println("Decompressed section not the same as requested. got: " + key + " expected: " + section.key);
|
||||||
return false;
|
// return false;
|
||||||
}
|
//}
|
||||||
|
|
||||||
for (int i = 0; i < section.data.length; i++) {
|
for (int i = 0; i < section.data.length; i++) {
|
||||||
short lutId = data.getShort();
|
short lutId = data.getShort();
|
||||||
|
|||||||
@@ -49,8 +49,6 @@ public class WorldEngine {
|
|||||||
//TODO: regenerate the section from children
|
//TODO: regenerate the section from children
|
||||||
Arrays.fill(into.data, Mapper.AIR);
|
Arrays.fill(into.data, Mapper.AIR);
|
||||||
System.err.println("Section " + into.lvl + ", " + into.x + ", " + into.y + ", " + into.z + " was unable to load, removing");
|
System.err.println("Section " + into.lvl + ", " + into.x + ", " + into.y + ", " + into.z + " was unable to load, removing");
|
||||||
|
|
||||||
this.storage.deleteSectionData(into.key);
|
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -80,6 +78,23 @@ public class WorldEngine {
|
|||||||
return ((long)lvl<<60)|((long)(y&0xFF)<<52)|((long)(z&((1<<24)-1))<<28)|((long)(x&((1<<24)-1))<<4);//NOTE: 4 bits spare for whatever
|
return ((long)lvl<<60)|((long)(y&0xFF)<<52)|((long)(z&((1<<24)-1))<<28)|((long)(x&((1<<24)-1))<<4);//NOTE: 4 bits spare for whatever
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getLevel(long id) {
|
||||||
|
return (int) ((id>>60)&0xf);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: check these shifts are correct for all the gets
|
||||||
|
public static int getX(long id) {
|
||||||
|
return (int) ((id<<36)>>40);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getY(long id) {
|
||||||
|
return (int) ((id<<4)>>56);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getZ(long id) {
|
||||||
|
return (int) ((id<<12)>>40);
|
||||||
|
}
|
||||||
|
|
||||||
//Marks a section as dirty, enqueuing it for saving and or render data rebuilding
|
//Marks a section as dirty, enqueuing it for saving and or render data rebuilding
|
||||||
public void markDirty(WorldSection section) {
|
public void markDirty(WorldSection section) {
|
||||||
if (this.dirtyCallback != null) {
|
if (this.dirtyCallback != null) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class Mipper {
|
|||||||
if (!Mapper.isAir(I000)) {
|
if (!Mapper.isAir(I000)) {
|
||||||
return I000;
|
return I000;
|
||||||
}
|
}
|
||||||
//TODO: need to account for different light levels of "air"
|
|
||||||
int blockLight = (Mapper.getLightId(I000)&0xF0)+(Mapper.getLightId(I001)&0xF0)+(Mapper.getLightId(I010)&0xF0)+(Mapper.getLightId(I011)&0xF0)+
|
int blockLight = (Mapper.getLightId(I000)&0xF0)+(Mapper.getLightId(I001)&0xF0)+(Mapper.getLightId(I010)&0xF0)+(Mapper.getLightId(I011)&0xF0)+
|
||||||
(Mapper.getLightId(I100)&0xF0)+(Mapper.getLightId(I101)&0xF0)+(Mapper.getLightId(I110)&0xF0)+(Mapper.getLightId(I111)&0xF0);
|
(Mapper.getLightId(I100)&0xF0)+(Mapper.getLightId(I101)&0xF0)+(Mapper.getLightId(I110)&0xF0)+(Mapper.getLightId(I111)&0xF0);
|
||||||
int skyLight = (Mapper.getLightId(I000)&0x0F)+(Mapper.getLightId(I001)&0x0F)+(Mapper.getLightId(I010)&0x0F)+(Mapper.getLightId(I011)&0x0F)+
|
int skyLight = (Mapper.getLightId(I000)&0x0F)+(Mapper.getLightId(I001)&0x0F)+(Mapper.getLightId(I010)&0x0F)+(Mapper.getLightId(I011)&0x0F)+
|
||||||
|
|||||||
Reference in New Issue
Block a user