Start restructure of game data to support save/load

This commit is contained in:
2025-03-04 02:39:27 -08:00
parent a9cb43b79e
commit d35e81a9a8
8 changed files with 238 additions and 54 deletions

View File

@@ -2,9 +2,16 @@
namespace GameJamDungeon;
using Chickensoft.AutoInject;
using Chickensoft.Collections;
using Chickensoft.Introspection;
using Chickensoft.SaveFileBuilder;
using Chickensoft.Serialization;
using Chickensoft.Serialization.Godot;
using Godot;
using Org.BouncyCastle.Asn1.Pkcs;
using System;
using System.IO.Abstractions;
using System.Text.Json;
using static GameJamDungeon.GameLogic.State;
[Meta(typeof(IAutoNode))]
@@ -53,10 +60,30 @@ public partial class Game : Node3D, IGame
[Node] private IPlayer Player { get; set; } = default!;
#endregion
#region Save
public JsonSerializerOptions JsonOptions { get; set; } = default!;
public const string SAVE_FILE_NAME = "game.json";
public IFileSystem FileSystem { get; set; } = default!;
public string SaveFilePath { get; set; } = default!;
public ISaveFile<GameData> SaveFile { get; set; } = default!;
public ISaveChunk<GameData> GameChunk { get; set; } = default!;
ISaveChunk<GameData> IProvide<ISaveChunk<GameData>>.Value() => GameChunk;
#endregion
public RescuedItemDatabase RescuedItems { get; set; } = default!;
public void Setup()
{
FileSystem = new FileSystem();
SaveFilePath = FileSystem.Path.Join(OS.GetUserDataDir(), SAVE_FILE_NAME);
GameRepo = new GameRepo();
GameLogic = new GameLogic();
GameEventDepot = new GameEventDepot();
@@ -66,10 +93,78 @@ public partial class Game : Node3D, IGame
GameLogic.Set(Player);
Instantiator = new Instantiator(GetTree());
RescuedItems = new RescuedItemDatabase();
var resolver = new SerializableTypeResolver();
GodotSerialization.Setup();
var upgradeDependencies = new Blackboard();
JsonOptions = new JsonSerializerOptions
{
Converters = {
new SerializableTypeConverter(upgradeDependencies)
},
TypeInfoResolver = resolver,
WriteIndented = true
};
GameChunk = new SaveChunk<GameData>(
(chunk) =>
{
var gameData = new GameData()
{
PlayerData = new PlayerStats
{
CurrentHP = Player.Stats.CurrentHP.Value,
MaximumHP = Player.Stats.MaximumHP.Value,
CurrentVT = Player.Stats.CurrentVT.Value,
MaximumVT = Player.Stats.MaximumVT.Value,
CurrentAttack = Player.Stats.CurrentAttack.Value,
BonusAttack = Player.Stats.BonusAttack.Value,
MaxAttack = Player.Stats.MaxAttack.Value,
CurrentDefense = Player.Stats.CurrentDefense.Value,
BonusDefense = Player.Stats.BonusDefense.Value,
MaxDefense = Player.Stats.MaxDefense.Value,
CurrentExp = Player.Stats.CurrentExp.Value,
CurrentLevel = Player.Stats.CurrentLevel.Value,
ExpToNextLevel = Player.Stats.ExpToNextLevel.Value,
Luck = Player.Stats.Luck.Value
},
};
return gameData;
},
onLoad: (chunk, data) =>
{
chunk.LoadChunkSaveData(data.PlayerData);
}
);
}
public void OnResolved()
{
SaveFile = new SaveFile<GameData>(
root: GameChunk,
onSave: async (GameData data) =>
{
// Save the game data to disk.
var json = JsonSerializer.Serialize(data, JsonOptions);
await FileSystem.File.WriteAllTextAsync(SaveFilePath, json);
},
onLoad: async () =>
{
// Load the game data from disk.
if (!FileSystem.File.Exists(SaveFilePath))
{
GD.Print("No save file to load");
return null;
}
var json = await FileSystem.File.ReadAllTextAsync(SaveFilePath);
return JsonSerializer.Deserialize<GameData>(json, JsonOptions);
}
);
GameBinding = GameLogic.Bind();
GameBinding
.Handle((in GameLogic.Output.StartGame _) =>
@@ -131,6 +226,8 @@ public partial class Game : Node3D, IGame
public void ToggleInventory()
{
SaveFile.Load();
if (GameLogic.Value is InventoryOpened)
GameLogic.Input(new GameLogic.Input.CloseInventory());
else

View File

@@ -3,10 +3,11 @@ namespace GameJamDungeon;
using Chickensoft.AutoInject;
using Chickensoft.GodotNodeInterfaces;
using Chickensoft.SaveFileBuilder;
using Godot;
using System;
public interface IGame : IProvide<IGameRepo>, IProvide<IGameEventDepot>, IProvide<IGame>, IProvide<IPlayer>, INode3D
public interface IGame : IProvide<IGameRepo>, IProvide<IGameEventDepot>, IProvide<IGame>, IProvide<IPlayer>, IProvide<ISaveChunk<GameData>>, INode3D
{
event Game.StatRaisedAlertEventHandler StatRaisedAlert;