diff --git a/pom.xml b/pom.xml
index 83841bc..18bab9b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -128,11 +128,16 @@
logback-classic
1.5.18
-
- com.github.trilarion
- java-vorbis-support
- 1.2.1
-
+
+ com.github.trilarion
+ java-vorbis-support
+ 1.2.1
+
+
+ com.esotericsoftware
+ kryo
+ 5.6.2
+
diff --git a/src/main/java/cz/jzitnik/Main.java b/src/main/java/cz/jzitnik/Main.java
index d30f3cc..512958e 100644
--- a/src/main/java/cz/jzitnik/Main.java
+++ b/src/main/java/cz/jzitnik/Main.java
@@ -31,7 +31,8 @@ public class Main {
var spriteList = SpriteLoader.load();
var screenRenderer = new ScreenRenderer(spriteList, terminal);
- var game = GameSaver.load();
+ var gameSaver = new GameSaver();
+ var game = gameSaver.load();
final boolean[] isRunning = { true };
diff --git a/src/main/java/cz/jzitnik/game/Game.java b/src/main/java/cz/jzitnik/game/Game.java
index ca01f20..fedcf39 100644
--- a/src/main/java/cz/jzitnik/game/Game.java
+++ b/src/main/java/cz/jzitnik/game/Game.java
@@ -11,7 +11,6 @@ import cz.jzitnik.game.handlers.place.CustomPlaceHandler;
import cz.jzitnik.game.mobs.EntitySpawnProvider;
import cz.jzitnik.game.sprites.Breaking;
import cz.jzitnik.game.sprites.Steve.SteveState;
-import cz.jzitnik.game.annotations.AutoTransient;
import cz.jzitnik.game.annotations.WalkSound;
import cz.jzitnik.game.annotations.BreaksByPlace;
import cz.jzitnik.game.annotations.MineSound;
@@ -20,9 +19,6 @@ import cz.jzitnik.game.annotations.PlaceSound;
import cz.jzitnik.game.blocks.Chest;
import cz.jzitnik.game.blocks.Furnace;
import cz.jzitnik.game.config.Configuration;
-import cz.jzitnik.game.core.autotransient.AutoTransientSupport;
-import cz.jzitnik.game.core.autotransient.initilizers.GameMiningInitializer;
-import cz.jzitnik.game.core.autotransient.initilizers.GameWindowInitializer;
import cz.jzitnik.game.core.sound.SoundKey;
import cz.jzitnik.game.ui.Window;
import cz.jzitnik.game.ui.Inventory;
@@ -39,19 +35,15 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@Getter
-public class Game extends AutoTransientSupport {
+public class Game {
@SuppressWarnings("unchecked")
private final List[][] world = (List[][]) new CopyOnWriteArrayList[256][512];
private final Player player = new Player();
- @AutoTransient(initializer = GameMiningInitializer.class)
private transient boolean mining = false;
@Setter
- @AutoTransient(initializer = GameWindowInitializer.class)
private transient Window window = Window.WORLD;
private final Inventory inventory = new Inventory();
- @AutoTransient
private transient EntitySpawnProvider entitySpawnProvider = new EntitySpawnProvider();
- @AutoTransient
private transient GameStates gameStates = new GameStates(this);
@Setter
private int daytime = 0; // 0-600
diff --git a/src/main/java/cz/jzitnik/game/GameSaver.java b/src/main/java/cz/jzitnik/game/GameSaver.java
index 0001900..f18d586 100644
--- a/src/main/java/cz/jzitnik/game/GameSaver.java
+++ b/src/main/java/cz/jzitnik/game/GameSaver.java
@@ -1,46 +1,49 @@
package cz.jzitnik.game;
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+import lombok.extern.slf4j.Slf4j;
+
import java.io.*;
-import lombok.extern.slf4j.Slf4j;
-
@Slf4j
public class GameSaver {
+
+ private static final String SAVE_FILE = "world.ser";
+
+ private final Kryo kryo;
+
+ public GameSaver() {
+ this.kryo = new Kryo();
+ kryo.setRegistrationRequired(false);
+ kryo.setReferences(true);
+ }
+
public void save(Game game) {
- try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("world.ser"))) {
- out.writeObject(game);
+ try (Output output = new Output(new FileOutputStream(SAVE_FILE))) {
+ kryo.writeClassAndObject(output, game);
} catch (IOException e) {
- e.printStackTrace();
+ log.error("Failed to save game", e);
}
}
- // TODO: This will need rewrite
- public static Game load() {
+ public Game load() {
log.info("Loading game");
- File file = new File("world.ser");
+ File file = new File(SAVE_FILE);
if (!file.isFile()) {
+ log.info("No save file found, creating new game");
return new Game();
}
- try {
+ try (Input input = new Input(new FileInputStream(SAVE_FILE))) {
log.info("Loading game from save file");
- FileInputStream fileIn = new FileInputStream("world.ser");
-
- ObjectInputStream in = new ObjectInputStream(fileIn);
-
- // Read the object from the file
- Object object = in.readObject();
-
- Game game = (Game) object;
-
- in.close();
- fileIn.close();
-
- return game;
- } catch (IOException | ClassNotFoundException e) {
+ Object object = kryo.readClassAndObject(input);
+ return (Game) object;
+ } catch (IOException e) {
+ log.error("Failed to load game", e);
throw new RuntimeException(e);
}
-
}
}
diff --git a/src/main/java/cz/jzitnik/game/annotations/AutoTransient.java b/src/main/java/cz/jzitnik/game/annotations/AutoTransient.java
deleted file mode 100644
index a8012c2..0000000
--- a/src/main/java/cz/jzitnik/game/annotations/AutoTransient.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cz.jzitnik.game.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import cz.jzitnik.game.core.autotransient.AutoTransientInitializer;
-import cz.jzitnik.game.core.autotransient.DefaultInitializer;
-
-
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface AutoTransient {
- Class extends AutoTransientInitializer>> initializer() default DefaultInitializer.class;
-}
diff --git a/src/main/java/cz/jzitnik/game/config/Configuration.java b/src/main/java/cz/jzitnik/game/config/Configuration.java
index c8f8153..dfca34c 100644
--- a/src/main/java/cz/jzitnik/game/config/Configuration.java
+++ b/src/main/java/cz/jzitnik/game/config/Configuration.java
@@ -1,12 +1,10 @@
package cz.jzitnik.game.config;
-import java.io.Serializable;
-
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
-public class Configuration implements Serializable {
+public class Configuration {
private int soundVolume = 100; // 0-100
}
diff --git a/src/main/java/cz/jzitnik/game/core/autotransient/AutoTransientInitializer.java b/src/main/java/cz/jzitnik/game/core/autotransient/AutoTransientInitializer.java
deleted file mode 100644
index 5a66737..0000000
--- a/src/main/java/cz/jzitnik/game/core/autotransient/AutoTransientInitializer.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package cz.jzitnik.game.core.autotransient;
-
-public interface AutoTransientInitializer {
- T initialize(Object parent);
-}
diff --git a/src/main/java/cz/jzitnik/game/core/autotransient/AutoTransientSupport.java b/src/main/java/cz/jzitnik/game/core/autotransient/AutoTransientSupport.java
deleted file mode 100644
index 79cbb45..0000000
--- a/src/main/java/cz/jzitnik/game/core/autotransient/AutoTransientSupport.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package cz.jzitnik.game.core.autotransient;
-
-import cz.jzitnik.game.annotations.AutoTransient;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.Serial;
-import java.io.Serializable;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-
-public abstract class AutoTransientSupport implements Serializable {
-
- @Serial
- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
- in.defaultReadObject();
- reinitializeAutoTransients();
- }
-
- protected void reinitializeAutoTransients() {
- for (Field field : this.getClass().getDeclaredFields()) {
- if (field.isAnnotationPresent(AutoTransient.class)) {
- field.setAccessible(true);
- AutoTransient annotation = field.getAnnotation(AutoTransient.class);
- try {
- Object value;
-
- // Use initializer if provided
- Class extends AutoTransientInitializer>> initializerClass = annotation.initializer();
- if (!initializerClass.equals(DefaultInitializer.class)) {
- AutoTransientInitializer> initializer = initializerClass.getDeclaredConstructor().newInstance();
- value = initializer.initialize(this);
- } else {
- // Fallback to default instantiation
- value = instantiateField(field.getType());
- }
-
- if (value != null) {
- field.set(this, value);
- }
-
- } catch (Exception e) {
- throw new RuntimeException("Failed to reinitialize @AutoTransient field: " + field.getName(), e);
- }
- }
- }
- }
-
- protected Object instantiateField(Class> clazz) {
- try {
- // Try constructor with (this) reference first
- Constructor> constructor = clazz.getDeclaredConstructor(this.getClass());
- return constructor.newInstance(this);
- } catch (NoSuchMethodException e) {
- // Fallback to default constructor
- try {
- return clazz.getDeclaredConstructor().newInstance();
- } catch (Exception ex) {
- ex.printStackTrace();
- return null;
- }
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-}
diff --git a/src/main/java/cz/jzitnik/game/core/autotransient/DefaultInitializer.java b/src/main/java/cz/jzitnik/game/core/autotransient/DefaultInitializer.java
deleted file mode 100644
index cf43534..0000000
--- a/src/main/java/cz/jzitnik/game/core/autotransient/DefaultInitializer.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package cz.jzitnik.game.core.autotransient;
-
-public class DefaultInitializer implements AutoTransientInitializer