using UnityEngine;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
///
/// 进程锁(架构 09_ProgressionModule §12)。
/// 单向/永久性阻挡,需满足特定条件(击败 Boss)才能解锁。
/// 通过 ServiceLocator.GetOrDefault<SaveManager>() 读取进度,订阅 BossDefeated 事件实时响应。
///
public class ProgressLock : MonoBehaviour, ISaveable
{
[Header("解锁条件")]
[SerializeField] private string _requiredBossId; // 空 = 不检查 Boss
[SerializeField] private string _requiredItemId; // 空 = 不检查道具(P1 预留)
[Header("物理表现")]
[SerializeField] private GameObject _lockedVisuals; // 锁住状态视觉
[SerializeField] private GameObject _unlockedVisuals; // 开启状态视觉(可 null)
[SerializeField] private Collider2D _blockCollider;
[Header("存档")]
[SerializeField] private string _lockId; // 唯一 ID,存档记录开启状态
[Header("Event Channels")]
[SerializeField] private StringEventChannelSO _onBossDefeated; // EVT_BossDefeated
private readonly CompositeDisposable _subs = new();
private bool _isUnlocked;
private void Awake()
{
ServiceLocator.GetOrDefault()?.Register(this);
}
private void OnDestroy()
{
ServiceLocator.GetOrDefault()?.Unregister(this);
}
private void Start()
{
ApplyState(CheckUnlocked());
}
private void OnEnable()
{
_onBossDefeated?.Subscribe(OnBossDefeated).AddTo(_subs);
}
private void OnDisable()
{
_subs.Clear();
}
private void OnBossDefeated(string bossId)
{
if (!string.IsNullOrEmpty(_requiredBossId) && bossId != _requiredBossId) return;
if (CheckUnlocked()) ApplyState(true);
}
// ── ISaveable ─────────────────────────────────────────────────────────
public void OnSave(SaveData data)
{
if (_isUnlocked && !string.IsNullOrEmpty(_lockId)
&& !data.World.OpenedDoors.Contains(_lockId))
data.World.OpenedDoors.Add(_lockId);
}
public void OnLoad(SaveData data)
{
// 状态由 CheckUnlocked() 读取 IsDoorOpened(从 SaveData.OpenedDoors),应于 Start() 和 OnBossDefeated() 重新评估
}
private bool CheckUnlocked()
{
var sm = ServiceLocator.GetOrDefault();
if (sm == null) return false;
if (!string.IsNullOrEmpty(_requiredBossId) && !sm.IsBossDefeated(_requiredBossId))
return false;
return string.IsNullOrEmpty(_lockId) || sm.IsDoorOpened(_lockId);
}
private void ApplyState(bool unlocked)
{
_isUnlocked = unlocked;
if (_blockCollider != null) _blockCollider.enabled = !unlocked;
if (_lockedVisuals != null) _lockedVisuals.SetActive(!unlocked);
if (_unlockedVisuals != null) _unlockedVisuals.SetActive(unlocked);
}
}
}