Serialization system works
This commit is contained in:
@@ -4,6 +4,8 @@ import me.cortex.voxy.client.config.VoxyConfig;
|
|||||||
import me.cortex.voxy.common.storage.StorageBackend;
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
import me.cortex.voxy.common.storage.compressors.ZSTDCompressor;
|
import me.cortex.voxy.common.storage.compressors.ZSTDCompressor;
|
||||||
import me.cortex.voxy.common.storage.config.ConfigBuildCtx;
|
import me.cortex.voxy.common.storage.config.ConfigBuildCtx;
|
||||||
|
import me.cortex.voxy.common.storage.config.Serialization;
|
||||||
|
import me.cortex.voxy.common.storage.config.StorageConfig;
|
||||||
import me.cortex.voxy.common.storage.other.CompressionStorageAdaptor;
|
import me.cortex.voxy.common.storage.other.CompressionStorageAdaptor;
|
||||||
import me.cortex.voxy.common.storage.other.TranslocatingStorageAdaptor;
|
import me.cortex.voxy.common.storage.other.TranslocatingStorageAdaptor;
|
||||||
import me.cortex.voxy.common.storage.rocksdb.RocksDBStorageBackend;
|
import me.cortex.voxy.common.storage.rocksdb.RocksDBStorageBackend;
|
||||||
@@ -17,7 +19,9 @@ import java.util.List;
|
|||||||
// this is a bit tricky as each world has its own config, e.g. storage configuration
|
// this is a bit tricky as each world has its own config, e.g. storage configuration
|
||||||
public class WorldSelectionSystem {
|
public class WorldSelectionSystem {
|
||||||
public static class Selection {
|
public static class Selection {
|
||||||
public WorldEngine createEngine() {
|
private VoxyConfig config;
|
||||||
|
|
||||||
|
public StorageBackend createStorageBackend() {
|
||||||
var baseDB = new RocksDBStorageBackend.Config();
|
var baseDB = new RocksDBStorageBackend.Config();
|
||||||
baseDB.path = VoxyConfig.CONFIG.storagePath;
|
baseDB.path = VoxyConfig.CONFIG.storagePath;
|
||||||
|
|
||||||
@@ -33,13 +37,15 @@ public class WorldSelectionSystem {
|
|||||||
translocator.transforms.add(new TranslocatingStorageAdaptor.BoxTransform(0,5,0, 200, 64, 200, 0, -5, 0));
|
translocator.transforms.add(new TranslocatingStorageAdaptor.BoxTransform(0,5,0, 200, 64, 200, 0, -5, 0));
|
||||||
|
|
||||||
var ctx = new ConfigBuildCtx();
|
var ctx = new ConfigBuildCtx();
|
||||||
var storage = translocator.build(ctx);
|
return translocator.build(ctx);
|
||||||
return new WorldEngine(storage, VoxyConfig.CONFIG.ingestThreads, VoxyConfig.CONFIG.savingThreads, 5);
|
|
||||||
|
|
||||||
//StorageBackend storage = new RocksDBStorageBackend(VoxyConfig.CONFIG.storagePath);
|
//StorageBackend storage = new RocksDBStorageBackend(VoxyConfig.CONFIG.storagePath);
|
||||||
////StorageBackend storage = new FragmentedStorageBackendAdaptor(new File(VoxyConfig.CONFIG.storagePath));
|
////StorageBackend storage = new FragmentedStorageBackendAdaptor(new File(VoxyConfig.CONFIG.storagePath));
|
||||||
//storage = new CompressionStorageAdaptor(new ZSTDCompressor(VoxyConfig.CONFIG.savingCompressionLevel), storage);
|
//return new CompressionStorageAdaptor(new ZSTDCompressor(VoxyConfig.CONFIG.savingCompressionLevel), storage);
|
||||||
//return new WorldEngine(storage, VoxyConfig.CONFIG.ingestThreads, VoxyConfig.CONFIG.savingThreads, 5);
|
}
|
||||||
|
|
||||||
|
public WorldEngine createEngine() {
|
||||||
|
return new WorldEngine(this.createStorageBackend(), 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?
|
//Saves the config for the world selection or something, need to figure out how to make it work with dimensional configs maybe?
|
||||||
|
|||||||
@@ -3,14 +3,32 @@ 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.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Stack;
|
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}";
|
||||||
|
|
||||||
|
|
||||||
|
private final Map<String, String> properties = new HashMap<>();
|
||||||
private final Stack<String> pathStack = new Stack<>();
|
private final Stack<String> pathStack = new Stack<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a builder property
|
||||||
|
* @param property property name
|
||||||
|
* @param value property value
|
||||||
|
* @return the builder context
|
||||||
|
*/
|
||||||
|
public ConfigBuildCtx setProperty(String property, String value) {
|
||||||
|
if (!(property.startsWith("{") && property.endsWith("}"))) {
|
||||||
|
throw new IllegalArgumentException("Property name doesnt start with { and end with }");
|
||||||
|
}
|
||||||
|
this.properties.put(property, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pushes a path to the build context so that when resolvePath is called it is with respect to the added path
|
* 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
|
* @param path the path to add to the stack
|
||||||
@@ -76,7 +94,9 @@ public class ConfigBuildCtx {
|
|||||||
* @return substituted string
|
* @return substituted string
|
||||||
*/
|
*/
|
||||||
public String substituteString(String string) {
|
public String substituteString(String string) {
|
||||||
//TODO: this
|
for (var entry : this.properties.entrySet()) {
|
||||||
|
string = string.replace(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package me.cortex.voxy.common.storage.config;
|
package me.cortex.voxy.common.storage.config;
|
||||||
|
|
||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
|
import com.google.gson.internal.bind.JsonTreeWriter;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import com.google.gson.stream.JsonReader;
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonToken;
|
||||||
import com.google.gson.stream.JsonWriter;
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@@ -19,8 +21,8 @@ public class Serialization {
|
|||||||
public static final Set<Class<?>> CONFIG_TYPES = new HashSet<>();
|
public static final Set<Class<?>> CONFIG_TYPES = new HashSet<>();
|
||||||
public static final Gson GSON;
|
public static final Gson GSON;
|
||||||
|
|
||||||
private static final class GsonConfigSerialization <T> {
|
private static final class GsonConfigSerialization <T> implements TypeAdapterFactory {
|
||||||
private final String typeField = "config_type";
|
private final String typeField = "TYPE";
|
||||||
private final Class<T> clz;
|
private final Class<T> clz;
|
||||||
|
|
||||||
private final Map<String, Class<? extends T>> name2type = new HashMap<>();
|
private final Map<String, Class<? extends T>> name2type = new HashMap<>();
|
||||||
@@ -39,6 +41,50 @@ public class Serialization {
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private T deserialize(Gson gson, JsonElement json) {
|
||||||
|
var retype = this.name2type.get(json.getAsJsonObject().remove(this.typeField).getAsString());
|
||||||
|
return gson.getDelegateAdapter(this, TypeToken.get(retype)).fromJsonTree(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonElement serialize(Gson gson, T value) {
|
||||||
|
String name = this.type2name.get(value.getClass());
|
||||||
|
if (name == null) {
|
||||||
|
name = "UNKNOWN_TYPE_{" + value.getClass().getName() + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
var vjson = gson
|
||||||
|
.getDelegateAdapter(this, TypeToken.get((Class<T>) value.getClass()))
|
||||||
|
.toJsonTree(value);
|
||||||
|
//All of this is so that the config_type is at the top :blob_face:
|
||||||
|
var json = new JsonObject();
|
||||||
|
json.addProperty(this.typeField, name);
|
||||||
|
vjson.getAsJsonObject().asMap().forEach(json::add);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> TypeAdapter<X> create(Gson gson, TypeToken<X> type) {
|
||||||
|
if (this.clz.isAssignableFrom(type.getRawType())) {
|
||||||
|
var jsonObjectAdapter = gson.getAdapter(JsonElement.class);
|
||||||
|
|
||||||
|
return (TypeAdapter<X>) new TypeAdapter<T>() {
|
||||||
|
@Override
|
||||||
|
public void write(JsonWriter out, T value) throws IOException {
|
||||||
|
jsonObjectAdapter.write(out, GsonConfigSerialization.this.serialize(gson, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T read(JsonReader in) throws IOException {
|
||||||
|
var obj = jsonObjectAdapter.read(in);
|
||||||
|
return GsonConfigSerialization.this.deserialize(gson, obj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -77,9 +123,9 @@ public class Serialization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var builder = new GsonBuilder();
|
var builder = new GsonBuilder();
|
||||||
//for (var entry : serializers.entrySet()) {
|
for (var entry : serializers.entrySet()) {
|
||||||
// builder.registerTypeHierarchyAdapter(entry.getKey(), entry.getValue());
|
builder.registerTypeAdapterFactory(entry.getValue());
|
||||||
//}
|
}
|
||||||
|
|
||||||
GSON = builder.create();
|
GSON = builder.create();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,12 +55,26 @@ public class TranslocatingStorageAdaptor extends DelegatingStorageAdaptor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSectionData(long key, ByteBuffer data) {
|
public void setSectionData(long key, ByteBuffer data) {
|
||||||
super.setSectionData(this.transformPosition(key), data);
|
//Dont save data if its a transformed position
|
||||||
|
for (var transform : this.transforms) {
|
||||||
|
long tpos = transform.transformIfInBox(key);
|
||||||
|
if (tpos != -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.setSectionData(key, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteSectionData(long key) {
|
public void deleteSectionData(long key) {
|
||||||
super.deleteSectionData(this.transformPosition(key));
|
//Dont delete save data if its a transformed position
|
||||||
|
for (var transform : this.transforms) {
|
||||||
|
long tpos = transform.transformIfInBox(key);
|
||||||
|
if (tpos != -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.deleteSectionData(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Config extends StorageConfig {
|
public static class Config extends StorageConfig {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public class SaveLoadSystem {
|
|||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean deserialize(WorldSection section, ByteBuffer data) {
|
public static boolean deserialize(WorldSection section, ByteBuffer data, boolean ignoreMismatchPosition) {
|
||||||
long hash = 0;
|
long hash = 0;
|
||||||
long key = data.getLong();
|
long key = data.getLong();
|
||||||
int lutLen = data.getInt();
|
int lutLen = data.getInt();
|
||||||
@@ -66,11 +66,11 @@ public class SaveLoadSystem {
|
|||||||
hash ^= lut[i];
|
hash ^= lut[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (section.key != key) {
|
if ((!ignoreMismatchPosition) && 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();
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class WorldEngine {
|
|||||||
var data = this.storage.getSectionData(into.key);
|
var data = this.storage.getSectionData(into.key);
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
try {
|
try {
|
||||||
if (!SaveLoadSystem.deserialize(into, data)) {
|
if (!SaveLoadSystem.deserialize(into, data, true)) {
|
||||||
this.storage.deleteSectionData(into.key);
|
this.storage.deleteSectionData(into.key);
|
||||||
//TODO: regenerate the section from children
|
//TODO: regenerate the section from children
|
||||||
Arrays.fill(into.data, Mapper.AIR);
|
Arrays.fill(into.data, Mapper.AIR);
|
||||||
|
|||||||
Reference in New Issue
Block a user