diff --git a/src/main/java/me/cortex/voxy/client/saver/WorldSelectionSystem.java b/src/main/java/me/cortex/voxy/client/saver/WorldSelectionSystem.java index 4988c51f..fc593688 100644 --- a/src/main/java/me/cortex/voxy/client/saver/WorldSelectionSystem.java +++ b/src/main/java/me/cortex/voxy/client/saver/WorldSelectionSystem.java @@ -4,6 +4,8 @@ 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.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.TranslocatingStorageAdaptor; 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 public class WorldSelectionSystem { public static class Selection { - public WorldEngine createEngine() { + private VoxyConfig config; + + public StorageBackend createStorageBackend() { var baseDB = new RocksDBStorageBackend.Config(); 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)); var ctx = new ConfigBuildCtx(); - var storage = translocator.build(ctx); - return new WorldEngine(storage, VoxyConfig.CONFIG.ingestThreads, VoxyConfig.CONFIG.savingThreads, 5); + return translocator.build(ctx); //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); + //return new CompressionStorageAdaptor(new ZSTDCompressor(VoxyConfig.CONFIG.savingCompressionLevel), storage); + } + + 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? diff --git a/src/main/java/me/cortex/voxy/common/storage/config/ConfigBuildCtx.java b/src/main/java/me/cortex/voxy/common/storage/config/ConfigBuildCtx.java index bf35f9ff..8601d79c 100644 --- a/src/main/java/me/cortex/voxy/common/storage/config/ConfigBuildCtx.java +++ b/src/main/java/me/cortex/voxy/common/storage/config/ConfigBuildCtx.java @@ -3,14 +3,32 @@ package me.cortex.voxy.common.storage.config; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; import java.util.Stack; public class ConfigBuildCtx { //List of tokens public static final String BASE_LEVEL_PATH = "{base_level_path}"; + + private final Map properties = new HashMap<>(); private final Stack 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 * @param path the path to add to the stack @@ -76,7 +94,9 @@ public class ConfigBuildCtx { * @return substituted string */ public String substituteString(String string) { - //TODO: this + for (var entry : this.properties.entrySet()) { + string = string.replace(entry.getKey(), entry.getValue()); + } return string; } diff --git a/src/main/java/me/cortex/voxy/common/storage/config/Serialization.java b/src/main/java/me/cortex/voxy/common/storage/config/Serialization.java index 38b61aa0..4b963ee0 100644 --- a/src/main/java/me/cortex/voxy/common/storage/config/Serialization.java +++ b/src/main/java/me/cortex/voxy/common/storage/config/Serialization.java @@ -1,8 +1,10 @@ package me.cortex.voxy.common.storage.config; import com.google.gson.*; +import com.google.gson.internal.bind.JsonTreeWriter; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import java.io.BufferedReader; @@ -19,8 +21,8 @@ public class Serialization { public static final Set> CONFIG_TYPES = new HashSet<>(); public static final Gson GSON; - private static final class GsonConfigSerialization { - private final String typeField = "config_type"; + private static final class GsonConfigSerialization implements TypeAdapterFactory { + private final String typeField = "TYPE"; private final Class clz; private final Map> name2type = new HashMap<>(); @@ -39,6 +41,50 @@ public class Serialization { } 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) 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 TypeAdapter create(Gson gson, TypeToken type) { + if (this.clz.isAssignableFrom(type.getRawType())) { + var jsonObjectAdapter = gson.getAdapter(JsonElement.class); + + return (TypeAdapter) new TypeAdapter() { + @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 { @@ -77,9 +123,9 @@ public class Serialization { } var builder = new GsonBuilder(); - //for (var entry : serializers.entrySet()) { - // builder.registerTypeHierarchyAdapter(entry.getKey(), entry.getValue()); - //} + for (var entry : serializers.entrySet()) { + builder.registerTypeAdapterFactory(entry.getValue()); + } GSON = builder.create(); } diff --git a/src/main/java/me/cortex/voxy/common/storage/other/TranslocatingStorageAdaptor.java b/src/main/java/me/cortex/voxy/common/storage/other/TranslocatingStorageAdaptor.java index 1cfb83dd..079f8f2a 100644 --- a/src/main/java/me/cortex/voxy/common/storage/other/TranslocatingStorageAdaptor.java +++ b/src/main/java/me/cortex/voxy/common/storage/other/TranslocatingStorageAdaptor.java @@ -55,12 +55,26 @@ public class TranslocatingStorageAdaptor extends DelegatingStorageAdaptor { @Override 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 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 { diff --git a/src/main/java/me/cortex/voxy/common/world/SaveLoadSystem.java b/src/main/java/me/cortex/voxy/common/world/SaveLoadSystem.java index af812bcf..fda83614 100644 --- a/src/main/java/me/cortex/voxy/common/world/SaveLoadSystem.java +++ b/src/main/java/me/cortex/voxy/common/world/SaveLoadSystem.java @@ -53,7 +53,7 @@ public class SaveLoadSystem { return raw; } - public static boolean deserialize(WorldSection section, ByteBuffer data) { + public static boolean deserialize(WorldSection section, ByteBuffer data, boolean ignoreMismatchPosition) { long hash = 0; long key = data.getLong(); int lutLen = data.getInt(); @@ -66,11 +66,11 @@ public class SaveLoadSystem { hash ^= lut[i]; } - //if (section.key != 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); - // return false; - //} + if ((!ignoreMismatchPosition) && section.key != 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); + return false; + } for (int i = 0; i < section.data.length; i++) { short lutId = data.getShort(); diff --git a/src/main/java/me/cortex/voxy/common/world/WorldEngine.java b/src/main/java/me/cortex/voxy/common/world/WorldEngine.java index e0a04418..fd7df97b 100644 --- a/src/main/java/me/cortex/voxy/common/world/WorldEngine.java +++ b/src/main/java/me/cortex/voxy/common/world/WorldEngine.java @@ -44,7 +44,7 @@ public class WorldEngine { var data = this.storage.getSectionData(into.key); if (data != null) { try { - if (!SaveLoadSystem.deserialize(into, data)) { + if (!SaveLoadSystem.deserialize(into, data, true)) { this.storage.deleteSectionData(into.key); //TODO: regenerate the section from children Arrays.fill(into.data, Mapper.AIR);