diff --git a/Autoloads/SaveSystem.cs b/Autoloads/SaveSystem.cs index 56afb00..e48c031 100644 --- a/Autoloads/SaveSystem.cs +++ b/Autoloads/SaveSystem.cs @@ -1,16 +1,18 @@ +using System.Collections.Generic; using System.Text.Json; using Godot; +using Mr.BrickAdventures.scripts.Resources; using Mr.BrickAdventures.scripts.State; namespace Mr.BrickAdventures.Autoloads; /// -/// Save system that serializes POCOs directly to JSON. +/// Save system that serializes state to JSON using DTOs. /// public partial class SaveSystem : Node { [Export] public string SavePath { get; set; } = "user://savegame.json"; - [Export] public int Version { get; set; } = 2; // Bumped version for new format + [Export] public int Version { get; set; } = 2; private static readonly JsonSerializerOptions JsonOptions = new() { @@ -18,11 +20,6 @@ public partial class SaveSystem : Node PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; - public override void _Ready() - { - // No longer needs GameManager reference - works with GameStateStore directly - } - public void SaveGame() { var store = GameStateStore.Instance; @@ -32,11 +29,18 @@ public partial class SaveSystem : Node return; } - var saveData = new SaveData + // Convert to DTO (only serializable data) + var saveData = new SaveDataDto { Version = Version, - Player = store.Player, - CurrentLevel = store.Session.CurrentLevel + Coins = store.Player.Coins, + Lives = store.Player.Lives, + CurrentLevel = store.Session.CurrentLevel, + CompletedLevels = [.. store.Player.CompletedLevels], + UnlockedLevels = new List(store.Player.UnlockedLevels), + UnlockedSkillNames = GetSkillNames(store.Player.UnlockedSkills), + UnlockedAchievements = new List(store.Player.UnlockedAchievements), + Statistics = new Dictionary(store.Player.Statistics) }; try @@ -65,7 +69,7 @@ public partial class SaveSystem : Node { using var file = FileAccess.Open(SavePath, FileAccess.ModeFlags.Read); var json = file.GetAsText(); - var saveData = JsonSerializer.Deserialize(json, JsonOptions); + var saveData = JsonSerializer.Deserialize(json, JsonOptions); if (saveData == null) { @@ -87,9 +91,18 @@ public partial class SaveSystem : Node } // Apply loaded state - store.Player = saveData.Player ?? new PlayerState(); + store.Player.Coins = saveData.Coins; + store.Player.Lives = saveData.Lives; store.Session.CurrentLevel = saveData.CurrentLevel; + store.Player.CompletedLevels = saveData.CompletedLevels ?? new List(); + store.Player.UnlockedLevels = saveData.UnlockedLevels ?? new List { 0 }; + store.Player.UnlockedAchievements = saveData.UnlockedAchievements ?? new List(); + store.Player.Statistics = saveData.Statistics ?? new Dictionary(); + + // Reload skills by name from SkillManager + store.Player.UnlockedSkills = LoadSkillsByName(saveData.UnlockedSkillNames); + GD.Print("Game loaded from: ", SavePath); return true; } @@ -100,6 +113,44 @@ public partial class SaveSystem : Node } } + private static List GetSkillNames(List skills) + { + var names = new List(); + foreach (var skill in skills) + { + if (skill != null) + names.Add(skill.Name); + } + return names; + } + + private List LoadSkillsByName(List skillNames) + { + var skills = new List(); + if (skillNames == null) return skills; + + var skillManager = GetNodeOrNull(Constants.SkillManagerPath); + if (skillManager == null) + { + GD.PrintErr("SaveSystem: SkillManager not available to resolve skill names."); + return skills; + } + + foreach (var name in skillNames) + { + var skill = skillManager.GetSkillByName(name); + if (skill != null) + { + skills.Add(skill); + } + else + { + GD.PrintErr($"SaveSystem: Skill '{name}' not found in SkillManager."); + } + } + return skills; + } + public bool CheckSaveExists() => FileAccess.FileExists(SavePath); public void DeleteSave() @@ -113,11 +164,17 @@ public partial class SaveSystem : Node } /// -/// Container for save data. +/// Serializable DTO for save data - no Godot types. /// -public class SaveData +public class SaveDataDto { public int Version { get; set; } - public PlayerState Player { get; set; } + public int Coins { get; set; } + public int Lives { get; set; } public int CurrentLevel { get; set; } + public List CompletedLevels { get; set; } + public List UnlockedLevels { get; set; } + public List UnlockedSkillNames { get; set; } + public List UnlockedAchievements { get; set; } + public Dictionary Statistics { get; set; } } \ No newline at end of file diff --git a/scripts/components/PlayerDeathComponent.cs b/scripts/components/PlayerDeathComponent.cs index 5f8eb7b..1482530 100644 --- a/scripts/components/PlayerDeathComponent.cs +++ b/scripts/components/PlayerDeathComponent.cs @@ -32,7 +32,7 @@ public partial class PlayerDeathComponent : Node2D effect.Scale = EffectScale; } - _gameManager.RemoveLives(1); - _gameManager.ResetCurrentSessionState(); + // Lives are now decremented by LivesStateHandler via PlayerDied event + // Session state is reset by LivesStateHandler as well } } \ No newline at end of file