using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using BaseGames.Core;
using BaseGames.Player;
using BaseGames.Core.Events;
using BaseGames.Core.Save;
using BaseGames.Skills;
using BaseGames.Feedback;
namespace BaseGames.Equipment
{
///
/// 装备管理器(架构 09_ProgressionModule §6)。
/// 挂在 Player 上,管理护符的装备/卸下及 Notch 容量。
/// 实现 ISaveable 以持久化装备状态。
///
public class EquipmentManager : MonoBehaviour, ISaveable, IEquipmentService
{
[Header("配置")]
[SerializeField] private EquipmentConfigSO _config;
[SerializeField] private CharmCatalogSO _charmCatalog;
[Header("Event Channels")]
[SerializeField] private CharmEventChannelSO _onCharmEquipped;
[SerializeField] private CharmEventChannelSO _onCharmUnequipped;
[SerializeField] private VoidEventChannelSO _onEquipmentChanged;
[Tooltip("AchievementManager 解锁授予凹槽成就时发布;订阅后调用 IncreaseNotches(1)。")]
[SerializeField] private VoidEventChannelSO _onAchievementNotchGranted;
private readonly List _equipped = new(4);
private readonly List _collected = new(32);
private int _currentNotchCapacity;
private int _usedNotches;
private EquipmentContext _ctx;
private readonly CompositeDisposable _subs = new();
// ── 生命周期 ──────────────────────────────────────────────────────────
private void OnEnable()
{
ServiceLocator.Register(this);
ServiceLocator.GetOrDefault()?.Register(this);
_onAchievementNotchGranted?.Subscribe(() => IncreaseNotches(1)).AddTo(_subs);
}
private void OnDisable()
{
ServiceLocator.Unregister(this);
ServiceLocator.GetOrDefault()?.Unregister(this);
_subs.Clear();
}
private void Awake()
{
_ctx = new EquipmentContext
{
Stats = GetComponent(),
Feedback = GetComponent(),
Events = ServiceLocator.GetOrDefault(),
SkillMods = GetComponent(),
WeaponMgr = GetComponent(),
};
Debug.Assert(_config != null, "[EquipmentManager] _config 未赋值,请在 Inspector 中指定 EquipmentConfigSO。", this);
Debug.Assert(_charmCatalog != null, "[EquipmentManager] _charmCatalog 未赋值,请在 Inspector 中指定 CharmCatalogSO。", this);
_currentNotchCapacity = _config.initialNotchCount;
Debug.Assert(_ctx.Stats != null, "[EquipmentManager] 缺少 PlayerStats,护符效果无法修改属性。", this);
Debug.Assert(_ctx.Feedback != null, "[EquipmentManager] 缺少 PlayerFeedback,护符效果无法触发反馈。", this);
Debug.Assert(_ctx.SkillMods != null, "[EquipmentManager] 缺少 SkillModifierRegistry。", this);
}
// ── 查询属性 ─────────────────────────────────────────────────────────
public int UsedNotches => _usedNotches; // 缓存值,避免每次调用 LINQ Sum
public int TotalNotches => _currentNotchCapacity;
public IReadOnlyList Equipped => _equipped;
public IReadOnlyList Collected => _collected;
// ── 装备操作 ─────────────────────────────────────────────────────────
///
/// 装备护符。返回 null 表示成功;返回错误字符串表示失败原因。
///
public string TryEquipCharm(CharmSO charm)
{
if (charm == null) return "护符不存在";
if (_equipped.Contains(charm)) return "已经装备";
if (!_collected.Contains(charm)) return "尚未收集此护符";
int remaining = _currentNotchCapacity - UsedNotches;
if (charm.notchCost > remaining)
return $"笔记不足(需要 {charm.notchCost},剩余 {remaining})";
_equipped.Add(charm);
_usedNotches += charm.notchCost;
foreach (var fx in charm.effects) fx?.OnEquip(_ctx);
_onCharmEquipped?.Raise(charm);
_onEquipmentChanged?.Raise();
return null;
}
public void UnequipCharm(CharmSO charm)
{
if (charm == null || !_equipped.Remove(charm)) return;
_usedNotches -= charm.notchCost;
foreach (var fx in charm.effects) fx?.OnUnequip(_ctx);
_onCharmUnequipped?.Raise(charm);
_onEquipmentChanged?.Raise();
}
/// 将护符加入收藏(拾取时调用)。
public void AddToCollection(string charmId)
{
var charm = _charmCatalog.Find(charmId);
if (charm == null) { Debug.LogWarning($"[EquipmentManager] 找不到护符: {charmId}"); return; }
if (!_collected.Contains(charm))
_collected.Add(charm);
}
public void IncreaseNotches(int amount)
{
_currentNotchCapacity += amount;
_onEquipmentChanged?.Raise();
}
// ── ISaveable ────────────────────────────────────────────────────────
public void OnSave(SaveData data)
{
data.Equipment.EquippedCharmIds.Clear();
data.Equipment.EquippedCharmIds.AddRange(_equipped.Select(c => c.charmId));
data.Equipment.OwnedCharmIds.Clear();
data.Equipment.OwnedCharmIds.AddRange(_collected.Select(c => c.charmId));
data.Equipment.MaxNotches = _currentNotchCapacity;
}
public void OnLoad(SaveData data)
{
// 卸下所有当前护符(不触发事件,逆序遍历避免 ToList() GC 分配)
for (int i = _equipped.Count - 1; i >= 0; i--)
foreach (var fx in _equipped[i].effects) fx?.OnUnequip(_ctx);
_equipped.Clear();
_usedNotches = 0;
// 恢复 Notch 上限(若存档值为 0 则使用初始默认值)
_currentNotchCapacity = data.Equipment.MaxNotches > 0
? data.Equipment.MaxNotches
: _config.initialNotchCount;
// 从 CharmCatalog 按 ID 恢复收藏并重新装备
_collected.Clear();
foreach (var id in data.Equipment.OwnedCharmIds)
{
var charm = _charmCatalog.Find(id);
if (charm != null && !_collected.Contains(charm))
_collected.Add(charm);
}
foreach (var id in data.Equipment.EquippedCharmIds)
{
var charm = _charmCatalog.Find(id);
if (charm != null) TryEquipCharm(charm);
}
_onEquipmentChanged?.Raise();
}
}
}