JisolGame/JEX_GAS/Assets/GAS/Runtime/Component/AbilitySystemComponent.cs

414 lines
14 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using UnityEngine;
namespace GAS.Runtime
{
2024-10-18 17:48:59 +08:00
public class AbilitySystemComponent : IAbilitySystemComponent
{
2024-10-18 17:48:59 +08:00
private AbilitySystemComponentPreset preset;
public AbilitySystemComponentPreset Preset => preset;
2024-10-18 17:48:59 +08:00
public int EntityId { get; protected set; }
public int Level { get; protected set; }
public GameplayEffectContainer GameplayEffectContainer { get; private set; }
public GameplayTagAggregator GameplayTagAggregator { get; private set; }
public AbilityContainer AbilityContainer { get; private set; }
public AttributeSetContainer AttributeSetContainer { get; private set; }
public object UserData { get; set; }
private bool _ready;
private void Prepare()
{
if (_ready) return;
AbilityContainer = new AbilityContainer(this);
GameplayEffectContainer = new GameplayEffectContainer(this);
AttributeSetContainer = new AttributeSetContainer(this);
GameplayTagAggregator = new GameplayTagAggregator(this);
_ready = true;
}
public void Enable()
{
AttributeSetContainer.OnEnable();
}
public void Disable()
{
AttributeSetContainer.OnDisable();
DisableAllAbilities();
ClearGameplayEffects();
GameplayTagAggregator?.OnDisable();
}
private void Awake()
{
Prepare();
}
private void OnDestroy()
{
AttributeSetContainer.OnDestroy();
UserData = null;
}
private void OnEnable()
{
Prepare();
GameplayAbilitySystem.GAS.Register(this);
GameplayTagAggregator?.OnEnable();
Enable();
}
private void OnDisable()
{
Disable();
GameplayAbilitySystem.GAS.Unregister(this);
}
public void SetPreset(AbilitySystemComponentPreset ascPreset)
{
preset = ascPreset;
}
public void Init(GameplayTag[] baseTags, Type[] attrSetTypes, AbilityAsset[] baseAbilities, int level)
{
Prepare();
SetLevel(level);
if (baseTags != null) GameplayTagAggregator.Init(baseTags);
if (attrSetTypes != null)
{
foreach (var attrSetType in attrSetTypes)
AttributeSetContainer.AddAttributeSet(attrSetType);
}
if (baseAbilities != null)
{
foreach (var info in baseAbilities)
GrantAbility(info);
}
}
private void GrantAbility(AbilityAsset info)
{
if (info == null)
{
Debug.LogWarning($"[EX] Try To Grant a NULL Ability!");
return;
}
try
{
var ability = Activator.CreateInstance(info.AbilityType(), args: info) as AbstractAbility;
AbilityContainer.GrantAbility(ability);
}
#pragma warning disable CS0168 // 声明了变量,但从未使用过
catch (MissingMethodException e)
#pragma warning restore CS0168 // 声明了变量,但从未使用过
{
// 踩坑日志:
// 复制了某个AbilityAsset实现类的代码但忘记更新AbilityType()方法的返回值。
// 一般来说AbilityAsset和Ability应该是配套的, 比如在"GAA_xxx"中返回"GA_xxx"的类型.
Debug.LogError($"[EX] 创建能力失败: " +
$"请检查AbilityAsset实现类'{info.GetType().FullName}'中的AbilityType()方法" +
$"是否正确返回了能力类型(当前为'{info.AbilityType()?.FullName ?? "null"}')。");
throw;
}
}
public void SetLevel(int level)
{
Level = level;
}
public bool HasTag(in GameplayTag gameplayTag)
{
return GameplayTagAggregator.HasTag(gameplayTag);
}
public bool HasAllTags(in GameplayTagSet tags)
{
return GameplayTagAggregator.HasAllTags(tags);
}
public bool HasAnyTags(in GameplayTagSet tags)
{
return GameplayTagAggregator.HasAnyTags(tags);
}
public void AddFixedTags(in GameplayTagSet tags)
{
GameplayTagAggregator.AddFixedTag(tags);
}
public void RemoveFixedTags(in GameplayTagSet tags)
{
GameplayTagAggregator.RemoveFixedTag(tags);
}
public void AddFixedTag(in GameplayTag gameplayTag)
{
GameplayTagAggregator.AddFixedTag(gameplayTag);
}
public void RemoveFixedTag(in GameplayTag gameplayTag)
{
GameplayTagAggregator.RemoveFixedTag(gameplayTag);
}
public void RemoveGameplayEffect(GameplayEffectSpec spec)
{
GameplayEffectContainer.RemoveGameplayEffectSpec(spec);
}
public void RemoveGameplayEffect(in EntityRef<GameplayEffectSpec> spec)
{
GameplayEffectContainer.RemoveGameplayEffectSpec(spec);
}
public void RemoveGameplayEffectWithAnyTags(in GameplayTagSet tags)
{
GameplayEffectContainer.RemoveGameplayEffectWithAnyTags(tags);
}
public EntityRef<GameplayEffectSpec> ApplyGameplayEffectTo(GameplayEffectSpec gameplayEffectSpec, AbilitySystemComponent target)
{
return target.AddGameplayEffect(this, gameplayEffectSpec);
}
public EntityRef<GameplayEffectSpec> ApplyGameplayEffectTo(in EntityRef<GameplayEffectSpec> gameplayEffectSpecRef, AbilitySystemComponent target)
{
var gameplayEffectSpec = gameplayEffectSpecRef.Value;
if (gameplayEffectSpec == null)
{
#if UNITY_EDITOR
2024-10-18 17:48:59 +08:00
Debug.LogError($"[EX] Try To Apply a invalid EntityRef of GameplayEffectSpec From {EntityId} To {target.EntityId}!");
#endif
return null;
}
return target.AddGameplayEffect(this, gameplayEffectSpec);
}
public EntityRef<GameplayEffectSpec> ApplyGameplayEffectTo(GameplayEffect gameplayEffect, AbilitySystemComponent target)
{
if (gameplayEffect == null)
{
#if UNITY_EDITOR
2024-10-18 17:48:59 +08:00
Debug.LogError($"[EX] Try To Apply a NULL GameplayEffect From {EntityId} To {target.EntityId}!");
#endif
return null;
}
var spec = gameplayEffect.CreateSpec();
return ApplyGameplayEffectTo(spec, target);
}
public EntityRef<GameplayEffectSpec> ApplyGameplayEffectTo(GameplayEffect gameplayEffect, AbilitySystemComponent target, int effectLevel)
{
if (gameplayEffect == null)
{
#if UNITY_EDITOR
2024-10-18 17:48:59 +08:00
Debug.LogError($"[EX] Try To Apply a NULL GameplayEffect From {EntityId} To {target.EntityId}!");
#endif
return null;
}
var spec = gameplayEffect.CreateSpec();
spec.Value.SetLevel(effectLevel);
return ApplyGameplayEffectTo(spec, target);
}
public EntityRef<GameplayEffectSpec> ApplyGameplayEffectToSelf(GameplayEffectSpec gameplayEffectSpec)
{
return ApplyGameplayEffectTo(gameplayEffectSpec, this);
}
public EntityRef<GameplayEffectSpec> ApplyGameplayEffectToSelf(GameplayEffect gameplayEffect)
{
return ApplyGameplayEffectTo(gameplayEffect, this);
}
public void RemoveGameplayEffectSpec(GameplayEffectSpec gameplayEffectSpec)
{
GameplayEffectContainer.RemoveGameplayEffectSpec(gameplayEffectSpec);
}
public void RemoveGameplayEffectSpec(in EntityRef<GameplayEffectSpec> gameplayEffectSpecRef)
{
GameplayEffectContainer.RemoveGameplayEffectSpec(gameplayEffectSpecRef);
}
public AbilitySpec GrantAbility(AbstractAbility ability)
{
AbilityContainer.GrantAbility(ability);
return AbilityContainer.AbilitySpecs()[ability.Name];
}
public void RemoveAbility(string abilityName)
{
AbilityContainer.RemoveAbility(abilityName);
}
public AttributeValue? GetAttributeAttributeValue(string attrSetName, string attrShortName)
{
var value = AttributeSetContainer.GetAttributeAttributeValue(attrSetName, attrShortName);
return value;
}
public CalculateMode? GetAttributeCalculateMode(string attrSetName, string attrShortName)
{
var value = AttributeSetContainer.GetAttributeCalculateMode(attrSetName, attrShortName);
return value;
}
public float? GetAttributeCurrentValue(string setName, string attributeShortName)
{
var value = AttributeSetContainer.GetAttributeCurrentValue(setName, attributeShortName);
return value;
}
public float? GetAttributeBaseValue(string setName, string attributeShortName)
{
var value = AttributeSetContainer.GetAttributeBaseValue(setName, attributeShortName);
return value;
}
public void Tick()
{
AbilityContainer.Tick();
GameplayEffectContainer.Tick();
}
public Dictionary<string, float> DataSnapshot()
{
return AttributeSetContainer.Snapshot();
}
public bool TryActivateAbility(string abilityName, object arg = null)
{
return AbilityContainer.TryActivateAbility(abilityName, arg, null);
}
internal bool TryActivateAbility(string abilityName, GameplayEffectSpec gameplayEffectSpec)
{
return AbilityContainer.TryActivateAbility(abilityName, null, gameplayEffectSpec);
}
public void TryEndAbility(string abilityName)
{
AbilityContainer.EndAbility(abilityName);
}
public void TryCancelAbility(string abilityName)
{
AbilityContainer.CancelAbility(abilityName);
}
public void ApplyModFromInstantGameplayEffect(GameplayEffectSpec spec)
{
foreach (var modifier in spec.Modifiers)
{
var attributeValue = GetAttributeAttributeValue(modifier.AttributeSetName, modifier.AttributeShortName);
if (attributeValue == null) continue;
if (attributeValue.Value.IsSupportOperation(modifier.Operation) == false)
{
throw new InvalidOperationException("Unsupported operation.");
}
if (attributeValue.Value.CalculateMode != CalculateMode.Stacking)
{
throw new InvalidOperationException(
$"[EX] Instant GameplayEffect Can Only Modify Stacking Mode Attribute! " +
$"But {modifier.AttributeSetName}.{modifier.AttributeShortName} is {attributeValue.Value.CalculateMode}");
}
var magnitude = modifier.CalculateMagnitude(spec, modifier.ModiferMagnitude);
var baseValue = attributeValue.Value.BaseValue;
switch (modifier.Operation)
{
case GEOperation.Add:
baseValue += magnitude;
break;
case GEOperation.Minus:
baseValue -= magnitude;
break;
case GEOperation.Multiply:
baseValue *= magnitude;
break;
case GEOperation.Divide:
baseValue /= magnitude;
break;
case GEOperation.Override:
baseValue = magnitude;
break;
default:
throw new ArgumentOutOfRangeException();
}
AttributeSetContainer.Sets[modifier.AttributeSetName]
.ChangeAttributeBase(modifier.AttributeShortName, baseValue);
}
}
public CooldownTimer CheckCooldownFromTags(in GameplayTagSet tags)
{
return GameplayEffectContainer.CheckCooldownFromTags(tags);
}
public T AttrSet<T>() where T : AttributeSet
{
AttributeSetContainer.TryGetAttributeSet<T>(out var attrSet);
return attrSet;
}
public void ClearGameplayEffect()
{
// _abilityContainer = new AbilityContainer(this);
// GameplayEffectContainer = new GameplayEffectContainer(this);
// _attributeSetContainer = new AttributeSetContainer(this);
// tagAggregator = new GameplayTagAggregator(this);
GameplayEffectContainer.ClearGameplayEffect();
}
private EntityRef<GameplayEffectSpec> AddGameplayEffect(AbilitySystemComponent source, GameplayEffectSpec effectSpec)
{
return GameplayEffectContainer.AddGameplayEffectSpec(source, effectSpec);
}
private EntityRef<GameplayEffectSpec> AddGameplayEffect(AbilitySystemComponent source, GameplayEffectSpec effectSpec, int effectLevel)
{
return GameplayEffectContainer.AddGameplayEffectSpec(source, effectSpec, true, effectLevel);
}
private void DisableAllAbilities()
{
AbilityContainer.CancelAllAbilities();
}
private void ClearGameplayEffects()
{
GameplayEffectContainer.ClearGameplayEffect();
}
2024-10-18 17:48:59 +08:00
/// <summary>
/// 返回视图
/// </summary>
/// <returns></returns>
public virtual GameObject GetView()
{
return null;
}
}
2024-10-18 17:48:59 +08:00
}