2024-10-18 03:16:09 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using GAS.General;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
namespace GAS.Runtime
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 注意: 永远不要直接持有对GameplayEffectSpec的引用, 用EntityRef代替, 否则当它回收入池再次使用时会出现问题
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class GameplayEffectSpec : IEntity, IPool
|
|
|
|
|
{
|
|
|
|
|
private Dictionary<GameplayTag, float> _valueMapWithTag;
|
|
|
|
|
private Dictionary<string, float> _valueMapWithName;
|
|
|
|
|
private List<GameplayCueDurationalSpec> _cueDurationalSpecs;
|
|
|
|
|
|
|
|
|
|
public object UserData { get; set; }
|
|
|
|
|
|
|
|
|
|
private event Action<AbilitySystemComponent, GameplayEffectSpec> OnImmunityBlock;
|
|
|
|
|
|
|
|
|
|
private event Action<int, int> OnStackChanged;
|
|
|
|
|
|
|
|
|
|
public ulong InstanceId { get; private set; }
|
|
|
|
|
|
|
|
|
|
public bool IsFromPool { get; set; }
|
|
|
|
|
|
|
|
|
|
public void Awake(GameplayEffect gameplayEffect, object userData = null)
|
|
|
|
|
{
|
|
|
|
|
InstanceId = IdGenerator.Next;
|
|
|
|
|
|
|
|
|
|
GameplayEffect = gameplayEffect;
|
|
|
|
|
UserData = userData;
|
|
|
|
|
Duration = GameplayEffect.Duration;
|
|
|
|
|
DurationPolicy = GameplayEffect.DurationPolicy;
|
|
|
|
|
Stacking = GameplayEffect.Stacking;
|
|
|
|
|
Modifiers = GameplayEffect.Modifiers;
|
|
|
|
|
if (gameplayEffect.DurationPolicy != EffectsDurationPolicy.Instant)
|
|
|
|
|
{
|
2024-10-18 17:48:59 +08:00
|
|
|
|
var periodTicker = JexGasObjectPool.Instance.Fetch<GameplayEffectPeriodTicker>();
|
2024-10-18 03:16:09 +08:00
|
|
|
|
periodTicker.Awake(this);
|
|
|
|
|
// EntityRef之前必须确定InstanceId的值
|
|
|
|
|
PeriodTicker = periodTicker;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Recycle()
|
|
|
|
|
{
|
|
|
|
|
if (InstanceId != 0)
|
|
|
|
|
{
|
|
|
|
|
InstanceId = 0;
|
|
|
|
|
|
|
|
|
|
GameplayEffect = default;
|
|
|
|
|
ActivationTime = default;
|
|
|
|
|
Level = default;
|
|
|
|
|
Source = default;
|
|
|
|
|
Owner = default;
|
|
|
|
|
IsApplied = default;
|
|
|
|
|
IsActive = default;
|
|
|
|
|
|
|
|
|
|
var gameplayEffectPeriodTicker = PeriodTicker.Value;
|
|
|
|
|
if (gameplayEffectPeriodTicker != null)
|
|
|
|
|
{
|
|
|
|
|
gameplayEffectPeriodTicker.Release();
|
2024-10-18 17:48:59 +08:00
|
|
|
|
JexGasObjectPool.Instance.Recycle(gameplayEffectPeriodTicker);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PeriodTicker = default;
|
|
|
|
|
|
|
|
|
|
Duration = default;
|
|
|
|
|
DurationPolicy = default;
|
|
|
|
|
PeriodExecution.Value?.Recycle();
|
|
|
|
|
PeriodExecution = default;
|
|
|
|
|
Modifiers = default;
|
|
|
|
|
|
|
|
|
|
if (GrantedAbilitiesSpecFromEffect != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (GrantedAbilitySpecFromEffect grantedAbilitySpecFromEffect in GrantedAbilitiesSpecFromEffect)
|
|
|
|
|
{
|
|
|
|
|
if (grantedAbilitySpecFromEffect != null)
|
|
|
|
|
{
|
|
|
|
|
grantedAbilitySpecFromEffect.Release();
|
2024-10-18 17:48:59 +08:00
|
|
|
|
JexGasObjectPool.Instance.Recycle(grantedAbilitySpecFromEffect);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GrantedAbilitiesSpecFromEffect.Clear();
|
2024-10-18 17:48:59 +08:00
|
|
|
|
JexGasObjectPool.Instance.Recycle(GrantedAbilitiesSpecFromEffect);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
GrantedAbilitiesSpecFromEffect = default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Stacking = default;
|
|
|
|
|
|
|
|
|
|
// 注意: SnapshotSourceAttributes 和 SnapshotTargetAttributes 可能是同一个对象
|
|
|
|
|
if (SnapshotSourceAttributes != null)
|
|
|
|
|
{
|
|
|
|
|
SnapshotSourceAttributes.Clear();
|
2024-10-18 17:48:59 +08:00
|
|
|
|
JexGasObjectPool.Instance.Recycle(SnapshotSourceAttributes);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SnapshotTargetAttributes != null && SnapshotSourceAttributes != SnapshotTargetAttributes)
|
|
|
|
|
{
|
|
|
|
|
SnapshotTargetAttributes.Clear();
|
2024-10-18 17:48:59 +08:00
|
|
|
|
JexGasObjectPool.Instance.Recycle(SnapshotTargetAttributes);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SnapshotSourceAttributes = null;
|
|
|
|
|
SnapshotTargetAttributes = null;
|
|
|
|
|
|
|
|
|
|
StackCount = 1;
|
|
|
|
|
|
|
|
|
|
if (_valueMapWithTag != null)
|
|
|
|
|
{
|
|
|
|
|
_valueMapWithTag.Clear();
|
2024-10-18 17:48:59 +08:00
|
|
|
|
JexGasObjectPool.Instance.Recycle(_valueMapWithTag);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
_valueMapWithTag = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_valueMapWithName != null)
|
|
|
|
|
{
|
|
|
|
|
_valueMapWithName.Clear();
|
2024-10-18 17:48:59 +08:00
|
|
|
|
JexGasObjectPool.Instance.Recycle(_valueMapWithName);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
_valueMapWithName = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReleaseCueDurationalSpecs();
|
|
|
|
|
|
|
|
|
|
OnImmunityBlock = default;
|
|
|
|
|
OnStackChanged = default;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-18 17:48:59 +08:00
|
|
|
|
JexGasObjectPool.Instance.Recycle(this);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Init(AbilitySystemComponent source, AbilitySystemComponent owner, float level = 1)
|
|
|
|
|
{
|
|
|
|
|
Source = source;
|
|
|
|
|
Owner = owner;
|
|
|
|
|
Level = level;
|
|
|
|
|
if (GameplayEffect.DurationPolicy != EffectsDurationPolicy.Instant)
|
|
|
|
|
{
|
|
|
|
|
if (GameplayEffect.PeriodExecution is not null)
|
|
|
|
|
{
|
|
|
|
|
PeriodExecution = GameplayEffect.PeriodExecution.CreateSpec(source, owner);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetGrantedAbility(GameplayEffect.GrantedAbilities);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CaptureAttributesSnapshot();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public GameplayEffect GameplayEffect { get; private set; }
|
|
|
|
|
public float ActivationTime { get; private set; }
|
|
|
|
|
public float Level { get; private set; }
|
|
|
|
|
public AbilitySystemComponent Source { get; private set; }
|
|
|
|
|
public AbilitySystemComponent Owner { get; private set; }
|
|
|
|
|
public bool IsApplied { get; private set; }
|
|
|
|
|
public bool IsActive { get; private set; }
|
|
|
|
|
internal EntityRef<GameplayEffectPeriodTicker> PeriodTicker { get; private set; }
|
|
|
|
|
public float Duration { get; private set; }
|
|
|
|
|
public EffectsDurationPolicy DurationPolicy { get; private set; }
|
|
|
|
|
public EntityRef<GameplayEffectSpec> PeriodExecution { get; private set; }
|
|
|
|
|
public GameplayEffectModifier[] Modifiers { get; private set; }
|
|
|
|
|
public List<EntityRef<GrantedAbilitySpecFromEffect>> GrantedAbilitiesSpecFromEffect { get; private set; }
|
|
|
|
|
public GameplayEffectStacking Stacking { get; private set; }
|
|
|
|
|
|
|
|
|
|
public GameplayEffectSnapshotPolicy SnapshotPolicy => GameplayEffect.SnapshotPolicy;
|
|
|
|
|
public Dictionary<string, float> SnapshotSourceAttributes { get; private set; }
|
|
|
|
|
public Dictionary<string, float> SnapshotTargetAttributes { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 堆叠数
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int StackCount { get; private set; } = 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public float DurationRemaining()
|
|
|
|
|
{
|
|
|
|
|
if (DurationPolicy == EffectsDurationPolicy.Infinite)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return Mathf.Max(0, Duration - (Time.time - ActivationTime));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetLevel(float level)
|
|
|
|
|
{
|
|
|
|
|
Level = level;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetActivationTime(float activationTime)
|
|
|
|
|
{
|
|
|
|
|
ActivationTime = activationTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetDuration(float duration)
|
|
|
|
|
{
|
|
|
|
|
Duration = duration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetDurationPolicy(EffectsDurationPolicy durationPolicy)
|
|
|
|
|
{
|
|
|
|
|
DurationPolicy = durationPolicy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetPeriodExecution(GameplayEffectSpec periodExecution)
|
|
|
|
|
{
|
|
|
|
|
PeriodExecution.Value?.Recycle();
|
|
|
|
|
PeriodExecution = periodExecution;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetModifiers(GameplayEffectModifier[] modifiers)
|
|
|
|
|
{
|
|
|
|
|
Modifiers = modifiers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetGrantedAbility(GrantedAbilityFromEffect[] grantedAbilityFromEffects)
|
|
|
|
|
{
|
|
|
|
|
ReleaseGrantedAbilitiesSpecFromEffect();
|
|
|
|
|
|
|
|
|
|
if (grantedAbilityFromEffects is null) return;
|
|
|
|
|
if (grantedAbilityFromEffects.Length == 0) return;
|
|
|
|
|
|
2024-10-18 17:48:59 +08:00
|
|
|
|
GrantedAbilitiesSpecFromEffect = JexGasObjectPool.Instance.Fetch<List<EntityRef<GrantedAbilitySpecFromEffect>>>();
|
2024-10-18 03:16:09 +08:00
|
|
|
|
foreach (var grantedAbilityFromEffect in grantedAbilityFromEffects)
|
|
|
|
|
{
|
|
|
|
|
GrantedAbilitiesSpecFromEffect.Add(grantedAbilityFromEffect.CreateSpec(this));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ReleaseGrantedAbilitiesSpecFromEffect()
|
|
|
|
|
{
|
|
|
|
|
if (GrantedAbilitiesSpecFromEffect == null) return;
|
|
|
|
|
foreach (var grantedAbilitySpecFromEffectRef in GrantedAbilitiesSpecFromEffect)
|
|
|
|
|
{
|
|
|
|
|
var grantedAbilitySpecFromEffect = grantedAbilitySpecFromEffectRef.Value;
|
|
|
|
|
if (grantedAbilitySpecFromEffect != null)
|
|
|
|
|
{
|
|
|
|
|
grantedAbilitySpecFromEffect.Release();
|
2024-10-18 17:48:59 +08:00
|
|
|
|
JexGasObjectPool.Instance.Recycle(grantedAbilitySpecFromEffect);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GrantedAbilitiesSpecFromEffect.Clear();
|
2024-10-18 17:48:59 +08:00
|
|
|
|
JexGasObjectPool.Instance.Recycle(GrantedAbilitiesSpecFromEffect);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetStacking(GameplayEffectStacking stacking)
|
|
|
|
|
{
|
|
|
|
|
Stacking = stacking;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Apply()
|
|
|
|
|
{
|
|
|
|
|
if (IsApplied) return;
|
|
|
|
|
IsApplied = true;
|
|
|
|
|
|
|
|
|
|
if (GameplayEffect.CanRunning(Owner))
|
|
|
|
|
{
|
|
|
|
|
Activate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DisApply()
|
|
|
|
|
{
|
|
|
|
|
if (!IsApplied) return;
|
|
|
|
|
IsApplied = false;
|
|
|
|
|
Deactivate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Activate()
|
|
|
|
|
{
|
|
|
|
|
if (IsActive) return;
|
|
|
|
|
IsActive = true;
|
|
|
|
|
ActivationTime = Time.time;
|
|
|
|
|
TriggerOnActivation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Deactivate()
|
|
|
|
|
{
|
|
|
|
|
if (!IsActive) return;
|
|
|
|
|
IsActive = false;
|
|
|
|
|
TriggerOnDeactivation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Tick()
|
|
|
|
|
{
|
|
|
|
|
PeriodTicker.Value?.Tick();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TriggerInstantCues(GameplayCueInstant[] cues)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
foreach (var cue in cues) cue.ApplyFrom(this);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void TriggerCueOnExecute()
|
|
|
|
|
{
|
|
|
|
|
if (GameplayEffect.CueOnExecute == null || GameplayEffect.CueOnExecute.Length <= 0) return;
|
|
|
|
|
TriggerInstantCues(GameplayEffect.CueOnExecute);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void TriggerCueOnAdd()
|
|
|
|
|
{
|
|
|
|
|
if (GameplayEffect.CueOnAdd is { Length: > 0 })
|
|
|
|
|
TriggerInstantCues(GameplayEffect.CueOnAdd);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
ReleaseCueDurationalSpecs();
|
|
|
|
|
if (GameplayEffect.CueDurational is { Length: > 0 })
|
|
|
|
|
{
|
2024-10-18 17:48:59 +08:00
|
|
|
|
_cueDurationalSpecs = JexGasObjectPool.Instance.Fetch<List<GameplayCueDurationalSpec>>();
|
2024-10-18 03:16:09 +08:00
|
|
|
|
foreach (var cueDurational in GameplayEffect.CueDurational)
|
|
|
|
|
{
|
|
|
|
|
var cueSpec = cueDurational.ApplyFrom(this);
|
|
|
|
|
if (cueSpec != null) _cueDurationalSpecs.Add(cueSpec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var cue in _cueDurationalSpecs)
|
2024-10-18 17:48:59 +08:00
|
|
|
|
cue.OnAdd(-1,-1,-1);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void TriggerCueOnRemove()
|
|
|
|
|
{
|
|
|
|
|
if (GameplayEffect.CueOnRemove is { Length: > 0 })
|
|
|
|
|
TriggerInstantCues(GameplayEffect.CueOnRemove);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (_cueDurationalSpecs != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var cue in _cueDurationalSpecs)
|
2024-10-18 17:48:59 +08:00
|
|
|
|
cue.OnRemove(-1,-1,-1);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError(e);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
ReleaseCueDurationalSpecs();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void TriggerCueOnActivation()
|
|
|
|
|
{
|
|
|
|
|
if (GameplayEffect.CueOnActivate is { Length: > 0 })
|
|
|
|
|
TriggerInstantCues(GameplayEffect.CueOnActivate);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (_cueDurationalSpecs != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var cue in _cueDurationalSpecs)
|
|
|
|
|
cue.OnGameplayEffectActivate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void TriggerCueOnDeactivation()
|
|
|
|
|
{
|
|
|
|
|
if (GameplayEffect.CueOnDeactivate is { Length: > 0 })
|
|
|
|
|
TriggerInstantCues(GameplayEffect.CueOnDeactivate);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (_cueDurationalSpecs != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var cue in _cueDurationalSpecs)
|
|
|
|
|
cue.OnGameplayEffectDeactivate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CueOnTick()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (_cueDurationalSpecs != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var cue in _cueDurationalSpecs)
|
2024-10-18 17:48:59 +08:00
|
|
|
|
cue.OnTick(-1,-1,-1);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void TriggerOnExecute()
|
|
|
|
|
{
|
|
|
|
|
Owner.GameplayEffectContainer.RemoveGameplayEffectWithAnyTags(GameplayEffect.TagContainer
|
|
|
|
|
.RemoveGameplayEffectsWithTags);
|
|
|
|
|
Owner.ApplyModFromInstantGameplayEffect(this);
|
|
|
|
|
|
|
|
|
|
TriggerCueOnExecute();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void TriggerOnAdd()
|
|
|
|
|
{
|
|
|
|
|
TriggerCueOnAdd();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void TriggerOnRemove()
|
|
|
|
|
{
|
|
|
|
|
TryRemoveGrantedAbilities();
|
|
|
|
|
TriggerCueOnRemove();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void TriggerOnActivation()
|
|
|
|
|
{
|
|
|
|
|
Owner.GameplayTagAggregator.ApplyGameplayEffectDynamicTag(this);
|
|
|
|
|
Owner.GameplayEffectContainer.RemoveGameplayEffectWithAnyTags(GameplayEffect.TagContainer.RemoveGameplayEffectsWithTags);
|
|
|
|
|
|
|
|
|
|
TryActivateGrantedAbilities();
|
|
|
|
|
TriggerCueOnActivation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void TriggerOnDeactivation()
|
|
|
|
|
{
|
|
|
|
|
Owner.GameplayTagAggregator.RestoreGameplayEffectDynamicTags(this);
|
|
|
|
|
|
|
|
|
|
TryDeactivateGrantedAbilities();
|
|
|
|
|
TriggerCueOnDeactivation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void TriggerOnTick()
|
|
|
|
|
{
|
|
|
|
|
if (DurationPolicy is EffectsDurationPolicy.Duration or EffectsDurationPolicy.Infinite)
|
|
|
|
|
CueOnTick();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void TriggerOnImmunity()
|
|
|
|
|
{
|
|
|
|
|
OnImmunityBlock?.Invoke(Owner, this);
|
|
|
|
|
OnImmunityBlock = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RegisterOnImmunityBlock(Action<AbilitySystemComponent, GameplayEffectSpec> callback)
|
|
|
|
|
{
|
|
|
|
|
OnImmunityBlock += callback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void UnregisterOnImmunityBlock(Action<AbilitySystemComponent, GameplayEffectSpec> callback)
|
|
|
|
|
{
|
|
|
|
|
OnImmunityBlock -= callback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RemoveSelf()
|
|
|
|
|
{
|
|
|
|
|
Owner.GameplayEffectContainer.RemoveGameplayEffectSpec(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CaptureAttributesSnapshot()
|
|
|
|
|
{
|
|
|
|
|
switch (SnapshotPolicy)
|
|
|
|
|
{
|
|
|
|
|
case GameplayEffectSnapshotPolicy.Specified:
|
|
|
|
|
if (GameplayEffect.SpecifiedSnapshotConfigs != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var config in GameplayEffect.SpecifiedSnapshotConfigs)
|
|
|
|
|
{
|
|
|
|
|
switch (config.SnapshotTarget)
|
|
|
|
|
{
|
|
|
|
|
case GameplayEffectSpecifiedSnapshotConfig.ESnapshotTarget.Source:
|
|
|
|
|
{
|
2024-10-18 17:48:59 +08:00
|
|
|
|
SnapshotSourceAttributes ??= JexGasObjectPool.Instance.Fetch<Dictionary<string, float>>();
|
2024-10-18 03:16:09 +08:00
|
|
|
|
var attribute = Source.AttributeSetContainer.GetAttributeAttributeValue(config.AttributeSetName, config.AttributeShortName);
|
|
|
|
|
if (attribute != null)
|
|
|
|
|
{
|
|
|
|
|
SnapshotSourceAttributes[config.AttributeName] = attribute.Value.CurrentValue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError($"Snapshot Source Attribute \"{config.AttributeName}\" not found in AttributeSet \"{config.AttributeSetName}\"");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GameplayEffectSpecifiedSnapshotConfig.ESnapshotTarget.Target:
|
|
|
|
|
{
|
2024-10-18 17:48:59 +08:00
|
|
|
|
SnapshotTargetAttributes ??= JexGasObjectPool.Instance.Fetch<Dictionary<string, float>>();
|
2024-10-18 03:16:09 +08:00
|
|
|
|
var attribute = Owner.AttributeSetContainer.GetAttributeAttributeValue(config.AttributeSetName, config.AttributeShortName);
|
|
|
|
|
if (attribute != null)
|
|
|
|
|
{
|
|
|
|
|
SnapshotTargetAttributes[config.AttributeName] = attribute.Value.CurrentValue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError($"Snapshot Target Attribute {config.AttributeName} not found in AttributeSet {config.AttributeSetName}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case GameplayEffectSnapshotPolicy.AllOfSource:
|
|
|
|
|
SnapshotSourceAttributes = Source.DataSnapshot();
|
|
|
|
|
break;
|
|
|
|
|
case GameplayEffectSnapshotPolicy.AllOfTarget:
|
|
|
|
|
SnapshotTargetAttributes = Owner.DataSnapshot();
|
|
|
|
|
break;
|
|
|
|
|
case GameplayEffectSnapshotPolicy.AllOfBoth:
|
|
|
|
|
SnapshotSourceAttributes = Source.DataSnapshot();
|
|
|
|
|
SnapshotTargetAttributes = Source == Owner ? SnapshotSourceAttributes : Owner.DataSnapshot();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
Debug.LogError($"Unsupported SnapshotPolicy: {SnapshotPolicy}, GameplayEffect: {GameplayEffect.GameplayEffectName}");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RegisterValue(in GameplayTag tag, float value)
|
|
|
|
|
{
|
2024-10-18 17:48:59 +08:00
|
|
|
|
_valueMapWithTag ??= JexGasObjectPool.Instance.Fetch<Dictionary<GameplayTag, float>>();
|
2024-10-18 03:16:09 +08:00
|
|
|
|
_valueMapWithTag[tag] = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RegisterValue(string name, float value)
|
|
|
|
|
{
|
2024-10-18 17:48:59 +08:00
|
|
|
|
_valueMapWithName ??= JexGasObjectPool.Instance.Fetch<Dictionary<string, float>>();
|
2024-10-18 03:16:09 +08:00
|
|
|
|
_valueMapWithName[name] = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool UnregisterValue(in GameplayTag tag)
|
|
|
|
|
{
|
|
|
|
|
if (_valueMapWithTag == null) return false;
|
|
|
|
|
return _valueMapWithTag.Remove(tag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool UnregisterValue(string name)
|
|
|
|
|
{
|
|
|
|
|
if (_valueMapWithName == null) return false;
|
|
|
|
|
return _valueMapWithName.Remove(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public float? GetMapValue(in GameplayTag tag)
|
|
|
|
|
{
|
|
|
|
|
if (_valueMapWithTag == null) return null;
|
|
|
|
|
return _valueMapWithTag.TryGetValue(tag, out var value) ? value : (float?)null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public float? GetMapValue(string name)
|
|
|
|
|
{
|
|
|
|
|
if (_valueMapWithName == null) return null;
|
|
|
|
|
return _valueMapWithName.TryGetValue(name, out var value) ? value : (float?)null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void TryActivateGrantedAbilities()
|
|
|
|
|
{
|
|
|
|
|
if (GrantedAbilitiesSpecFromEffect == null) return;
|
|
|
|
|
foreach (GrantedAbilitySpecFromEffect grantedAbilitySpec in GrantedAbilitiesSpecFromEffect)
|
|
|
|
|
{
|
|
|
|
|
if (grantedAbilitySpec is { ActivationPolicy: GrantedAbilityActivationPolicy.SyncWithEffect })
|
|
|
|
|
{
|
|
|
|
|
Owner.TryActivateAbility(grantedAbilitySpec.AbilityName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void TryDeactivateGrantedAbilities()
|
|
|
|
|
{
|
|
|
|
|
if (GrantedAbilitiesSpecFromEffect == null) return;
|
|
|
|
|
foreach (GrantedAbilitySpecFromEffect grantedAbilitySpec in GrantedAbilitiesSpecFromEffect)
|
|
|
|
|
{
|
|
|
|
|
if (grantedAbilitySpec is { DeactivationPolicy: GrantedAbilityDeactivationPolicy.SyncWithEffect })
|
|
|
|
|
{
|
|
|
|
|
Owner.TryEndAbility(grantedAbilitySpec.AbilityName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void TryRemoveGrantedAbilities()
|
|
|
|
|
{
|
|
|
|
|
if (GrantedAbilitiesSpecFromEffect == null) return;
|
|
|
|
|
foreach (GrantedAbilitySpecFromEffect grantedAbilitySpec in GrantedAbilitiesSpecFromEffect)
|
|
|
|
|
{
|
|
|
|
|
if (grantedAbilitySpec is { RemovePolicy: GrantedAbilityRemovePolicy.SyncWithEffect })
|
|
|
|
|
{
|
|
|
|
|
Owner.TryCancelAbility(grantedAbilitySpec.AbilityName);
|
|
|
|
|
Owner.RemoveAbility(grantedAbilitySpec.AbilityName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ReleaseCueDurationalSpecs()
|
|
|
|
|
{
|
|
|
|
|
if (_cueDurationalSpecs != null)
|
|
|
|
|
{
|
|
|
|
|
_cueDurationalSpecs.Clear();
|
2024-10-18 17:48:59 +08:00
|
|
|
|
JexGasObjectPool.Instance.Recycle(_cueDurationalSpecs);
|
2024-10-18 03:16:09 +08:00
|
|
|
|
_cueDurationalSpecs = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region ABOUT STACKING
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Stack Count是否变化</returns>
|
|
|
|
|
public bool RefreshStack()
|
|
|
|
|
{
|
|
|
|
|
var oldStackCount = StackCount;
|
|
|
|
|
RefreshStack(StackCount + 1);
|
|
|
|
|
OnStackCountChange(oldStackCount, StackCount);
|
|
|
|
|
return oldStackCount != StackCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RefreshStack(int stackCount)
|
|
|
|
|
{
|
|
|
|
|
if (stackCount <= Stacking.limitCount)
|
|
|
|
|
{
|
|
|
|
|
// 更新栈数
|
|
|
|
|
StackCount = Mathf.Max(1, stackCount); // 最小层数为1
|
|
|
|
|
// 是否刷新Duration
|
|
|
|
|
if (Stacking.durationRefreshPolicy == DurationRefreshPolicy.RefreshOnSuccessfulApplication)
|
|
|
|
|
{
|
|
|
|
|
RefreshDuration();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 是否重置Period
|
|
|
|
|
if (Stacking.periodResetPolicy == PeriodResetPolicy.ResetOnSuccessfulApplication)
|
|
|
|
|
{
|
|
|
|
|
PeriodTicker.Value.ResetPeriod();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 溢出GE生效
|
|
|
|
|
foreach (var overflowEffect in Stacking.overflowEffects)
|
|
|
|
|
Owner.ApplyGameplayEffectToSelf(overflowEffect);
|
|
|
|
|
|
|
|
|
|
if (Stacking.durationRefreshPolicy == DurationRefreshPolicy.RefreshOnSuccessfulApplication)
|
|
|
|
|
{
|
|
|
|
|
if (Stacking.denyOverflowApplication)
|
|
|
|
|
{
|
|
|
|
|
//当DenyOverflowApplication为True是才有效,当Overflow时是否直接删除所有层数
|
|
|
|
|
if (Stacking.clearStackOnOverflow)
|
|
|
|
|
{
|
|
|
|
|
RemoveSelf();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RefreshDuration();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RefreshDuration()
|
|
|
|
|
{
|
|
|
|
|
ActivationTime = Time.time;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnStackCountChange(int oldStackCount, int newStackCount)
|
|
|
|
|
{
|
|
|
|
|
OnStackChanged?.Invoke(oldStackCount, newStackCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RegisterOnStackCountChanged(Action<int, int> callback)
|
|
|
|
|
{
|
|
|
|
|
OnStackChanged += callback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void UnregisterOnStackCountChanged(Action<int, int> callback)
|
|
|
|
|
{
|
|
|
|
|
OnStackChanged -= callback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|