344 lines
10 KiB
C#
344 lines
10 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using UnityEngine;
|
||
|
||
namespace CapabilitySystem
|
||
{
|
||
/// <summary>
|
||
/// Capability组件,挂载到GameObject上管理Capability
|
||
/// </summary>
|
||
public class CapabilityComponent : MonoBehaviour
|
||
{
|
||
[SerializeField]
|
||
[Tooltip("默认应用的Sheet列表")]
|
||
private List<CapabilitySheet> defaultSheets = new List<CapabilitySheet>();
|
||
|
||
// 所有Capability实例
|
||
private List<Capability> capabilities = new List<Capability>();
|
||
|
||
// Capability引用计数:Type -> (Capability, RefCount)
|
||
private Dictionary<Type, (Capability capability, int refCount)> capabilityRegistry = new Dictionary<Type, (Capability, int)>();
|
||
|
||
// 标签阻塞器:Tag -> Instigator列表
|
||
private Dictionary<CapabilityTag, List<Instigator>> tagBlockers = new Dictionary<CapabilityTag, List<Instigator>>();
|
||
|
||
// 已应用的Sheet(用于运行时管理)
|
||
private HashSet<CapabilitySheet> appliedSheets = new HashSet<CapabilitySheet>();
|
||
|
||
// 黑板系统(用于Capability间通信)
|
||
private CapabilityBlackboard blackboard = new CapabilityBlackboard();
|
||
|
||
// 时间记录器(用于调试和回放)
|
||
private TemporalLogger temporalLogger;
|
||
|
||
#region Unity Lifecycle
|
||
|
||
private void Awake()
|
||
{
|
||
// 初始化 TemporalLogger(不能在字段初始化器中创建,因为会调用 Time.time)
|
||
temporalLogger = new TemporalLogger();
|
||
|
||
// 应用默认Sheet
|
||
foreach (var sheet in defaultSheets)
|
||
{
|
||
if (sheet != null)
|
||
{
|
||
AddSheet(sheet);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
// 销毁所有Capability
|
||
foreach (var capability in capabilities.ToList())
|
||
{
|
||
capability.Destroy();
|
||
}
|
||
capabilities.Clear();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Sheet Management
|
||
|
||
/// <summary>
|
||
/// 添加Sheet
|
||
/// </summary>
|
||
public void AddSheet(CapabilitySheet sheet)
|
||
{
|
||
if (sheet == null || appliedSheets.Contains(sheet))
|
||
return;
|
||
|
||
appliedSheets.Add(sheet);
|
||
sheet.ApplyToGameObject(gameObject, this);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移除Sheet
|
||
/// </summary>
|
||
public void RemoveSheet(CapabilitySheet sheet)
|
||
{
|
||
if (sheet == null || !appliedSheets.Contains(sheet))
|
||
return;
|
||
|
||
appliedSheets.Remove(sheet);
|
||
|
||
// 移除Sheet创建的Capability(通过引用计数)
|
||
sheet.RemoveFromGameObject(this);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Capability Management
|
||
|
||
/// <summary>
|
||
/// 添加Capability实例(内部使用,支持引用计数)
|
||
/// </summary>
|
||
internal void AddCapability(Capability capability, bool incrementRefCount = true)
|
||
{
|
||
if (capability == null)
|
||
return;
|
||
|
||
Type capabilityType = capability.GetType();
|
||
|
||
// 检查是否已存在
|
||
if (capabilityRegistry.ContainsKey(capabilityType))
|
||
{
|
||
if (incrementRefCount)
|
||
{
|
||
// 增加引用计数
|
||
var entry = capabilityRegistry[capabilityType];
|
||
capabilityRegistry[capabilityType] = (entry.capability, entry.refCount + 1);
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 添加新Capability
|
||
capabilities.Add(capability);
|
||
capabilityRegistry[capabilityType] = (capability, 1);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移除Capability实例(内部使用,支持引用计数)
|
||
/// </summary>
|
||
internal void RemoveCapability(Capability capability, bool decrementRefCount = true)
|
||
{
|
||
if (capability == null)
|
||
return;
|
||
|
||
Type capabilityType = capability.GetType();
|
||
|
||
if (!capabilityRegistry.ContainsKey(capabilityType))
|
||
return;
|
||
|
||
if (decrementRefCount)
|
||
{
|
||
var entry = capabilityRegistry[capabilityType];
|
||
int newRefCount = entry.refCount - 1;
|
||
|
||
if (newRefCount > 0)
|
||
{
|
||
// 还有其他引用,只减少计数
|
||
capabilityRegistry[capabilityType] = (entry.capability, newRefCount);
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 引用计数为0,真正移除
|
||
capabilities.Remove(capability);
|
||
capabilityRegistry.Remove(capabilityType);
|
||
capability.Destroy();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 运行时添加Capability(泛型方法)
|
||
/// </summary>
|
||
public T AddCapability<T>() where T : Capability, new()
|
||
{
|
||
return AddCapability<T>(null);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 运行时添加Capability(泛型方法,带配置数据)
|
||
/// </summary>
|
||
public T AddCapability<T>(CapabilityData data) where T : Capability, new()
|
||
{
|
||
Type capabilityType = typeof(T);
|
||
|
||
// 检查是否已存在
|
||
if (capabilityRegistry.ContainsKey(capabilityType))
|
||
{
|
||
Debug.LogWarning($"[CapabilityComponent] Capability of type {capabilityType.Name} already exists on {gameObject.name}");
|
||
return capabilityRegistry[capabilityType].capability as T;
|
||
}
|
||
|
||
// 创建新实例
|
||
T capability = new T();
|
||
capability.Initialize(gameObject, this, data);
|
||
AddCapability(capability, false);
|
||
|
||
return capability;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 运行时移除Capability(泛型方法)
|
||
/// </summary>
|
||
public void RemoveCapability<T>() where T : Capability
|
||
{
|
||
Type capabilityType = typeof(T);
|
||
|
||
if (capabilityRegistry.TryGetValue(capabilityType, out var entry))
|
||
{
|
||
RemoveCapability(entry.capability, false);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取Capability(泛型方法)
|
||
/// </summary>
|
||
public T GetCapability<T>() where T : Capability
|
||
{
|
||
Type capabilityType = typeof(T);
|
||
|
||
if (capabilityRegistry.TryGetValue(capabilityType, out var entry))
|
||
{
|
||
return entry.capability as T;
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查是否有指定类型的Capability
|
||
/// </summary>
|
||
public bool HasCapability<T>() where T : Capability
|
||
{
|
||
return capabilityRegistry.ContainsKey(typeof(T));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查是否有指定类型的Capability(非泛型版本)
|
||
/// </summary>
|
||
public bool HasCapabilityOfType(Type capabilityType)
|
||
{
|
||
return capabilityRegistry.ContainsKey(capabilityType);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有Capability
|
||
/// </summary>
|
||
public IReadOnlyList<Capability> GetAllCapabilities()
|
||
{
|
||
return capabilities.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取黑板系统
|
||
/// </summary>
|
||
public CapabilityBlackboard Blackboard => blackboard;
|
||
|
||
/// <summary>
|
||
/// 获取时间记录器
|
||
/// </summary>
|
||
public TemporalLogger TemporalLogger => temporalLogger;
|
||
|
||
/// <summary>
|
||
/// 获取所有Capability的激活历史记录(用于调试器)
|
||
/// </summary>
|
||
public List<(Capability capability, CapabilityActivationRecord record)> GetActivationHistory()
|
||
{
|
||
var allRecords = new List<(Capability capability, CapabilityActivationRecord record)>();
|
||
|
||
foreach (var capability in capabilities)
|
||
{
|
||
foreach (var record in capability.ActivationHistory)
|
||
{
|
||
allRecords.Add((capability: capability, record: record));
|
||
}
|
||
}
|
||
|
||
// 按激活时间排序
|
||
allRecords.Sort((a, b) => a.record.ActivateTime.CompareTo(b.record.ActivateTime));
|
||
|
||
return allRecords;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Tag Blocking
|
||
|
||
/// <summary>
|
||
/// 阻塞指定Tag
|
||
/// </summary>
|
||
public void BlockTag(CapabilityTag tag, Instigator instigator)
|
||
{
|
||
if (tag == null || instigator == null)
|
||
return;
|
||
|
||
if (!tagBlockers.ContainsKey(tag))
|
||
{
|
||
tagBlockers[tag] = new List<Instigator>();
|
||
}
|
||
|
||
if (!tagBlockers[tag].Contains(instigator))
|
||
{
|
||
tagBlockers[tag].Add(instigator);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 解除阻塞指定Tag
|
||
/// </summary>
|
||
public void UnblockTag(CapabilityTag tag, Instigator instigator)
|
||
{
|
||
if (tag == null || instigator == null)
|
||
return;
|
||
|
||
if (tagBlockers.ContainsKey(tag))
|
||
{
|
||
tagBlockers[tag].Remove(instigator);
|
||
|
||
// 如果没有阻塞者了,移除字典项
|
||
if (tagBlockers[tag].Count == 0)
|
||
{
|
||
tagBlockers.Remove(tag);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查Tag是否被阻塞
|
||
/// </summary>
|
||
public bool IsTagBlocked(CapabilityTag tag)
|
||
{
|
||
if (tag == null)
|
||
return false;
|
||
|
||
return tagBlockers.ContainsKey(tag) && tagBlockers[tag].Count > 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取阻塞指定Tag的所有Instigator
|
||
/// </summary>
|
||
public IReadOnlyList<Instigator> GetTagBlockers(CapabilityTag tag)
|
||
{
|
||
if (tag == null || !tagBlockers.ContainsKey(tag))
|
||
return new List<Instigator>().AsReadOnly();
|
||
|
||
return tagBlockers[tag].AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有被阻塞的Tag
|
||
/// </summary>
|
||
public IEnumerable<CapabilityTag> GetBlockedTags()
|
||
{
|
||
return tagBlockers.Keys;
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|