using System.Collections.Generic;
using UnityEngine;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
///
/// 图鉴追踪服务(仿 的 ISaveable + ServiceLocator 模式)。
/// 订阅 EVT_EnemyDied(payload=enemyId),记录已发现敌人与击杀次数,持久化到 。
/// 仅依赖字符串 enemyId 与事件频道,不引用敌人程序集(asmdef 解耦);敌人代码零改动。
/// 挂在 Persistent 的 [GameManagers] 下,OnEnable 注册 IBestiaryService 与 ISaveableRegistry。
///
public class BestiaryService : MonoBehaviour, ISaveable, IBestiaryService
{
[Header("事件频道")]
[Tooltip("EVT_EnemyDied:payload = enemyId。敌人 / Boss 死亡时由 EnemyBase 广播。")]
[SerializeField] private StringEventChannelSO _onEnemyDied;
[Tooltip("EVT_BestiaryUpdated:payload = enemyId。新发现 / 击杀计数更新时广播,驱动图鉴 UI 实时刷新。")]
[SerializeField] private StringEventChannelSO _onBestiaryUpdated;
private readonly HashSet _discovered = new();
private readonly Dictionary _killCounts = new();
private readonly CompositeDisposable _subs = new();
// ── IBestiaryService ─────────────────────────────────────────────────
public int DiscoveredCount => _discovered.Count;
public bool IsDiscovered(string enemyId)
=> !string.IsNullOrEmpty(enemyId) && _discovered.Contains(enemyId);
public int GetKillCount(string enemyId)
=> !string.IsNullOrEmpty(enemyId) && _killCounts.TryGetValue(enemyId, out var n) ? n : 0;
// ── 生命周期 ──────────────────────────────────────────────────────────
private void OnEnable()
{
ServiceLocator.Register(this);
ServiceLocator.GetOrDefault()?.Register(this);
_onEnemyDied?.Subscribe(OnEnemyDied).AddTo(_subs);
}
private void OnDisable()
{
ServiceLocator.Unregister(this);
ServiceLocator.GetOrDefault()?.Unregister(this);
_subs.Clear();
}
// ── 解锁处理 ──────────────────────────────────────────────────────────
private void OnEnemyDied(string enemyId)
{
if (string.IsNullOrEmpty(enemyId)) return;
_discovered.Add(enemyId);
_killCounts.TryGetValue(enemyId, out var n);
_killCounts[enemyId] = n + 1;
_onBestiaryUpdated?.Raise(enemyId);
}
// ── ISaveable ─────────────────────────────────────────────────────────
public void OnSave(SaveData data)
{
var j = data.Journal;
j.DiscoveredEnemyIds.Clear();
foreach (var id in _discovered) j.DiscoveredEnemyIds.Add(id);
j.EnemyKillCounts.Clear();
foreach (var kv in _killCounts) j.EnemyKillCounts[kv.Key] = kv.Value;
}
public void OnLoad(SaveData data)
{
_discovered.Clear();
_killCounts.Clear();
var j = data.Journal;
if (j == null) return;
if (j.DiscoveredEnemyIds != null)
foreach (var id in j.DiscoveredEnemyIds) _discovered.Add(id);
if (j.EnemyKillCounts != null)
foreach (var kv in j.EnemyKillCounts) _killCounts[kv.Key] = kv.Value;
}
}
}