234 lines
10 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|