角色能力,存档
This commit is contained in:
@@ -5,17 +5,48 @@ using BaseGames.Core.Save;
|
||||
|
||||
namespace BaseGames.World
|
||||
{
|
||||
public class SavePoint : MonoBehaviour, IInteractable, ISaveable
|
||||
/// <summary>
|
||||
/// 存档点(也是复活点)。
|
||||
/// 玩家互动后:恢复 HP → 写入存档(场景、出生点 ID、世界状态)→ 广播激活事件。
|
||||
/// 传送点(快速旅行面板)是独立的 TeleportStation 组件,不在此处处理。
|
||||
///
|
||||
/// 继承 SaveableMonoBehaviour 以自动向 ISaveableRegistry 注册/注销,
|
||||
/// 确保 GameSaveManager 在 SaveAsync/LoadAsync 时回调本组件。
|
||||
///
|
||||
/// OnSave 仅在 _isActivated=true 时写入复活字段,
|
||||
/// 防止自动存档期间未激活的存档点覆盖玩家的正确复活位置。
|
||||
/// </summary>
|
||||
public class SavePoint : SaveableMonoBehaviour, IInteractable
|
||||
{
|
||||
[Header("Config")]
|
||||
[SerializeField] private string _savePointId;
|
||||
[SerializeField] private bool _restoreSpring = true;
|
||||
|
||||
[Header("Event Channels")]
|
||||
[SerializeField] private StringEventChannelSO _onSavePointActivated;
|
||||
[SerializeField] private VoidEventChannelSO _onFastTravelOpen;
|
||||
[Header("Event Channels - Listen")]
|
||||
[Tooltip("EVT_SceneLoaded — 用于追踪当前场景名,写入 Player.Scene")]
|
||||
[SerializeField] private StringEventChannelSO _onSceneLoaded;
|
||||
|
||||
private bool _isActivated;
|
||||
[Header("Event Channels - Raise")]
|
||||
[SerializeField] private StringEventChannelSO _onSavePointActivated;
|
||||
|
||||
private bool _isActivated;
|
||||
private string _currentSceneName;
|
||||
|
||||
private readonly CompositeDisposable _subs = new();
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable(); // 向 ISaveableRegistry 注册,确保 OnSave/OnLoad 被回调
|
||||
_onSceneLoaded?.Subscribe(OnSceneLoaded).AddTo(_subs);
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable(); // 从 ISaveableRegistry 注销
|
||||
_subs.Clear();
|
||||
}
|
||||
|
||||
private void OnSceneLoaded(string sceneName) => _currentSceneName = sceneName;
|
||||
|
||||
// ── IInteractable ──────────────────────────────────────────────────────
|
||||
public bool CanInteract => true;
|
||||
@@ -24,6 +55,7 @@ namespace BaseGames.World
|
||||
public void Interact(Transform player)
|
||||
{
|
||||
_isActivated = true;
|
||||
|
||||
var restorer = player.GetComponentInChildren<IRestoreOnSave>();
|
||||
if (restorer != null)
|
||||
{
|
||||
@@ -32,27 +64,43 @@ namespace BaseGames.World
|
||||
}
|
||||
|
||||
_onSavePointActivated?.Raise(_savePointId);
|
||||
_onFastTravelOpen?.Raise();
|
||||
|
||||
// 触发存档:OnSave() 由 SaveAsync 回调所有 ISaveable,包含本组件
|
||||
var svc = ServiceLocator.GetOrDefault<ISaveService>();
|
||||
if (svc != null)
|
||||
_ = svc.SaveAsync(svc.ActiveSlot);
|
||||
else
|
||||
Debug.LogWarning("[SavePoint] ISaveService 未注册,跳过存档。", this);
|
||||
}
|
||||
|
||||
public void OnPlayerEnterRange(Transform player) { }
|
||||
public void OnPlayerExitRange() { }
|
||||
|
||||
// ── 存档集成 ────────────────────────────────────────────────────────────
|
||||
// ── ISaveable(通过 SaveableMonoBehaviour 注册)────────────────────────
|
||||
public bool IsActivated => _isActivated;
|
||||
public void SetActivated(bool val) => _isActivated = val;
|
||||
|
||||
public void OnSave(SaveData data)
|
||||
public override void OnSave(SaveData data)
|
||||
{
|
||||
if (_isActivated && !string.IsNullOrEmpty(_savePointId)
|
||||
// 仅在本存档点已激活(玩家坐过)时更新复活字段。
|
||||
// 自动存档也会触发此方法,必须守卫以防止覆盖玩家真正的复活位置。
|
||||
if (!_isActivated) return;
|
||||
|
||||
if (!string.IsNullOrEmpty(_currentSceneName))
|
||||
data.Player.Scene = _currentSceneName;
|
||||
if (!string.IsNullOrEmpty(_savePointId))
|
||||
data.Meta.SavePointId = _savePointId;
|
||||
|
||||
if (!string.IsNullOrEmpty(_savePointId)
|
||||
&& !data.World.ActivatedSavePoints.Contains(_savePointId))
|
||||
data.World.ActivatedSavePoints.Add(_savePointId);
|
||||
}
|
||||
|
||||
public void OnLoad(SaveData data)
|
||||
public override void OnLoad(SaveData data)
|
||||
{
|
||||
_isActivated = !string.IsNullOrEmpty(_savePointId)
|
||||
&& data.World.ActivatedSavePoints.Contains(_savePointId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user