JisolGame/JEX_GAS/Assets/GAS/Runtime/Effects/GameplayEffectStacking.cs
2024-10-18 03:16:09 +08:00

239 lines
9.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using GAS.General;
using Sirenix.OdinInspector;
using UnityEngine;
namespace GAS.Runtime
{
public enum StackingType
{
[LabelText("独立", SdfIconType.XCircleFill)]
None, //不会叠加如果多次释放则每个Effect相当于单个Effect
[LabelText("来源", SdfIconType.Magic)]
AggregateBySource, //目标(Target)上的每个源(Source)ASC都有一个单独的堆栈实例, 每个源(Source)可以应用堆栈中的X个GameplayEffect.
[LabelText("目标", SdfIconType.Person)]
AggregateByTarget //目标(Target)上只有一个堆栈实例而不管源(Source)如何, 每个源(Source)都可以在共享堆栈限制(Shared Stack Limit)内应用堆栈.
}
public enum DurationRefreshPolicy
{
[LabelText("NeverRefresh - 不刷新Effect的持续时间", SdfIconType.XCircleFill)]
NeverRefresh, //不刷新Effect的持续时间
[LabelText(
"RefreshOnSuccessfulApplication - 每次apply成功后刷新持续时间",
SdfIconType.HourglassTop)]
RefreshOnSuccessfulApplication //每次apply成功后刷新Effect的持续时间, denyOverflowApplication如果为True则多余的Apply不会刷新Duration
}
public enum PeriodResetPolicy
{
[LabelText("NeverReset - 不重置Effect的周期计时", SdfIconType.XCircleFill)]
NeverRefresh, //不重置Effect的周期计时
[LabelText("ResetOnSuccessfulApplication - 每次apply成功后重置Effect的周期计时", SdfIconType.HourglassTop)]
ResetOnSuccessfulApplication //每次apply成功后重置Effect的周期计时
}
public enum ExpirationPolicy
{
[LabelText("ClearEntireStack - 持续时间结束时, 清除所有层数", SdfIconType.TrashFill)]
ClearEntireStack, //持续时间结束时,清除所有层数
[LabelText("RemoveSingleStackAndRefreshDuration - 持续时间结束时减少一层然后重新经历一个Duration", SdfIconType.EraserFill)]
RemoveSingleStackAndRefreshDuration, //持续时间结束时减少一层然后重新经历一个Duration一直持续到层数减为0
[LabelText("RefreshDuration - 持续时间结束时,再次刷新Duration", SdfIconType.HourglassTop)]
RefreshDuration //持续时间结束时,再次刷新Duration这相当于无限Duration
//TODO :可以通过调用GameplayEffectsContainer的OnStackCountChange(GameplayEffect ActiveEffect, int OldStackCount, int NewStackCount)来处理层数,
//TODO :可以达到Duration结束时减少两层并刷新Duration这样复杂的效果。
}
// GE堆栈数据结构
public struct GameplayEffectStacking
{
public string stackingCodeName; // 实际允许不会使用而是使用stackingCodeName的hash值, 即stackingHashCode
public int stackingHashCode;
public StackingType stackingType;
public int limitCount;
public DurationRefreshPolicy durationRefreshPolicy;
public PeriodResetPolicy periodResetPolicy;
public ExpirationPolicy expirationPolicy;
// Overflow 溢出逻辑处理
public bool denyOverflowApplication; //对应于StackDurationRefreshPolicy如果为True则多余的Apply不会刷新Duration
public bool clearStackOnOverflow; //当DenyOverflowApplication为True是才有效当Overflow时是否直接删除所有层数
public GameplayEffect[] overflowEffects; // 超过StackLimitCount数量的Effect被Apply时将会调用该OverflowEffects
public void SetStackingCodeName(string stackingCodeName)
{
this.stackingCodeName = stackingCodeName;
this.stackingHashCode = stackingCodeName?.GetHashCode() ?? 0; // 兼容旧的SO数据
}
public void SetStackingHashCode(int stackingHashCode)
{
this.stackingHashCode = stackingHashCode;
}
public void SetStackingType(StackingType stackingType)
{
this.stackingType = stackingType;
}
public void SetLimitCount(int limitCount)
{
this.limitCount = limitCount;
}
public void SetDurationRefreshPolicy(DurationRefreshPolicy durationRefreshPolicy)
{
this.durationRefreshPolicy = durationRefreshPolicy;
}
public void SetPeriodResetPolicy(PeriodResetPolicy periodResetPolicy)
{
this.periodResetPolicy = periodResetPolicy;
}
public void SetExpirationPolicy(ExpirationPolicy expirationPolicy)
{
this.expirationPolicy = expirationPolicy;
}
public void SetOverflowEffects(GameplayEffect[] overflowEffects)
{
this.overflowEffects = overflowEffects;
}
public void SetOverflowEffects(GameplayEffectAsset[] overflowEffectAssets)
{
overflowEffects = new GameplayEffect[overflowEffectAssets.Length];
for (var i = 0; i < overflowEffectAssets.Length; ++i)
{
overflowEffects[i] = overflowEffectAssets[i].SharedInstance;
}
}
public void SetDenyOverflowApplication(bool denyOverflowApplication)
{
this.denyOverflowApplication = denyOverflowApplication;
}
public void SetClearStackOnOverflow(bool clearStackOnOverflow)
{
this.clearStackOnOverflow = clearStackOnOverflow;
}
public static GameplayEffectStacking None
{
get
{
var stack = new GameplayEffectStacking();
stack.SetStackingType(StackingType.None);
return stack;
}
}
}
[Serializable]
public sealed class GameplayEffectStackingConfig
{
private const int LABEL_WIDTH = 100;
[LabelWidth(LABEL_WIDTH)]
[VerticalGroup]
[LabelText(GASTextDefine.LABEL_GE_STACKING_TYPE)]
[EnumToggleButtons]
public StackingType stackingType;
[LabelWidth(LABEL_WIDTH)]
[VerticalGroup]
[HideIf("IsNoStacking")]
[LabelText(GASTextDefine.LABEL_GE_STACKING_CODENAME)]
[CustomContextMenu("清除","@stackingCodeName = \"\"")]
public string stackingCodeName;
[LabelWidth(LABEL_WIDTH)]
[VerticalGroup]
[LabelText(GASTextDefine.LABEL_GE_STACKING_COUNT)]
[HideIf("IsNoStacking")]
[CustomContextMenu("设为0","@limitCount = 0")]
[CustomContextMenu("设为1","@limitCount = 1")]
[CustomContextMenu("设为最大值","@limitCount = int.MaxValue")]
[MinValue(0),MaxValue(int.MaxValue)]
public int limitCount;
[LabelWidth(LABEL_WIDTH)]
[VerticalGroup]
[LabelText(GASTextDefine.LABEL_GE_STACKING_DURATION_REFRESH_POLICY)]
[HideIf("IsNoStacking")]
[InfoBox(GASTextDefine.LABEL_GE_STACKING_DENY_OVERFLOW_APPLICATION+"为True时多余的Apply不会刷新Duration", InfoMessageType.None,
VisibleIf =
"@durationRefreshPolicy == DurationRefreshPolicy.RefreshOnSuccessfulApplication && denyOverflowApplication")]
public DurationRefreshPolicy durationRefreshPolicy;
[LabelWidth(LABEL_WIDTH)]
[VerticalGroup]
[LabelText(GASTextDefine.LABEL_GE_STACKING_PERIOD_RESET_POLICY)]
[HideIf("IsNoStacking")]
public PeriodResetPolicy periodResetPolicy;
[LabelWidth(LABEL_WIDTH)]
[VerticalGroup]
[LabelText(GASTextDefine.LABEL_GE_STACKING_EXPIRATION_POLICY)]
[HideIf("IsNoStacking")]
public ExpirationPolicy expirationPolicy;
// Overflow 溢出逻辑处理
[LabelWidth(LABEL_WIDTH)]
[VerticalGroup]
[LabelText(GASTextDefine.LABEL_GE_STACKING_DENY_OVERFLOW_APPLICATION)]
[HideIf("@IsNoStacking() || IsNeverRefreshDuration()")]
public bool denyOverflowApplication;
[VerticalGroup]
[LabelWidth(LABEL_WIDTH)]
[LabelText(GASTextDefine.LABEL_GE_STACKING_CLEAR_STACK_ON_OVERFLOW)]
[ShowIf("IsDenyOverflowApplication")]
public bool clearStackOnOverflow;
[VerticalGroup]
[LabelWidth(LABEL_WIDTH)]
[LabelText(GASTextDefine.LABEL_GE_STACKING_CLEAR_OVERFLOW_EFFECTS)]
[HideIf("IsNoStacking")]
public GameplayEffectAsset[] overflowEffects;
/// <summary>
/// 转换为运行时数据
/// </summary>
/// <returns></returns>
public GameplayEffectStacking ToRuntimeData()
{
var stack = new GameplayEffectStacking();
stack.SetStackingCodeName(stackingCodeName);
stack.SetStackingType(stackingType);
stack.SetLimitCount(limitCount);
stack.SetDurationRefreshPolicy(durationRefreshPolicy);
stack.SetPeriodResetPolicy(periodResetPolicy);
stack.SetExpirationPolicy(expirationPolicy);
stack.SetOverflowEffects(overflowEffects);
stack.SetDenyOverflowApplication(denyOverflowApplication);
stack.SetClearStackOnOverflow(clearStackOnOverflow);
return stack;
}
#region UTIL FUNCTION FOR ODIN INSPECTOR
public bool IsNoStacking() => stackingType == StackingType.None;
public bool IsNeverRefreshDuration() =>
IsNoStacking() || durationRefreshPolicy == DurationRefreshPolicy.NeverRefresh;
public bool IsDenyOverflowApplication() => !IsNoStacking() && denyOverflowApplication;
#endregion
}
}