213 lines
9.2 KiB
C#
213 lines
9.2 KiB
C#
using Map;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using UnityEngine;
|
||
using Utils;
|
||
|
||
/// <summary>
|
||
/// Program 类作为单例模式的核心管理器,负责维护和管理游戏或应用中的维度(Dimension)实例和焦点状态。
|
||
/// 它提供了维度注册、注销、获取以及焦点维度设置的功能。
|
||
/// </summary>
|
||
public class Program : Singleton<Program>
|
||
{
|
||
/// <summary>
|
||
/// 指示是否需要加载数据的标志,例如在游戏启动或场景切换时。
|
||
/// </summary>
|
||
public bool needLoad = true;
|
||
|
||
/// <summary>
|
||
/// 当前聚焦的实体对象。
|
||
/// 变更为属性,并私有化setter,确保通过 SetFocusedEntity 方法集中管理其更新和事件触发。
|
||
/// </summary>
|
||
public Entity.Entity FocusedEntity { get; private set; } = null;
|
||
|
||
/// <summary>
|
||
/// 当焦点实体发生变化时触发的事件。
|
||
/// 事件参数为新的焦点 Entity 实例,如果焦点被清除则为 null。
|
||
/// </summary>
|
||
public event Action<Entity.Entity> OnFocusedEntityChanged;
|
||
|
||
/// <summary>
|
||
/// 当前活跃焦点的维度唯一标识符,可能为空。
|
||
/// 变更为属性,并私有化setter,确保通过 SetFocusedDimension 方法集中管理其更新。
|
||
/// </summary>
|
||
// 逻辑修改1:修正属性名 'focuseDimensionId' 为 'focusedDimensionId'
|
||
public string FocusedDimensionId { get; private set; } = null;
|
||
|
||
/// <summary>
|
||
/// 当前聚焦的维度对象实例。当 <see cref="FocusedDimensionId"/> 不为空时,此属性指向对应的维度实例。
|
||
/// </summary>
|
||
public Dimension FocusedDimension { get; private set; }
|
||
|
||
/// <summary>
|
||
/// 维护所有已注册的维度实例的字典,键是维度的唯一标识符 (ID)。
|
||
/// </summary>
|
||
private readonly Dictionary<string, Dimension> _registeredDimensions = new Dictionary<string, Dimension>();
|
||
|
||
/// <summary>
|
||
/// 获取所有已注册的维度。返回一个只读字典副本,防止外部直接修改。
|
||
/// </summary>
|
||
public IReadOnlyDictionary<string, Dimension> RegisteredDimensions => _registeredDimensions;
|
||
|
||
/// <summary>
|
||
/// 当焦点维度发生变化时触发的事件。
|
||
/// 事件参数为新的焦点 Dimension 实例,如果焦点被清除则为 null。
|
||
/// </summary>
|
||
public event Action<Dimension> OnFocusedDimensionChanged;
|
||
|
||
public int DimensionCount => _registeredDimensions.Count;
|
||
public string[] Dimensions => _registeredDimensions.Keys.ToArray();
|
||
|
||
/// <summary>
|
||
/// 注册一个维度实例到 Program。
|
||
/// </summary>
|
||
/// <param name="dimension">要注册的维度实例。</param>
|
||
public void RegisterDimension(Dimension dimension)
|
||
{
|
||
if (dimension == null)
|
||
{
|
||
Debug.LogError("[Program] Attempted to register a null Dimension.");
|
||
return;
|
||
}
|
||
var id = dimension.DimensionId;
|
||
if (string.IsNullOrEmpty(id))
|
||
{
|
||
Debug.LogError($"[Program] Attempted to register a Dimension with an empty or null ID: {dimension.name}");
|
||
return;
|
||
}
|
||
if (_registeredDimensions.ContainsKey(id))
|
||
{
|
||
Debug.LogWarning($"[Program] Dimension with ID '{id}' is already registered. Skipping duplicate registration for {dimension.name}.");
|
||
return;
|
||
}
|
||
_registeredDimensions.Add(id, dimension);
|
||
|
||
// 逻辑修改:此处不需要if语句包裹_registeredDimensions.Add,因为前置的ContainsKey已确保不会抛异常。
|
||
// 确保任何对焦点的潜在更新都通过 SetFocusedDimension 进行,
|
||
// 从而集中管理焦点状态的同步和事件的触发。
|
||
// 如果注册的维度恰好是当前 focusedDimensionId, SetFocusedDimension(id) 将负责更新 FocusedDimension 并触发事件。
|
||
// 并且,由于SetFocusedDimension会清空FocusedEntity,这也符合新维度的行为。
|
||
// 逻辑修改1:修正属性名 'focuseDimensionId' 为 'focusedDimensionId'
|
||
if (FocusedDimensionId == id)
|
||
{
|
||
SetFocusedDimension(id);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从 Program 注销一个维度实例。
|
||
/// </summary>
|
||
/// <param name="dimension">要注销的维度实例。</param>
|
||
public void UnregisterDimension(Dimension dimension)
|
||
{
|
||
if (dimension == null)
|
||
{
|
||
Debug.LogWarning("[Program] Attempted to unregister a null Dimension. Skipping.");
|
||
return;
|
||
}
|
||
var id = dimension.DimensionId;
|
||
if (_registeredDimensions.Remove(id))
|
||
{
|
||
// 确保任何对焦点的潜在更新都通过 SetFocusedDimension 进行,
|
||
// 从而集中管理焦点状态的同步和事件的触发。
|
||
// 如果注销的维度是当前焦点维度,则调用 SetFocusedDimension(null) 清除焦点并触发事件。
|
||
// 逻辑修改1:修正属性名 'focuseDimensionId' 为 'focusedDimensionId'
|
||
if (FocusedDimensionId == id)
|
||
{
|
||
SetFocusedDimension(null); // 清除焦点
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning($"[Program] Attempted to unregister Dimension '{id}' which was not found in the registered list.");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据ID获取一个已注册的维度。
|
||
/// </summary>
|
||
/// <param name="dimensionId">维度的唯一标识符。</param>
|
||
/// <returns>对应的Dimension实例,如果未找到则返回null。</returns>
|
||
public Dimension GetDimension(string dimensionId)
|
||
{
|
||
_registeredDimensions.TryGetValue(dimensionId, out var dimension);
|
||
return dimension;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置当前聚焦的维度。
|
||
/// 这是更改焦点维度的唯一官方入口。
|
||
/// </summary>
|
||
/// <param name="dimensionId">要设置为焦点的维度的唯一标识符。如果传入null或空字符串,将清除当前焦点维度。</param>
|
||
public void SetFocusedDimension(string dimensionId)
|
||
{
|
||
// 1. 确定新的焦点维度及其ID
|
||
Dimension newFocusedDimension = null; // 默认为清除焦点
|
||
string newFocusedDimensionId = null; // 逻辑修改1:修正属性名 'newFocuseDimensionId' 为 'newFocusedDimensionId'
|
||
|
||
if (!string.IsNullOrEmpty(dimensionId))
|
||
{
|
||
if (_registeredDimensions.TryGetValue(dimensionId, out var foundDimension))
|
||
{
|
||
newFocusedDimensionId = dimensionId; // 逻辑修改1:修正属性名
|
||
newFocusedDimension = foundDimension;
|
||
}
|
||
else
|
||
{
|
||
// 如果尝试设置未注册的维度,警告并直接返回,不改变当前焦点状态。
|
||
Debug.LogWarning($"[Program] Attempted to set focus to unregistered dimension ID: '{dimensionId}'. Focus not changed.");
|
||
return;
|
||
}
|
||
}
|
||
// 如果 dimensionId 为 null 或空, newFocusedDimension 和 newFocusedDimensionId 将保持为 null,表示清除焦点。
|
||
|
||
// 2. 优化:检查是否实际发生变化,避免不必要的更新和事件触发
|
||
// 只有当新的ID或新的维度对象引用与当前的不一致时,才执行更新。
|
||
// 逻辑修改1:修正属性名 'focuseDimensionId' 为 'focusedDimensionId'
|
||
// 逻辑修改1:修正局部变量名 'newFocuseDimensionId' 为 'newFocusedDimensionId'
|
||
if (FocusedDimensionId == newFocusedDimensionId && FocusedDimension == newFocusedDimension)
|
||
{
|
||
// Debug.Log($"[Program] SetFocusedDimension: ID '{dimensionId}' already current. No change needed.");
|
||
return;
|
||
}
|
||
|
||
if (FocusedEntity != null)
|
||
{
|
||
FocusedEntity.PlayerControlled = false;
|
||
}
|
||
// 3. 更新内部状态
|
||
FocusedDimensionId = newFocusedDimensionId; // 逻辑修改1:修正属性名
|
||
FocusedDimension = newFocusedDimension;
|
||
|
||
// 逻辑修改2:功能缺失修复 - 切换维度时,焦点实体应该置为空
|
||
// 确保功能一致性:当维度焦点改变(或被清除)时,任何实体焦点也应被清除。
|
||
SetFocusedEntity(null);
|
||
|
||
// 4. 触发事件
|
||
OnFocusedDimensionChanged?.Invoke(FocusedDimension);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置当前聚焦的实体。
|
||
/// 这是更改焦点实体的唯一官方入口,并会在实体改变时触发 OnFocusedEntityChanged 事件。
|
||
/// </summary>
|
||
/// <param name="entity">要设置为焦点的实体实例。如果传入null,将清除当前焦点实体。</param>
|
||
public void SetFocusedEntity(Entity.Entity entity)
|
||
{
|
||
// 优化:检查是否实际发生变化,避免不必要的更新和事件触发。
|
||
// 如果新的实体与当前焦点实体相同(按引用比较),则不执行任何操作。
|
||
if (FocusedEntity == entity)
|
||
{
|
||
// Debug.Log($"[Program] SetFocusedEntity: Entity '{entity?.name ?? "null"}' already current. No change needed.");
|
||
return;
|
||
}
|
||
|
||
// 更新内部状态
|
||
FocusedEntity = entity;
|
||
|
||
// 触发事件,将新的焦点实体(或 null)作为参数传递。
|
||
OnFocusedEntityChanged?.Invoke(FocusedEntity);
|
||
}
|
||
}
|