mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-27 10:46:17 +00:00
简单提交
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96394ec4a5d1af149b3ff68a9a0e6e2c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using GAS.General;
|
||||
using JNGame.Serialization;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public abstract class AbilityAsset : ScriptableObject, IAbilityAsset
|
||||
{
|
||||
protected const int WIDTH_LABEL = 70;
|
||||
|
||||
public abstract Type AbilityType();
|
||||
|
||||
public string Name => name;
|
||||
|
||||
[TitleGroup("Base")]
|
||||
[HorizontalGroup("Base/H1")]
|
||||
[TabGroup("Base/H1/V1", "Summary", SdfIconType.InfoSquareFill, TextColor = "#0BFFC5", Order = 1)]
|
||||
[HideLabel]
|
||||
[MultiLineProperty(10)]
|
||||
[FormerlySerializedAs("Description")]
|
||||
public string description;
|
||||
|
||||
[TabGroup("Base/H1/V2", "General", SdfIconType.AwardFill, TextColor = "#FF7F00", Order = 2)]
|
||||
[LabelText("所属能力", SdfIconType.FileCodeFill)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[ShowInInspector]
|
||||
[InfoBox("Ability Class is NULL!!! Please check.", InfoMessageType.Error, VisibleIf = "@AbilityType() == null")]
|
||||
[PropertyOrder(-1)]
|
||||
public string InstanceAbilityClassFullName => AbilityType()?.FullName;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[TabGroup("Base/H1/V2", "General")]
|
||||
[TabGroup("Base/H1/V2", "Detail", SdfIconType.TicketDetailedFill, TextColor = "#BC2FDE")]
|
||||
[LabelText("类型名称", SdfIconType.FileCodeFill)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[ShowInInspector]
|
||||
[PropertyOrder(-1)]
|
||||
public string TypeName => GetType().Name;
|
||||
|
||||
[TabGroup("Base/H1/V2", "Detail")]
|
||||
[LabelText("类型全名", SdfIconType.FileCodeFill)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[ShowInInspector]
|
||||
[PropertyOrder(-1)]
|
||||
public string TypeFullName => GetType().FullName;
|
||||
|
||||
[TabGroup("Base/H1/V2", "Detail")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false, ShowPaging = false)]
|
||||
[ShowInInspector]
|
||||
[LabelText("继承关系")]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[PropertyOrder(-1)]
|
||||
public string[] InheritanceChain => GetType().GetInheritanceChain().Reverse().ToArray();
|
||||
#endif
|
||||
|
||||
[TabGroup("Base/H1/V2", "General", SdfIconType.AwardFill)]
|
||||
[InfoBox(GASTextDefine.TIP_UNAME, InfoMessageType.None)]
|
||||
[LabelText("U-Name", SdfIconType.Fingerprint)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[InfoBox("无效的名字 - 不符合C#标识符命名规则", InfoMessageType.Error, "@GAS.General.Validation.Validations.IsValidVariableName($value) == false")]
|
||||
[FormerlySerializedAs("UniqueName")]
|
||||
public string uniqueName;
|
||||
|
||||
[TabGroup("Base/H1/V2", "General", SdfIconType.AwardFill)]
|
||||
[LabelText("技能id", SdfIconType.Fingerprint)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[FormerlySerializedAs("SkillId")]
|
||||
public int skillId;
|
||||
|
||||
[TabGroup("Base/H1/V2", "General")]
|
||||
[Title("消耗&冷却", bold: true)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[AssetSelector]
|
||||
[LabelText(SdfIconType.HeartHalf, Text = GASTextDefine.ABILITY_EFFECT_COST)]
|
||||
[FormerlySerializedAs("Cost")]
|
||||
public GameplayEffectAsset cost;
|
||||
|
||||
// [TabGroup("Base/H1/V2", "General")]
|
||||
// [LabelWidth(WIDTH_LABEL)]
|
||||
// [AssetSelector]
|
||||
// [LabelText(SdfIconType.StopwatchFill, Text = GASTextDefine.ABILITY_EFFECT_CD)]
|
||||
// public GameplayEffectAsset Cooldown;
|
||||
|
||||
[TabGroup("Base/H1/V2", "General")]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[LabelText(SdfIconType.ClockFill, Text = GASTextDefine.ABILITY_CD_TIME)]
|
||||
[Unit(Units.Millisecond)]
|
||||
[FormerlySerializedAs("CooldownTime")]
|
||||
public int cooldownTime;
|
||||
|
||||
// Tags
|
||||
[TabGroup("Base/H1/V3", "Tags", SdfIconType.TagsFill, TextColor = "#45B1FF", Order = 3)]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[Tooltip("描述性质的标签,用来描述Ability的特性表现,比如伤害、治疗、控制等。")]
|
||||
[FormerlySerializedAs("AssetTags")]
|
||||
public GameplayTag[] assetTags;
|
||||
|
||||
[TabGroup("Base/H1/V3", "Tags")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[LabelText("CancelAbility With Tags ")]
|
||||
[Space]
|
||||
[Tooltip("Ability激活时,Ability持有者当前持有的所有Ability中,拥有【任意】这些标签的Ability会被取消。")]
|
||||
[FormerlySerializedAs("CancelAbilityTags")]
|
||||
public GameplayTag[] cancelAbilityTags;
|
||||
|
||||
[TabGroup("Base/H1/V3", "Tags")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[LabelText("BlockAbility With Tags ")]
|
||||
[Space]
|
||||
[Tooltip("Ability激活时,Ability持有者当前持有的所有Ability中,拥有【任意】这些标签的Ability会被阻塞激活。")]
|
||||
[FormerlySerializedAs("BlockAbilityTags")]
|
||||
public GameplayTag[] blockAbilityTags;
|
||||
|
||||
[TabGroup("Base/H1/V3", "Tags")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[Space]
|
||||
[Tooltip("Ability激活时,持有者会获得这些标签,Ability被失活时,这些标签也会被移除。")]
|
||||
[FormerlySerializedAs("ActivationOwnedTags")]
|
||||
public GameplayTag[] activationOwnedTags;
|
||||
|
||||
[TabGroup("Base/H1/V3", "Tags")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[Space]
|
||||
[Tooltip("Ability只有在其拥有者拥有【所有】这些标签时才可激活。")]
|
||||
[FormerlySerializedAs("ActivationRequiredTags")]
|
||||
public GameplayTag[] activationRequiredTags;
|
||||
|
||||
[TabGroup("Base/H1/V3", "Tags")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[Space]
|
||||
[Tooltip("Ability在其拥有者拥有【任意】这些标签时不能被激活。")]
|
||||
[FormerlySerializedAs("ActivationBlockedTags")]
|
||||
public GameplayTag[] activationBlockedTags;
|
||||
|
||||
public string UniqueName => uniqueName;
|
||||
|
||||
public int SkillId => skillId;
|
||||
|
||||
public IGameplayEffectData Cost => cost;
|
||||
|
||||
public int CooldownTime => cooldownTime;
|
||||
|
||||
public GameplayTag[] AssetTags => assetTags;
|
||||
|
||||
public GameplayTag[] CancelAbilityTags => cancelAbilityTags;
|
||||
|
||||
public GameplayTag[] BlockAbilityTags => blockAbilityTags;
|
||||
|
||||
public GameplayTag[] ActivationOwnedTags => activationOwnedTags;
|
||||
|
||||
public GameplayTag[] ActivationRequiredTags => activationRequiredTags;
|
||||
|
||||
public GameplayTag[] ActivationBlockedTags => activationBlockedTags;
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 544108d1f0e34b7fb2a77be04ed89be6
|
||||
timeCreated: 1703762750
|
@@ -0,0 +1,88 @@
|
||||
|
||||
using System.Linq;
|
||||
using GAS.General;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using Sirenix.Utilities.Editor;
|
||||
#endif
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[CreateAssetMenu(fileName = "AbilitySystemComponentPreset", menuName = "GAS/AbilitySystemComponentPreset")]
|
||||
public sealed class AbilitySystemComponentPreset : ScriptableObject
|
||||
{
|
||||
private const int WIDTH_LABEL = 70;
|
||||
private const string ERROR_ABILITY = "Ability can't be NONE!!";
|
||||
|
||||
[TitleGroup("Base")]
|
||||
[HorizontalGroup("Base/H1", Width = 1 / 3f)]
|
||||
[TabGroup("Base/H1/V1", "Summary", SdfIconType.InfoSquareFill, TextColor = "#0BFFC5", Order = 1)]
|
||||
[HideLabel]
|
||||
[MultiLineProperty(10)]
|
||||
[FormerlySerializedAs("Description")]
|
||||
public string description;
|
||||
|
||||
|
||||
[TabGroup("Base/H1/V2", "Attribute Sets", SdfIconType.PersonLinesFill, TextColor = "#FF7F00", Order = 2)]
|
||||
[LabelText(GASTextDefine.ASC_AttributeSet)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false, OnTitleBarGUI = "DrawAttributeSetsButtons")]
|
||||
[ValueDropdown("@ValueDropdownHelper.AttributeSetChoices", IsUniqueList = true)]
|
||||
[FormerlySerializedAs("AttributeSets")]
|
||||
public string[] attributeSets;
|
||||
|
||||
private void DrawAttributeSetsButtons()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (SirenixEditorGUI.ToolbarButton(SdfIconType.SortAlphaDown))
|
||||
{
|
||||
attributeSets = attributeSets.OrderBy(x => x).ToArray();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
[TabGroup("Base/H1/V3", "Tags", SdfIconType.TagsFill, TextColor = "#45B1FF", Order = 3)]
|
||||
[LabelText(GASTextDefine.ASC_BASE_TAG)]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false, OnTitleBarGUI = "DrawBaseTagsButtons")]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[FormerlySerializedAs("BaseTags")]
|
||||
public GameplayTag[] baseTags;
|
||||
|
||||
private void DrawBaseTagsButtons()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (SirenixEditorGUI.ToolbarButton(SdfIconType.SortAlphaDown))
|
||||
{
|
||||
baseTags = baseTags.OrderBy(x => x.Name).ToArray();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
[HorizontalGroup("Base/H2")]
|
||||
[TabGroup("Base/H2/V1", "Abilities", SdfIconType.YinYang, TextColor = "#D6626E", Order = 1)]
|
||||
[LabelText(GASTextDefine.ASC_BASE_ABILITY)]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false, OnTitleBarGUI = "DrawBaseAbilitiesButtons")]
|
||||
[AssetSelector]
|
||||
[InfoBox(ERROR_ABILITY, InfoMessageType.Error, VisibleIf = "@IsAbilityNone()")]
|
||||
[FormerlySerializedAs("BaseAbilities")]
|
||||
public AbilityAsset[] baseAbilities;
|
||||
|
||||
private void DrawBaseAbilitiesButtons()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (SirenixEditorGUI.ToolbarButton(SdfIconType.SortAlphaDown))
|
||||
{
|
||||
baseAbilities = baseAbilities.OrderBy(x => x.name).ToArray();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsAbilityNone()
|
||||
{
|
||||
return baseAbilities != null && baseAbilities.Any(ability => ability == null);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85dd2a6201f04545b5a8b020edcb2690
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c81dce2ab8504416b1d9b64d46767fd2
|
||||
timeCreated: 1701938889
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35878043833f4ae3bb6976f748a85a8b
|
||||
timeCreated: 1705029950
|
@@ -0,0 +1,93 @@
|
||||
using System.Linq;
|
||||
using GAS.General;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
public enum EnumCueFlag
|
||||
{
|
||||
INSTANT = 0, // 瞬时Cue,自动管理Cue的生命周期,结束自动回收
|
||||
DURATIONAL = 1, // 持续Cue,外部手动管理Cue的生命周期
|
||||
}
|
||||
|
||||
public abstract class GameplayCue : ScriptableObject
|
||||
{
|
||||
protected const int WIDTH_LABEL = 70;
|
||||
|
||||
[TitleGroup("Base")]
|
||||
[HorizontalGroup("Base/H1")]
|
||||
[TabGroup("Base/H1/V1", "Summary", SdfIconType.InfoSquareFill, TextColor = "#0BFFC5", Order = 1)]
|
||||
[HideLabel]
|
||||
[MultiLineProperty(10)]
|
||||
[FormerlySerializedAs("Description")]
|
||||
public string description;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[TabGroup("Base/H1/V2", "General", SdfIconType.AwardFill, TextColor = "#FF7F00", Order = 2)]
|
||||
[TabGroup("Base/H1/V2", "Detail", SdfIconType.TicketDetailedFill, TextColor = "#BC2FDE")]
|
||||
[LabelText("类型名称", SdfIconType.FileCodeFill)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[ShowInInspector]
|
||||
[PropertyOrder(-1)]
|
||||
public string TypeName => GetType().Name;
|
||||
|
||||
[TabGroup("Base/H1/V2", "Detail")]
|
||||
[LabelText("类型全名", SdfIconType.FileCodeFill)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[ShowInInspector]
|
||||
[PropertyOrder(-1)]
|
||||
public string TypeFullName => GetType().FullName;
|
||||
|
||||
[TabGroup("Base/H1/V2", "Detail")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false, ShowPaging = false)]
|
||||
[ShowInInspector]
|
||||
[LabelText("继承关系")]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[PropertyOrder(-1)]
|
||||
public string[] InheritanceChain => GetType().GetInheritanceChain().Reverse().ToArray();
|
||||
#endif
|
||||
// Tags
|
||||
[TabGroup("Base/H1/V3", "Tags", SdfIconType.TagsFill, TextColor = "#45B1FF", Order = 3)]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[LabelText("RequiredTags - 持有所有标签才可触发")]
|
||||
[FormerlySerializedAs("RequiredTags")]
|
||||
public GameplayTag[] requiredTags;
|
||||
|
||||
[TabGroup("Base/H1/V3", "Tags")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[LabelText("ImmunityTags - 持有任意标签不可触发")]
|
||||
[FormerlySerializedAs("ImmunityTags")]
|
||||
public GameplayTag[] immunityTags;
|
||||
|
||||
|
||||
public string Name => throw new System.NotImplementedException();
|
||||
|
||||
public GameplayTag[] RequiredTags => requiredTags;
|
||||
public GameplayTag[] ImmunityTags => immunityTags;
|
||||
public abstract string VfxName { get; }
|
||||
public abstract EnumCueFlag Flag { get; }
|
||||
|
||||
public virtual bool Triggerable(AbilitySystemComponent owner)
|
||||
{
|
||||
if (owner == null) return false;
|
||||
// 持有【所有】RequiredTags才可触发
|
||||
if (!owner.HasAllTags(new GameplayTagSet(requiredTags)))
|
||||
return false;
|
||||
|
||||
// 持有【任意】ImmunityTags不可触发
|
||||
if (owner.HasAnyTags(new GameplayTagSet(immunityTags)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class GameplayCue<T> : GameplayCue where T : GameplayCueSpec
|
||||
{
|
||||
protected abstract T CreateSpec(GameplayCueParameters parameters);
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24a60d4a49b842c28e848c52adb587e4
|
||||
timeCreated: 1702536571
|
@@ -0,0 +1,63 @@
|
||||
using JNGame.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
public abstract class GameplayCueDurational : GameplayCue<GameplayCueDurationalSpec>
|
||||
{
|
||||
public string txName;
|
||||
|
||||
public override string VfxName => txName;
|
||||
public override EnumCueFlag Flag => EnumCueFlag.DURATIONAL;
|
||||
|
||||
public GameplayCueDurationalSpec ApplyFrom(GameplayEffectSpec gameplayEffectSpec)
|
||||
{
|
||||
if (!Triggerable(gameplayEffectSpec.Owner)) { return null; }
|
||||
var durationalCue = CreateSpec(new GameplayCueParameters
|
||||
{
|
||||
sourceGameplayEffectSpec = gameplayEffectSpec
|
||||
});
|
||||
return durationalCue;
|
||||
}
|
||||
|
||||
public GameplayCueDurationalSpec ApplyFrom(AbilitySpec abilitySpec, params object[] customArguments)
|
||||
{
|
||||
if (!Triggerable(abilitySpec.Owner)) { return null; }
|
||||
var durationalCue = CreateSpec(new GameplayCueParameters
|
||||
{
|
||||
sourceAbilitySpec = abilitySpec,
|
||||
customArguments = customArguments
|
||||
});
|
||||
return durationalCue;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public virtual void OnEditorPreview(UnityEngine.GameObject previewObject, int frameIndex, int startFrame, int endFrame)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public abstract class GameplayCueDurationalSpec : GameplayCueSpec
|
||||
{
|
||||
protected GameplayCueDurationalSpec(GameplayCueDurational cue, GameplayCueParameters parameters) :
|
||||
base(cue, parameters)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract void OnAdd(int frame,int startFrame,int endFrame);
|
||||
public abstract void OnRemove(int frame,int startFrame,int endFrame);
|
||||
public abstract void OnGameplayEffectActivate();
|
||||
public abstract void OnGameplayEffectDeactivate();
|
||||
public abstract void OnTick(int frame,int startFrame,int endFrame);
|
||||
}
|
||||
|
||||
public abstract class GameplayCueDurationalSpec<T> : GameplayCueDurationalSpec where T : GameplayCueDurational
|
||||
{
|
||||
public readonly T cue;
|
||||
|
||||
protected GameplayCueDurationalSpec(T cue, GameplayCueParameters parameters) : base(cue, parameters)
|
||||
{
|
||||
this.cue = cue;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cfc27df4bdc54282b3e7540eef7f4679
|
||||
timeCreated: 1705027856
|
@@ -0,0 +1,58 @@
|
||||
using JNGame.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
public abstract class GameplayCueInstant : GameplayCue<GameplayCueInstantSpec>
|
||||
{
|
||||
public string txName;
|
||||
|
||||
public override string VfxName => txName;
|
||||
public override EnumCueFlag Flag => EnumCueFlag.INSTANT;
|
||||
|
||||
public virtual void ApplyFrom(GameplayEffectSpec gameplayEffectSpec)
|
||||
{
|
||||
if (Triggerable(gameplayEffectSpec.Owner))
|
||||
{
|
||||
var instantCue = CreateSpec(new GameplayCueParameters
|
||||
{ sourceGameplayEffectSpec = gameplayEffectSpec });
|
||||
instantCue?.Trigger();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ApplyFrom(AbilitySpec abilitySpec, params object[] customArguments)
|
||||
{
|
||||
if (Triggerable(abilitySpec.Owner))
|
||||
{
|
||||
var instantCue = CreateSpec(new GameplayCueParameters
|
||||
{ sourceAbilitySpec = abilitySpec, customArguments = customArguments });
|
||||
instantCue?.Trigger();
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public virtual void OnEditorPreview(UnityEngine.GameObject previewObject, int frame, int startFrame)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public abstract class GameplayCueInstantSpec : GameplayCueSpec
|
||||
{
|
||||
public GameplayCueInstantSpec(GameplayCueInstant cue, GameplayCueParameters parameters) : base(cue,
|
||||
parameters)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract void Trigger();
|
||||
}
|
||||
|
||||
public abstract class GameplayCueInstantSpec<T>:GameplayCueInstantSpec where T:GameplayCueInstant
|
||||
{
|
||||
public readonly T cue;
|
||||
|
||||
public GameplayCueInstantSpec(T cue, GameplayCueParameters parameters) : base(cue, parameters)
|
||||
{
|
||||
this.cue = cue;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2483d9a3b6064679b6ec7cf5fc2831b6
|
||||
timeCreated: 1705027797
|
@@ -0,0 +1,15 @@
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
public struct GameplayCueParameters
|
||||
{
|
||||
public GameplayEffectSpec sourceGameplayEffectSpec;
|
||||
|
||||
public AbilitySpec sourceAbilitySpec;
|
||||
|
||||
public object[] customArguments;
|
||||
// AggregatedSourceTags
|
||||
// AggregatedTargetTags
|
||||
// EffectContext
|
||||
// Magnitude
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71478534541e4560a993cd0ead34edc3
|
||||
timeCreated: 1705915979
|
@@ -0,0 +1,29 @@
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
public abstract class GameplayCueSpec
|
||||
{
|
||||
protected readonly GameplayCue _cue;
|
||||
protected readonly GameplayCueParameters _parameters;
|
||||
public AbilitySystemComponent Owner { get; protected set; }
|
||||
|
||||
public virtual bool Triggerable()
|
||||
{
|
||||
return _cue.Triggerable(Owner);
|
||||
}
|
||||
|
||||
public GameplayCueSpec(GameplayCue cue, GameplayCueParameters cueParameters)
|
||||
{
|
||||
_cue = cue;
|
||||
_parameters = cueParameters;
|
||||
if (_parameters.sourceGameplayEffectSpec != null)
|
||||
{
|
||||
Owner = _parameters.sourceGameplayEffectSpec.Owner;
|
||||
}
|
||||
else if (_parameters.sourceAbilitySpec != null)
|
||||
{
|
||||
Owner = _parameters.sourceAbilitySpec.Owner;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2c7719fe70c46e98344f1d9d8ebb9e6
|
||||
timeCreated: 1705042515
|
@@ -0,0 +1,104 @@
|
||||
// using GAS.General;
|
||||
// using Sirenix.OdinInspector;
|
||||
// using UnityEngine;
|
||||
//
|
||||
// namespace GAS.Runtime
|
||||
// {
|
||||
// public class CueAnimation : GameplayCueDurational
|
||||
// {
|
||||
// [BoxGroup]
|
||||
// [InfoBox(GASTextDefine.CUE_ANIMATION_PATH_TIP)]
|
||||
// [LabelText(GASTextDefine.CUE_ANIMATION_PATH)]
|
||||
// [SerializeField]
|
||||
// private string _animatorRelativePath;
|
||||
//
|
||||
// [BoxGroup]
|
||||
// [InfoBox(GASTextDefine.CUE_ANIMATION_INCLUDE_CHILDREN_ANIMATOR_TIP)]
|
||||
// [SerializeField]
|
||||
// private bool _includeChildrenAnimator;
|
||||
//
|
||||
// [BoxGroup]
|
||||
// [LabelText(GASTextDefine.CUE_ANIMATION_STATE)]
|
||||
// [SerializeField]
|
||||
// private string _stateName;
|
||||
//
|
||||
// public string AnimatorRelativePath => _animatorRelativePath;
|
||||
// public bool IncludeChildrenAnimator => _includeChildrenAnimator;
|
||||
// public string StateName => _stateName;
|
||||
//
|
||||
//
|
||||
// public override GameplayCueDurationalSpec CreateSpec(GameplayCueParameters parameters)
|
||||
// {
|
||||
// return new CueAnimationSpec(this, parameters);
|
||||
// }
|
||||
//
|
||||
// #if UNITY_EDITOR
|
||||
// public override void OnEditorPreview(GameObject previewObject, int frame, int startFrame, int endFrame)
|
||||
// {
|
||||
// if (startFrame <= frame && frame <= endFrame)
|
||||
// {
|
||||
// var transform = previewObject.transform.Find(AnimatorRelativePath);
|
||||
// var animator = IncludeChildrenAnimator ? transform.GetComponentInChildren<Animator>() : transform.GetComponent<Animator>();
|
||||
// if (animator != null)
|
||||
// {
|
||||
// var stateMap = animator.GetAllAnimationState();
|
||||
// if (stateMap.TryGetValue(StateName, out var clip))
|
||||
// {
|
||||
// float clipFrameCount = (int)(clip.frameRate * clip.length);
|
||||
// if (frame <= clipFrameCount + startFrame)
|
||||
// {
|
||||
// var progress = (frame - startFrame) / clipFrameCount;
|
||||
// if (progress > 1 && clip.isLooping) progress -= (int)progress;
|
||||
// clip.SampleAnimation(animator.gameObject, progress * clip.length);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Debug.LogError($"Animator is null. Please check the cue asset: {name}, AnimatorRelativePath: {AnimatorRelativePath}, IncludeChildrenAnimator: {IncludeChildrenAnimator}");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
// }
|
||||
//
|
||||
// public class CueAnimationSpec : GameplayCueDurationalSpec<CueAnimation>
|
||||
// {
|
||||
// private readonly Animator _animator;
|
||||
//
|
||||
// public CueAnimationSpec(CueAnimation cue, GameplayCueParameters parameters) : base(cue,
|
||||
// parameters)
|
||||
// {
|
||||
// var transform = Owner.transform.Find(cue.AnimatorRelativePath);
|
||||
// _animator = cue.IncludeChildrenAnimator ? transform.GetComponentInChildren<Animator>() : transform.GetComponent<Animator>();
|
||||
// if (_animator == null)
|
||||
// {
|
||||
// Debug.LogError($"Animator is null. Please check the cue asset: {cue.name}, AnimatorRelativePath: {cue.AnimatorRelativePath}, IncludeChildrenAnimator: {cue.IncludeChildrenAnimator}");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public override void OnAdd()
|
||||
// {
|
||||
// if (_animator != null)
|
||||
// {
|
||||
// _animator.Play(cue.StateName);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public override void OnRemove()
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// public override void OnGameplayEffectActivate()
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// public override void OnGameplayEffectDeactivate()
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// public override void OnTick()
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
// }
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b9fc094e7fa46ac85ce5efa6359b74f
|
||||
timeCreated: 1711451948
|
@@ -0,0 +1,103 @@
|
||||
// using GAS.General;
|
||||
// using Sirenix.OdinInspector;
|
||||
// using UnityEngine;
|
||||
//
|
||||
// namespace GAS.Runtime
|
||||
// {
|
||||
// [CreateAssetMenu(fileName = "CuePlayAnimation", menuName = "GAS/Cue/CuePlayAnimation")]
|
||||
// public class CueAnimationOneShot : GameplayCueInstant
|
||||
// {
|
||||
// [BoxGroup]
|
||||
// [InfoBox(GASTextDefine.CUE_ANIMATION_PATH_TIP)]
|
||||
// [LabelText(GASTextDefine.CUE_ANIMATION_PATH)]
|
||||
// [SerializeField]
|
||||
// private string _animatorRelativePath;
|
||||
//
|
||||
// [BoxGroup]
|
||||
// [InfoBox(GASTextDefine.CUE_ANIMATION_INCLUDE_CHILDREN_ANIMATOR_TIP)]
|
||||
// [SerializeField]
|
||||
// private bool _includeChildrenAnimator;
|
||||
//
|
||||
// [BoxGroup]
|
||||
// [LabelText(GASTextDefine.CUE_ANIMATION_STATE)]
|
||||
// [SerializeField]
|
||||
// private string _stateName;
|
||||
//
|
||||
// public string AnimatorRelativePath => _animatorRelativePath;
|
||||
// public bool IncludeChildrenAnimator => _includeChildrenAnimator;
|
||||
// public string StateName => _stateName;
|
||||
//
|
||||
//
|
||||
// public override GameplayCueInstantSpec CreateSpec(GameplayCueParameters parameters)
|
||||
// {
|
||||
// return new CueAnimationOneShotSpec(this, parameters);
|
||||
// }
|
||||
//
|
||||
// #if UNITY_EDITOR
|
||||
// public override void OnEditorPreview(GameObject previewObject, int frame, int startFrame)
|
||||
// {
|
||||
// if (startFrame <= frame)
|
||||
// {
|
||||
// var transform = previewObject.transform.Find(AnimatorRelativePath);
|
||||
// Animator animator = null;
|
||||
// if (transform != null)
|
||||
// {
|
||||
// animator = IncludeChildrenAnimator
|
||||
// ? transform.GetComponentInChildren<Animator>()
|
||||
// : transform.GetComponent<Animator>();
|
||||
// }
|
||||
//
|
||||
// if (animator == null)
|
||||
// {
|
||||
// Debug.LogError(
|
||||
// $"Animator is null. Please check the cue asset: {name}, AnimatorRelativePath: {AnimatorRelativePath}, IncludeChildrenAnimator: {IncludeChildrenAnimator}");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// var stateMap = animator.GetAllAnimationState();
|
||||
// if (stateMap.TryGetValue(StateName, out var clip))
|
||||
// {
|
||||
// float clipFrameCount = (int)(clip.frameRate * clip.length);
|
||||
// if (frame <= clipFrameCount + startFrame)
|
||||
// {
|
||||
// var progress = (frame - startFrame) / clipFrameCount;
|
||||
// if (progress > 1 && clip.isLooping) progress -= (int)progress;
|
||||
// clip.SampleAnimation(animator.gameObject, progress * clip.length);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
// }
|
||||
//
|
||||
// public class CueAnimationOneShotSpec : GameplayCueInstantSpec<CueAnimationOneShot>
|
||||
// {
|
||||
// private readonly Animator _animator;
|
||||
//
|
||||
// public CueAnimationOneShotSpec(CueAnimationOneShot cue, GameplayCueParameters parameters)
|
||||
// : base(cue, parameters)
|
||||
// {
|
||||
// var transform = Owner.transform.Find(cue.AnimatorRelativePath);
|
||||
// if (transform != null)
|
||||
// {
|
||||
// _animator = cue.IncludeChildrenAnimator
|
||||
// ? transform.GetComponentInChildren<Animator>()
|
||||
// : transform.GetComponent<Animator>();
|
||||
// }
|
||||
//
|
||||
// if (_animator == null)
|
||||
// {
|
||||
// Debug.LogError(
|
||||
// $"Animator is null. Please check the cue asset: {cue.name}, AnimatorRelativePath: {cue.AnimatorRelativePath}, IncludeChildrenAnimator: {cue.IncludeChildrenAnimator}");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public override void Trigger()
|
||||
// {
|
||||
// if (_animator != null)
|
||||
// {
|
||||
// _animator.Play(cue.StateName);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0831f70ea054910b7c7a907e5121590
|
||||
timeCreated: 1703670598
|
@@ -0,0 +1,78 @@
|
||||
// using System;
|
||||
// using GAS.General;
|
||||
// using Sirenix.OdinInspector;
|
||||
// using UnityEngine;
|
||||
// using Object = UnityEngine.Object;
|
||||
//
|
||||
// namespace GAS.Runtime
|
||||
// {
|
||||
// public class CuePlaySound : GameplayCueDurational
|
||||
// {
|
||||
// [BoxGroup]
|
||||
// [LabelText(GASTextDefine.CUE_SOUND_EFFECT)]
|
||||
// public AudioClip soundEffect;
|
||||
//
|
||||
// [BoxGroup]
|
||||
// [LabelText(GASTextDefine.CUE_ATTACH_TO_OWNER)]
|
||||
// public bool isAttachToOwner = true;
|
||||
//
|
||||
// public override GameplayCueDurationalSpec CreateSpec(GameplayCueParameters parameters)
|
||||
// {
|
||||
// return new CuePlaySoundSpec(this, parameters);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class CuePlaySoundSpec : GameplayCueDurationalSpec<CuePlaySound>
|
||||
// {
|
||||
// private AudioSource _audioSource;
|
||||
//
|
||||
// public CuePlaySoundSpec(CuePlaySound cue, GameplayCueParameters parameters) : base(cue,
|
||||
// parameters)
|
||||
// {
|
||||
// if (cue.isAttachToOwner)
|
||||
// {
|
||||
// _audioSource = Owner.gameObject.GetComponent<AudioSource>();
|
||||
// if (_audioSource == null)
|
||||
// {
|
||||
// _audioSource = Owner.gameObject.AddComponent<AudioSource>();
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// var soundRoot = new GameObject("SoundRoot");
|
||||
// soundRoot.transform.position = Owner.transform.position;
|
||||
// _audioSource = soundRoot.AddComponent<AudioSource>();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public override void OnAdd()
|
||||
// {
|
||||
// _audioSource.clip = cue.soundEffect;
|
||||
// _audioSource.Play();
|
||||
// }
|
||||
//
|
||||
// public override void OnRemove()
|
||||
// {
|
||||
// if (!cue.isAttachToOwner)
|
||||
// {
|
||||
// Object.Destroy(_audioSource.gameObject);
|
||||
// }else
|
||||
// {
|
||||
// _audioSource.Stop();
|
||||
// _audioSource.clip = null;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public override void OnGameplayEffectActivate()
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// public override void OnGameplayEffectDeactivate()
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// public override void OnTick()
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
// }
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c3aca85c2044621903d913d5bd792b1
|
||||
timeCreated: 1703670793
|
@@ -0,0 +1,146 @@
|
||||
// using GAS.General;
|
||||
// using Sirenix.OdinInspector;
|
||||
// using UnityEngine;
|
||||
|
||||
// namespace GAS.Runtime
|
||||
// {
|
||||
// public class CueVFX : GameplayCueDurational
|
||||
// {
|
||||
// [BoxGroup]
|
||||
// [LabelText(GASTextDefine.CUE_VFX_PREFAB)]
|
||||
// public GameObject VfxPrefab;
|
||||
|
||||
// [BoxGroup]
|
||||
// [LabelText(GASTextDefine.CUE_ATTACH_TO_OWNER)]
|
||||
// public bool IsAttachToTarget = true;
|
||||
|
||||
// [BoxGroup]
|
||||
// [LabelText(GASTextDefine.CUE_VFX_OFFSET)]
|
||||
// public Vector3 Offset;
|
||||
|
||||
// [BoxGroup]
|
||||
// [LabelText(GASTextDefine.CUE_VFX_ROTATION)]
|
||||
// public Vector3 Rotation;
|
||||
|
||||
// [BoxGroup]
|
||||
// [LabelText(GASTextDefine.CUE_VFX_SCALE)]
|
||||
// public Vector3 Scale = Vector3.one;
|
||||
|
||||
// [BoxGroup]
|
||||
// [LabelText(GASTextDefine.CUE_VFX_ACTIVE_WHEN_ADDED)]
|
||||
// public bool ActiveWhenAdded = false;
|
||||
|
||||
// public override GameplayCueDurationalSpec CreateSpec(GameplayCueParameters parameters)
|
||||
// {
|
||||
// return new CueVFXSpec(this, parameters);
|
||||
// }
|
||||
|
||||
// #if UNITY_EDITOR
|
||||
// private GameObject _effectPreviewInstance;
|
||||
// public override void OnEditorPreview(GameObject preview, int frameIndex, int startFrame, int endFrame)
|
||||
// {
|
||||
// if (VfxPrefab == null) return;
|
||||
// if (frameIndex >= startFrame && frameIndex <= endFrame)
|
||||
// {
|
||||
// if (_effectPreviewInstance != null && _effectPreviewInstance.name != VfxPrefab.name)
|
||||
// {
|
||||
// DestroyImmediate(_effectPreviewInstance);
|
||||
// _effectPreviewInstance = null;
|
||||
// }
|
||||
|
||||
// if (_effectPreviewInstance == null)
|
||||
// {
|
||||
// _effectPreviewInstance = Instantiate(VfxPrefab, preview.transform);
|
||||
// _effectPreviewInstance.name = VfxPrefab.name;
|
||||
// _effectPreviewInstance.transform.localPosition = Offset;
|
||||
// _effectPreviewInstance.transform.localEulerAngles = Rotation;
|
||||
// _effectPreviewInstance.transform.localScale = Scale;
|
||||
// }
|
||||
|
||||
// // 模拟例子的播放
|
||||
// var particleSystems = _effectPreviewInstance.GetComponentsInChildren<ParticleSystem>();
|
||||
// foreach (var ps in particleSystems)
|
||||
// {
|
||||
// var t = (frameIndex - startFrame) / GASTimer.FrameRate;
|
||||
// ps.Simulate(t);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (_effectPreviewInstance != null)
|
||||
// {
|
||||
// DestroyImmediate(_effectPreviewInstance);
|
||||
// _effectPreviewInstance = null;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
// }
|
||||
|
||||
// public class CueVFXSpec : GameplayCueDurationalSpec<CueVFX>
|
||||
// {
|
||||
// private GameObject _vfxInstance;
|
||||
|
||||
// public CueVFXSpec(CueVFX cue, GameplayCueParameters parameters) : base(cue,
|
||||
// parameters)
|
||||
// {
|
||||
// }
|
||||
|
||||
// public override void OnAdd()
|
||||
// {
|
||||
// if (cue.VfxPrefab != null)
|
||||
// {
|
||||
// _vfxInstance = cue.IsAttachToTarget
|
||||
// ? Object.Instantiate(cue.VfxPrefab, Owner.transform)
|
||||
// : Object.Instantiate(cue.VfxPrefab, Owner.transform.position, Quaternion.identity);
|
||||
|
||||
// _vfxInstance.transform.localPosition = cue.Offset;
|
||||
// _vfxInstance.transform.localEulerAngles = cue.Rotation;
|
||||
// _vfxInstance.transform.localScale = cue.Scale;
|
||||
// _vfxInstance.SetActive(cue.ActiveWhenAdded);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// #if UNITY_EDITOR
|
||||
// Debug.LogError("VFX prefab is null!");
|
||||
// #endif
|
||||
// }
|
||||
// }
|
||||
|
||||
// public override void OnRemove()
|
||||
// {
|
||||
// if (_vfxInstance != null)
|
||||
// {
|
||||
// Object.Destroy(_vfxInstance);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public override void OnGameplayEffectActivate()
|
||||
// {
|
||||
// if (_vfxInstance != null)
|
||||
// {
|
||||
// _vfxInstance.SetActive(true);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public override void OnGameplayEffectDeactivate()
|
||||
// {
|
||||
// if (_vfxInstance != null)
|
||||
// {
|
||||
// _vfxInstance.SetActive(false);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public override void OnTick()
|
||||
// {
|
||||
// }
|
||||
|
||||
// public void SetVisible(bool visible)
|
||||
// {
|
||||
// if (_vfxInstance != null)
|
||||
// {
|
||||
// _vfxInstance.SetActive(visible);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1261c2b342e03224ebc341132b01bf92
|
||||
timeCreated: 1703670852
|
@@ -0,0 +1,576 @@
|
||||
using GAS.General;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using System.Linq;
|
||||
#endif
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[CreateAssetMenu(fileName = "GameplayEffect", menuName = "GAS/GameplayEffect")]
|
||||
public class GameplayEffectAsset : ScriptableObject, IGameplayEffectData
|
||||
{
|
||||
private const string GRP_BASE = "Base";
|
||||
private const string GRP_BASE_H = "Base/H";
|
||||
private const string GRP_BASE_H_LEFT = "Base/H/Left";
|
||||
private const string GRP_BASE_H_RIGHT = "Base/H/Right";
|
||||
|
||||
private const string GRP_DATA = "Data";
|
||||
private const string GRP_DATA_H = "Data/H";
|
||||
private const string GRP_DATA_TAG = "Data/H/Tags";
|
||||
private const string GRP_DATA_MOD = "Data/H/Modifiers";
|
||||
private const string GRP_DATA_CUE = "Data/H/Cues";
|
||||
private const string GRP_DATA_H2 = "Data/H2";
|
||||
private const string GRP_DATA_STACK = "Data/H2/Stack";
|
||||
private const string GRP_DATA_GRANTED_ABILITIES = "Data/H2/GrantedAbilities";
|
||||
private const string GRP_DATA_H3 = "Data/H3";
|
||||
private const string GRP_DATA_EXPIRATION = "Data/H3/Expiration";
|
||||
private const string GRP_DATA_TICKEVENTGE = "Data/H3/TickEventGE";
|
||||
|
||||
private const int WIDTH_LABEL = 70;
|
||||
|
||||
private const string ERROR_NONE_CUE = "Cue CAN NOT be NONE!";
|
||||
private const string ERROR_DURATION = "Duration must be > 0.";
|
||||
private const string ERROR_PERIOD_GE_NONE = "Period GameplayEffect CAN NOT be NONE!";
|
||||
private const string ERROR_GRANTED_ABILITY_INVALID = "存在无效的Ability!";
|
||||
|
||||
#region Base Info
|
||||
|
||||
public string Name => name;
|
||||
|
||||
[TitleGroup(GRP_BASE)]
|
||||
[HorizontalGroup(GRP_BASE_H, Width = 1 - 0.618f)]
|
||||
[TabGroup(GRP_BASE_H_LEFT, "Summary", SdfIconType.InfoSquareFill, TextColor = "#0BFFC5")]
|
||||
[HideLabel]
|
||||
[MultiLineProperty(5)]
|
||||
[FormerlySerializedAs("Description")]
|
||||
public string description;
|
||||
|
||||
#endregion Base Info
|
||||
|
||||
#region Policy
|
||||
|
||||
[HorizontalGroup(GRP_BASE_H)]
|
||||
[TabGroup(GRP_BASE_H_RIGHT, "Policy", SdfIconType.AwardFill, TextColor = "#FF7F00")]
|
||||
[LabelText(GASTextDefine.LABLE_GE_POLICY, SdfIconType.Diagram3Fill)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[EnumToggleButtons]
|
||||
[PropertyOrder(1)]
|
||||
[FormerlySerializedAs("DurationPolicy")]
|
||||
public EffectsDurationPolicy durationPolicy = EffectsDurationPolicy.Instant;
|
||||
|
||||
[TabGroup(GRP_BASE_H_RIGHT, "Policy")]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[EnableIf("@durationPolicy == EffectsDurationPolicy.Duration")]
|
||||
[Unit(Units.Millisecond)]
|
||||
[ValidateInput("@durationPolicy != EffectsDurationPolicy.Duration || duration > 0", ERROR_DURATION)]
|
||||
[LabelText(GASTextDefine.LABLE_GE_DURATION, SdfIconType.HourglassSplit)]
|
||||
[PropertyOrder(2)]
|
||||
[FormerlySerializedAs("Duration")]
|
||||
public int duration;
|
||||
|
||||
[TabGroup(GRP_BASE_H_RIGHT, "Policy")]
|
||||
[LabelText(GASTextDefine.LABLE_GE_INTERVAL, SdfIconType.AlarmFill)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[ShowIf("@durationPolicy != EffectsDurationPolicy.Duration")]
|
||||
[EnableIf("IsDurationalPolicy")]
|
||||
[Unit(Units.Millisecond)]
|
||||
[PropertyOrder(3)]
|
||||
[FormerlySerializedAs("Period")]
|
||||
public int period;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[TabGroup(GRP_BASE_H_RIGHT, "Policy")]
|
||||
[LabelText(GASTextDefine.LABLE_GE_INTERVAL, SdfIconType.AlarmFill)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[ShowIf("@durationPolicy == EffectsDurationPolicy.Duration")]
|
||||
[EnableIf("IsDurationalPolicy")]
|
||||
[Unit(Units.Millisecond)]
|
||||
[PropertyOrder(3)]
|
||||
[PropertyRange(0, "@duration")]
|
||||
[ShowInInspector]
|
||||
// 这个Property是为了给"限时型"效果绘制一个范围滑动条
|
||||
public int PeriodForDurational
|
||||
{
|
||||
get => period;
|
||||
set => period = value;
|
||||
}
|
||||
#endif
|
||||
|
||||
[TabGroup(GRP_BASE_H_RIGHT, "Policy")]
|
||||
[LabelText("间隔效果id", SdfIconType.Ticket)]
|
||||
[LabelWidth(WIDTH_LABEL + 17)]
|
||||
[EnableIf("IsPeriodic")]
|
||||
[PropertyOrder(4)]
|
||||
[FormerlySerializedAs("PeriodExecutionId")]
|
||||
public int periodExecutionId = 0;
|
||||
|
||||
[TabGroup(GRP_BASE_H_RIGHT, "Policy")]
|
||||
[LabelText(GASTextDefine.LABLE_GE_EXEC, SdfIconType.Magic)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[EnableIf("IsPeriodic")]
|
||||
[AssetSelector]
|
||||
[InfoBox(ERROR_PERIOD_GE_NONE, InfoMessageType.Error, VisibleIf = "IsPeriodGameplayEffectNone")]
|
||||
[InfoBox("不可为永久(Infinite)类型", InfoMessageType.Error,
|
||||
VisibleIf =
|
||||
"@IsPeriodic() && (periodExecution != null && periodExecution.durationPolicy == EffectsDurationPolicy.Infinite)")]
|
||||
[PropertyOrder(5)]
|
||||
[FormerlySerializedAs("PeriodExecution")]
|
||||
public GameplayEffectAsset periodExecution;
|
||||
|
||||
public EffectsDurationPolicy DurationPolicy => durationPolicy;
|
||||
public int Duration => duration;
|
||||
public int Period => period;
|
||||
public int PeriodExecutionId => periodExecutionId;
|
||||
public IGameplayEffectData PeriodExcutionAsset => periodExecution;
|
||||
|
||||
[TabGroup(GRP_BASE_H_RIGHT, "Policy")]
|
||||
[PropertyOrder(6)]
|
||||
[Button("Save")]
|
||||
void PolicySave()
|
||||
{
|
||||
SaveAssets();
|
||||
}
|
||||
|
||||
#endregion Policy
|
||||
|
||||
#region Stack
|
||||
|
||||
[TitleGroup(GRP_DATA)]
|
||||
[HorizontalGroup(GRP_DATA_H2, order: 2, Width = 1 - 0.618f)]
|
||||
[TabGroup(GRP_DATA_STACK, "Stacking", SdfIconType.Stack, TextColor = "#9B4AE3", Order = 1)]
|
||||
[HideLabel]
|
||||
[EnableIf("IsDurationalPolicy")]
|
||||
[InfoBox("瞬时效果无法叠加", InfoMessageType.None, VisibleIf = "@IsInstantPolicy()")]
|
||||
[FormerlySerializedAs("Stacking")]
|
||||
public GameplayEffectStackingConfig stacking;
|
||||
|
||||
public GameplayEffectStacking GetStackingRuntimeData()
|
||||
{
|
||||
return stacking.ToRuntimeData();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[TabGroup(GRP_DATA_STACK, "Stacking")]
|
||||
[ShowIf("@IsDurationalPolicy() && stacking.stackingType != EnumStackingType.None")]
|
||||
[Button("使用资产名称作为堆叠识别码", ButtonSizes.Medium, Icon = SdfIconType.Hammer)]
|
||||
private void SetStackingCodeNameAsAssetName()
|
||||
{
|
||||
var stacking = this.stacking;
|
||||
stacking.stackingCodeName = name;
|
||||
this.stacking = stacking;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion Stack
|
||||
|
||||
#region Granted Abilities
|
||||
|
||||
[TabGroup(GRP_DATA_GRANTED_ABILITIES, "Granted Abilities", SdfIconType.YinYang, TextColor = "#D6626E",
|
||||
Order = 2)]
|
||||
[EnableIf("IsDurationalPolicy")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[InfoBox(ERROR_GRANTED_ABILITY_INVALID, InfoMessageType.Error, VisibleIf = "IsGrantedAbilitiesInvalid")]
|
||||
[FormerlySerializedAs("GrantedAbilities")]
|
||||
public GrantedAbilityConfig[] grantedAbilities;
|
||||
|
||||
public GrantedAbilityFromEffect[] GetGrantedAbilities()
|
||||
{
|
||||
// var grantedAbilityList = new List<GrantedAbilityFromEffect>();
|
||||
// foreach (var grantedAbilityConfig in grantedAbilities)
|
||||
// {
|
||||
// if (grantedAbilityConfig.abilityAsset == null) continue;
|
||||
// grantedAbilityList.Add(new GrantedAbilityFromEffect(grantedAbilityConfig));
|
||||
// }
|
||||
|
||||
// return grantedAbilityList.ToArray();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion Granted Abilities
|
||||
|
||||
#region Modifiers
|
||||
|
||||
[HorizontalGroup(GRP_DATA_H, order: 1, Width = 0.618f * 0.618f)]
|
||||
[TabGroup(GRP_DATA_MOD, "Modifiers", SdfIconType.CalculatorFill, TextColor = "#FFE60B", Order = 2)]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[InfoBox("依次执行多个修改器, 请注意执行顺序", InfoMessageType.Warning, VisibleIf = "@$value != null && $value.Length > 1")]
|
||||
[LabelText(@"@IsInstantPolicy() ? ""仅在成功应用时执行"":""每次激活时都会执行""")]
|
||||
[FormerlySerializedAs("Modifiers")]
|
||||
public GameplayEffectModifier[] modifiers;
|
||||
public GEModifierCfg[] GEModifierCfg => null;
|
||||
|
||||
#endregion Modifiers
|
||||
|
||||
#region Tags
|
||||
|
||||
[HorizontalGroup(GRP_DATA_H, order: 1, Width = 1 - 0.618f)]
|
||||
[TabGroup(GRP_DATA_TAG, "Tags", SdfIconType.TagsFill, TextColor = "#45B1FF", Order = 1)]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[LabelText(GASTextDefine.TITLE_GE_TAG_AssetTags)]
|
||||
[Tooltip(GASTextDefine.TIP_GE_TAG_AssetTags)]
|
||||
[ShowIf("IsDurationalPolicy")]
|
||||
[FormerlySerializedAs("AssetTags")]
|
||||
public GameplayTag[] assetTags;
|
||||
|
||||
[Space()]
|
||||
[TabGroup(GRP_DATA_TAG, "Tags")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[LabelText(GASTextDefine.TITLE_GE_TAG_GrantedTags)]
|
||||
[Tooltip(GASTextDefine.TIP_GE_TAG_GrantedTags)]
|
||||
[ShowIf("IsDurationalPolicy")]
|
||||
[FormerlySerializedAs("GrantedTags")]
|
||||
public GameplayTag[] grantedTags;
|
||||
|
||||
[Space()]
|
||||
[TabGroup(GRP_DATA_TAG, "Tags")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[LabelText(GASTextDefine.TITLE_GE_TAG_ApplicationRequiredTags)]
|
||||
[Tooltip(GASTextDefine.TIP_GE_TAG_ApplicationRequiredTags)]
|
||||
[FormerlySerializedAs("ApplicationRequiredTags")]
|
||||
public GameplayTag[] applicationRequiredTags;
|
||||
|
||||
[Space()]
|
||||
[TabGroup(GRP_DATA_TAG, "Tags")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[LabelText(GASTextDefine.TITLE_GE_TAG_OngoingRequiredTags)]
|
||||
[Tooltip(GASTextDefine.TIP_GE_TAG_OngoingRequiredTags)]
|
||||
[ShowIf("IsDurationalPolicy")]
|
||||
[FormerlySerializedAs("OngoingRequiredTags")]
|
||||
public GameplayTag[] ongoingRequiredTags;
|
||||
|
||||
[Space()]
|
||||
[TabGroup(GRP_DATA_TAG, "Tags")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[LabelText(GASTextDefine.TITLE_GE_TAG_RemoveGameplayEffectsWithTags)]
|
||||
[Tooltip(GASTextDefine.TIP_GE_TAG_RemoveGameplayEffectsWithTags)]
|
||||
[FormerlySerializedAs("RemoveGameplayEffectsWithTags")]
|
||||
public GameplayTag[] removeGameplayEffectsWithTags;
|
||||
|
||||
[Space()]
|
||||
[TabGroup(GRP_DATA_TAG, "Tags")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[LabelText(GASTextDefine.TITLE_GE_TAG_ApplicationImmunityTags)]
|
||||
[Tooltip(GASTextDefine.TIP_GE_TAG_ApplicationImmunityTags)]
|
||||
[FormerlySerializedAs("ApplicationImmunityTags")]
|
||||
public GameplayTag[] applicationImmunityTags;
|
||||
|
||||
public GameplayTag[] AssetTags => assetTags;
|
||||
public GameplayTag[] GrantedTags => grantedTags;
|
||||
public GameplayTag[] ApplicationRequiredTags => applicationRequiredTags;
|
||||
public GameplayTag[] OngoingRequiredTags => ongoingRequiredTags;
|
||||
public GameplayTag[] RemoveGameplayEffectsWithTags => removeGameplayEffectsWithTags;
|
||||
public GameplayTag[] ApplicationImmunityTags => applicationImmunityTags;
|
||||
|
||||
#endregion Tags
|
||||
|
||||
#region Cues
|
||||
|
||||
[TabGroup(GRP_DATA_CUE, "Cues", SdfIconType.Stars, TextColor = "#00FFFF", Order = 3)]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ShowIf("IsInstantPolicy")]
|
||||
[InfoBox(ERROR_NONE_CUE, InfoMessageType.Error, VisibleIf = "IsCueExecuteNone")]
|
||||
[AssetSelector]
|
||||
[LabelText(GASTextDefine.TITLE_GE_CUE_CueOnExecute)]
|
||||
[FormerlySerializedAs("CueOnExecute")]
|
||||
public GameplayCueInstant[] cueOnExecute;
|
||||
|
||||
[Space()]
|
||||
[TabGroup(GRP_DATA_CUE, "Cues")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ShowIf("IsDurationalPolicy")]
|
||||
[InfoBox(ERROR_NONE_CUE, InfoMessageType.Error, VisibleIf = "IsCueDurationalNone")]
|
||||
[AssetSelector]
|
||||
[LabelText(GASTextDefine.TITLE_GE_CUE_CueDurational)]
|
||||
[Tooltip("生命周期完全和GameplayEffect同步")]
|
||||
[FormerlySerializedAs("CueDurational")]
|
||||
public GameplayCueDurational[] cueDurational;
|
||||
|
||||
[Space()]
|
||||
[TabGroup(GRP_DATA_CUE, "Cues")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ShowIf("IsDurationalPolicy")]
|
||||
[AssetSelector]
|
||||
[LabelText(GASTextDefine.TITLE_GE_CUE_CueOnAdd)]
|
||||
[FormerlySerializedAs("CueOnAdd")]
|
||||
public GameplayCueInstant[] cueOnAdd;
|
||||
|
||||
[Space()]
|
||||
[TabGroup(GRP_DATA_CUE, "Cues")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ShowIf("IsDurationalPolicy")]
|
||||
[AssetSelector]
|
||||
[LabelText(GASTextDefine.TITLE_GE_CUE_CueOnRemove)]
|
||||
[FormerlySerializedAs("CueOnRemove")]
|
||||
public GameplayCueInstant[] cueOnRemove;
|
||||
|
||||
[Space()]
|
||||
[TabGroup(GRP_DATA_CUE, "Cues")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ShowIf("IsDurationalPolicy")]
|
||||
[AssetSelector]
|
||||
[LabelText(GASTextDefine.TITLE_GE_CUE_CueOnActivate)]
|
||||
[FormerlySerializedAs("CueOnActivate")]
|
||||
public GameplayCueInstant[] cueOnActivate;
|
||||
|
||||
[Space()]
|
||||
[TabGroup(GRP_DATA_CUE, "Cues")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[ShowIf("IsDurationalPolicy")]
|
||||
[AssetSelector]
|
||||
[LabelText(GASTextDefine.TITLE_GE_CUE_CueOnDeactivate)]
|
||||
[FormerlySerializedAs("CueOnDeactivate")]
|
||||
public GameplayCueInstant[] cueOnDeactivate;
|
||||
|
||||
private string[] m_CueAssetOnExcute;
|
||||
public string[] CueAssetOnExcute
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_CueAssetOnExcute == null)
|
||||
{
|
||||
m_CueAssetOnExcute = new string[cueOnExecute.Length];
|
||||
for (int i = 0; i < m_CueAssetOnExcute.Length; ++i)
|
||||
{
|
||||
m_CueAssetOnExcute[i] = cueOnExecute[i].name;
|
||||
}
|
||||
}
|
||||
return m_CueAssetOnExcute;
|
||||
}
|
||||
}
|
||||
private string[] m_CueAssetOnDurational;
|
||||
public string[] CueAssetOnDurational
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_CueAssetOnDurational == null)
|
||||
{
|
||||
m_CueAssetOnDurational = new string[cueDurational.Length];
|
||||
for (int i = 0; i < m_CueAssetOnDurational.Length; ++i)
|
||||
{
|
||||
m_CueAssetOnDurational[i] = cueDurational[i].name;
|
||||
}
|
||||
}
|
||||
return m_CueAssetOnDurational;
|
||||
}
|
||||
}
|
||||
private string[] m_CueAssetOnAdd;
|
||||
public string[] CueAssetOnAdd
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_CueAssetOnAdd == null)
|
||||
{
|
||||
m_CueAssetOnAdd = new string[cueOnAdd.Length];
|
||||
for (int i = 0; i < m_CueAssetOnAdd.Length; ++i)
|
||||
{
|
||||
m_CueAssetOnAdd[i] = cueOnAdd[i].name;
|
||||
}
|
||||
}
|
||||
return m_CueAssetOnAdd;
|
||||
}
|
||||
}
|
||||
private string[] m_CueAssetOnRemove;
|
||||
public string[] CueAssetOnRemove
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_CueAssetOnRemove == null)
|
||||
{
|
||||
m_CueAssetOnRemove = new string[cueOnRemove.Length];
|
||||
for (int i = 0; i < m_CueAssetOnRemove.Length; ++i)
|
||||
{
|
||||
m_CueAssetOnRemove[i] = cueOnRemove[i].name;
|
||||
}
|
||||
}
|
||||
return m_CueAssetOnRemove;
|
||||
}
|
||||
}
|
||||
private string[] m_CueAssetOnActive;
|
||||
public string[] CueAssetOnActive
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_CueAssetOnActive == null)
|
||||
{
|
||||
m_CueAssetOnActive = new string[cueOnActivate.Length];
|
||||
for (int i = 0; i < m_CueAssetOnActive.Length; ++i)
|
||||
{
|
||||
m_CueAssetOnActive[i] = cueOnActivate[i].name;
|
||||
}
|
||||
}
|
||||
return m_CueAssetOnActive;
|
||||
}
|
||||
}
|
||||
private string[] m_CueAssetOnDeactive;
|
||||
public string[] CueAssetOnDeactive
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_CueAssetOnDeactive == null)
|
||||
{
|
||||
m_CueAssetOnDeactive = new string[cueOnDeactivate.Length];
|
||||
for (int i = 0; i < m_CueAssetOnDeactive.Length; ++i)
|
||||
{
|
||||
m_CueAssetOnDeactive[i] = cueOnDeactivate[i].name;
|
||||
}
|
||||
}
|
||||
return m_CueAssetOnDeactive;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Cues
|
||||
|
||||
#region Expiration
|
||||
|
||||
[TitleGroup(GRP_DATA)]
|
||||
[HorizontalGroup(GRP_DATA_H3, order: 3, Width = 1 - 0.618f)]
|
||||
[TabGroup(GRP_DATA_EXPIRATION, "Expiration", SdfIconType.Watch, TextColor = "#7575E3", Order = 1)]
|
||||
[EnableIf("IsDurationalPolicy")]
|
||||
[InfoBox("瞬时效果没有过期", InfoMessageType.None, VisibleIf = "@!IsDurationalPolicy()")]
|
||||
[LabelText("过早到期 施加的GE", SdfIconType.Magic)]
|
||||
[FormerlySerializedAs("PrematureExpirationEffect")]
|
||||
public GameplayEffectAssetData[] prematureExpirationEffect;
|
||||
|
||||
[TitleGroup(GRP_DATA)]
|
||||
[TabGroup(GRP_DATA_EXPIRATION, "Expiration")]
|
||||
[EnableIf("IsDurationalPolicy")]
|
||||
[LabelText("正常到期 施加的GE", SdfIconType.Magic)]
|
||||
[FormerlySerializedAs("RoutineExpirationEffectClasses")]
|
||||
public GameplayEffectAssetData[] routineExpirationEffectClasses;
|
||||
|
||||
public LinkGEAsset[] PrematureExpirationEffect => null; // prematureExpirationEffect;
|
||||
public LinkGEAsset[] RoutineExpirationEffectClasses => null; // routineExpirationEffectClasses;
|
||||
|
||||
[TitleGroup(GRP_DATA)]
|
||||
[TabGroup(GRP_DATA_EXPIRATION, "Expiration")]
|
||||
[ShowIf("IsDurationalPolicy")]
|
||||
[Button("Save")]
|
||||
void ExpirationEffectSave()
|
||||
{
|
||||
SaveAssets();
|
||||
}
|
||||
|
||||
#endregion Expiration
|
||||
|
||||
#region TickEventGE
|
||||
|
||||
[TitleGroup(GRP_DATA)]
|
||||
[HorizontalGroup(GRP_DATA_H3, order: 3)]
|
||||
[TabGroup(GRP_DATA_TICKEVENTGE, "TickEvent", SdfIconType.Ticket, TextColor = "#7575E3", Order = 2)]
|
||||
[EnableIf("IsDurationalPolicy")]
|
||||
[InfoBox("瞬时效果不可用", InfoMessageType.None, VisibleIf = "@!IsDurationalPolicy()")]
|
||||
[LabelText("生效期间通过TickEvent触发效果", SdfIconType.Box)]
|
||||
[OnValueChanged("OnIsUseTickEventGEChanged")]
|
||||
[FormerlySerializedAs("IsUseTickEventGE")]
|
||||
public bool isUseTickEventGE = false;
|
||||
|
||||
[TitleGroup(GRP_DATA)]
|
||||
[TabGroup(GRP_DATA_TICKEVENTGE, "TickEvent")]
|
||||
[ShowIf("IsUseTickEvent")]
|
||||
[LabelText("触发需要的TickEvent", SdfIconType.Magic)]
|
||||
[ValueDropdown("@ValueDropdownHelper.GameplayTagTickEventChoices", IsUniqueList = true, HideChildProperties = true)]
|
||||
[FormerlySerializedAs("TickEventTag")]
|
||||
public GameplayTag tickEventTag;
|
||||
|
||||
[TitleGroup(GRP_DATA)]
|
||||
[TabGroup(GRP_DATA_TICKEVENTGE, "TickEvent")]
|
||||
[ShowIf("IsUseTickEvent")]
|
||||
[LabelText("触发的效果GE", SdfIconType.Magic)]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false)]
|
||||
[FormerlySerializedAs("TickEventEffect")]
|
||||
public GameplayEffectAssetData[] tickEventEffect;
|
||||
|
||||
public bool IsUseTickEventGE => isUseTickEventGE;
|
||||
public GameplayTag TickEventTag => tickEventTag;
|
||||
public LinkGEAsset[] TickEventEffect => null; // tickEventEffect;
|
||||
|
||||
[TitleGroup(GRP_DATA)]
|
||||
[TabGroup(GRP_DATA_TICKEVENTGE, "TickEvent")]
|
||||
[ShowIf("IsUseTickEvent")]
|
||||
[Button("Save")]
|
||||
void TickEventEffectSave()
|
||||
{
|
||||
SaveAssets();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO
|
||||
[HideInInspector]
|
||||
public ExecutionCalculation[] Executions;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
bool IsPeriodic()
|
||||
{
|
||||
return IsDurationalPolicy() && period > 0;
|
||||
}
|
||||
|
||||
bool IsDurationalPolicy()
|
||||
{
|
||||
return durationPolicy == EffectsDurationPolicy.Duration || durationPolicy == EffectsDurationPolicy.Infinite;
|
||||
}
|
||||
|
||||
bool IsInstantPolicy() => durationPolicy == EffectsDurationPolicy.Instant;
|
||||
|
||||
bool IsCueExecuteNone() => cueOnExecute != null && cueOnExecute.Any(cue => cue == null);
|
||||
|
||||
bool IsCueDurationalNone()
|
||||
{
|
||||
return (cueDurational != null && cueDurational.Any(cue => cue == null)) ||
|
||||
(cueOnAdd != null && cueOnAdd.Any(cue => cue == null)) ||
|
||||
(cueOnRemove != null && cueOnRemove.Any(cue => cue == null)) ||
|
||||
(cueOnActivate != null && cueOnActivate.Any(cue => cue == null)) ||
|
||||
(cueOnDeactivate != null && cueOnDeactivate.Any(cue => cue == null));
|
||||
}
|
||||
|
||||
bool IsPeriodGameplayEffectNone()
|
||||
{
|
||||
return IsPeriodic() && periodExecution == null;
|
||||
}
|
||||
|
||||
bool IsDurationInvalid() => durationPolicy == EffectsDurationPolicy.Duration && duration <= 0;
|
||||
bool IsPeriodInvalid() => IsDurationalPolicy() && period < 0;
|
||||
|
||||
bool IsGrantedAbilitiesInvalid()
|
||||
{
|
||||
return IsDurationalPolicy() &&
|
||||
grantedAbilities != null &&
|
||||
grantedAbilities.Any(abilityConfig => abilityConfig.abilityAsset == null);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IsUseTickEvent()
|
||||
{
|
||||
return isUseTickEventGE;
|
||||
}
|
||||
private void OnIsUseTickEventGEChanged()
|
||||
{
|
||||
if (!isUseTickEventGE)
|
||||
{
|
||||
tickEventTag = new GameplayTag("");
|
||||
tickEventEffect = null;
|
||||
SaveAssets();
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveAssets()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorUtility.SetDirty(this);
|
||||
AssetDatabase.SaveAssets();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9395a0be3e547f48bd1c8320edc6c58
|
||||
timeCreated: 1703260426
|
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using JNGame.Math;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public class GameplayEffectModifier : IGEModifierCfg
|
||||
{
|
||||
private const int LABEL_WIDTH = 70;
|
||||
|
||||
[LabelText("修改属性", SdfIconType.Fingerprint)]
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[OnValueChanged("OnAttributeChanged")]
|
||||
[ValueDropdown("@ValueDropdownHelper.AttributeChoices", IsUniqueList = true)]
|
||||
[Tooltip("指的是GameplayEffect作用对象被修改的属性。")]
|
||||
[InfoBox("未选择属性", InfoMessageType.Error, VisibleIf = "@string.IsNullOrWhiteSpace($value)")]
|
||||
[PropertyOrder(1)]
|
||||
[FormerlySerializedAs("AttributeName")]
|
||||
public string attributeName;
|
||||
|
||||
[HideInInspector]
|
||||
[FormerlySerializedAs("AttributeSetName")]
|
||||
public string attributeSetName;
|
||||
|
||||
[HideInInspector]
|
||||
[FormerlySerializedAs("AttributeShortName")]
|
||||
public string attributeShortName;
|
||||
|
||||
[LabelText("修改参数", SdfIconType.Activity)]
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[Tooltip("修改器的基础数值。这个数值如何使用由MMC的运行逻辑决定。\nMMC未指定时直接使用这个值。")]
|
||||
[PropertyOrder(3)]
|
||||
[FormerlySerializedAs("ModiferMagnitude")]
|
||||
public LFloat modiferMagnitude;
|
||||
|
||||
[LabelText("修改类型", SdfIconType.PlusSlashMinus)]
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[Tooltip("操作类型:是对属性的操作类型,\n有3种:\nAdd : 加法(取值为负便是减法)\nMultiply: 乘法(除法取倒数即可)\nOverride:覆写属性值")]
|
||||
[EnumToggleButtons]
|
||||
[PropertyOrder(2)]
|
||||
[FormerlySerializedAs("Operation")]
|
||||
public EnumGEOperation operation;
|
||||
|
||||
[LabelText("参数修饰", SdfIconType.CpuFill)]
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[AssetSelector]
|
||||
[Tooltip("ModifierMagnitudeCalculation,修改器,负责GAS中Attribute的数值计算逻辑。\n可以为空(不对\"计算参数\"做任何修改)。")]
|
||||
[PropertyOrder(4)]
|
||||
[FormerlySerializedAs("MMC")]
|
||||
public ModifierMagnitudeCalculation mmc;
|
||||
|
||||
public GameplayEffectModifier(
|
||||
string attributeName,
|
||||
LFloat modiferMagnitude,
|
||||
EnumGEOperation operation,
|
||||
ModifierMagnitudeCalculation mmc)
|
||||
{
|
||||
this.attributeName = attributeName;
|
||||
var splits = attributeName.Split('.');
|
||||
attributeSetName = splits[0];
|
||||
attributeShortName = splits[1];
|
||||
this.modiferMagnitude = modiferMagnitude;
|
||||
this.operation = operation;
|
||||
this.mmc = mmc;
|
||||
}
|
||||
|
||||
public string AttributeName => attributeName;
|
||||
|
||||
public string AttributeShortName => attributeShortName;
|
||||
|
||||
public string AttributeSetName => attributeSetName;
|
||||
|
||||
public LFloat ModifierMagnitude => modiferMagnitude;
|
||||
|
||||
public EnumGEOperation Operation => operation;
|
||||
|
||||
public PureModifierMagnitudeCalculation MMC => null; // mmc;
|
||||
|
||||
public LFloat CalculateMagnitude(GameplayEffectSpec spec, LFloat modifierMagnitude)
|
||||
{
|
||||
return mmc == null ? modiferMagnitude : mmc.CalculateMagnitude(spec, modifierMagnitude);
|
||||
}
|
||||
|
||||
public void SetModiferMagnitude(LFloat value)
|
||||
{
|
||||
modiferMagnitude = value;
|
||||
}
|
||||
|
||||
void OnAttributeChanged()
|
||||
{
|
||||
var split = attributeName.Split('.');
|
||||
attributeSetName = split[0];
|
||||
attributeShortName = split[1];
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0b20897a5ad4adc9ac45f147879fee1
|
||||
timeCreated: 1702376348
|
@@ -0,0 +1,105 @@
|
||||
|
||||
using System;
|
||||
using GAS.General;
|
||||
using Sirenix.OdinInspector;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class GameplayEffectStackingConfig
|
||||
{
|
||||
private const int LABEL_WIDTH = 100;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[VerticalGroup]
|
||||
[LabelText(GASTextDefine.LABEL_GE_STACKING_TYPE)]
|
||||
[EnumToggleButtons]
|
||||
public EnumStackingType stackingType;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[VerticalGroup]
|
||||
[HideIf("IsNoStacking")]
|
||||
[LabelText(GASTextDefine.LABEL_GE_STACKING_CODENAME)]
|
||||
[InlineButton(@"@stackingCodeName = """"", SdfIconType.EraserFill, "")]
|
||||
public string stackingCodeName;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[VerticalGroup]
|
||||
[LabelText(GASTextDefine.LABEL_GE_STACKING_COUNT)]
|
||||
[HideIf("IsNoStacking")]
|
||||
[InlineButton(@"@limitCount = int.MaxValue", SdfIconType.Hammer, "max")]
|
||||
[InlineButton(@"@limitCount = 0", SdfIconType.Hammer, "min")]
|
||||
[ValidateInput("@limitCount >= 0", "必须>=0")]
|
||||
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 == EnumDurationRefreshPolicy.RefreshOnSuccessfulApplication && denyOverflowApplication")]
|
||||
public EnumDurationRefreshPolicy durationRefreshPolicy;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[VerticalGroup]
|
||||
[LabelText(GASTextDefine.LABEL_GE_STACKING_PERIOD_RESET_POLICY)]
|
||||
[HideIf("IsNoStacking")]
|
||||
public EnumPeriodResetPolicy periodResetPolicy;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[VerticalGroup]
|
||||
[LabelText(GASTextDefine.LABEL_GE_STACKING_EXPIRATION_POLICY)]
|
||||
[HideIf("IsNoStacking")]
|
||||
public EnumExpirationPolicy 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 GameplayEffectAssetData[] 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 == EnumStackingType.None;
|
||||
|
||||
public bool IsNeverRefreshDuration() =>
|
||||
IsNoStacking() || durationRefreshPolicy == EnumDurationRefreshPolicy.NeverRefresh;
|
||||
|
||||
public bool IsDenyOverflowApplication() => !IsNoStacking() && denyOverflowApplication;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc3a34741eb56da46b0de533d8cb1e12
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,52 @@
|
||||
|
||||
using System;
|
||||
using GAS.General;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// GE授予技能的ScriptableObject配置
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct GrantedAbilityConfig : IGrantAbilityCfg
|
||||
{
|
||||
private const int LABEL_WIDTH = 50;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[LabelText(GASTextDefine.LABEL_GRANT_ABILITY)]
|
||||
[AssetSelector]
|
||||
public AbilityAsset abilityAsset;
|
||||
public IAbilityAsset GrantAbilityAsset => abilityAsset;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[LabelText(GASTextDefine.LABEL_GRANT_ABILITY_LEVEL)]
|
||||
[FormerlySerializedAs("AbilityLevel")]
|
||||
public int abilityLevel;
|
||||
public int AbilityLevel => abilityLevel;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[LabelText(GASTextDefine.LABEL_GRANT_ABILITY_ACTIVATION_POLICY)]
|
||||
[Tooltip(GASTextDefine.TIP_GRANT_ABILITY_ACTIVATION_POLICY)]
|
||||
[FormerlySerializedAs("ActivationPolicy")]
|
||||
public EnumGrantedAbilityActivationPolicy activationPolicy;
|
||||
public EnumGrantedAbilityActivationPolicy ActivationPolicy => activationPolicy;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[LabelText(GASTextDefine.LABEL_GRANT_ABILITY_DEACTIVATION_POLICY)]
|
||||
[Tooltip(GASTextDefine.TIP_GRANT_ABILITY_DEACTIVATION_POLICY)]
|
||||
[FormerlySerializedAs("DeactivationPolicy")]
|
||||
public EnumGrantedAbilityDeactivationPolicy deactivationPolicy;
|
||||
public EnumGrantedAbilityDeactivationPolicy DeactivationPolicy => deactivationPolicy;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[LabelText(GASTextDefine.LABEL_GRANT_ABILITY_REMOVE_POLICY)]
|
||||
[Tooltip(GASTextDefine.TIP_GRANT_ABILITY_REMOVE_POLICY)]
|
||||
[FormerlySerializedAs("RemovePolicy")]
|
||||
public EnumGrantedAbilityRemovePolicy removePolicy;
|
||||
public EnumGrantedAbilityRemovePolicy RemovePolicy => removePolicy;
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18b9e82f24170c349a69cb426e52e89f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5375b45c42364cffb54cb4d972235f75
|
||||
timeCreated: 1702439022
|
@@ -0,0 +1,75 @@
|
||||
using JNGame.Math;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 基于属性混合GE堆栈的MMC
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "AttrBasedWithStackModCalculation", menuName = "GAS/MMC/AttrBasedWithStackModCalculation")]
|
||||
public partial class AttrBasedWithStackModCalculation : AttributeBasedModCalculation
|
||||
{
|
||||
public enum StackMagnitudeOperation
|
||||
{
|
||||
Add,
|
||||
Multiply
|
||||
}
|
||||
|
||||
[InfoBox(" 公式:StackCount * sK + sB")]
|
||||
[TabGroup("Default", "AttributeBasedModCalculation")]
|
||||
[Title("堆叠幅值计算")]
|
||||
[LabelText("系数(sK)")]
|
||||
public LFloat sK = 1;
|
||||
|
||||
[TabGroup("Default", "AttributeBasedModCalculation")]
|
||||
[LabelText("常量(sB)")]
|
||||
public LFloat sB = 0;
|
||||
|
||||
[TabGroup("Default", "AttributeBasedModCalculation")]
|
||||
[Title("最终结果")]
|
||||
[InfoBox(" 最终公式: \n" +
|
||||
"Add:(AttributeValue * k + b)+(StackCount * sK + sB); \n" +
|
||||
"Multiply:(AttributeValue * k + b)*(StackCount * sK + sB)")]
|
||||
[LabelText("Stack幅值与Attr幅值计算方式")]
|
||||
public StackMagnitudeOperation stackMagnitudeOperation;
|
||||
|
||||
[TabGroup("Default", "AttributeBasedModCalculation")]
|
||||
[LabelText("最终公式")]
|
||||
[ShowInInspector]
|
||||
[DisplayAsString(TextAlignment.Left, true)]
|
||||
public string FinalFormulae
|
||||
{
|
||||
get
|
||||
{
|
||||
var formulae = stackMagnitudeOperation switch
|
||||
{
|
||||
StackMagnitudeOperation.Add => $"({attributeName} * {k} + {b}) + (StackCount * {sK} + {sB})",
|
||||
StackMagnitudeOperation.Multiply => $"({attributeName} * {k} + {b}) * (StackCount * {sK} + {sB})",
|
||||
_ => ""
|
||||
};
|
||||
|
||||
return $"<size=15><b><color=green>{formulae}</color></b></size>";
|
||||
}
|
||||
}
|
||||
|
||||
public override LFloat CalculateMagnitude(GameplayEffectSpec spec, LFloat modifierMagnitude)
|
||||
{
|
||||
var attrMagnitude = base.CalculateMagnitude(spec, modifierMagnitude);
|
||||
|
||||
if (spec.Stacking.stackingType == EnumStackingType.None) return attrMagnitude;
|
||||
|
||||
var stackMagnitude = spec.StackCount * sK + sB;
|
||||
|
||||
return stackMagnitudeOperation switch
|
||||
{
|
||||
StackMagnitudeOperation.Add => attrMagnitude + stackMagnitude,
|
||||
StackMagnitudeOperation.Multiply => attrMagnitude * stackMagnitude,
|
||||
_ => attrMagnitude + stackMagnitude
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8a883d343584d7d9b8a711cf045ca84
|
||||
timeCreated: 1717082065
|
@@ -0,0 +1,103 @@
|
||||
using JNGame.Math;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[CreateAssetMenu(fileName = "AttributeBasedModCalculation", menuName = "GAS/MMC/AttributeBasedModCalculation")]
|
||||
public partial class AttributeBasedModCalculation : ModifierMagnitudeCalculation
|
||||
{
|
||||
[TabGroup("Default", "AttributeBasedModCalculation", SdfIconType.PersonBoundingBox, TextColor = "blue")]
|
||||
[InfoBox(" 以什么方式(Capture Type)从谁身上(Attribute From)捕获哪个属性的值(Attribute Name)。")]
|
||||
[EnumToggleButtons]
|
||||
[LabelText("捕获方式(Capture Type)")]
|
||||
public EnumGEAttributeCaptureType captureType;
|
||||
|
||||
[TabGroup("Default", "AttributeBasedModCalculation")]
|
||||
[EnumToggleButtons]
|
||||
[LabelText("捕获目标(Attribute From)")]
|
||||
public EnumAttributeFrom attributeFromType;
|
||||
|
||||
[TabGroup("Default", "AttributeBasedModCalculation")]
|
||||
[ValueDropdown("@ValueDropdownHelper.AttributeChoices", IsUniqueList = true)]
|
||||
[LabelText("属性的名称(Attribute Name)")]
|
||||
[OnValueChanged("@OnAttributeNameChanged()")]
|
||||
[InfoBox("未指定属性名称", InfoMessageType.Error, VisibleIf = "@string.IsNullOrWhiteSpace(attributeName)")]
|
||||
public string attributeName;
|
||||
|
||||
[TabGroup("Default", "Details", SdfIconType.Bug, TextColor = "orange")]
|
||||
[ReadOnly]
|
||||
public string attributeSetName;
|
||||
|
||||
[TabGroup("Default", "Details")]
|
||||
[ReadOnly]
|
||||
public string attributeShortName;
|
||||
|
||||
[InfoBox("计算逻辑与ScalableFloatModCalculation一致, 公式:AttributeValue * k + b")]
|
||||
[TabGroup("Default", "AttributeBasedModCalculation")]
|
||||
[LabelText("系数(k)")]
|
||||
public LFloat k = 1;
|
||||
|
||||
[TabGroup("Default", "AttributeBasedModCalculation")]
|
||||
[LabelText("常量(b)")]
|
||||
public LFloat b = 0;
|
||||
|
||||
public override LFloat CalculateMagnitude(GameplayEffectSpec spec, LFloat modifierMagnitude)
|
||||
{
|
||||
#if USE_GAS_SNAPSHOT
|
||||
if (attributeFromType == AttributeFrom.Source)
|
||||
{
|
||||
if (captureType == GEAttributeCaptureType.SnapShot)
|
||||
{
|
||||
var snapShot = spec.Source.DataSnapshot();
|
||||
var attribute = snapShot[attributeName];
|
||||
return attribute * k + b;
|
||||
}
|
||||
else
|
||||
{
|
||||
var attribute = spec.Source.GetAttributeCurrentValue(attributeSetName, attributeShortName);
|
||||
return (attribute ?? 1) * k + b;
|
||||
}
|
||||
}
|
||||
|
||||
if (captureType == GEAttributeCaptureType.SnapShot)
|
||||
{
|
||||
var attribute = spec.Owner.DataSnapshot()[attributeName];
|
||||
return attribute * k + b;
|
||||
}
|
||||
else
|
||||
{
|
||||
var attribute = spec.Owner.GetAttributeCurrentValue(attributeSetName, attributeShortName);
|
||||
return (attribute ?? 1) * k + b;
|
||||
}
|
||||
#else
|
||||
int attribute;
|
||||
if (attributeFromType == EnumAttributeFrom.Source)
|
||||
{
|
||||
attribute = spec.Source.GetAttributeCurrentValue(attributeSetName, attributeShortName) ?? 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
attribute = spec.Owner.GetAttributeCurrentValue(attributeSetName, attributeShortName) ?? 1;
|
||||
}
|
||||
|
||||
return attribute * k + b;
|
||||
#endif
|
||||
}
|
||||
|
||||
private void OnAttributeNameChanged()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(attributeName))
|
||||
{
|
||||
var split = attributeName.Split('.');
|
||||
attributeSetName = split[0];
|
||||
attributeShortName = split[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
attributeSetName = null;
|
||||
attributeShortName = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c712e05924784c5593896e5c7c1d2708
|
||||
timeCreated: 1703494252
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa6c2a659573f3746822f24c54cf95f6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,96 @@
|
||||
|
||||
using JNGame.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
public abstract partial class ModifierMagnitudeCalculation : ISerializable
|
||||
{
|
||||
public virtual void Deserialize(Deserializer reader)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Serialize(Serializer writer)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public partial class AttrBasedWithStackModCalculation
|
||||
{
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
sK = reader.ReadLFloat();
|
||||
sB = reader.ReadLFloat();
|
||||
stackMagnitudeOperation = (StackMagnitudeOperation)reader.ReadByte();
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(sK);
|
||||
writer.Write(sB);
|
||||
writer.Write((byte)stackMagnitudeOperation);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class AttributeBasedModCalculation
|
||||
{
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
captureType = (EnumGEAttributeCaptureType)reader.ReadByte();
|
||||
attributeFromType = (EnumAttributeFrom)reader.ReadByte();
|
||||
attributeName = reader.ReadString();
|
||||
attributeSetName = reader.ReadString();
|
||||
attributeShortName = reader.ReadString();
|
||||
k = reader.ReadLFloat();
|
||||
b = reader.ReadLFloat();
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((byte)captureType);
|
||||
writer.Write((byte)attributeFromType);
|
||||
writer.Write(attributeName);
|
||||
writer.Write(attributeSetName);
|
||||
writer.Write(attributeShortName);
|
||||
writer.Write(k);
|
||||
writer.Write(b);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ScalableFloatModCalculation
|
||||
{
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
k = reader.ReadLFloat();
|
||||
b = reader.ReadLFloat();
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(k);
|
||||
writer.Write(b);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class StackModCalculation
|
||||
{
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
k = reader.ReadLFloat();
|
||||
b = reader.ReadLFloat();
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(k);
|
||||
writer.Write(b);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1edddc8bc2e5e074e95a12800e94d722
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,62 @@
|
||||
using System.Linq;
|
||||
using GAS.General;
|
||||
using JNGame.Math;
|
||||
using JNGame.Serialization;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
public abstract partial class ModifierMagnitudeCalculation : ScriptableObject, IModifierMagnitudeCalculation, ISerializable
|
||||
{
|
||||
public virtual ushort TypeId => 0;
|
||||
|
||||
protected const int WIDTH_LABEL = 70;
|
||||
|
||||
[TitleGroup("Base")]
|
||||
[HorizontalGroup("Base/H1", width: 1 - 0.618f)]
|
||||
[TabGroup("Base/H1/V1", "Summary", SdfIconType.InfoSquareFill, TextColor = "#0BFFC5", Order = 1)]
|
||||
[HideLabel]
|
||||
[MultiLineProperty(10)]
|
||||
[FormerlySerializedAs("Description")]
|
||||
public string description;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[TabGroup("Base/H1/V2", "General", SdfIconType.AwardFill, TextColor = "#FF7F00", Order = 2)]
|
||||
[TabGroup("Base/H1/V2", "Detail", SdfIconType.TicketDetailedFill, TextColor = "#BC2FDE")]
|
||||
[LabelText("类型名称", SdfIconType.FileCodeFill)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[ShowInInspector]
|
||||
[PropertyOrder(-1)]
|
||||
public string TypeName => GetType().Name;
|
||||
|
||||
[TabGroup("Base/H1/V2", "Detail")]
|
||||
[LabelText("类型全名", SdfIconType.FileCodeFill)]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[ShowInInspector]
|
||||
[PropertyOrder(-1)]
|
||||
public string TypeFullName => GetType().FullName;
|
||||
|
||||
[TabGroup("Base/H1/V2", "Detail")]
|
||||
[ListDrawerSettings(ShowFoldout = true, ShowItemCount = false, ShowPaging = false)]
|
||||
[ShowInInspector]
|
||||
[LabelText("继承关系")]
|
||||
[LabelWidth(WIDTH_LABEL)]
|
||||
[PropertyOrder(-1)]
|
||||
public string[] InheritanceChain => GetType().GetInheritanceChain().Reverse().ToArray();
|
||||
#endif
|
||||
|
||||
public abstract LFloat CalculateMagnitude(GameplayEffectSpec spec, LFloat modifierMagnitude);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnValidate()
|
||||
{
|
||||
// if(Application.isPlaying) return;
|
||||
// EditorUtility.SetDirty(this);
|
||||
// AssetDatabase.SaveAssets();
|
||||
// AssetDatabase.Refresh();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a19086b31e7847ccaa9ec35657197357
|
||||
timeCreated: 1702624467
|
@@ -0,0 +1,26 @@
|
||||
using JNGame.Math;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[CreateAssetMenu(fileName = "ScalableFloatModCalculation", menuName = "GAS/MMC/ScalableFloatModCalculation")]
|
||||
public partial class ScalableFloatModCalculation : ModifierMagnitudeCalculation
|
||||
{
|
||||
private const string Desc = "计算公式:ModifierMagnitude * k + b";
|
||||
|
||||
private const string Detail =
|
||||
"ScalableFloatModCalculation:可缩放浮点数计算\n该类型是根据Magnitude计算Modifier模值的,计算公式为:ModifierMagnitude * k + b 实际上就是一个线性函数,k和b为可编辑参数,可以在编辑器中设置。";
|
||||
|
||||
[DetailedInfoBox(Desc, Detail, InfoMessageType.Info)]
|
||||
[SerializeField]
|
||||
private LFloat k = 1;
|
||||
|
||||
[SerializeField] private LFloat b = 0;
|
||||
|
||||
public override LFloat CalculateMagnitude(GameplayEffectSpec spec, LFloat input)
|
||||
{
|
||||
return input * k + b;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b127451ee4eb4575be21eb8e5744a5da
|
||||
timeCreated: 1703493960
|
@@ -0,0 +1,27 @@
|
||||
using JNGame.Math;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[CreateAssetMenu(fileName = "StackModCalculation", menuName = "GAS/MMC/StackModCalculation")]
|
||||
public partial class StackModCalculation : ModifierMagnitudeCalculation
|
||||
{
|
||||
[InfoBox("计算逻辑与ScalableFloatModCalculation一致, 公式:(StackCount) * k + b")]
|
||||
[TabGroup("Default", "StackModCalculation")]
|
||||
[LabelText("系数(k)")]
|
||||
public LFloat k = 1;
|
||||
|
||||
[TabGroup("Default", "StackModCalculation")]
|
||||
[LabelText("常量(b)")]
|
||||
public LFloat b = 0;
|
||||
|
||||
public override LFloat CalculateMagnitude(GameplayEffectSpec spec, LFloat modifierMagnitude)
|
||||
{
|
||||
if (spec.Stacking.stackingType == EnumStackingType.None) return 0;
|
||||
|
||||
var stackCount = spec.StackCount;
|
||||
return stackCount * k + b;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21d2ef437f1e4ec9900650b169b66e77
|
||||
timeCreated: 1717073260
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbeb02116afc4e53b4325da574d435c7
|
||||
timeCreated: 1709537763
|
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using GAS.General;
|
||||
using JNGame.Runtime.Util;
|
||||
using JNGame.Serialization;
|
||||
using JNGame.Util;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public abstract class AbilityTaskData
|
||||
{
|
||||
[FormerlySerializedAs("TaskData")]
|
||||
public JsonData taskData;
|
||||
|
||||
public virtual AbilityTaskBase Create(AbilitySpec abilitySpec)
|
||||
{
|
||||
var task = Load();
|
||||
task.Init(abilitySpec);
|
||||
return task;
|
||||
}
|
||||
|
||||
public void Save(AbilityTaskBase task)
|
||||
{
|
||||
var jsonData = JsonUtil.ToJson(task);
|
||||
var dataType = task.GetType().FullName;
|
||||
taskData = new JsonData
|
||||
{
|
||||
Type = dataType,
|
||||
Data = jsonData
|
||||
};
|
||||
}
|
||||
|
||||
public abstract AbilityTaskBase Load();
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94b0d93e175744309457ec20f699f54d
|
||||
timeCreated: 1709537306
|
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GAS.General;
|
||||
using JNGame.Runtime.Util;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class InstantTaskData : AbilityTaskData
|
||||
{
|
||||
public InstantTaskData()
|
||||
{
|
||||
taskData = new JsonData()
|
||||
{
|
||||
Type = typeof(DefaultInstantAbilityTask).FullName,
|
||||
};
|
||||
}
|
||||
|
||||
public InstantAbilityTask CreateTask(AbilitySpec abilitySpec)
|
||||
{
|
||||
var task = base.Create(abilitySpec);
|
||||
var instantAbilityTask = task as InstantAbilityTask;
|
||||
return instantAbilityTask;
|
||||
}
|
||||
|
||||
public override AbilityTaskBase Load()
|
||||
{
|
||||
InstantAbilityTask task = null;
|
||||
var jsonData = taskData.Data;
|
||||
var dataType = string.IsNullOrEmpty(taskData.Type) ? typeof(DefaultInstantAbilityTask).FullName : taskData.Type;
|
||||
|
||||
Type type = null;
|
||||
foreach (var sonType in InstantTaskSonTypes)
|
||||
{
|
||||
if (sonType.FullName == dataType)
|
||||
{
|
||||
type = sonType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
Debug.LogError($"[EX] InstantAbilityTask SonType not found: {dataType}");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(jsonData))
|
||||
{
|
||||
task = Activator.CreateInstance(type) as InstantAbilityTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
task = JsonUtil.ToObject(jsonData, type) as InstantAbilityTask;
|
||||
}
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
#region SonTypes
|
||||
|
||||
private static Type[] _instantTaskSonTypes;
|
||||
|
||||
public static Type[] InstantTaskSonTypes =>
|
||||
_instantTaskSonTypes ??= TypeUtil.GetAllSonTypesOf(typeof(InstantAbilityTask));
|
||||
|
||||
public static List<string> InstantTaskSonTypeChoices
|
||||
{
|
||||
get
|
||||
{
|
||||
var list = new List<String>();
|
||||
foreach (var sonType in InstantTaskSonTypes)
|
||||
{
|
||||
list.Add(sonType.FullName);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 474a7b1c8cea4801abb10dccf9a04a9a
|
||||
timeCreated: 1709537777
|
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GAS.General;
|
||||
using JNGame.Runtime.Util;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public class OngoingTaskData : AbilityTaskData
|
||||
{
|
||||
public OngoingTaskData()
|
||||
{
|
||||
taskData = new JsonData()
|
||||
{
|
||||
Type = typeof(DefaultOngoingAbilityTask).FullName,
|
||||
};
|
||||
}
|
||||
|
||||
public OngoingAbilityTask CreateTask(AbilitySpec abilitySpec)
|
||||
{
|
||||
var task = base.Create(abilitySpec);
|
||||
var ongoingAbilityTask = task as OngoingAbilityTask;
|
||||
return ongoingAbilityTask;
|
||||
}
|
||||
|
||||
public override AbilityTaskBase Load()
|
||||
{
|
||||
OngoingAbilityTask task = null;
|
||||
var jsonData = taskData.Data;
|
||||
var dataType = string.IsNullOrEmpty(taskData.Type) ? typeof(DefaultOngoingAbilityTask).FullName : taskData.Type;
|
||||
|
||||
Type type = null;
|
||||
foreach (var sonType in OngoingTaskSonTypes)
|
||||
{
|
||||
if (sonType.FullName == dataType)
|
||||
{
|
||||
type = sonType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
Debug.LogError($"[EX] OngoingAbilityTask SonType not found: {dataType}");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(jsonData))
|
||||
{
|
||||
task = Activator.CreateInstance(type) as OngoingAbilityTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
task = JsonUtil.ToObject(jsonData, type) as OngoingAbilityTask;
|
||||
}
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
|
||||
#region SonTypes
|
||||
|
||||
private static Type[] _ongoingTaskSonTypes;
|
||||
|
||||
public static Type[] OngoingTaskSonTypes =>
|
||||
_ongoingTaskSonTypes ??= TypeUtil.GetAllSonTypesOf(typeof(OngoingAbilityTask));
|
||||
|
||||
public static List<string> OngoingTaskSonTypeChoices
|
||||
{
|
||||
get
|
||||
{
|
||||
var list = new List<String>();
|
||||
foreach (var sonType in OngoingTaskSonTypes)
|
||||
{
|
||||
list.Add(sonType.FullName);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6237a13b66514fb98982b19e91b75259
|
||||
timeCreated: 1709538170
|
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GAS.General;
|
||||
using JNGame.Runtime.Util;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public class PassiveTaskData : AbilityTaskData
|
||||
{
|
||||
public PassiveTaskData()
|
||||
{
|
||||
taskData = new JsonData()
|
||||
{
|
||||
Type = typeof(DefaultPassiveAbilityTask).FullName,
|
||||
};
|
||||
}
|
||||
|
||||
public PassiveAbilityTask CreateTask(AbilitySpec abilitySpec)
|
||||
{
|
||||
var task = base.Create(abilitySpec);
|
||||
var passiveAbilityTask = task as PassiveAbilityTask;
|
||||
return passiveAbilityTask;
|
||||
}
|
||||
|
||||
public override AbilityTaskBase Load()
|
||||
{
|
||||
PassiveAbilityTask task = null;
|
||||
var jsonData = taskData.Data;
|
||||
var dataType = string.IsNullOrEmpty(taskData.Type) ? typeof(DefaultPassiveAbilityTask).FullName : taskData.Type;
|
||||
|
||||
Type type = null;
|
||||
foreach (var sonType in PassiveTaskSonTypes)
|
||||
{
|
||||
if (sonType.FullName == dataType)
|
||||
{
|
||||
type = sonType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
Debug.LogError($"[EX] PassiveAbilityTask SonType not found: {dataType}");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(jsonData))
|
||||
{
|
||||
task = Activator.CreateInstance(type) as PassiveAbilityTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
task = JsonUtil.ToObject(jsonData, type) as PassiveAbilityTask;
|
||||
}
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
#region SonTypes
|
||||
|
||||
private static Type[] _passiveTaskSonTypes;
|
||||
|
||||
public static Type[] PassiveTaskSonTypes =>
|
||||
_passiveTaskSonTypes ??= TypeUtil.GetAllSonTypesOf(typeof(PassiveAbilityTask));
|
||||
|
||||
public static List<string> PassiveTaskSonTypeChoices
|
||||
{
|
||||
get
|
||||
{
|
||||
var list = new List<String>();
|
||||
foreach (var sonType in PassiveTaskSonTypes)
|
||||
{
|
||||
list.Add(sonType.FullName);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5db1b94c5ab4790b32fe66dd6d4ac84
|
||||
timeCreated: 1717572936
|
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GAS.General;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public class TimelineAbilityAsset : AbilityAsset
|
||||
{
|
||||
[BoxGroup]
|
||||
[LabelText(GASTextDefine.ABILITY_MANUAL_ENDABILITY)]
|
||||
[LabelWidth(100)]
|
||||
public bool manualEndAbility;
|
||||
|
||||
[HideInInspector]
|
||||
[FormerlySerializedAs("FrameCount")]
|
||||
public int frameCount; // 能力结束时间
|
||||
|
||||
[HideInInspector]
|
||||
[FormerlySerializedAs("DurationalCues")]
|
||||
public List<DurationalCueTrackData> durationalCues = new List<DurationalCueTrackData>();
|
||||
|
||||
[HideInInspector]
|
||||
[FormerlySerializedAs("InstantCues")]
|
||||
public List<InstantCueTrackData> instantCues = new List<InstantCueTrackData>();
|
||||
|
||||
[HideInInspector]
|
||||
[FormerlySerializedAs("ReleaseGameplayEffect")]
|
||||
public List<ReleaseGameplayEffectTrackData> releaseGameplayEffect = new List<ReleaseGameplayEffectTrackData>();
|
||||
|
||||
[HideInInspector]
|
||||
[FormerlySerializedAs("BuffGameplayEffects")]
|
||||
public List<BuffGameplayEffectTrackData> buffGameplayEffects = new List<BuffGameplayEffectTrackData>();
|
||||
|
||||
[HideInInspector]
|
||||
[FormerlySerializedAs("InstantTasks")]
|
||||
public List<TaskMarkEventTrackData> instantTasks = new List<TaskMarkEventTrackData>();
|
||||
|
||||
[HideInInspector]
|
||||
[FormerlySerializedAs("OngoingTasks")]
|
||||
public List<TaskClipEventTrackData> ongoingTasks = new List<TaskClipEventTrackData>();
|
||||
|
||||
[HideInInspector]
|
||||
[FormerlySerializedAs("PassiveGameplayEffects")]
|
||||
public List<PassiveGameplayEffectTrackData> passiveGameplayEffects = new();
|
||||
|
||||
[HideInInspector]
|
||||
[FormerlySerializedAs("PassiveTasks")]
|
||||
public List<PassiveTaskClipEventTrackData> passiveTasks = new();
|
||||
|
||||
public override Type AbilityType()
|
||||
{
|
||||
return typeof(TimelineAbility);
|
||||
}
|
||||
|
||||
public bool ManualEndAbility => manualEndAbility;
|
||||
|
||||
public int FrameCount => frameCount;
|
||||
|
||||
public List<DurationalCueTrackData> DurationalCues => durationalCues;
|
||||
|
||||
public List<InstantCueTrackData> InstantCues => instantCues;
|
||||
|
||||
public List<ReleaseGameplayEffectTrackData> ReleaseGameplayEffect => releaseGameplayEffect;
|
||||
|
||||
public List<BuffGameplayEffectTrackData> BuffGameplayEffects => buffGameplayEffects;
|
||||
|
||||
public List<TaskMarkEventTrackData> InstantTasks => instantTasks;
|
||||
|
||||
public List<TaskClipEventTrackData> OngoingTasks => ongoingTasks;
|
||||
|
||||
public List<PassiveGameplayEffectTrackData> PassiveGameplayEffects => passiveGameplayEffects;
|
||||
|
||||
public List<PassiveTaskClipEventTrackData> PassiveTasks => passiveTasks;
|
||||
|
||||
public TimelineInfo TimelineAbilityInfo => null;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public void Save()
|
||||
{
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d763af469c524557946c477b9bea3a46
|
||||
timeCreated: 1708250516
|
@@ -0,0 +1,500 @@
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using System.Collections.Generic;
|
||||
using GAS.General;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
internal abstract class RuntimeClipInfo
|
||||
{
|
||||
public int endFrame;
|
||||
public int startFrame;
|
||||
}
|
||||
|
||||
internal class RuntimeDurationCueClip : RuntimeClipInfo
|
||||
{
|
||||
public GameplayCueDurationalSpec cueSpec;
|
||||
}
|
||||
|
||||
internal class RuntimeBuffClip : RuntimeClipInfo
|
||||
{
|
||||
public GameplayEffect buff;
|
||||
public GameplayEffectSpec buffSpec;
|
||||
}
|
||||
internal class RuntimePassiveClip : RuntimeClipInfo
|
||||
{
|
||||
public GameplayEffect passive;
|
||||
public GameplayEffectSpec passiveSpec;
|
||||
}
|
||||
internal class RuntimeTaskClip : RuntimeClipInfo
|
||||
{
|
||||
public OngoingAbilityTask task;
|
||||
}
|
||||
internal class RuntimePassiveTaskClip : RuntimeClipInfo
|
||||
{
|
||||
public PassiveAbilityTask task;
|
||||
}
|
||||
|
||||
internal class RuntimeTaskMark
|
||||
{
|
||||
public int startFrame;
|
||||
public InstantAbilityTask task;
|
||||
}
|
||||
|
||||
public class TimelineAbilityPlayer
|
||||
{
|
||||
private readonly TimelineAbilitySpec _abilitySpec;
|
||||
private readonly List<RuntimeBuffClip> _cacheBuffGameplayEffectTrack = new();
|
||||
private readonly List<RuntimePassiveClip> _cachePassiveGameplayEffectTrack = new();
|
||||
|
||||
private readonly List<RuntimeDurationCueClip> _cacheDurationalCueTrack = new();
|
||||
|
||||
private readonly List<InstantCueMarkEvent> _cacheInstantCues = new();
|
||||
|
||||
private readonly List<RuntimeTaskMark> _cacheInstantTasks = new();
|
||||
private readonly List<RuntimeTaskClip> _cacheOngoingTaskTrack = new();
|
||||
private readonly List<RuntimePassiveTaskClip> _cachePassiveTaskTrack = new();
|
||||
|
||||
private readonly List<ReleaseGameplayEffectMarkEvent> _cacheReleaseGameplayEffect = new();
|
||||
|
||||
// cache for target catcher, avoid new in TickFrame
|
||||
// 这个是一个泛型类, 这个变量就不作为static了
|
||||
private readonly List<AbilitySystemComponent> _targets = new();
|
||||
|
||||
private int _currentFrame;
|
||||
private int _playTotalTime;//毫秒
|
||||
|
||||
public TimelineAbilityPlayer(TimelineAbilitySpec abilitySpec)
|
||||
{
|
||||
_abilitySpec = abilitySpec;
|
||||
Cache();
|
||||
}
|
||||
|
||||
public bool IsPlaying { get; private set; }
|
||||
|
||||
public TimelineAbilityAsset AbilityAsset => _abilitySpec.Ability.DataReference as TimelineAbilityAsset;
|
||||
private int FrameCount => AbilityAsset.FrameCount;
|
||||
|
||||
private void Cache()
|
||||
{
|
||||
Cache_InstantCues();
|
||||
Cache_ReleaseGameplayEffects();
|
||||
Cache_InstantTasks();
|
||||
Cache_DurationalGameplayCues();
|
||||
Cache_BuffGameplayEffects();
|
||||
Cache_OngoingTasks();
|
||||
Cache_PassiveGameplayEffects();
|
||||
Cache_PassiveTasks();
|
||||
}
|
||||
|
||||
private void Cache_InstantCues()
|
||||
{
|
||||
_cacheInstantCues.Clear();
|
||||
foreach (var trackData in AbilityAsset.InstantCues)
|
||||
{
|
||||
_cacheInstantCues.AddRange(trackData.markEvents);
|
||||
}
|
||||
_cacheInstantCues.Sort((a, b) => a.startFrame.CompareTo(b.startFrame));
|
||||
}
|
||||
|
||||
private void Cache_ReleaseGameplayEffects()
|
||||
{
|
||||
_cacheReleaseGameplayEffect.Clear();
|
||||
foreach (var trackData in AbilityAsset.ReleaseGameplayEffect)
|
||||
{
|
||||
_cacheReleaseGameplayEffect.AddRange(trackData.markEvents);
|
||||
}
|
||||
|
||||
_cacheReleaseGameplayEffect.Sort((a, b) => a.startFrame.CompareTo(b.startFrame));
|
||||
foreach (var releaseGameplayEffectMarkEvent in _cacheReleaseGameplayEffect)
|
||||
{
|
||||
releaseGameplayEffectMarkEvent.CacheTargetCatcher();
|
||||
}
|
||||
}
|
||||
|
||||
private void Cache_InstantTasks()
|
||||
{
|
||||
_cacheInstantTasks.Clear();
|
||||
foreach (var trackData in AbilityAsset.InstantTasks)
|
||||
{
|
||||
foreach (var markEvent in trackData.markEvents)
|
||||
{
|
||||
foreach (var taskData in markEvent.instantTasks)
|
||||
{
|
||||
var runtimeTaskMark = new RuntimeTaskMark
|
||||
{
|
||||
startFrame = markEvent.startFrame,
|
||||
task = taskData.CreateTask(_abilitySpec)
|
||||
};
|
||||
_cacheInstantTasks.Add(runtimeTaskMark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_cacheInstantTasks.Sort((a, b) => a.startFrame.CompareTo(b.startFrame));
|
||||
}
|
||||
|
||||
private void Cache_DurationalGameplayCues()
|
||||
{
|
||||
_cacheDurationalCueTrack.Clear();
|
||||
foreach (var track in AbilityAsset.DurationalCues)
|
||||
{
|
||||
foreach (var clipEvent in track.clipEvents)
|
||||
{
|
||||
var cueSpec = clipEvent.cue.ApplyFrom(_abilitySpec);
|
||||
if (cueSpec == null) continue;
|
||||
var runtimeDurationCueClip = new RuntimeDurationCueClip
|
||||
{
|
||||
startFrame = clipEvent.startFrame,
|
||||
endFrame = clipEvent.EndFrame,
|
||||
cueSpec = cueSpec
|
||||
};
|
||||
_cacheDurationalCueTrack.Add(runtimeDurationCueClip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Cache_BuffGameplayEffects()
|
||||
{
|
||||
_cacheBuffGameplayEffectTrack.Clear();
|
||||
foreach (var track in AbilityAsset.BuffGameplayEffects)
|
||||
{
|
||||
foreach (var clipEvent in track.clipEvents)
|
||||
{
|
||||
// 只有持续型的GameplayEffect可视作buff
|
||||
if (clipEvent.gameplayEffect.durationPolicy is EffectsDurationPolicy.Duration
|
||||
or EffectsDurationPolicy.Infinite)
|
||||
{
|
||||
var runtimeBuffClip = new RuntimeBuffClip
|
||||
{
|
||||
startFrame = clipEvent.startFrame,
|
||||
endFrame = clipEvent.EndFrame,
|
||||
buff = new GameplayEffect(clipEvent.gameplayEffect, clipEvent.gameplayEffectValueId),
|
||||
buffSpec = null
|
||||
};
|
||||
_cacheBuffGameplayEffectTrack.Add(runtimeBuffClip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Cache_PassiveGameplayEffects()
|
||||
{
|
||||
_cachePassiveGameplayEffectTrack.Clear();
|
||||
foreach (var track in AbilityAsset.PassiveGameplayEffects)
|
||||
{
|
||||
foreach (var clipEvent in track.clipEvents)
|
||||
{
|
||||
// 只有持续型的GameplayEffect可视作Passive
|
||||
if (clipEvent.gameplayEffect.durationPolicy is EffectsDurationPolicy.Duration
|
||||
or EffectsDurationPolicy.Infinite)
|
||||
{
|
||||
var runtimePassiveClip = new RuntimePassiveClip
|
||||
{
|
||||
startFrame = clipEvent.startFrame,
|
||||
endFrame = -1,
|
||||
passive = new GameplayEffect(clipEvent.gameplayEffect, clipEvent.gameplayEffectValueId),
|
||||
passiveSpec = null
|
||||
};
|
||||
_cachePassiveGameplayEffectTrack.Add(runtimePassiveClip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Cache_OngoingTasks()
|
||||
{
|
||||
_cacheOngoingTaskTrack.Clear();
|
||||
foreach (var track in AbilityAsset.OngoingTasks)
|
||||
{
|
||||
foreach (var clip in track.clipEvents)
|
||||
{
|
||||
var runtimeTaskClip = new RuntimeTaskClip
|
||||
{
|
||||
startFrame = clip.startFrame,
|
||||
endFrame = clip.EndFrame,
|
||||
task = clip.ongoingTask.CreateTask(_abilitySpec)
|
||||
};
|
||||
_cacheOngoingTaskTrack.Add(runtimeTaskClip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Cache_PassiveTasks()
|
||||
{
|
||||
_cachePassiveTaskTrack.Clear();
|
||||
foreach (var track in AbilityAsset.PassiveTasks)
|
||||
{
|
||||
foreach (var clip in track.clipEvents)
|
||||
{
|
||||
var runtimeTaskClip = new RuntimePassiveTaskClip
|
||||
{
|
||||
startFrame = clip.startFrame,
|
||||
endFrame = clip.EndFrame,
|
||||
task = clip.passiveTask.CreateTask(_abilitySpec)
|
||||
};
|
||||
_cachePassiveTaskTrack.Add(runtimeTaskClip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Prepare()
|
||||
{
|
||||
foreach (var runtimeBuffClip in _cacheBuffGameplayEffectTrack)
|
||||
{
|
||||
runtimeBuffClip.buffSpec = null;
|
||||
}
|
||||
foreach (var runtimePassiveClip in _cachePassiveGameplayEffectTrack)
|
||||
{
|
||||
runtimePassiveClip.passiveSpec = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
_currentFrame = -1; // 为了播放第0帧
|
||||
_playTotalTime = 0;
|
||||
IsPlaying = true;
|
||||
Prepare();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
// 修改后,Passive的GE不会因为timeline播放完成移除,需要自行移除
|
||||
foreach (var clip in _cachePassiveGameplayEffectTrack)
|
||||
{
|
||||
if (clip.passiveSpec != null)
|
||||
_abilitySpec.Owner.RemoveGameplayEffect(clip.passiveSpec);
|
||||
}
|
||||
|
||||
// 修改后,PassiveTask的GE不会因为timeline播放完成执行OnEnd,需要在ability结束时调用
|
||||
foreach (var taskClip in _cachePassiveTaskTrack)
|
||||
{
|
||||
taskClip.task.OnEnd();
|
||||
}
|
||||
|
||||
if (!IsPlaying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var clip in _cacheDurationalCueTrack)
|
||||
{
|
||||
clip.cueSpec.OnRemove(-1,clip.startFrame,clip.endFrame);
|
||||
}
|
||||
|
||||
foreach (var clip in _cacheBuffGameplayEffectTrack)
|
||||
{
|
||||
if (clip.buffSpec != null)
|
||||
_abilitySpec.Owner.RemoveGameplayEffect(clip.buffSpec);
|
||||
}
|
||||
|
||||
foreach (var clip in _cacheOngoingTaskTrack)
|
||||
{
|
||||
clip.task.OnEnd(clip.endFrame);
|
||||
}
|
||||
|
||||
IsPlaying = false;
|
||||
}
|
||||
|
||||
public void Tick(int deltaTime)
|
||||
{
|
||||
if (!IsPlaying)
|
||||
{
|
||||
if (_currentFrame >= FrameCount)
|
||||
{
|
||||
TickFrame_PassiveTasks(deltaTime);
|
||||
}
|
||||
return;
|
||||
}
|
||||
_playTotalTime += deltaTime;
|
||||
var targetFrame = (int)(_playTotalTime / GASTimer.TimeLineAbilityTickTime);
|
||||
|
||||
// 追帧
|
||||
while (_currentFrame < targetFrame)
|
||||
{
|
||||
_currentFrame++;
|
||||
TickFrame(_currentFrame, deltaTime);
|
||||
}
|
||||
|
||||
if (_currentFrame >= FrameCount)
|
||||
{
|
||||
OnPlayEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 播放结束
|
||||
/// </summary>
|
||||
private void OnPlayEnd()
|
||||
{
|
||||
IsPlaying = false;
|
||||
if (!AbilityAsset.ManualEndAbility)
|
||||
{
|
||||
_abilitySpec.TryEndAbility();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前帧的事件
|
||||
/// </summary>
|
||||
/// <param name="frame"></param>
|
||||
/// <param name="deltaTime"></param>
|
||||
private void TickFrame(int frame, int deltaTime)
|
||||
{
|
||||
TickFrame_InstantGameplayCues(frame);
|
||||
TickFrame_ReleaseGameplayEffects(frame);
|
||||
TickFrame_InstantTasks(frame);
|
||||
TickFrame_DurationalGameplayCues(frame, deltaTime);
|
||||
TickFrame_BuffGameplayEffects(frame);
|
||||
TickFrame_PassiveGameplayEffects(frame);
|
||||
TickFrame_OngoingTasks(frame);
|
||||
TickFrame_PassiveTasks(deltaTime);
|
||||
}
|
||||
|
||||
private void TickFrame_InstantGameplayCues(int frame)
|
||||
{
|
||||
foreach (var cueMark in _cacheInstantCues)
|
||||
{
|
||||
if (frame == cueMark.startFrame)
|
||||
{
|
||||
foreach (var cue in cueMark.cues)
|
||||
{
|
||||
cue.ApplyFrom(_abilitySpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TickFrame_ReleaseGameplayEffects(int frame)
|
||||
{
|
||||
foreach (var mark in _cacheReleaseGameplayEffect)
|
||||
{
|
||||
if (frame == mark.startFrame)
|
||||
{
|
||||
var catcher = mark.TargetCatcher;
|
||||
catcher.Init(_abilitySpec.Owner);
|
||||
|
||||
catcher.CatchTargetsNonAllocSafe(_abilitySpec.Target, _targets);
|
||||
|
||||
foreach (var asc in _targets)
|
||||
{
|
||||
foreach (var gea in mark.gameplayEffectAssets)
|
||||
{
|
||||
var ge = new GameplayEffect(gea.asset, gea.id);
|
||||
_abilitySpec.Owner.ApplyGameplayEffectTo(ge, asc, _abilitySpec.Ability.SkillId);
|
||||
}
|
||||
}
|
||||
|
||||
_targets.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TickFrame_InstantTasks(int frame)
|
||||
{
|
||||
foreach (var instantTask in _cacheInstantTasks)
|
||||
{
|
||||
if (frame == instantTask.startFrame)
|
||||
{
|
||||
instantTask.task.OnExecute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TickFrame_DurationalGameplayCues(int frame, int deltaTime)
|
||||
{
|
||||
foreach (var cueClip in _cacheDurationalCueTrack)
|
||||
{
|
||||
if (frame == cueClip.startFrame)
|
||||
{
|
||||
cueClip.cueSpec.OnAdd(frame,cueClip.startFrame,cueClip.endFrame);
|
||||
}
|
||||
|
||||
if (frame >= cueClip.startFrame && frame <= cueClip.endFrame)
|
||||
{
|
||||
cueClip.cueSpec.OnTick(frame,cueClip.startFrame,cueClip.endFrame);
|
||||
}
|
||||
|
||||
if (frame == cueClip.endFrame)
|
||||
{
|
||||
cueClip.cueSpec.OnRemove(frame,cueClip.startFrame,cueClip.endFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TickFrame_BuffGameplayEffects(int frame)
|
||||
{
|
||||
// buff持续时间以Timeline配置时间为准(执行策略全部改为Infinite)
|
||||
foreach (var buffClip in _cacheBuffGameplayEffectTrack)
|
||||
{
|
||||
if (frame == buffClip.startFrame)
|
||||
{
|
||||
var buffSpec = _abilitySpec.Owner.ApplyGameplayEffectToSelf(buffClip.buff, _abilitySpec.Ability.SkillId);
|
||||
if (buffSpec != null)
|
||||
{
|
||||
buffSpec.SetDurationPolicy(EffectsDurationPolicy.Infinite);
|
||||
buffClip.buffSpec = buffSpec;
|
||||
}
|
||||
}
|
||||
|
||||
if (frame == buffClip.endFrame)
|
||||
{
|
||||
if (buffClip.buffSpec != null)
|
||||
{
|
||||
_abilitySpec.Owner.RemoveGameplayEffect(buffClip.buffSpec);
|
||||
}
|
||||
|
||||
buffClip.buffSpec = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TickFrame_PassiveGameplayEffects(int frame)
|
||||
{
|
||||
// passive在TimelineAbility激活时一直生效
|
||||
foreach (var buffClip in _cachePassiveGameplayEffectTrack)
|
||||
{
|
||||
if (frame != buffClip.startFrame) continue;
|
||||
var passiveSpec = _abilitySpec.Owner.ApplyGameplayEffectToSelf(buffClip.passive, _abilitySpec.Ability.SkillId);
|
||||
passiveSpec.SetDurationPolicy(EffectsDurationPolicy.Infinite);
|
||||
buffClip.passiveSpec = passiveSpec;
|
||||
}
|
||||
}
|
||||
|
||||
private void TickFrame_OngoingTasks(int frame)
|
||||
{
|
||||
foreach (var taskClip in _cacheOngoingTaskTrack)
|
||||
{
|
||||
if (frame == taskClip.startFrame)
|
||||
{
|
||||
taskClip.task.OnStart(frame);
|
||||
}
|
||||
|
||||
if (frame >= taskClip.startFrame && frame <= taskClip.endFrame)
|
||||
{
|
||||
taskClip.task.OnTick(frame, taskClip.startFrame, taskClip.endFrame);
|
||||
}
|
||||
|
||||
if (frame == taskClip.endFrame)
|
||||
{
|
||||
taskClip.task.OnEnd(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TickFrame_PassiveTasks(int deltaTime)
|
||||
{
|
||||
foreach (var taskClip in _cachePassiveTaskTrack)
|
||||
{
|
||||
if (_currentFrame == taskClip.startFrame)
|
||||
{
|
||||
taskClip.task.OnStart();
|
||||
}
|
||||
taskClip.task.OnTick(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b17a33afb534946b70239808a6015eb
|
||||
timeCreated: 1708672766
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3cfd0d21847f461d96661a737d97d32e
|
||||
timeCreated: 1708504113
|
@@ -0,0 +1,25 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class BuffGameplayEffectTrackData : TrackDataBase
|
||||
{
|
||||
public List<BuffGameplayEffectClipEvent> clipEvents = new List<BuffGameplayEffectClipEvent>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class BuffGameplayEffectClipEvent : ClipEventBase
|
||||
{
|
||||
[FormerlySerializedAs("GameplayEffectValueId")]
|
||||
public int gameplayEffectValueId;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[UnityEngine.Serialization.FormerlySerializedAs("gameplayEffects")]
|
||||
#endif
|
||||
public GameplayEffectAsset gameplayEffect;
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5742faeb4aee4f058f69e6b0922a540d
|
||||
timeCreated: 1709018398
|
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class DurationalCueTrackData : TrackDataBase
|
||||
{
|
||||
public List<DurationalCueClipEvent> clipEvents = new List<DurationalCueClipEvent>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class DurationalCueClipEvent : ClipEventBase
|
||||
{
|
||||
public GameplayCueDurational cue;
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eda585ff2c7143d8bfcb34857b7cc068
|
||||
timeCreated: 1709017864
|
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class InstantCueTrackData : TrackDataBase
|
||||
{
|
||||
public List<InstantCueMarkEvent> markEvents = new List<InstantCueMarkEvent>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class InstantCueMarkEvent : MarkEventBase
|
||||
{
|
||||
public List<GameplayCueInstant> cues = new List<GameplayCueInstant>();
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2f9017c20dc4fc5b36fa15ba97371df
|
||||
timeCreated: 1709106070
|
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class PassiveGameplayEffectTrackData : TrackDataBase
|
||||
{
|
||||
public List<PassiveGameplayEffectClipEvent> clipEvents = new List<PassiveGameplayEffectClipEvent>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class PassiveGameplayEffectClipEvent : ClipEventBase
|
||||
{
|
||||
[FormerlySerializedAs("GameplayEffectValueId")]
|
||||
public int gameplayEffectValueId;
|
||||
public GameplayEffectAsset gameplayEffect;
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a11dfb65b3d43a5adb7dce5380d7b48
|
||||
timeCreated: 1717124072
|
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JNGame.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class PassiveTaskClipEventTrackData : TrackDataBase
|
||||
{
|
||||
public List<PassiveTaskClipEvent> clipEvents = new List<PassiveTaskClipEvent>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class PassiveTaskClipEvent : ClipEventBase
|
||||
{
|
||||
public PassiveTaskData passiveTask;
|
||||
|
||||
public PassiveAbilityTask Load()
|
||||
{
|
||||
return passiveTask.Load() as PassiveAbilityTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6df758a2d053435289ea91db6852c3cc
|
||||
timeCreated: 1717573205
|
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GAS.General;
|
||||
using JNGame.Runtime.Util;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class ReleaseGameplayEffectTrackData : TrackDataBase
|
||||
{
|
||||
public List<ReleaseGameplayEffectMarkEvent> markEvents = new List<ReleaseGameplayEffectMarkEvent>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class GameplayEffectAssetData
|
||||
{
|
||||
[FormerlySerializedAs("Id")]
|
||||
public int id;
|
||||
|
||||
[FormerlySerializedAs("Asset")]
|
||||
public GameplayEffectAsset asset;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReleaseGameplayEffectMarkEvent : MarkEventBase
|
||||
{
|
||||
public JsonData jsonTargetCatcher = new JsonData()
|
||||
{
|
||||
Type = typeof(CatchSelf).FullName // 默认 CatchSelf
|
||||
};
|
||||
|
||||
public List<GameplayEffectAssetData> gameplayEffectAssets = new List<GameplayEffectAssetData>();
|
||||
|
||||
private TargetCatcherBase _targetCatcher;
|
||||
|
||||
public TargetCatcherBase TargetCatcher
|
||||
{
|
||||
get
|
||||
{
|
||||
// 如果是反序列化的数据,没有执行构造函数, 需要加载
|
||||
var ltc = LoadTargetCatcher();
|
||||
if (ltc != null)
|
||||
{
|
||||
_targetCatcher = ltc;
|
||||
}
|
||||
|
||||
return _targetCatcher;
|
||||
}
|
||||
}
|
||||
|
||||
public void CacheTargetCatcher()
|
||||
{
|
||||
_targetCatcher = LoadTargetCatcher();
|
||||
}
|
||||
|
||||
public void SaveTargetCatcher(TargetCatcherBase targetCatcher)
|
||||
{
|
||||
var jsonData = JsonUtil.ToJson(targetCatcher);
|
||||
var dataType = targetCatcher.GetType().FullName;
|
||||
jsonTargetCatcher = new JsonData
|
||||
{
|
||||
Type = dataType,
|
||||
Data = jsonData
|
||||
};
|
||||
}
|
||||
|
||||
private TargetCatcherBase LoadTargetCatcher()
|
||||
{
|
||||
TargetCatcherBase targetCatcher = null;
|
||||
var jsonData = jsonTargetCatcher.Data;
|
||||
var dataType = jsonTargetCatcher.Type;
|
||||
|
||||
Type type = null;
|
||||
foreach (var t in TargetCatcherSonTypes)
|
||||
{
|
||||
if (t.FullName == dataType)
|
||||
{
|
||||
type = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
Debug.LogError($"[EX] TargetCatcherBase SonType not found: {dataType}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Profiler.BeginSample(
|
||||
$"{nameof(ReleaseGameplayEffectMarkEvent)}::LoadTargetCatcher() -> Activator.CreateInstance GC Alloc");
|
||||
if (string.IsNullOrEmpty(jsonData))
|
||||
{
|
||||
targetCatcher = Activator.CreateInstance(type) as TargetCatcherBase;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetCatcher = JsonUtil.ToObject(jsonData, type) as TargetCatcherBase;
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
return targetCatcher;
|
||||
}
|
||||
|
||||
#region TargetCatcher SonTypes
|
||||
|
||||
private static Type[] _targetCatcherSonTypes;
|
||||
|
||||
public static Type[] TargetCatcherSonTypes =>
|
||||
_targetCatcherSonTypes ??= TypeUtil.GetAllSonTypesOf(typeof(TargetCatcherBase));
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd623f4d1cda4cca925861de81dec26a
|
||||
timeCreated: 1709134057
|
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JNGame.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class TaskClipEventTrackData : TrackDataBase
|
||||
{
|
||||
public List<TaskClipEvent> clipEvents = new List<TaskClipEvent>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class TaskClipEvent : ClipEventBase
|
||||
{
|
||||
public OngoingTaskData ongoingTask;
|
||||
|
||||
public OngoingAbilityTask Load()
|
||||
{
|
||||
return ongoingTask.Load() as OngoingAbilityTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1768937addbc4d9f8d41e4fd0f8b244b
|
||||
timeCreated: 1709188720
|
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class TaskMarkEventTrackData : TrackDataBase
|
||||
{
|
||||
public List<TaskMarkEvent> markEvents = new List<TaskMarkEvent>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class TaskMarkEvent : MarkEventBase
|
||||
{
|
||||
[FormerlySerializedAs("InstantTasks")]
|
||||
public List<InstantTaskData> instantTasks = new List<InstantTaskData>();
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af15d283c4a24926bc40197f96a859f6
|
||||
timeCreated: 1709188733
|
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Timeline的轨道数据基类
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class TrackDataBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 编辑器下显示用,运行时无用
|
||||
/// </summary>
|
||||
public string trackName;
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a32efd9a68f4192a3531ed7c05576d5
|
||||
timeCreated: 1709018475
|
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Track上的触发事件
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class TrackEventBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 事件触发起始帧
|
||||
/// </summary>
|
||||
public int startFrame;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 瞬时事件,执行一帧
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class MarkEventBase : TrackEventBase
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 持续事件,跨多帧执行
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class ClipEventBase : TrackEventBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 持续的帧长度
|
||||
/// </summary>
|
||||
public int durationFrame;
|
||||
|
||||
/// <summary>
|
||||
/// 结束帧
|
||||
/// </summary>
|
||||
public int EndFrame => startFrame + durationFrame;
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8307d7f9f424132a2d448a75c22fa63
|
||||
timeCreated: 1708504213
|
Reference in New Issue
Block a user