Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Managers/AffiliationManager.cs

234 lines
10 KiB
C#

using Data;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Managers
{
/// <summary>
/// 阵营管理器,负责管理游戏中的所有阵营定义及其相互关系。
/// 继承自 <see cref="Utils.Singleton{T}"/> ,确保全局只有一个实例。
/// </summary>
public class AffiliationManager : Utils.Singleton<AffiliationManager>, ILaunchManager
{
/// <summary>
/// 存储所有已加载的阵营定义,键为阵营的唯一名称,值为对应的 <see cref="AffiliationDef"/> 对象。
/// </summary>
private readonly Dictionary<string, AffiliationDef> _affiliations = new();
public string StepDescription => "正在区分派系";
/// <summary>
/// 初始化阵营管理器,从 <see cref="DefineManager"/> 加载所有 <see cref="AffiliationDef"/>。
/// 在首次需要阵营数据时调用。
/// </summary>
public void Init()
{
// 如果管理器已经初始化,则直接返回,避免重复加载。
if (_affiliations.Count > 0)
{
return;
}
var affiliationList = Managers.DefineManager.Instance.QueryDefinesByType<AffiliationDef>();
if (affiliationList == null || affiliationList.Length == 0)
{
// 记录警告,说明未能加载任何阵营定义。
Debug.LogWarning("未找到任何 AffiliationDef 或阵营列表为空。");
return;
}
foreach (var affiliation in affiliationList)
{
// 尝试将阵营定义添加到字典中。如果名称已存在,则记录错误。
if (!_affiliations.TryAdd(affiliation.defName, affiliation))
{
Debug.LogError($"添加阵营 '{affiliation.defName}' 失败。已存在同名阵营。");
}
}
// 验证并修复加载后的阵营关系,以确保数据一致性。
ValidateAndFixRelationships();
}
/// <summary>
/// 清除所有已加载的阵营定义。
/// 在游戏会话结束或需要重新加载所有定义时调用。
/// </summary>
public void Clear()
{
_affiliations.Clear();
}
/// <summary>
/// 根据阵营定义名称获取其默认名称。
/// </summary>
/// <param name="defName">阵营的定义名称。</param>
/// <returns>阵营的默认名称。</returns>
public string GetAffiliationName(string defName)
{
return _affiliations[defName].defName;
}
/// <summary>
/// 获取两个阵营间的关系。
/// </summary>
/// <param name="affiliation1">第一个阵营的 <see cref="AffiliationDef"/> 对象。</param>
/// <param name="affiliation2">第二个阵营的 <see cref="AffiliationDef"/> 对象。</param>
/// <returns>两个阵营之间的 <see cref="Relation"/>。</returns>
public Relation GetRelation(AffiliationDef affiliation1, AffiliationDef affiliation2)
{
// 如果任一阵营定义为空,则返回中立关系。
if (affiliation1 == null || affiliation2 == null)
{
return Relation.Neutral;
}
return GetRelation(affiliation1.defName, affiliation2.defName);
}
public Relation GetRelation(Entity.Entity entity1, Entity.Entity entity2)
{
return GetRelation(entity1.affiliation, entity2.affiliation);
}
/// <summary>
/// 获取两个阵营名称之间的关系。
/// </summary>
/// <param name="factionName1">第一个阵营的名称。</param>
/// <param name="factionName2">第二个阵营的名称。</param>
/// <returns>两个阵营之间的 <see cref="Relation"/>。</returns>
public Relation GetRelation(string factionName1, string factionName2)
{
// 如果查询的是同一个阵营,则默认为友好关系。
if (factionName1 == factionName2)
{
return Relation.Friendly;
}
// 尝试获取两个阵营的定义。
if (!_affiliations.TryGetValue(factionName1, out var faction1) ||
!_affiliations.TryGetValue(factionName2, out _))
{
// 如果第一个阵营存在,但第二个不存在,返回第一个阵营的默认关系;
// 否则(两个都不存在或第一个不存在),返回中立。
if (faction1 != null) return faction1.defaultRelation;
// 注意:由于上面已经有一个 TryGetValue 判断,
// 此时 faction1 为 null 表示 factionName1 也不存在,所以应返回中立。
return Relation.Neutral;
}
// 检查 faction1 是否将 faction2 明确列为敌对。
if (faction1.hostileFactions != null && faction1.hostileFactions.Contains(factionName2))
{
return Relation.Hostile;
}
// 检查 faction1 是否将 faction2 明确列为友好。
if (faction1.friendlyFactions != null && faction1.friendlyFactions.Contains(factionName2))
{
return Relation.Friendly;
}
// 检查 faction1 是否将 faction2 明确列为中立。
if (faction1.neutralFactions != null && faction1.neutralFactions.Contains(factionName2))
{
return Relation.Neutral;
}
// 如果 faction1 没有明确设置与 faction2 的关系,则使用 faction1 的默认关系。
return faction1.defaultRelation;
}
/// <summary>
/// 设置两个阵营之间的关系。
/// </summary>
/// <param name="factionName1">第一个阵营的名称。</param>
/// <param name="factionName2">第二个阵营的名称。</param>
/// <param name="relation">要设置的 <see cref="Relation"/>。</param>
/// <exception cref="ArgumentException">当尝试设置同一个阵营的关系或其中一个阵营不存在时抛出。</exception>
/// <exception cref="ArgumentOutOfRangeException">当传入的关系类型无效时抛出。</exception>
public void SetRelation(string factionName1, string factionName2, Relation relation)
{
// 不能设置自己与自己的关系。
if (factionName1 == factionName2)
{
throw new ArgumentException("不能设置同一个阵营之间的关系");
}
// 确保两个阵营都存在。
if (!_affiliations.TryGetValue(factionName1, out var faction1) ||
!_affiliations.TryGetValue(factionName2, out _))
{
throw new ArgumentException("一个或两个阵营不存在");
}
// 确保关系列表已初始化,避免空引用异常。
faction1.hostileFactions ??= new List<string>();
faction1.friendlyFactions ??= new List<string>();
faction1.neutralFactions ??= new List<string>();
// 先移除 factionName2 在 faction1 所有关系列表中的现有关系。
faction1.hostileFactions.Remove(factionName2);
faction1.friendlyFactions.Remove(factionName2);
faction1.neutralFactions.Remove(factionName2);
// 根据传入的关系类型,将 factionName2 添加到对应列表中。
switch (relation)
{
case Relation.Hostile:
faction1.hostileFactions.Add(factionName2);
break;
case Relation.Friendly:
faction1.friendlyFactions.Add(factionName2);
break;
case Relation.Neutral:
faction1.neutralFactions.Add(factionName2);
break;
default:
// 如果传入的关系类型无效,抛出异常。
throw new ArgumentOutOfRangeException(nameof(relation), relation, null);
}
}
/// <summary>
/// 检查并修复所有阵营之间的关系,以确保没有冲突。
/// 修复遵循优先级规则:友好关系优先于敌对关系,敌对关系优先于中立关系。
/// </summary>
private void ValidateAndFixRelationships()
{
foreach (var faction in _affiliations.Values)
{
// 确保所有关系列表已初始化,避免空引用异常。
faction.hostileFactions ??= new List<string>();
faction.friendlyFactions ??= new List<string>();
faction.neutralFactions ??= new List<string>();
// 遍历并检查所有敌对阵营。由于可能修改列表,使用 ToList() 创建副本进行遍历。
foreach (var hostileFaction in faction.hostileFactions.ToList())
{
// 如果敌对阵营同时存在于友好列表中,则移除其敌对关系(友好关系具有更高优先级)。
if (faction.friendlyFactions.Contains(hostileFaction))
{
faction.hostileFactions.Remove(hostileFaction);
continue; // 继续检查下一个敌对阵营。
}
// 如果敌对阵营同时存在于中立列表中,则移除其中立关系(敌对关系具有更高优先级)。
if (faction.neutralFactions.Contains(hostileFaction))
{
faction.neutralFactions.Remove(hostileFaction);
}
}
// 遍历并检查所有中立阵营。由于可能修改列表,使用 ToList() 创建副本进行遍历。
foreach (var neutralFaction in faction.neutralFactions.ToList())
{
// 如果中立阵营同时存在于友好列表中,则移除其中立关系(友好关系具有更高优先级)。
if (faction.friendlyFactions.Contains(neutralFaction))
{
faction.neutralFactions.Remove(neutralFaction);
}
}
}
}
}
}