存档完善和修复

This commit is contained in:
2026-05-20 15:10:35 +08:00
parent 84528403ec
commit ec633d9b79
17 changed files with 254 additions and 67 deletions

View File

@@ -71,7 +71,12 @@ namespace BaseGames.Core
_onQuestStateChanged? .Subscribe(OnQuestStateChanged) .AddTo(_subs);
}
private void OnDisable() => _subs.Clear();
private void OnDisable()
{
StopAllCoroutines();
_onCooldown = false;
_subs.Clear();
}
// ── 触发处理 ───────────────────────────────────────────────────────────

View File

@@ -66,7 +66,10 @@ namespace BaseGames.Core
Debug.LogWarning("[GameServiceRegistrar] ⚠ _eventChannelRegistry 未绑定IEventChannelRegistry 未注册。", this);
if (_saveManager)
{
_saveManager.Initialize(new BaseGames.Core.Save.LocalFileStorage());
ServiceLocator.Register<ISaveService>(new SaveServiceAdapter(_saveManager));
}
else
Debug.LogWarning("[GameServiceRegistrar] ⚠ _saveManager 未绑定ISaveService 未注册。", this);
@@ -228,5 +231,6 @@ namespace BaseGames.Core
public void SetFlag(string flagId, bool value) => _save.SetFlag(flagId, value);
public System.Collections.Generic.IEnumerable<string> GetCompletedChains() => _save.GetCompletedChains();
public void SetChainCompleted(string chainId) => _save.SetChainCompleted(chainId);
public void MarkBossDefeated(string bossId) => _save.MarkBossDefeated(bossId);
}
}

View File

@@ -0,0 +1,12 @@
namespace BaseGames.Core
{
/// <summary>
/// 提供当前玩家灵珠数量的只读接口。
/// 置于 BaseGames.Core 程序集,使 World 程序集中的组件(如 DeathShadeManager
/// 无需直接引用 BaseGames.Player 程序集即可读取灵珠值。
/// </summary>
public interface ILingZhuProvider
{
int CurrentLingZhu { get; }
}
}

View File

@@ -73,5 +73,8 @@ namespace BaseGames.Core
/// <summary>标记某条事件链已完成。</summary>
void SetChainCompleted(string chainId);
/// <summary>标记某个 Boss 已被击败,立即写入当前 SaveData无需等待下次存档。</summary>
void MarkBossDefeated(string bossId);
}
}

View File

@@ -28,7 +28,7 @@ namespace BaseGames.Core.Save
private void Update()
{
if (!_gameplayActive || _saveManager == null) return;
_timer += Time.deltaTime;
_timer += Time.unscaledDeltaTime;
if (_timer >= _intervalSeconds)
{
_timer = 0f;

View File

@@ -39,8 +39,15 @@ namespace BaseGames.Core.Save
if (_instance != null) { Destroy(gameObject); return; }
_instance = this;
ServiceLocator.Register<ISaveableRegistry>(this);
}
_storage = new LocalFileStorage();
/// <summary>
/// 注入存储后端。由 GameServiceRegistrar.Awake 在注册服务后立即调用。
/// 允许在测试环境替换为 InMemoryStorage 等替代实现。
/// </summary>
public void Initialize(ISaveStorage storage)
{
_storage = storage;
}
// ── ISaveable 注册 ────────────────────────────────────────────────────
@@ -105,8 +112,12 @@ namespace BaseGames.Core.Save
if (!ValidateChecksum(loaded, json))
{
if (loaded.Meta.IsSteelSoul)
{
Debug.LogError("[SaveManager] 钢铁之魂存档 checksum 校验失败,拒绝加载以防止作弊。");
return false;
}
Debug.LogWarning("[SaveManager] 存档 checksum 校验失败。");
// 非 SteelSoul 模式仍允许加载(只是警告)
}
loaded = SaveMigrator.Migrate(loaded);
@@ -179,6 +190,13 @@ namespace BaseGames.Core.Save
public bool IsBossDefeated(string bossId)
=> _current?.World.DefeatedBossIds.Contains(bossId) == true;
public void MarkBossDefeated(string bossId)
{
_current ??= new SaveData();
if (!_current.World.DefeatedBossIds.Contains(bossId))
_current.World.DefeatedBossIds.Add(bossId);
}
// ── 存档槽摘要 ────────────────────────────────────────────────────────
public async Task<SlotSummary> GetSlotSummaryAsync(int slotIndex)
{

View File

@@ -50,7 +50,6 @@ namespace BaseGames.Core.Save
[Serializable]
public class PlayerSaveData
{
public float PosX, PosY;
public string Scene;
public int CurrentHP, MaxHP;
public int CurrentLingZhu, LifetimeLingZhu;
@@ -97,7 +96,6 @@ namespace BaseGames.Core.Save
public List<string> DefeatedBossIds = new();
public List<string> CollectedIds = new();
public List<string> DestroyedObjectIds = new();
public Dictionary<string, bool> Switches = new();
public Dictionary<string, int> NpcRelations = new();
public HashSet<string> ChallengeFirstClears = new();
}
@@ -106,9 +104,9 @@ namespace BaseGames.Core.Save
[Serializable]
public class MapSaveData
{
public List<string> ExploredRooms = new(); // 踏入过的房间 ID
public List<string> MappedRooms = new(); // 完整地图信息(购买/存档点揭示)
public List<MapPin> Pins = new(); // 玩家自定义地图标记
public HashSet<string> ExploredRooms = new(); // 踏入过的房间 ID
public HashSet<string> MappedRooms = new(); // 完整地图信息(购买/存档点揭示)
public List<MapPin> Pins = new(); // 玩家自定义地图标记
}
/// <summary>玩家在地图上放置的自定义标记(架构 15_MapShopModule §1.5)。</summary>
@@ -171,7 +169,6 @@ namespace BaseGames.Core.Save
public int LingZhuEarned, LingZhuLost;
public float DistanceTraveled;
public float SpeedrunTime;
public int SaveCount;
public Dictionary<string, int> SkillUseCounts = new();
public Dictionary<string, int> DeathsByBoss = new();
}

View File

@@ -26,10 +26,6 @@ namespace BaseGames.Core.Save
data.ChallengeRooms ??= new ChallengeRoomsSaveData();
data.NGPlus = null; // 非 NG+ 模式
// Player 子字段兼容(旧版本可能未记录 DeathShade
if (data.Player != null)
data.Player.DeathShade ??= new DeathShadeSaveData();
Debug.Log($"[SaveMigrator] 从 '{v}' 迁移至 '2.0'。");
v = "2.0";
}