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> 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> 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 { - @Override - public Object initialize(Object parent) { - return null; - } -} diff --git a/src/main/java/cz/jzitnik/game/core/autotransient/initilizers/GameMiningInitializer.java b/src/main/java/cz/jzitnik/game/core/autotransient/initilizers/GameMiningInitializer.java deleted file mode 100644 index a9991de..0000000 --- a/src/main/java/cz/jzitnik/game/core/autotransient/initilizers/GameMiningInitializer.java +++ /dev/null @@ -1,10 +0,0 @@ -package cz.jzitnik.game.core.autotransient.initilizers; - -import cz.jzitnik.game.core.autotransient.AutoTransientInitializer; - -public class GameMiningInitializer implements AutoTransientInitializer { - @Override - public Boolean initialize(Object parent) { - return false; - } -} diff --git a/src/main/java/cz/jzitnik/game/core/autotransient/initilizers/GameWindowInitializer.java b/src/main/java/cz/jzitnik/game/core/autotransient/initilizers/GameWindowInitializer.java deleted file mode 100644 index 2e4af04..0000000 --- a/src/main/java/cz/jzitnik/game/core/autotransient/initilizers/GameWindowInitializer.java +++ /dev/null @@ -1,11 +0,0 @@ -package cz.jzitnik.game.core.autotransient.initilizers; - -import cz.jzitnik.game.core.autotransient.AutoTransientInitializer; -import cz.jzitnik.game.ui.Window; - -public class GameWindowInitializer implements AutoTransientInitializer { - @Override - public Window initialize(Object parent) { - return Window.WORLD; - } -} diff --git a/src/main/java/cz/jzitnik/game/entities/Block.java b/src/main/java/cz/jzitnik/game/entities/Block.java index 0092732..8490b00 100644 --- a/src/main/java/cz/jzitnik/game/entities/Block.java +++ b/src/main/java/cz/jzitnik/game/entities/Block.java @@ -6,15 +6,16 @@ import cz.jzitnik.game.entities.items.ItemType; import cz.jzitnik.game.entities.items.ToolVariant; import cz.jzitnik.game.ui.Inventory; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; -import java.io.Serializable; import java.util.ArrayList; import java.util.List; @Getter @Setter -public class Block implements Serializable { +@NoArgsConstructor +public class Block { private String blockId; private SpriteLoader.SPRITES sprite; private MyOptional spriteState = MyOptional.empty(); diff --git a/src/main/java/cz/jzitnik/game/entities/MyOptional.java b/src/main/java/cz/jzitnik/game/entities/MyOptional.java index b82e529..29bd986 100644 --- a/src/main/java/cz/jzitnik/game/entities/MyOptional.java +++ b/src/main/java/cz/jzitnik/game/entities/MyOptional.java @@ -1,10 +1,9 @@ package cz.jzitnik.game.entities; -import java.io.*; import java.util.NoSuchElementException; import java.util.function.*; -public class MyOptional implements Serializable { +public class MyOptional { private T value; private boolean isPresent; @@ -64,22 +63,6 @@ public class MyOptional implements Serializable { return this; } - @Serial - private void writeObject(ObjectOutputStream out) throws IOException { - out.writeBoolean(isPresent); - if (isPresent) { - out.writeObject(value); - } - } - - @Serial - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - isPresent = in.readBoolean(); - if (isPresent) { - value = (T) in.readObject(); - } - } - @Override public String toString() { return isPresent ? "SerializableOptional[" + value + "]" : "SerializableOptional.empty"; @@ -100,4 +83,4 @@ public class MyOptional implements Serializable { public boolean isEmpty() { return !isPresent; } -} \ No newline at end of file +} diff --git a/src/main/java/cz/jzitnik/game/entities/Player.java b/src/main/java/cz/jzitnik/game/entities/Player.java index 130314b..608834f 100644 --- a/src/main/java/cz/jzitnik/game/entities/Player.java +++ b/src/main/java/cz/jzitnik/game/entities/Player.java @@ -3,7 +3,6 @@ package cz.jzitnik.game.entities; import lombok.Getter; import lombok.Setter; -import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.util.List; @@ -15,7 +14,7 @@ import cz.jzitnik.tui.ScreenRenderer; @Getter @Setter -public class Player implements Serializable { +public class Player { private int health = 10; private int hunger = 10; private int fallDistance = 0; diff --git a/src/main/java/cz/jzitnik/game/entities/SteveData.java b/src/main/java/cz/jzitnik/game/entities/SteveData.java index c822323..c5de2e8 100644 --- a/src/main/java/cz/jzitnik/game/entities/SteveData.java +++ b/src/main/java/cz/jzitnik/game/entities/SteveData.java @@ -1,7 +1,5 @@ package cz.jzitnik.game.entities; -import java.io.Serializable; - import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -9,6 +7,6 @@ import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Getter -public class SteveData implements Serializable { +public class SteveData { private boolean top = false; } diff --git a/src/main/java/cz/jzitnik/game/entities/items/InventoryItem.java b/src/main/java/cz/jzitnik/game/entities/items/InventoryItem.java index 36664e9..44d59fa 100644 --- a/src/main/java/cz/jzitnik/game/entities/items/InventoryItem.java +++ b/src/main/java/cz/jzitnik/game/entities/items/InventoryItem.java @@ -3,13 +3,12 @@ package cz.jzitnik.game.entities.items; import lombok.AllArgsConstructor; import lombok.Getter; -import java.io.Serializable; import java.util.ArrayList; import java.util.List; @Getter @AllArgsConstructor -public class InventoryItem implements Serializable { +public class InventoryItem { private int amount; private final List item; diff --git a/src/main/java/cz/jzitnik/game/entities/items/Item.java b/src/main/java/cz/jzitnik/game/entities/items/Item.java index 58e4f2a..16bac79 100644 --- a/src/main/java/cz/jzitnik/game/entities/items/Item.java +++ b/src/main/java/cz/jzitnik/game/entities/items/Item.java @@ -7,12 +7,10 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; -import java.io.Serializable; - @Getter @Setter @AllArgsConstructor -public class Item implements Serializable { +public class Item { private String id; private String name; private ItemType type; diff --git a/src/main/java/cz/jzitnik/game/logic/services/farmable/FarmableData.java b/src/main/java/cz/jzitnik/game/logic/services/farmable/FarmableData.java index 644ab74..6e58155 100644 --- a/src/main/java/cz/jzitnik/game/logic/services/farmable/FarmableData.java +++ b/src/main/java/cz/jzitnik/game/logic/services/farmable/FarmableData.java @@ -1,13 +1,11 @@ package cz.jzitnik.game.logic.services.farmable; -import java.io.Serializable; - import lombok.Getter; import lombok.Setter; @Getter @Setter -public class FarmableData implements Serializable { +public class FarmableData { private int age = 0; private int state = 0; } diff --git a/src/main/java/cz/jzitnik/game/logic/services/farmland/FarmlandData.java b/src/main/java/cz/jzitnik/game/logic/services/farmland/FarmlandData.java index e1f9336..442423f 100644 --- a/src/main/java/cz/jzitnik/game/logic/services/farmland/FarmlandData.java +++ b/src/main/java/cz/jzitnik/game/logic/services/farmland/FarmlandData.java @@ -3,11 +3,9 @@ package cz.jzitnik.game.logic.services.farmland; import lombok.Getter; import lombok.Setter; -import java.io.Serializable; - @Getter @Setter -public class FarmlandData implements Serializable { +public class FarmlandData { private int age = 0; private int dryAge = 0; private boolean watered = false; diff --git a/src/main/java/cz/jzitnik/game/logic/services/flowing/FlowingData.java b/src/main/java/cz/jzitnik/game/logic/services/flowing/FlowingData.java index ef5af50..4056f4a 100644 --- a/src/main/java/cz/jzitnik/game/logic/services/flowing/FlowingData.java +++ b/src/main/java/cz/jzitnik/game/logic/services/flowing/FlowingData.java @@ -3,10 +3,8 @@ package cz.jzitnik.game.logic.services.flowing; import lombok.Getter; import lombok.Setter; -import java.io.Serializable; - @Getter @Setter -public class FlowingData implements Serializable { +public class FlowingData { protected boolean isSource = true; } diff --git a/src/main/java/cz/jzitnik/game/logic/services/grass/GrassDirtData.java b/src/main/java/cz/jzitnik/game/logic/services/grass/GrassDirtData.java index a8b2151..a217a49 100644 --- a/src/main/java/cz/jzitnik/game/logic/services/grass/GrassDirtData.java +++ b/src/main/java/cz/jzitnik/game/logic/services/grass/GrassDirtData.java @@ -3,11 +3,9 @@ package cz.jzitnik.game.logic.services.grass; import lombok.Getter; import lombok.Setter; -import java.io.Serializable; - @Getter @Setter -public class GrassDirtData implements Serializable { +public class GrassDirtData { private int age = 0; public void increaseAge() { diff --git a/src/main/java/cz/jzitnik/game/logic/services/saplings/SaplingData.java b/src/main/java/cz/jzitnik/game/logic/services/saplings/SaplingData.java index 871ad51..31ab442 100644 --- a/src/main/java/cz/jzitnik/game/logic/services/saplings/SaplingData.java +++ b/src/main/java/cz/jzitnik/game/logic/services/saplings/SaplingData.java @@ -3,12 +3,11 @@ package cz.jzitnik.game.logic.services.saplings; import lombok.Getter; import lombok.Setter; -import java.io.Serializable; import java.util.Random; @Getter @Setter -public class SaplingData implements Serializable { +public class SaplingData { private int growWait; public SaplingData() { diff --git a/src/main/java/cz/jzitnik/game/mobs/services/cow/CowData.java b/src/main/java/cz/jzitnik/game/mobs/services/cow/CowData.java index 0516381..dba80ff 100644 --- a/src/main/java/cz/jzitnik/game/mobs/services/cow/CowData.java +++ b/src/main/java/cz/jzitnik/game/mobs/services/cow/CowData.java @@ -3,8 +3,6 @@ package cz.jzitnik.game.mobs.services.cow; import lombok.Getter; import lombok.Setter; -import java.io.Serializable; - import cz.jzitnik.game.Game; import cz.jzitnik.game.annotations.RightClickLogic; import cz.jzitnik.game.entities.items.ItemBlockSupplier; @@ -14,7 +12,7 @@ import cz.jzitnik.tui.ScreenRenderer; @Getter @Setter @RightClickLogic -public class CowData implements Serializable, RightClickHandler { +public class CowData implements RightClickHandler { private int lastDirection = 1; // 1 = right, -1 = left private int movementCooldown = 0; private int jumpAttempts = 0; diff --git a/src/main/java/cz/jzitnik/game/mobs/services/pig/PigData.java b/src/main/java/cz/jzitnik/game/mobs/services/pig/PigData.java index e611fa6..8f95ab7 100644 --- a/src/main/java/cz/jzitnik/game/mobs/services/pig/PigData.java +++ b/src/main/java/cz/jzitnik/game/mobs/services/pig/PigData.java @@ -3,11 +3,9 @@ package cz.jzitnik.game.mobs.services.pig; import lombok.Getter; import lombok.Setter; -import java.io.Serializable; - @Getter @Setter -public class PigData implements Serializable { +public class PigData { private int lastDirection = 1; // 1 = right, -1 = left private int movementCooldown = 0; private int jumpAttempts = 0; diff --git a/src/main/java/cz/jzitnik/game/mobs/services/sheep/SheepData.java b/src/main/java/cz/jzitnik/game/mobs/services/sheep/SheepData.java index 4caa046..ab3e4bf 100644 --- a/src/main/java/cz/jzitnik/game/mobs/services/sheep/SheepData.java +++ b/src/main/java/cz/jzitnik/game/mobs/services/sheep/SheepData.java @@ -3,11 +3,9 @@ package cz.jzitnik.game.mobs.services.sheep; import lombok.Getter; import lombok.Setter; -import java.io.Serializable; - @Getter @Setter -public class SheepData implements Serializable { +public class SheepData { private int lastDirection = 1; // 1 = right, -1 = left private int movementCooldown = 0; private int jumpAttempts = 0; diff --git a/src/main/java/cz/jzitnik/game/ui/HomeScreen.java b/src/main/java/cz/jzitnik/game/ui/HomeScreen.java new file mode 100644 index 0000000..d2c4f2d --- /dev/null +++ b/src/main/java/cz/jzitnik/game/ui/HomeScreen.java @@ -0,0 +1,5 @@ +package cz.jzitnik.game.ui; + +public class HomeScreen { + +} diff --git a/src/main/java/cz/jzitnik/game/ui/Inventory.java b/src/main/java/cz/jzitnik/game/ui/Inventory.java index 7aa0812..afdb8f2 100644 --- a/src/main/java/cz/jzitnik/game/ui/Inventory.java +++ b/src/main/java/cz/jzitnik/game/ui/Inventory.java @@ -1,8 +1,6 @@ package cz.jzitnik.game.ui; import cz.jzitnik.game.Game; -import cz.jzitnik.game.annotations.AutoTransient; -import cz.jzitnik.game.core.autotransient.AutoTransientSupport; import cz.jzitnik.game.entities.items.InventoryItem; import cz.jzitnik.game.entities.items.Item; import cz.jzitnik.tui.utils.SpriteCombiner; @@ -17,7 +15,7 @@ import java.util.List; import java.util.Optional; @Getter -public class Inventory extends AutoTransientSupport { +public class Inventory { public static final int INVENTORY_SIZE_PX = 470; public static final int COLUMN_AMOUNT = 5; public static final int ROW_AMOUNT = 4; @@ -25,7 +23,6 @@ public class Inventory extends AutoTransientSupport { private final InventoryItem[] items = new InventoryItem[20]; private final InventoryItem[] hotbar = new InventoryItem[9]; - @AutoTransient private transient SmallCraftingTable smallCraftingTable = new SmallCraftingTable(this); @Setter diff --git a/src/main/java/cz/jzitnik/game/ui/Options.java b/src/main/java/cz/jzitnik/game/ui/Options.java index dac9886..9215c50 100644 --- a/src/main/java/cz/jzitnik/game/ui/Options.java +++ b/src/main/java/cz/jzitnik/game/ui/Options.java @@ -18,7 +18,6 @@ public class Options { this.game = game; } - public void render(StringBuilder buffer, Terminal terminal) { var buf = new StringBuilder(); var font = game.getGameStates().dependencies.font;