Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/main/java/dev/cattyn/microkits/kit/KitMigration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package dev.cattyn.microkits.kit;

import com.google.gson.JsonObject;
import dev.cattyn.microkits.kit.migrations.Migrator;

import java.util.Map;
import java.util.TreeMap;

public final class KitMigration {
private final Map<Integer, Migrator> migrators = new TreeMap<>();

KitMigration() {
}

public KitMigration register(Migrator migrator) {
migrators.put(migrator.getInitialVersion(), migrator);
return this;
}

public JsonObject migrate(JsonObject root) throws MigrationException {
int version = root.has("v") ? root.get("v").getAsInt() : 1;
while (version < KitStorageJson.KIT_FORMAT) {
Migrator migrator = migrators.get(version);
if (migrator == null)
throw new IllegalStateException("No migrator for version " + version);

try {
root = migrator.migrate(root);
} catch (Throwable t) {
throw new MigrationException(t);
}
version++;
root.addProperty("v", version);
}

return root;
}

public static class MigrationException extends Exception {
public MigrationException(Throwable t) {
super(t);
}
}
}
25 changes: 21 additions & 4 deletions src/main/java/dev/cattyn/microkits/kit/KitStorageJson.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import dev.cattyn.microkits.MicroKits;
import dev.cattyn.microkits.api.kit.Kit;
import dev.cattyn.microkits.api.kit.KitStorage;
import dev.cattyn.microkits.kit.migrations.MigratorV1ToV2;
import dev.cattyn.microkits.utils.Globals;

import java.io.IOException;
Expand All @@ -18,8 +18,13 @@
import java.util.UUID;

public class KitStorageJson implements KitStorage {
public static final int KIT_FORMAT = 2;

private static final PlayerKit.Serializer serializer = new PlayerKit.Serializer();

private static final KitMigration migrations = new KitMigration()
.register(new MigratorV1ToV2());

private final Path root;

public KitStorageJson(Path root) {
Expand All @@ -34,9 +39,14 @@ public void save(UUID uuid, List<Kit> kits) {
JsonObject object = new JsonObject();
JsonArray array = new JsonArray();
for (Kit kit : kits) {
array.add(serializer.serialize(kit));
try {
array.add(serializer.serialize(kit));
} catch (RuntimeException e) {
e.printStackTrace();
}
}
object.add("kits", array);
object.addProperty("v", KIT_FORMAT);

try {
Files.writeString(path, Globals.GSON.toJson(object));
Expand All @@ -47,14 +57,17 @@ public void save(UUID uuid, List<Kit> kits) {

@Override
public Optional<List<Kit>> load(UUID uuid) {
Path path = MicroKits.getKitsPath().resolve(uuid.toString() + ".json");
Path path = getPath(uuid);

if (!path.toFile().exists())
return Optional.empty();

try {
String s = Files.readString(path);
JsonObject object = JsonParser.parseString(s).getAsJsonObject();

object = migrations.migrate(object);

if (!object.has("kits")) return Optional.empty();

List<Kit> kits = new ArrayList<>();
Expand All @@ -63,10 +76,14 @@ public Optional<List<Kit>> load(UUID uuid) {

if (kits.isEmpty()) return Optional.empty();
return Optional.of(kits);
} catch (IOException e) {
} catch (IOException | KitMigration.MigrationException e) {
e.printStackTrace();
}

return Optional.empty();
}

private Path getPath(UUID uuid) {
return root.resolve(uuid.toString() + ".json");
}
}
77 changes: 51 additions & 26 deletions src/main/java/dev/cattyn/microkits/kit/PlayerKit.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package dev.cattyn.microkits.kit;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import dev.cattyn.microkits.api.kit.Kit;
import dev.cattyn.microkits.utils.SerializationUtil;
import dev.cattyn.microkits.utils.CompressionUtil;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.io.BukkitObjectInputStream;
import org.bukkit.util.io.BukkitObjectOutputStream;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.DataFormatException;

public class PlayerKit implements Kit {
private final Map<Integer, ItemStack> content = new HashMap<>();
Expand All @@ -32,16 +38,19 @@ public Map<Integer, ItemStack> getItems() {
public static class Serializer {
public JsonElement serialize(Kit kit) {
JsonObject object = new JsonObject();
JsonArray content = new JsonArray();
object.addProperty("name", kit.getName());
for (var entry : kit.getItems().entrySet()) {
JsonObject part = new JsonObject();
part.addProperty("slot", entry.getKey());
part.add("stack", SerializationUtil.serialize(entry.getValue()));
content.add(part);

ByteArrayOutputStream out = new ByteArrayOutputStream();
try (BukkitObjectOutputStream os = new BukkitObjectOutputStream(out)) {
write(os, kit);
} catch (IOException e) {
throw new RuntimeException(e);
}

object.add("content", content);
byte[] contentBytes = CompressionUtil.compress(out.toByteArray());
String contentString = Base64.getEncoder().encodeToString(contentBytes);

object.addProperty("base64", contentString);

return object;
}
Expand All @@ -52,30 +61,46 @@ public Kit deserialize(JsonElement jsonElement) {

JsonObject object = jsonElement.getAsJsonObject();

if (!object.has("name") || !object.has("content"))
if (!object.has("name") || !object.has("base64"))
throw new JsonParseException("Invalid json object.");


String name = object.get("name").getAsString();
PlayerKit kit = new PlayerKit(name);
for (JsonElement element : object.getAsJsonArray("content")) {
if (!element.isJsonObject())
continue;

JsonObject part = element.getAsJsonObject();
if (!part.has("slot") || !part.has("stack"))
continue;

int slot = part.get("slot").getAsInt();
try {
ItemStack stack = SerializationUtil.deserialize(part.get("stack"));
kit.getItems().put(slot, stack);
} catch (Throwable e) {
throw new JsonParseException("Invalid content.");
}
String contentString = object.get("base64").getAsString();
byte[] contentBytesCompressed = Base64.getDecoder().decode(contentString);
byte[] contentBytes;

try {
contentBytes = CompressionUtil.decompress(contentBytesCompressed);
} catch (DataFormatException e) {
throw new JsonParseException("Failed to decompress", e);
}

PlayerKit kit = new PlayerKit(name);
try (BukkitObjectInputStream is = new BukkitObjectInputStream(new ByteArrayInputStream(contentBytes))) {
read(is, kit);
} catch (IOException | ClassNotFoundException e) {
throw new JsonParseException(e);
}

return kit;
}

private static void write(BukkitObjectOutputStream os, Kit kit) throws IOException {
os.writeInt(kit.getItems().size());
for (var entry : kit.getItems().entrySet()) {
os.writeInt(entry.getKey());
os.writeObject(entry.getValue());
}
}

private static void read(BukkitObjectInputStream is, Kit kit) throws IOException, ClassNotFoundException {
int size = is.readInt();
for (int i = 0; i < size; i++) {
int slot = is.readInt();
ItemStack stack = (ItemStack) is.readObject();
kit.getItems().put(slot, stack);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dev.cattyn.microkits.kit.migrations;

import com.google.gson.JsonObject;

public interface Migrator {
int getInitialVersion();

JsonObject migrate(JsonObject object);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package dev.cattyn.microkits.kit.migrations;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import dev.cattyn.microkits.api.kit.Kit;
import dev.cattyn.microkits.kit.PlayerKit;
import dev.cattyn.microkits.utils.SerializationUtil;
import org.bukkit.inventory.ItemStack;

public final class MigratorV1ToV2 implements Migrator {
private static final PlayerKit.Serializer serializer = new PlayerKit.Serializer();

@Override
public int getInitialVersion() {
return 1;
}

@Override
public JsonObject migrate(JsonObject object) {
JsonArray newKits = new JsonArray();
JsonArray kits = object.getAsJsonArray("kits");
for (JsonElement element : kits) {
try {
newKits.add(serializer.serialize(deserialize(element)));
} catch (JsonParseException e) {
e.printStackTrace();
}
}
object.add("kits", newKits);
return object;
}

private Kit deserialize(JsonElement jsonElement) {
if (!jsonElement.isJsonObject())
throw new JsonParseException("Not a json object.");

JsonObject object = jsonElement.getAsJsonObject();

if (!object.has("name") || !object.has("content"))
throw new JsonParseException("Invalid json object.");

String name = object.get("name").getAsString();
PlayerKit kit = new PlayerKit(name);
for (JsonElement element : object.getAsJsonArray("content")) {
if (!element.isJsonObject())
continue;

JsonObject part = element.getAsJsonObject();
if (!part.has("slot") || !part.has("stack"))
continue;

int slot = part.get("slot").getAsInt();
try {
ItemStack stack = SerializationUtil.deserialize(part.get("stack"));
kit.getItems().put(slot, stack);
} catch (Throwable e) {
throw new JsonParseException("Invalid content.");
}

}

return kit;
}
}
52 changes: 52 additions & 0 deletions src/main/java/dev/cattyn/microkits/utils/CompressionUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package dev.cattyn.microkits.utils;

import java.io.ByteArrayOutputStream;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

public final class CompressionUtil {
private static final int BUF_SIZE = 2048;

CompressionUtil() {
}

public static byte[] compress(byte[] input) {
Deflater deflater = new Deflater();
try {
deflater.setInput(input);
deflater.finish();

ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] buf = new byte[BUF_SIZE];

while (!deflater.finished()) {
int len = deflater.deflate(buf);
os.write(buf, 0, len);
}

return os.toByteArray();
} finally {
deflater.end();
}
}

public static byte[] decompress(byte[] input) throws DataFormatException {
Inflater inflater = new Inflater();
try {
inflater.setInput(input);

ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] buf = new byte[BUF_SIZE];

while (!inflater.finished()) {
int len = inflater.inflate(buf);
os.write(buf, 0, len);
}

return os.toByteArray();
} finally {
inflater.end();
}
}
}
1 change: 0 additions & 1 deletion src/main/java/dev/cattyn/microkits/utils/Globals.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

public interface Globals {
Gson GSON = new GsonBuilder()
.setPrettyPrinting()
.setLenient()
.create();
}