forked from jzitnik/twodcraft
feat: Implemented saving of world
This commit is contained in:
parent
90408a723f
commit
32fba49587
pom.xml
src/main/java/cz/jzitnik
Main.java
game
Game.javaGameSaver.java
entities
logic/services
mobs/services
threads
ui
6
pom.xml
6
pom.xml
@ -128,6 +128,12 @@
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>2.0.17</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jdk8</artifactId>
|
||||
<version>2.15.0</version> <!-- Use the latest version -->
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -1,6 +1,6 @@
|
||||
package cz.jzitnik;
|
||||
|
||||
import cz.jzitnik.game.Game;
|
||||
import cz.jzitnik.game.GameSaver;
|
||||
import cz.jzitnik.game.logic.CustomLogicProvider;
|
||||
import cz.jzitnik.game.mobs.EntityLogicProvider;
|
||||
import cz.jzitnik.game.threads.HealthRegenerationThread;
|
||||
@ -28,7 +28,7 @@ public class Main {
|
||||
|
||||
var spriteList = SpriteLoader.load();
|
||||
var screenRenderer = new ScreenRenderer(spriteList, terminal);
|
||||
var game = new Game();
|
||||
var game = GameSaver.load();
|
||||
|
||||
final boolean[] isRunning = { true };
|
||||
|
||||
|
@ -22,12 +22,14 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
@Getter
|
||||
public class Game {
|
||||
public class Game implements Serializable {
|
||||
@SuppressWarnings("unchecked")
|
||||
private final List<Block>[][] world = (List<Block>[][]) new CopyOnWriteArrayList[256][512];
|
||||
private final Player player = new Player();
|
||||
@ -36,11 +38,17 @@ public class Game {
|
||||
private Window window = Window.WORLD;
|
||||
private final Inventory inventory = new Inventory();
|
||||
|
||||
@JsonIgnore
|
||||
private final EntitySpawnProvider entitySpawnProvider = new EntitySpawnProvider();
|
||||
private transient EntitySpawnProvider entitySpawnProvider = new EntitySpawnProvider();
|
||||
|
||||
@JsonIgnore
|
||||
private final GameStates gameStates = new GameStates(this);
|
||||
private transient GameStates gameStates = new GameStates(this);
|
||||
|
||||
@Serial
|
||||
private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
|
||||
entitySpawnProvider = new EntitySpawnProvider();
|
||||
gameStates = new GameStates(this);
|
||||
}
|
||||
|
||||
public Game() {
|
||||
Generation.generateWorld(this);
|
||||
|
41
src/main/java/cz/jzitnik/game/GameSaver.java
Normal file
41
src/main/java/cz/jzitnik/game/GameSaver.java
Normal file
@ -0,0 +1,41 @@
|
||||
package cz.jzitnik.game;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class GameSaver {
|
||||
public void save(Game game) {
|
||||
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("world.ser"))) {
|
||||
out.writeObject(game);
|
||||
System.out.println("Inner class saved!");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Game load() {
|
||||
File file = new File("world.ser");
|
||||
|
||||
if (!file.isFile()) {
|
||||
return new Game();
|
||||
}
|
||||
|
||||
try {
|
||||
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) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -8,20 +8,21 @@ import cz.jzitnik.game.ui.Inventory;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class Block {
|
||||
public class Block implements Serializable {
|
||||
private String blockId;
|
||||
private SpriteLoader.SPRITES sprite;
|
||||
private Optional<Enum> spriteState = Optional.empty();
|
||||
private MyOptional<Enum> spriteState = MyOptional.empty();
|
||||
private boolean ghost = false;
|
||||
private boolean isMineable = true;
|
||||
private int hardness = 1;
|
||||
private Optional<ItemType> tool = Optional.empty();
|
||||
private MyOptional<ItemType> tool = MyOptional.empty();
|
||||
private List<ToolVariant> toolVariants = new ArrayList<>();
|
||||
private List<Item> drops = new ArrayList<>();
|
||||
private Object data = null;
|
||||
@ -52,7 +53,7 @@ public class Block {
|
||||
this.blockId = blockId;
|
||||
this.sprite = sprite;
|
||||
this.hardness = hardness;
|
||||
this.tool = Optional.of(tool);
|
||||
this.tool = MyOptional.of(tool);
|
||||
this.toolVariants = toolVariants;
|
||||
}
|
||||
|
||||
@ -61,13 +62,13 @@ public class Block {
|
||||
this.blockId = blockId;
|
||||
this.sprite = sprite;
|
||||
this.hardness = hardness;
|
||||
this.tool = Optional.of(tool);
|
||||
this.tool = MyOptional.of(tool);
|
||||
this.toolVariants = toolVariants;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void setSpriteState(Enum spriteState) {
|
||||
this.spriteState = Optional.of(spriteState);
|
||||
this.spriteState = MyOptional.of(spriteState);
|
||||
}
|
||||
|
||||
public double calculateHardness(Inventory inventory) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cz.jzitnik.game.entities;
|
||||
|
||||
import cz.jzitnik.game.GameSaver;
|
||||
import cz.jzitnik.game.handlers.pickup.PickupHandlerProvider;
|
||||
import cz.jzitnik.game.handlers.place.PlaceHandler;
|
||||
import cz.jzitnik.game.mobs.EntityHurtAnimation;
|
||||
@ -10,4 +11,5 @@ public class Dependencies {
|
||||
public EntityHurtAnimation entityHurtAnimation = new EntityHurtAnimation();
|
||||
public EntityKill entityKill = new EntityKill();
|
||||
public PickupHandlerProvider pickupHandlerProvider = new PickupHandlerProvider();
|
||||
public GameSaver gameSaver = new GameSaver();
|
||||
}
|
||||
|
115
src/main/java/cz/jzitnik/game/entities/MyOptional.java
Normal file
115
src/main/java/cz/jzitnik/game/entities/MyOptional.java
Normal file
@ -0,0 +1,115 @@
|
||||
package cz.jzitnik.game.entities;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.function.*;
|
||||
|
||||
public class MyOptional<T> implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private T value;
|
||||
private boolean isPresent;
|
||||
|
||||
// Constructor
|
||||
public MyOptional() {
|
||||
this.isPresent = false;
|
||||
}
|
||||
|
||||
public MyOptional(T value) {
|
||||
this.value = value;
|
||||
this.isPresent = true;
|
||||
}
|
||||
|
||||
// Check if value is present
|
||||
public boolean isPresent() {
|
||||
return isPresent;
|
||||
}
|
||||
|
||||
// Get the value (or throw exception if not present)
|
||||
public T get() {
|
||||
if (!isPresent) {
|
||||
throw new NoSuchElementException("No value present");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Get the value or return default
|
||||
public T orElse(T other) {
|
||||
return isPresent ? value : other;
|
||||
}
|
||||
|
||||
// If value is present, apply function, else return another Optional
|
||||
public <U> MyOptional<U> map(Function<? super T, ? extends U> mapper) {
|
||||
if (!isPresent) {
|
||||
return new MyOptional<>();
|
||||
}
|
||||
return new MyOptional<>(mapper.apply(value));
|
||||
}
|
||||
|
||||
// If value is present, apply function and return a new Optional
|
||||
public <U> MyOptional<U> flatMap(Function<? super T, ? extends MyOptional<U>> mapper) {
|
||||
if (!isPresent) {
|
||||
return new MyOptional<>();
|
||||
}
|
||||
return mapper.apply(value);
|
||||
}
|
||||
|
||||
// Perform an action if value is present
|
||||
public void ifPresent(Consumer<? super T> action) {
|
||||
if (isPresent) {
|
||||
action.accept(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the value inside the Optional or default if not present
|
||||
public T orElseGet(Supplier<? extends T> other) {
|
||||
return isPresent ? value : other.get();
|
||||
}
|
||||
|
||||
// Filter the value based on a condition
|
||||
public MyOptional<T> filter(Predicate<? super T> predicate) {
|
||||
if (!isPresent || !predicate.test(value)) {
|
||||
return new MyOptional<>();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// Serialize the value
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
out.writeBoolean(isPresent);
|
||||
if (isPresent) {
|
||||
out.writeObject(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Deserialize the value
|
||||
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";
|
||||
}
|
||||
|
||||
// Static factory method for an empty SerializableOptional
|
||||
public static <T> MyOptional<T> empty() {
|
||||
return new MyOptional<>();
|
||||
}
|
||||
|
||||
// Static factory method for a present value
|
||||
public static <T> MyOptional<T> of(T value) {
|
||||
return new MyOptional<>(value);
|
||||
}
|
||||
|
||||
// Static factory method for a present value or null
|
||||
public static <T> MyOptional<T> ofNullable(T value) {
|
||||
return value == null ? empty() : new MyOptional<>(value);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return !isPresent;
|
||||
}
|
||||
}
|
@ -3,9 +3,11 @@ package cz.jzitnik.game.entities;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class Player {
|
||||
public class Player implements Serializable {
|
||||
private int health = 10;
|
||||
private int hunger = 10;
|
||||
private int fallDistance = 0;
|
||||
|
@ -3,12 +3,14 @@ package cz.jzitnik.game.entities.items;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.foreign.SegmentAllocator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class InventoryItem {
|
||||
public class InventoryItem implements Serializable {
|
||||
private int amount;
|
||||
private final List<Item> item;
|
||||
|
||||
|
@ -2,29 +2,31 @@ package cz.jzitnik.game.entities.items;
|
||||
|
||||
import cz.jzitnik.game.entities.Block;
|
||||
import cz.jzitnik.game.SpriteLoader;
|
||||
import cz.jzitnik.game.entities.MyOptional;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Optional;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
public class Item {
|
||||
public class Item implements Serializable {
|
||||
private String id;
|
||||
private String name;
|
||||
private ItemType type;
|
||||
private Optional<ToolVariant> toolVariant = Optional.empty();
|
||||
private MyOptional<ToolVariant> toolVariant = MyOptional.empty();
|
||||
private SpriteLoader.SPRITES sprite;
|
||||
private Optional<Enum> spriteState = Optional.empty();
|
||||
private MyOptional<Enum> spriteState = MyOptional.empty();
|
||||
private boolean stackable = true;
|
||||
private int durability;
|
||||
private double miningDecrease = 0;
|
||||
private int stackAmount = 64;
|
||||
private int addHunger = 0;
|
||||
private int dealDamage = 1;
|
||||
private Optional<Block> block = Optional.empty();
|
||||
private MyOptional<Block> block = MyOptional.empty();
|
||||
|
||||
public Item(String id, String name, ItemType type, SpriteLoader.SPRITES sprite, ToolVariant toolVariant,
|
||||
int durability, boolean stackable, int dealDamage) {
|
||||
@ -32,7 +34,7 @@ public class Item {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.sprite = sprite;
|
||||
this.toolVariant = Optional.of(toolVariant);
|
||||
this.toolVariant = MyOptional.of(toolVariant);
|
||||
this.durability = durability;
|
||||
this.stackable = stackable;
|
||||
this.dealDamage = dealDamage;
|
||||
@ -44,7 +46,7 @@ public class Item {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.sprite = sprite;
|
||||
this.toolVariant = Optional.of(toolVariant);
|
||||
this.toolVariant = MyOptional.of(toolVariant);
|
||||
this.miningDecrease = miningDecrease;
|
||||
this.durability = durability;
|
||||
this.stackable = stackable;
|
||||
@ -55,7 +57,7 @@ public class Item {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.sprite = sprite;
|
||||
this.block = Optional.of(block);
|
||||
this.block = MyOptional.of(block);
|
||||
}
|
||||
|
||||
public Item(String id, String name, ItemType type, SpriteLoader.SPRITES sprite) {
|
||||
@ -89,6 +91,6 @@ public class Item {
|
||||
}
|
||||
|
||||
public void setSpriteState(Enum spriteState) {
|
||||
this.spriteState = Optional.of(spriteState);
|
||||
this.spriteState = MyOptional.of(spriteState);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import cz.jzitnik.game.annotations.BlockRegistry;
|
||||
import cz.jzitnik.game.annotations.EntityRegistry;
|
||||
import cz.jzitnik.game.annotations.ItemRegistry;
|
||||
import cz.jzitnik.game.entities.Block;
|
||||
import cz.jzitnik.game.entities.MyOptional;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
@ -107,7 +108,7 @@ public class ItemBlockSupplier {
|
||||
try {
|
||||
Item item = registeredItems.get(key).newInstance();
|
||||
if (registeredBlocks.containsKey(blockList.get(key))) {
|
||||
item.setBlock(Optional.of(getBlock(blockList.get(key), item)));
|
||||
item.setBlock(MyOptional.of(getBlock(blockList.get(key), item)));
|
||||
}
|
||||
|
||||
return item;
|
||||
@ -121,9 +122,9 @@ public class ItemBlockSupplier {
|
||||
Item item = registeredItems.get(key).newInstance();
|
||||
|
||||
if (blockList.get(key).equals(block.getBlockId())) {
|
||||
item.setBlock(Optional.of(block));
|
||||
item.setBlock(MyOptional.of(block));
|
||||
} else {
|
||||
item.setBlock(Optional.of(getBlock(blockList.get(key), item)));
|
||||
item.setBlock(MyOptional.of(getBlock(blockList.get(key), item)));
|
||||
}
|
||||
|
||||
return item;
|
||||
|
@ -3,8 +3,10 @@ package cz.jzitnik.game.logic.services.flowing;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class FlowingData {
|
||||
public class FlowingData implements Serializable {
|
||||
protected boolean isSource = true;
|
||||
}
|
||||
|
@ -3,11 +3,12 @@ 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 {
|
||||
public class SaplingData implements Serializable {
|
||||
private int growWait;
|
||||
|
||||
public SaplingData() {
|
||||
|
@ -3,9 +3,11 @@ package cz.jzitnik.game.mobs.services.cow;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class CowData {
|
||||
public class CowData implements Serializable {
|
||||
private int lastDirection = 1; // 1 = right, -1 = left
|
||||
private int movementCooldown = 0;
|
||||
private int jumpAttempts = 0;
|
||||
|
@ -3,9 +3,11 @@ package cz.jzitnik.game.mobs.services.pig;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class PigData {
|
||||
public class PigData implements Serializable {
|
||||
private int lastDirection = 1; // 1 = right, -1 = left
|
||||
private int movementCooldown = 0;
|
||||
private int jumpAttempts = 0;
|
||||
|
@ -3,9 +3,11 @@ package cz.jzitnik.game.mobs.services.sheep;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class SheepData {
|
||||
public class SheepData implements Serializable {
|
||||
private int lastDirection = 1; // 1 = right, -1 = left
|
||||
private int movementCooldown = 0;
|
||||
private int jumpAttempts = 0;
|
||||
|
@ -84,6 +84,8 @@ public class InputHandlerThread extends Thread {
|
||||
case 'q' -> {
|
||||
System.out.println("Exiting game...");
|
||||
isRunning[0] = false;
|
||||
game.getGameStates().dependencies.gameSaver.save(game);
|
||||
System.exit(0);
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
|
@ -9,19 +9,28 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Getter
|
||||
public class Inventory {
|
||||
public class Inventory implements Serializable {
|
||||
public static final int INVENTORY_SIZE_PX = 470;
|
||||
public static final int COLUMN_AMOUNT = 5;
|
||||
public static final int ROW_AMOUNT = 4;
|
||||
|
||||
private final InventoryItem[] items = new InventoryItem[20];
|
||||
private final InventoryItem[] hotbar = new InventoryItem[9];
|
||||
private final SmallCraftingTable smallCraftingTable = new SmallCraftingTable(this);
|
||||
private transient SmallCraftingTable smallCraftingTable = new SmallCraftingTable(this);
|
||||
|
||||
@Serial
|
||||
private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
|
||||
smallCraftingTable = new SmallCraftingTable(this);
|
||||
}
|
||||
|
||||
@Setter
|
||||
private int itemInhHandIndex = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user