mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-06-26 19:34:47 +00:00
414 lines
14 KiB
C#
414 lines
14 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace GAS.Runtime
|
||
{
|
||
public class AbilitySystemComponent : IAbilitySystemComponent
|
||
{
|
||
|
||
private AbilitySystemComponentPreset preset;
|
||
public AbilitySystemComponentPreset Preset => preset;
|
||
|
||
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
|
||
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
|
||
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
|
||
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();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 返回视图
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public virtual GameObject GetView()
|
||
{
|
||
return null;
|
||
}
|
||
|
||
}
|
||
}
|