Files

270 lines
9.7 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using Base;
using Data;
using Entity;
using Managers;
using Map;
using UnityEngine;
using UnityEngine.SceneManagement;
using Utils;
using Random = UnityEngine.Random;
/// <summary>
/// Program 类作为单例模式的核心管理器,负责维护和管理游戏或应用中的维度(Dimension)实例和焦点状态。
/// 它提供了维度注册、注销、获取以及焦点维度设置的功能。
/// </summary>
public class Program : Singleton<Program>
{
/// <summary>
/// 维护所有已注册的维度实例的字典,键是维度的唯一标识符 (ID)。
/// </summary>
private readonly Dictionary<string, Dimension> _registeredDimensions = new();
// 指示是否需要加载数据的标志,例如在游戏启动或场景切换时。
private bool _needLoad = true;
// 当前角色定义
public CharacterDef CurrentCharacter { get; private set; }
/// <summary>
/// 指示是否需要加载数据的标志,例如在游戏启动或场景切换时。
/// </summary>
public bool NeedLoad
{
get => _needLoad;
set
{
if (value) CurrentCharacter = null;
_needLoad = value;
}
}
public bool OnPlay => CurrentCharacter != null;
/// <summary>
/// 当前聚焦的实体对象。
/// 变更为属性并私有化setter确保通过 SetFocusedEntity 方法集中管理其更新和事件触发。
/// </summary>
public Entity.Entity FocusedEntity => FocusedDimension?.focusEntity;
/// <summary>
/// 当前活跃焦点的维度唯一标识符,可能为空。
/// 变更为属性并私有化setter确保通过 SetFocusedDimension 方法集中管理其更新。
/// </summary>
public string FocusedDimensionId { get; private set; }
/// <summary>
/// 当前聚焦的维度对象实例。当 <see cref="FocusedDimensionId" /> 不为空时,此属性指向对应的维度实例。
/// </summary>
public Dimension FocusedDimension { get; private set; }
/// <summary>
/// 获取所有已注册的维度。返回一个只读字典副本,防止外部直接修改。
/// </summary>
public IReadOnlyDictionary<string, Dimension> RegisteredDimensions => _registeredDimensions;
/// <summary>
/// 获取已注册维度的数量。
/// </summary>
public int DimensionCount => _registeredDimensions.Count;
/// <summary>
/// 获取所有已注册维度的ID数组。
/// </summary>
public string[] Dimensions => _registeredDimensions.Keys.ToArray();
public bool CanOpenRightMenu => Setting.Instance.CurrentSettings.developerMode && !OnPlay;
public bool CanMoveCamera => CanOpenRightMenu && !UIInputControl.Instance.HasInputExclusionWindow;
public DimensionDef OutsidePlayDimension { get; private set; }
public int CoinCount
{
get => KeyValueArchiveManager.Instance.Get<int>("coinCount");
set => KeyValueArchiveManager.Instance.Set("coinCount", value);
}
public RobotLogicDef CurrentRobotLogic { get; set; }
/// <summary>
/// 当焦点实体发生变化时触发的事件。
/// 事件参数为新的焦点 Entity 实例,如果焦点被清除则为 null。
/// </summary>
public event Action<Entity.Entity> OnFocusedEntityChanged;
/// <summary>
/// 当焦点维度发生变化时触发的事件。
/// 事件参数为新的焦点 Dimension 实例,如果焦点被清除则为 null。
/// </summary>
public event Action<Dimension> OnFocusedDimensionChanged;
/// <summary>
/// 注册一个维度实例到 Program。
/// </summary>
/// <param name="dimension">要注册的维度实例。</param>
public void RegisterDimension(Dimension dimension)
{
if (dimension == null)
{
Debug.LogError("[Program] 尝试注册一个空的维度。");
return;
}
var id = dimension.DimensionId;
if (string.IsNullOrEmpty(id))
{
Debug.LogError($"[Program] 尝试注册一个ID为空的维度: {dimension.name}");
return;
}
if (!_registeredDimensions.TryAdd(id, dimension))
{
Debug.LogWarning($"[Program] ID为 '{id}' 的维度已注册。跳过重复注册 {dimension.name}。");
return;
}
// 如果注册的维度恰好是当前 focusedDimensionIdSetFocusedDimension(id) 将负责更新 FocusedDimension 并触发事件。
// 并且由于SetFocusedDimension会清空FocusedEntity这也符合新维度的行为。
if (FocusedDimensionId == id) SetFocusedDimension(id);
}
/// <summary>
/// 从 Program 注销一个维度实例。
/// </summary>
/// <param name="dimension">要注销的维度实例。</param>
public void UnregisterDimension(Dimension dimension)
{
if (dimension == null)
{
Debug.LogWarning("[Program] 尝试注销一个空的维度。");
return;
}
var id = dimension.DimensionId;
if (_registeredDimensions.Remove(id))
{
// 如果注销的维度是当前焦点维度,则调用 SetFocusedDimension(null) 清除焦点并触发事件。
if (FocusedDimensionId == id) SetFocusedDimension(null); // 清除焦点
}
else
{
Debug.LogWarning($"[Program] 尝试注销ID为 '{id}' 的维度,但未在已注册列表中找到。");
}
}
/// <summary>
/// 根据ID获取一个已注册的维度。
/// </summary>
/// <param name="dimensionId">维度的唯一标识符。</param>
/// <returns>对应的Dimension实例如果未找到则返回null。</returns>
public Dimension GetDimension(string dimensionId)
{
if (dimensionId == null)
return null;
_registeredDimensions.TryGetValue(dimensionId, out var dimension);
return dimension;
}
/// <summary>
/// 设置当前聚焦的维度。
/// 这是更改焦点维度的唯一官方入口。
/// </summary>
/// <param name="dimensionId">要设置为焦点的维度的唯一标识符。如果传入null或空字符串将清除当前焦点维度。</param>
public void SetFocusedDimension(string dimensionId)
{
// 确定新的焦点维度及其ID
Dimension newFocusedDimension = null; // 默认为清除焦点
string newFocusedDimensionId = null;
if (!string.IsNullOrEmpty(dimensionId))
{
if (_registeredDimensions.TryGetValue(dimensionId, out var foundDimension))
{
newFocusedDimensionId = dimensionId;
newFocusedDimension = foundDimension;
}
else
{
// 如果尝试设置未注册的维度,警告并直接返回,不改变当前焦点状态。
Debug.LogWarning($"[Program] 尝试设置焦点到未注册的维度ID: '{dimensionId}'。焦点未改变。");
return;
}
}
// 如果 dimensionId 为 null 或空, newFocusedDimension 和 newFocusedDimensionId 将保持为 null表示清除焦点。
// 检查是否实际发生变化
if (FocusedDimensionId == newFocusedDimensionId && FocusedDimension == newFocusedDimension) return;
if (FocusedEntity) FocusedEntity.PlayerControlled = false;
// 更新内部状态
FocusedDimensionId = newFocusedDimensionId;
FocusedDimension = newFocusedDimension;
// 触发事件
OnFocusedDimensionChanged?.Invoke(FocusedDimension);
}
/// <summary>
/// 设置当前聚焦的实体。
/// 这是更改焦点实体的唯一官方入口,并会在实体改变时触发 OnFocusedEntityChanged 事件。
/// </summary>
/// <param name="entity">要设置为焦点的实体实例。如果传入null将清除当前焦点实体。</param>
public void SetFocusedEntity(Entity.Entity entity)
{
// 检查是否实际发生变化
if (!FocusedDimension) return;
FocusedDimension.focusEntity = entity;
// 触发事件,将新的焦点实体(或 null作为参数传递。
OnFocusedEntityChanged?.Invoke(FocusedEntity);
if (entity is LivingEntity { getBaseHediff: false } livingEntity)
{
foreach (var hediffDef in HediffManager.Instance.BaseHediffs) livingEntity.AddHediff(new Hediff(hediffDef));
livingEntity.getBaseHediff = true;
}
}
public void SelectCharacterPlayGame(CharacterDef character)
{
CurrentCharacter = character;
if (character == null)
return;
PutPlayer();
}
public void PutPlayer()
{
if (FocusedEntity || CurrentCharacter == null)
return;
var pos = CameraControl.CameraControl.Instance.Position;
var player =
EntityManager.Instance.GenerateCharacterEntity(FocusedDimensionId, CurrentCharacter,
new Vector3(pos.x, pos.y));
if (!player)
return;
player.entity.PlayerControlled = true;
}
public void StartPlayGame(DimensionDef dimension)
{
OutsidePlayDimension = dimension;
PerlinNoise.Instance.Reinitialize(Random.Range(int.MinValue, int.MaxValue));
SceneManager.LoadScene("Play");
}
public void EndPlayGame()
{
OutsidePlayDimension = null;
CurrentCharacter = null;
SetFocusedDimension(null);
EventManager.Instance.StopAllStories();
}
public void ReturnBase()
{
Program.Instance.EndPlayGame();
SceneManager.LoadScene("Base");
}
}