mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-27 10:46:17 +00:00
崩溃了呀
This commit is contained in:
@@ -6,7 +6,7 @@ namespace GAS.Runtime
|
||||
public abstract class AbstractAbility
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly AbilityAsset DataReference;
|
||||
public readonly IAbilityAsset DataReference;
|
||||
|
||||
// TODO : AbilityTask
|
||||
// public List<OngoingAbilityTask> OngoingAbilityTasks=new List<OngoingAbilityTask>();
|
||||
@@ -20,7 +20,7 @@ namespace GAS.Runtime
|
||||
|
||||
public GameplayEffect Cost { get; protected set; }
|
||||
|
||||
public AbstractAbility(AbilityAsset abilityAsset)
|
||||
public AbstractAbility(IAbilityAsset abilityAsset)
|
||||
{
|
||||
DataReference = abilityAsset;
|
||||
|
||||
|
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JNGame.Serialization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
public abstract class TargetCatcherBase
|
||||
public abstract class TargetCatcherBase : ISerializable
|
||||
{
|
||||
public AbilitySystemComponent Owner;
|
||||
|
||||
@@ -41,5 +42,13 @@ namespace GAS.Runtime
|
||||
{
|
||||
}
|
||||
#endif
|
||||
public void Serialize(Serializer writer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Deserialize(Deserializer reader)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Timeline运行时节点枚举
|
||||
/// </summary>
|
||||
public enum EnumRuntimeClipNode : ushort
|
||||
{
|
||||
InstantGE = 1, // 直接添加一个GE效果,GE的时限效果由GE自己决定
|
||||
DurationalGE, // 持续性GE效果,Timeline控制其生命周期
|
||||
|
||||
InstantTask, // 瞬时的Task,Task可以理解为Condition+GE,判断条件,决定是否触发GE
|
||||
DurationalTask, // 持续一段时间的Task,Timeline控制其生命周期
|
||||
|
||||
PassiveGE, // 被动GE,Timeline只负责添加,不负责销毁,外部手动控制
|
||||
PassiveTask, // 被动Task,Timeline只负责添加,不负责销毁,外部手动控制
|
||||
|
||||
InstantCue, // 直接触发一个GameplayCue
|
||||
DurationalCue, // 持续型GameplayCue,Timeline控制其生命周期
|
||||
|
||||
EnumBuiltinCount = 100, // 内建行为树节点的类型上限,上层业务自行扩展的节点由此递增
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e5fff7d0f654e88af64865debbcaf7c
|
||||
timeCreated: 1729526089
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f1af82c0b5748feb2aa43dd183fd279
|
||||
timeCreated: 1729526102
|
@@ -0,0 +1,190 @@
|
||||
// Timeline节点的数据序列化
|
||||
|
||||
using JNGame.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
public partial struct LinkGEAsset : ISerializable
|
||||
{
|
||||
public void Deserialize(Deserializer reader)
|
||||
{
|
||||
valueId = reader.ReadInt32();
|
||||
linkAssetLocation = reader.ReadString();
|
||||
}
|
||||
|
||||
public readonly void Serialize(Serializer writer)
|
||||
{
|
||||
writer.Write(valueId);
|
||||
writer.Write(linkAssetLocation);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class RuntimeClipNode : ISerializable
|
||||
{
|
||||
public virtual void Deserialize(Deserializer reader)
|
||||
{
|
||||
startFrame = reader.ReadInt32();
|
||||
durationalFrame = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public virtual void Serialize(Serializer writer)
|
||||
{
|
||||
writer.Write(startFrame);
|
||||
writer.Write(durationalFrame);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class InstantGEClipNode
|
||||
{
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
// 目标捕获器
|
||||
ushort targetCatcherType = reader.ReadUInt16();
|
||||
targetCatcher = TargetCatcherFactory.CreateNode(targetCatcherType);
|
||||
targetCatcher.Deserialize(reader);
|
||||
// GE配置
|
||||
int length = reader.ReadInt32();
|
||||
linkGEAssets = new LinkGEAsset[length];
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
linkGEAssets[i].Deserialize(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
// 目标捕获器
|
||||
writer.Write(targetCatcher.TypeId);
|
||||
targetCatcher.Serialize(writer);
|
||||
// GE配置
|
||||
writer.Write(linkGEAssets.Length);
|
||||
for (int i = 0; i < linkGEAssets.Length; ++i)
|
||||
{
|
||||
linkGEAssets[i].Serialize(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class DurationalGEClipNode
|
||||
{
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
linkGEAsset = new LinkGEAsset();
|
||||
linkGEAsset.Deserialize(reader);
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
linkGEAsset.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class InstantTaskClipNode
|
||||
{
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
ushort typeId = reader.ReadUInt16();
|
||||
instantTask = AbilityTaskFactory.CreateInstantTask(typeId);
|
||||
instantTask.Deserialize(reader);
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(instantTask.TypeId);
|
||||
instantTask.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class DurationalTaskClipNode
|
||||
{
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
ushort typeId = reader.ReadUInt16();
|
||||
ongoingTask = AbilityTaskFactory.CreateOngoingTask(typeId);
|
||||
ongoingTask.Deserialize(reader);
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(ongoingTask.TypeId);
|
||||
ongoingTask.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class PassiveGEClipNode
|
||||
{
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
linkGEAsset = new LinkGEAsset();
|
||||
linkGEAsset.Deserialize(reader);
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
linkGEAsset.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class PassiveTaskClipNode
|
||||
{
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
ushort typeId = reader.ReadUInt16();
|
||||
passiveTask = AbilityTaskFactory.CreatePassiveTask(typeId);
|
||||
passiveTask.Deserialize(reader);
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(passiveTask.TypeId);
|
||||
passiveTask.Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class InstantCueClipNode
|
||||
{
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int count = reader.ReadUInt16();
|
||||
cueAssetLocations = new string[count];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
cueAssetLocations[i] = reader.ReadString();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(cueAssetLocations);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class DurationalCueClipNode
|
||||
{
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
cueAssetLocation = reader.ReadString();
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(cueAssetLocation);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7137dd96f3d58434fa035d073b5881eb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9d23e0917784dbba3773f52463eb252
|
||||
timeCreated: 1729526102
|
@@ -0,0 +1,47 @@
|
||||
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 持续型Cue节点
|
||||
/// </summary>
|
||||
public partial class DurationalCueClipNode : RuntimeClipNode
|
||||
{
|
||||
public override ushort TypeId => (ushort)EnumRuntimeClipNode.DurationalCue;
|
||||
|
||||
#region 序列化字段
|
||||
|
||||
/// <summary>
|
||||
/// 关联的Cue资源
|
||||
/// </summary>
|
||||
public string cueAssetLocation;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 表现层返回的Cue实例索引ID,用于逻辑层通知表现层移除使用,与逻辑层业务逻辑无关
|
||||
/// </summary>
|
||||
private int m_CueIndex = -1;
|
||||
|
||||
protected override void OnStart(TimelineWorkingContext workingContext)
|
||||
{
|
||||
if (workingContext == null || workingContext.OwnerAbility == null || workingContext.OwnerAbility.Owner == null)
|
||||
{
|
||||
Debug.Log("error");
|
||||
}
|
||||
m_CueIndex = workingContext.OwnerAbility.Owner.OnCueAdd(workingContext.OwnerAbility, cueAssetLocation);
|
||||
}
|
||||
|
||||
protected override void OnEnd(TimelineWorkingContext workingContext)
|
||||
{
|
||||
if (m_CueIndex < 0) { return; }
|
||||
workingContext.OwnerAbility.Owner.OnCueRemove(workingContext.OwnerAbility, m_CueIndex);
|
||||
m_CueIndex = -1;
|
||||
}
|
||||
|
||||
protected override void OnDestroy(TimelineWorkingContext workingContext)
|
||||
{
|
||||
OnEnd(workingContext);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68623f73aa1255d419c86dc8d08d246c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,52 @@
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 直接添加一个GE效果,GE的时限效果由GE自己决定
|
||||
/// </summary>
|
||||
public sealed partial class DurationalGEClipNode : RuntimeClipNode
|
||||
{
|
||||
public override ushort TypeId => (ushort)EnumRuntimeClipNode.DurationalGE;
|
||||
|
||||
#region 序列化数据
|
||||
|
||||
public LinkGEAsset linkGEAsset;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 持续性GE实例
|
||||
/// </summary>
|
||||
private GameplayEffectSpec m_EffectSpec;
|
||||
|
||||
protected override void OnStart(TimelineWorkingContext workingContext)
|
||||
{
|
||||
IGameplayEffectData geAsset = workingContext.GetGASResourceService().GetGameplayEffectData(linkGEAsset.linkAssetLocation);
|
||||
if (geAsset == null) { return; }
|
||||
// 只有持续型的GameplayEffect可视作buff
|
||||
if (geAsset.DurationPolicy is EffectsDurationPolicy.Duration or EffectsDurationPolicy.Infinite)
|
||||
{
|
||||
GameplayEffect ge = new GameplayEffect(geAsset, linkGEAsset.valueId);
|
||||
GameplayEffectSpec buffSpec = workingContext.OwnerAbility.Owner.ApplyGameplayEffectToSelf(ge, workingContext.OwnerAbility.Ability.SkillId);
|
||||
if (buffSpec != null)
|
||||
{ // buff持续时间以Timeline配置时间为准(执行策略全部改为Infinite)
|
||||
buffSpec.SetDurationPolicy(EffectsDurationPolicy.Infinite);
|
||||
m_EffectSpec = buffSpec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnEnd(TimelineWorkingContext workingContext)
|
||||
{
|
||||
if (m_EffectSpec == null) { return; }
|
||||
workingContext.OwnerAbility.Owner.RemoveGameplayEffect(m_EffectSpec);
|
||||
m_EffectSpec = null;
|
||||
}
|
||||
|
||||
protected override void OnDestroy(TimelineWorkingContext workingContext)
|
||||
{
|
||||
// 防止Timeline被打断执行,没有执行OnEnd
|
||||
OnEnd(workingContext);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73748f3e49399294c93c815c9bd90173
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,45 @@
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 瞬时Task节点
|
||||
/// </summary>
|
||||
public partial class DurationalTaskClipNode : RuntimeClipNode
|
||||
{
|
||||
public override ushort TypeId => (ushort)EnumRuntimeClipNode.DurationalTask;
|
||||
|
||||
#region 序列化字段
|
||||
|
||||
public OngoingAbilityTask ongoingTask;
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void OnAwake(TimelineWorkingContext workingContext)
|
||||
{
|
||||
ongoingTask.Init(workingContext.OwnerAbility);
|
||||
}
|
||||
|
||||
protected override void OnStart(TimelineWorkingContext workingContext)
|
||||
{
|
||||
ongoingTask.Init(workingContext.OwnerAbility);
|
||||
ongoingTask?.OnStart(workingContext.CurrentFrame);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(TimelineWorkingContext workingContext, int deltaTime)
|
||||
{
|
||||
ongoingTask?.OnTick(workingContext.CurrentFrame, startFrame, EndFrame);
|
||||
}
|
||||
|
||||
protected override void OnEnd(TimelineWorkingContext workingContext)
|
||||
{
|
||||
ongoingTask?.OnEnd(workingContext.CurrentFrame);
|
||||
}
|
||||
|
||||
protected override void OnDestroy(TimelineWorkingContext workingContext)
|
||||
{
|
||||
// 防止Timeline被打断执行,没有执行OnEnd
|
||||
ongoingTask?.OnEnd(EndFrame);
|
||||
ongoingTask?.Clear();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ccc58d735ca245c4dbc2545104b20811
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,22 @@
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 瞬时Cue节点
|
||||
/// </summary>
|
||||
public partial class InstantCueClipNode : RuntimeClipNode
|
||||
{
|
||||
public override ushort TypeId => (ushort)EnumRuntimeClipNode.InstantCue;
|
||||
|
||||
#region 序列化字段
|
||||
|
||||
public string[] cueAssetLocations;
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void OnStart(TimelineWorkingContext workingContext)
|
||||
{
|
||||
workingContext.OwnerAbility.Owner.OnCueExecute(workingContext.OwnerAbility, cueAssetLocations);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fa54cf9f74fa1c40be8ce5651dbab5d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,45 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 直接添加一个GE效果,GE的时限效果由GE自己决定
|
||||
/// </summary>
|
||||
public sealed partial class InstantGEClipNode : RuntimeClipNode
|
||||
{
|
||||
public override ushort TypeId => (ushort)EnumRuntimeClipNode.InstantGE;
|
||||
|
||||
#region 序列化数据
|
||||
|
||||
/// <summary>
|
||||
/// 关联的GE资源标识
|
||||
/// </summary>
|
||||
public LinkGEAsset[] linkGEAssets;
|
||||
|
||||
/// <summary>
|
||||
/// 目标捕获器
|
||||
/// </summary>
|
||||
public TargetCatcherBase targetCatcher;
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void OnStart(TimelineWorkingContext workingContext)
|
||||
{
|
||||
// 初始化目标捕获器,筛选GE的作用目标
|
||||
targetCatcher.Init(workingContext.OwnerAbility.Owner);
|
||||
targetCatcher.CatchTargetsNonAllocSafe(workingContext.OwnerAbility.Target, workingContext.Targets);
|
||||
// 添加GE
|
||||
foreach (var asc in workingContext.Targets)
|
||||
{
|
||||
foreach (var linkGEInfo in linkGEAssets)
|
||||
{
|
||||
IGameplayEffectData geAssetData = workingContext.GetGASResourceService().GetGameplayEffectData(linkGEInfo.linkAssetLocation);
|
||||
var ge = new GameplayEffect(geAssetData, linkGEInfo.valueId);
|
||||
workingContext.OwnerAbility.Owner.ApplyGameplayEffectTo(ge, asc, workingContext.OwnerAbility.Ability.SkillId);
|
||||
}
|
||||
}
|
||||
workingContext.Targets.Clear();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 558296a0eeb98f843aa2149d21834cca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,32 @@
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 瞬时Task节点
|
||||
/// </summary>
|
||||
public partial class InstantTaskClipNode : RuntimeClipNode
|
||||
{
|
||||
public override ushort TypeId => (ushort)EnumRuntimeClipNode.InstantTask;
|
||||
|
||||
#region 序列化字段
|
||||
|
||||
public InstantAbilityTask instantTask;
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void OnAwake(TimelineWorkingContext workingContext)
|
||||
{
|
||||
instantTask.Init(workingContext.OwnerAbility);
|
||||
}
|
||||
|
||||
protected override void OnStart(TimelineWorkingContext workingContext)
|
||||
{
|
||||
instantTask?.OnExecute();
|
||||
}
|
||||
|
||||
protected override void OnDestroy(TimelineWorkingContext workingContext)
|
||||
{
|
||||
instantTask.Clear();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcf8748d66384df458536a0246f1858f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,49 @@
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 被动持续的GE效果节点,不随Timline播放结束而结束
|
||||
/// </summary>
|
||||
public partial class PassiveGEClipNode : RuntimeClipNode
|
||||
{
|
||||
public override ushort TypeId => (ushort)EnumRuntimeClipNode.PassiveGE;
|
||||
|
||||
#region 序列化数据
|
||||
|
||||
/// <summary>
|
||||
/// 关联的GE配置
|
||||
/// </summary>
|
||||
public LinkGEAsset linkGEAsset;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 持续性GE实例
|
||||
/// </summary>
|
||||
private GameplayEffectSpec m_EffectSpec;
|
||||
|
||||
protected override void OnStart(TimelineWorkingContext workingContext)
|
||||
{
|
||||
IGameplayEffectData geAsset = workingContext.GetGASResourceService().GetGameplayEffectData(linkGEAsset.linkAssetLocation);
|
||||
if (geAsset == null) { return; }
|
||||
// 只有持续型的GameplayEffect可视作Passive
|
||||
if (geAsset.DurationPolicy is EffectsDurationPolicy.Duration or EffectsDurationPolicy.Infinite)
|
||||
{
|
||||
GameplayEffect ge = new GameplayEffect(geAsset, linkGEAsset.valueId);
|
||||
GameplayEffectSpec buffSpec = workingContext.OwnerAbility.Owner.ApplyGameplayEffectToSelf(ge, workingContext.OwnerAbility.Ability.SkillId);
|
||||
if (buffSpec != null)
|
||||
{ // passive在TimelineAbility激活时一直生效
|
||||
buffSpec.SetDurationPolicy(EffectsDurationPolicy.Infinite);
|
||||
m_EffectSpec = buffSpec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDestroy(TimelineWorkingContext workingContext)
|
||||
{
|
||||
if (m_EffectSpec == null) { return; }
|
||||
workingContext.OwnerAbility.Owner.RemoveGameplayEffect(m_EffectSpec);
|
||||
m_EffectSpec = null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5784d2561744253419d2cd63af70f7a7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,38 @@
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 被动持续的Task节点,不随Timline播放结束而结束
|
||||
/// </summary>
|
||||
public partial class PassiveTaskClipNode : RuntimeClipNode
|
||||
{
|
||||
public override ushort TypeId => (ushort)EnumRuntimeClipNode.PassiveTask;
|
||||
|
||||
#region 序列化字段
|
||||
|
||||
public PassiveAbilityTask passiveTask;
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void OnAwake(TimelineWorkingContext workingContext)
|
||||
{
|
||||
passiveTask.Init(workingContext.OwnerAbility);
|
||||
}
|
||||
|
||||
protected override void OnStart(TimelineWorkingContext workingContext)
|
||||
{
|
||||
passiveTask?.OnStart();
|
||||
}
|
||||
|
||||
protected override void OnUpdate(TimelineWorkingContext workingContext, int deltaTime)
|
||||
{
|
||||
passiveTask?.OnTick(deltaTime);
|
||||
}
|
||||
|
||||
protected override void OnDestroy(TimelineWorkingContext workingContext)
|
||||
{
|
||||
passiveTask?.OnEnd();
|
||||
passiveTask?.Clear();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b679e7a8b1b2e5f40925c990cd6d1c4f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,88 @@
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Timeline节点基类
|
||||
/// </summary>
|
||||
public abstract partial class RuntimeClipNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Timeline的节点类型
|
||||
/// </summary>
|
||||
public virtual ushort TypeId => 0;
|
||||
|
||||
#region 序列化字段
|
||||
|
||||
/// <summary>
|
||||
/// 开始执行帧
|
||||
/// </summary>
|
||||
public int startFrame;
|
||||
|
||||
/// <summary>
|
||||
/// 持续帧长度
|
||||
/// </summary>
|
||||
public int durationalFrame;
|
||||
|
||||
/// <summary>
|
||||
/// 结束执行帧
|
||||
/// </summary>
|
||||
public int EndFrame => startFrame + durationalFrame;
|
||||
|
||||
#endregion
|
||||
|
||||
public void Awake(TimelineWorkingContext workingContext)
|
||||
{
|
||||
OnAwake(workingContext);
|
||||
}
|
||||
|
||||
public void Start(TimelineWorkingContext workingContext)
|
||||
{
|
||||
OnStart(workingContext);
|
||||
}
|
||||
|
||||
public void Update(TimelineWorkingContext workingContext, int deltaTime)
|
||||
{
|
||||
OnUpdate(workingContext, deltaTime);
|
||||
}
|
||||
|
||||
public void End(TimelineWorkingContext workingContext)
|
||||
{
|
||||
OnEnd(workingContext);
|
||||
}
|
||||
|
||||
public void Destroy(TimelineWorkingContext workingContext)
|
||||
{
|
||||
OnDestroy(workingContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Timeline节点初始化
|
||||
/// </summary>
|
||||
/// <param name="workingContext"></param>
|
||||
protected virtual void OnAwake(TimelineWorkingContext workingContext)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Timeline节点开始触发
|
||||
/// </summary>
|
||||
protected abstract void OnStart(TimelineWorkingContext workingContext);
|
||||
|
||||
/// <summary>
|
||||
/// Timeline节点持续Tick
|
||||
/// </summary>
|
||||
/// <param name="deltaTime"></param>
|
||||
protected virtual void OnUpdate(TimelineWorkingContext workingContext, int deltaTime) { }
|
||||
|
||||
/// <summary>
|
||||
/// Timeline节点结束
|
||||
/// </summary>
|
||||
protected virtual void OnEnd(TimelineWorkingContext workingContext) { }
|
||||
|
||||
/// <summary>
|
||||
/// Timeline执行结束,清理操作
|
||||
/// </summary>
|
||||
/// <param name="workingContext"></param>
|
||||
protected virtual void OnDestroy(TimelineWorkingContext workingContext) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad651df4e15d4a36a37f0f3df0ba5f79
|
||||
timeCreated: 1729526089
|
@@ -0,0 +1,104 @@
|
||||
|
||||
|
||||
using JNGame.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Timeline运行结构描述,通过二进制文件反序列化而来
|
||||
/// </summary>
|
||||
public sealed class TimelineInfo : ISerializable
|
||||
{
|
||||
/// <summary>
|
||||
/// Timeline总帧长度
|
||||
/// </summary>
|
||||
public int speed;
|
||||
|
||||
/// <summary>
|
||||
/// Timeline总帧长度
|
||||
/// </summary>
|
||||
public int frameCount;
|
||||
|
||||
/// <summary>
|
||||
/// 是否手动结束Timeline
|
||||
/// </summary>
|
||||
public bool manualEndAbility;
|
||||
|
||||
/// <summary>
|
||||
/// Timeline节点的原生序列化数据
|
||||
/// </summary>
|
||||
public byte[] timelineBytes;
|
||||
|
||||
private Deserializer m_RealtimeReader;
|
||||
|
||||
public RuntimeClipNode[] CreateRealTimeClipNode()
|
||||
{
|
||||
m_RealtimeReader ??= new Deserializer();
|
||||
m_RealtimeReader.SetSource(timelineBytes);
|
||||
int length = m_RealtimeReader.ReadUInt16();
|
||||
RuntimeClipNode[] runtimeClipNodes = new RuntimeClipNode[length];
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
ushort typeId = m_RealtimeReader.ReadUInt16();
|
||||
RuntimeClipNode node = TimelineNodeFactory.CreateNode(typeId);
|
||||
node.Deserialize(m_RealtimeReader);
|
||||
runtimeClipNodes[i] = node;
|
||||
}
|
||||
|
||||
return runtimeClipNodes;
|
||||
}
|
||||
|
||||
public void Deserialize(Deserializer reader)
|
||||
{
|
||||
manualEndAbility = reader.ReadBoolean();
|
||||
frameCount = reader.ReadInt32();
|
||||
timelineBytes = reader.ReadArray(timelineBytes);
|
||||
}
|
||||
|
||||
public void Serialize(Serializer writer)
|
||||
{
|
||||
writer.Write(manualEndAbility);
|
||||
writer.Write(frameCount);
|
||||
writer.Write(timelineBytes);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Timeline的节点,按时序排序,编辑器下检查序列化是否一致使用
|
||||
/// </summary>
|
||||
public RuntimeClipNode[] runtimeClipNodes;
|
||||
|
||||
public void DeserializeForEditor(Deserializer reader)
|
||||
{
|
||||
manualEndAbility = reader.ReadBoolean();
|
||||
frameCount = reader.ReadInt32();
|
||||
reader.ReadUInt16();
|
||||
int length = reader.ReadUInt16();
|
||||
runtimeClipNodes = new RuntimeClipNode[length];
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
ushort typeId = reader.ReadUInt16();
|
||||
RuntimeClipNode node = TimelineNodeFactory.CreateNode(typeId);
|
||||
node.Deserialize(reader);
|
||||
runtimeClipNodes[i] = node;
|
||||
}
|
||||
}
|
||||
|
||||
public void SerializeForEditor(Serializer writer)
|
||||
{
|
||||
writer.Write(manualEndAbility);
|
||||
writer.Write(frameCount);
|
||||
Serializer timelineWriter = new Serializer();
|
||||
ushort length = (ushort)(runtimeClipNodes == null ? 0 : runtimeClipNodes.Length);
|
||||
timelineWriter.Write(length);
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
timelineWriter.Write(runtimeClipNodes[i].TypeId);
|
||||
runtimeClipNodes[i].Serialize(timelineWriter);
|
||||
}
|
||||
writer.Write(timelineWriter.CopyData());
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 543a951e473f42f5b8a85dbef59b2e66
|
||||
timeCreated: 1729525953
|
@@ -0,0 +1,52 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
public partial class TimelineNodeFactory
|
||||
{
|
||||
public delegate RuntimeClipNode NodeCreateFunc();
|
||||
|
||||
private static readonly Dictionary<ushort, NodeCreateFunc> s_TypeId2FactoryFunc;
|
||||
|
||||
static TimelineNodeFactory()
|
||||
{
|
||||
s_TypeId2FactoryFunc = new Dictionary<ushort, NodeCreateFunc>();
|
||||
Register((ushort)EnumRuntimeClipNode.InstantGE, () => new InstantGEClipNode());
|
||||
Register((ushort)EnumRuntimeClipNode.DurationalGE, () => new DurationalGEClipNode());
|
||||
Register((ushort)EnumRuntimeClipNode.InstantTask, () => new InstantTaskClipNode());
|
||||
Register((ushort)EnumRuntimeClipNode.DurationalTask, () => new DurationalTaskClipNode());
|
||||
Register((ushort)EnumRuntimeClipNode.PassiveGE, () => new PassiveGEClipNode());
|
||||
Register((ushort)EnumRuntimeClipNode.PassiveTask, () => new PassiveTaskClipNode());
|
||||
Register((ushort)EnumRuntimeClipNode.InstantCue, () => new InstantCueClipNode());
|
||||
Register((ushort)EnumRuntimeClipNode.DurationalCue, () => new DurationalCueClipNode());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册Timeline节点类型构造方法
|
||||
/// </summary>
|
||||
/// <param name="typeId"></param>
|
||||
/// <param name="func"></param>
|
||||
public static void Register(ushort typeId, NodeCreateFunc func)
|
||||
{
|
||||
s_TypeId2FactoryFunc[typeId] = func;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过节点类型创建Timeline节点
|
||||
/// </summary>
|
||||
/// <param name="typeId">Timeline节点类型</param>
|
||||
/// <returns></returns>
|
||||
public static RuntimeClipNode CreateNode(ushort typeId)
|
||||
{
|
||||
if (!s_TypeId2FactoryFunc.ContainsKey(typeId))
|
||||
{
|
||||
Debug.LogError($"Can Not Find TimelineClipNode Factory Function Id={typeId}");
|
||||
return null;
|
||||
}
|
||||
return s_TypeId2FactoryFunc[typeId]();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40797c0cb6a6439789f4a19cbca1b726
|
||||
timeCreated: 1729526094
|
@@ -0,0 +1,153 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 运行时的Timeline实例
|
||||
/// <para>包含反序列化的Timeline结构描述TimelineAsset(运行时不变),不同Timeline实例可指向同一TimelineAsset</para>
|
||||
/// </summary>
|
||||
public sealed class TimelinePlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// Timeline结构描述配置信息,二进制文件读入
|
||||
/// </summary>
|
||||
private TimelineInfo m_TimelineInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Timeline运行时数据,可在Timeline各节点间互相范围的公共数据
|
||||
/// </summary>
|
||||
private TimelineWorkingContext m_WorkingContext;
|
||||
public TimelineWorkingContext WorkingContext => m_WorkingContext;
|
||||
|
||||
public bool IsInitialized { get; private set; }
|
||||
public bool IsPlaying { get; private set; }
|
||||
|
||||
private RuntimeClipNode[] m_RuntimeClipNode;
|
||||
|
||||
private List<PassiveTaskClipNode> m_PassiveTaskNodes;
|
||||
|
||||
public void DoAwake(TimelineAbilitySpec abilitySpec)
|
||||
{
|
||||
IsInitialized = false;
|
||||
ITimelineAbilityAsset abilityAsset = abilitySpec.Ability.DataReference as ITimelineAbilityAsset;
|
||||
if (abilityAsset == null)
|
||||
{
|
||||
Debug.LogError($"AbilityTimeline异常,没有找到对应的Timeline技能配置,{abilitySpec.Ability.Name}");
|
||||
return;
|
||||
}
|
||||
m_WorkingContext = new TimelineWorkingContext(abilitySpec);
|
||||
m_TimelineInfo = abilityAsset.TimelineAbilityInfo;
|
||||
m_RuntimeClipNode = m_TimelineInfo.CreateRealTimeClipNode();
|
||||
// Passive缓存,需要在PlayEnd后继续Tick
|
||||
m_PassiveTaskNodes = new List<PassiveTaskClipNode>();
|
||||
for (int i = 0; i < m_RuntimeClipNode.Length; ++i)
|
||||
{
|
||||
if (m_RuntimeClipNode[i] is PassiveTaskClipNode passiveTaskClipNode)
|
||||
{
|
||||
m_PassiveTaskNodes.Add(passiveTaskClipNode);
|
||||
}
|
||||
}
|
||||
IsInitialized = true;
|
||||
IsPlaying = false;
|
||||
}
|
||||
|
||||
public void DoUpdate(int deltaTime)
|
||||
{
|
||||
if (!IsInitialized) { return; }
|
||||
|
||||
if (!IsPlaying)
|
||||
{ // 播放结束,仍然执行PassiveTask的Tick
|
||||
if (WorkingContext.CurrentFrame >= m_TimelineInfo.frameCount)
|
||||
{
|
||||
TickPassiveTask(deltaTime);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
WorkingContext.TotalRunTime += deltaTime;
|
||||
var targetFrame = WorkingContext.TotalRunTime / JexGasManager.FrameRate;
|
||||
while (WorkingContext.CurrentFrame < targetFrame)
|
||||
{
|
||||
++WorkingContext.CurrentFrame;
|
||||
TickNormal(WorkingContext.CurrentFrame, deltaTime);
|
||||
}
|
||||
if (WorkingContext.CurrentFrame >= m_TimelineInfo.frameCount)
|
||||
{ // 执行到最后一帧
|
||||
OnPlayEnd();
|
||||
}
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
if (!IsInitialized) { return; }
|
||||
m_WorkingContext.CurrentFrame = -1; // 为了播放第0帧
|
||||
m_WorkingContext.TotalRunTime = 0;
|
||||
foreach (var timelineNode in m_RuntimeClipNode)
|
||||
{
|
||||
timelineNode.Awake(m_WorkingContext);
|
||||
}
|
||||
IsPlaying = true;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (!IsInitialized) { return; }
|
||||
|
||||
foreach (RuntimeClipNode clipNode in m_RuntimeClipNode)
|
||||
{
|
||||
clipNode.Destroy(m_WorkingContext);
|
||||
}
|
||||
IsPlaying = false;
|
||||
// m_WorkingContext = null;
|
||||
// m_TimelineInfo = null;
|
||||
// m_PassiveTaskNodes = null;
|
||||
// IsInitialized = false;
|
||||
}
|
||||
|
||||
private void TickNormal(int currentFrame, int deltaTime)
|
||||
{
|
||||
foreach (RuntimeClipNode clipNode in m_RuntimeClipNode)
|
||||
{
|
||||
if (currentFrame == clipNode.startFrame)
|
||||
{
|
||||
clipNode.Start(m_WorkingContext);
|
||||
}
|
||||
if (currentFrame >= clipNode.startFrame && currentFrame <= clipNode.EndFrame)
|
||||
{
|
||||
clipNode.Update(m_WorkingContext, deltaTime);
|
||||
}
|
||||
if (currentFrame == clipNode.EndFrame)
|
||||
{
|
||||
clipNode.End(m_WorkingContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TickPassiveTask(int deltaTime)
|
||||
{
|
||||
int currentFrame = WorkingContext.CurrentFrame;
|
||||
for (int i = 0; i < m_PassiveTaskNodes.Count; ++i)
|
||||
{
|
||||
if (currentFrame == m_PassiveTaskNodes[i].startFrame)
|
||||
{
|
||||
m_PassiveTaskNodes[i].Start(m_WorkingContext);
|
||||
}
|
||||
m_PassiveTaskNodes[i].Update(m_WorkingContext, deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Timeline播放到最后一帧
|
||||
/// </summary>
|
||||
private void OnPlayEnd()
|
||||
{
|
||||
IsPlaying = false;
|
||||
if (!m_TimelineInfo.manualEndAbility)
|
||||
{
|
||||
m_WorkingContext.OwnerAbility.TryEndAbility();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a708ca560d114d338204c891f7279de4
|
||||
timeCreated: 1729525947
|
@@ -0,0 +1,43 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Lockstep.GAS;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Timeline运行时上下文数据,可在Timeline各节点间共享数据
|
||||
/// </summary>
|
||||
public class TimelineWorkingContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 关联的Ability运行时实例
|
||||
/// </summary>
|
||||
public TimelineAbilitySpec OwnerAbility { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// GE作用目标集
|
||||
/// </summary>
|
||||
private readonly List<AbilitySystemComponent> m_Targets = new List<AbilitySystemComponent>();
|
||||
public List<AbilitySystemComponent> Targets => m_Targets;
|
||||
|
||||
/// <summary>
|
||||
/// Timeline当前推进到的帧
|
||||
/// </summary>
|
||||
public int CurrentFrame { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timeline当前累计执行时长
|
||||
/// </summary>
|
||||
public int TotalRunTime { get; internal set; }
|
||||
|
||||
public TimelineWorkingContext(TimelineAbilitySpec abilitySpec)
|
||||
{
|
||||
OwnerAbility = abilitySpec;
|
||||
}
|
||||
|
||||
public IGASResourceService GetGASResourceService()
|
||||
{
|
||||
return OwnerAbility.Owner.GASResService;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12ee977f578c48c0863340e8375d89f9
|
||||
timeCreated: 1729526059
|
@@ -1,6 +1,8 @@
|
||||
namespace GAS.Runtime
|
||||
using JNGame.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
public abstract class AbilityTaskBase
|
||||
public abstract class AbilityTaskBase : ISerializable
|
||||
{
|
||||
protected AbilitySpec _spec;
|
||||
public AbilitySpec Spec => _spec;
|
||||
@@ -8,5 +10,18 @@
|
||||
{
|
||||
_spec = spec;
|
||||
}
|
||||
public virtual void Clear()
|
||||
{
|
||||
// m_Spec = null;
|
||||
}
|
||||
|
||||
public void Serialize(Serializer writer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Deserialize(Deserializer reader)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -68,9 +68,9 @@ namespace GAS.Runtime
|
||||
/// <summary>
|
||||
/// 这是一个最朴素的TimelineAbility实现, 如果要实现更复杂的TimelineAbility, 请用TimelineAbilityT和TimelineAbilitySpecT为基类
|
||||
/// </summary>
|
||||
public sealed class TimelineAbility : TimelineAbilityT<TimelineAbilityAsset>
|
||||
public sealed class TimelineAbility : AbstractAbility
|
||||
{
|
||||
public TimelineAbility(TimelineAbilityAsset abilityAsset) : base(abilityAsset)
|
||||
public TimelineAbility(ITimelineAbilityAsset abilityAsset) : base(abilityAsset)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -83,10 +83,48 @@ namespace GAS.Runtime
|
||||
/// <summary>
|
||||
/// 这是一个最朴素的TimelineAbilitySpec实现, 如果要实现更复杂的TimelineAbility, 请用TimelineAbilityT和TimelineAbilitySpecT为基类
|
||||
/// </summary>
|
||||
public sealed class TimelineAbilitySpec : TimelineAbilitySpecT<TimelineAbilityT<TimelineAbilityAsset>, TimelineAbilityAsset>
|
||||
public sealed class TimelineAbilitySpec : AbilitySpec
|
||||
{
|
||||
public TimelineAbilitySpec(TimelineAbilityT<TimelineAbilityAsset> ability, AbilitySystemComponent owner) : base(ability, owner)
|
||||
|
||||
/// <summary>
|
||||
/// 每个基于Timeline调度的技能实例,都有一个TimelinePlayer
|
||||
/// </summary>
|
||||
private readonly TimelinePlayer _player;
|
||||
|
||||
/// <summary>
|
||||
/// 指向性技能的作用目标
|
||||
/// </summary>
|
||||
public AbilitySystemComponent Target { get; private set; }
|
||||
|
||||
public TimelineAbilitySpec(TimelineAbility ability, AbilitySystemComponent owner) : base(ability, owner)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetAbilityTarget(AbilitySystemComponent mainTarget)
|
||||
{
|
||||
Target = mainTarget;
|
||||
}
|
||||
|
||||
public override void ActivateAbility()
|
||||
{
|
||||
_player.Play();
|
||||
}
|
||||
|
||||
public override void CancelAbility()
|
||||
{
|
||||
_player.Stop();
|
||||
}
|
||||
|
||||
public override void EndAbility()
|
||||
{
|
||||
_player.Stop();
|
||||
}
|
||||
|
||||
protected override void AbilityTick(int dt)
|
||||
{
|
||||
Profiler.BeginSample("TimelineAbilitySpecT<T>::AbilityTick()");
|
||||
_player.DoUpdate(dt);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using GAS.General;
|
||||
using JNGame.Math;
|
||||
using JNGame.Runtime.GAS;
|
||||
using Lockstep.GAS;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Runtime
|
||||
@@ -29,6 +30,11 @@ namespace GAS.Runtime
|
||||
|
||||
private bool _ready;
|
||||
|
||||
/// <summary>
|
||||
/// GAS资源服务
|
||||
/// </summary>
|
||||
public IGASResourceService GASResService { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建
|
||||
/// </summary>
|
||||
|
@@ -0,0 +1,80 @@
|
||||
|
||||
using GAS.Runtime;
|
||||
using System.Collections.Generic;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace Lockstep.GAS
|
||||
{
|
||||
/// <summary>
|
||||
/// GAS相关的逻辑层资源Service
|
||||
/// </summary>
|
||||
public interface IGASResourceService
|
||||
{
|
||||
/// <summary>
|
||||
/// 缓存全部的GE配置
|
||||
/// </summary>
|
||||
/// <param name="dictGEAssets"></param>
|
||||
void SetGameplayEffectData(Dictionary<string, IGameplayEffectData> dictGEAssets);
|
||||
|
||||
/// <summary>
|
||||
/// 缓存全部的GA配置
|
||||
/// </summary>
|
||||
/// <param name="dictGEAssets"></param>
|
||||
void SetAbilityAssetData(Dictionary<string, PureTimelineAbilityAsset> dictGAAssets);
|
||||
|
||||
/// <summary>
|
||||
/// 缓存全部的ASCPreset配置
|
||||
/// </summary>
|
||||
/// <param name="dictASCAssets"></param>
|
||||
void SetASCPresetAssetData(Dictionary<string, PureASCPresetAsset> dictASCAssets);
|
||||
|
||||
/// <summary>
|
||||
/// 获取GE配置
|
||||
/// </summary>
|
||||
/// <param name="geAssetLocation"></param>
|
||||
/// <returns></returns>
|
||||
IGameplayEffectData GetGameplayEffectData(string geAssetLocation);
|
||||
|
||||
/// <summary>
|
||||
/// 获取GA配置
|
||||
/// </summary>
|
||||
/// <param name="gaAssetLocation"></param>
|
||||
/// <returns></returns>
|
||||
PureTimelineAbilityAsset GetTimelineAbilityAsset(string gaAssetLocation);
|
||||
|
||||
/// <summary>
|
||||
/// 获取ASC预设配置
|
||||
/// </summary>
|
||||
/// <param name="ascAssetLocation"></param>
|
||||
/// <returns></returns>
|
||||
PureASCPresetAsset GetASCPresetAsset(string ascAssetLocation);
|
||||
|
||||
/// <summary>
|
||||
/// 创建运行时GE数据
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
GameplayEffect CreateRuntimeGE(string key);
|
||||
|
||||
/// <summary>
|
||||
/// 创建运行时GE数据
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
GameplayEffect CreateRuntimeGE(string key, LFloat value);
|
||||
|
||||
/// <summary>
|
||||
/// 创建运行时GE数据
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="valueId"></param>
|
||||
/// <returns></returns>
|
||||
GameplayEffect CreateRuntimeGE(string key, int valueId);
|
||||
|
||||
/// <summary>
|
||||
/// 指定关联资源的序列化对象绑定
|
||||
/// </summary>
|
||||
void GASBindAsset();
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c10a2c2836bd403192ab76376c74d63a
|
||||
timeCreated: 1729527589
|
@@ -92,13 +92,16 @@ namespace GAS.Runtime
|
||||
return spec;
|
||||
}
|
||||
|
||||
public GameplayEffect(IGameplayEffectData data)
|
||||
public GameplayEffect(IGameplayEffectData data, int geValueId)
|
||||
{
|
||||
if (data is null)
|
||||
{
|
||||
throw new Exception($"GE data can't be null!");
|
||||
}
|
||||
|
||||
m_OriginGEAsset = assetData;
|
||||
m_GameplayEffectValueId = geValueId;
|
||||
|
||||
GameplayEffectName = data.GetDisplayName();
|
||||
DurationPolicy = data.GetDurationPolicy();
|
||||
Duration = data.GetDuration();
|
||||
|
@@ -0,0 +1,215 @@
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// GE时限策略
|
||||
/// </summary>
|
||||
public enum EnumEffectsDurationPolicy : byte
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("瞬时(Instant)", Sirenix.OdinInspector.SdfIconType.LightningCharge)]
|
||||
#endif
|
||||
Instant = 1,
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("永久(Infinite)", Sirenix.OdinInspector.SdfIconType.Infinity)]
|
||||
#endif
|
||||
Infinite = 2,
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("限时(Duration)", Sirenix.OdinInspector.SdfIconType.HourglassSplit)]
|
||||
#endif
|
||||
Duration = 3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GE堆叠类型枚举
|
||||
/// </summary>
|
||||
public enum EnumStackingType : byte
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("独立", Sirenix.OdinInspector.SdfIconType.XCircleFill)]
|
||||
#endif
|
||||
None = 0, //不会叠加,如果多次释放则每个Effect相当于单个Effect
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("来源", Sirenix.OdinInspector.SdfIconType.Magic)]
|
||||
#endif
|
||||
AggregateBySource = 1, //目标(Target)上的每个源(Source)ASC都有一个单独的堆栈实例, 每个源(Source)可以应用堆栈中的X个GameplayEffect.
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("目标", Sirenix.OdinInspector.SdfIconType.Person)]
|
||||
#endif
|
||||
AggregateByTarget = 2 //目标(Target)上只有一个堆栈实例而不管源(Source)如何, 每个源(Source)都可以在共享堆栈限制(Shared Stack Limit)内应用堆栈.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GE堆叠时刷新策略枚举
|
||||
/// </summary>
|
||||
public enum EnumDurationRefreshPolicy : byte
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("NeverRefresh - 不刷新Effect的持续时间", Sirenix.OdinInspector.SdfIconType.XCircleFill)]
|
||||
#endif
|
||||
NeverRefresh = 0, //不刷新Effect的持续时间
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("RefreshOnSuccessfulApplication - 每次apply成功后刷新持续时间", Sirenix.OdinInspector.SdfIconType.HourglassTop)]
|
||||
#endif
|
||||
RefreshOnSuccessfulApplication = 1 //每次apply成功后刷新Effect的持续时间, denyOverflowApplication如果为True则多余的Apply不会刷新Duration
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GE周期效果计时重置策略
|
||||
/// </summary>
|
||||
public enum EnumPeriodResetPolicy : byte
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("NeverReset - 不重置Effect的周期计时", Sirenix.OdinInspector.SdfIconType.XCircleFill)]
|
||||
#endif
|
||||
NeverRefresh = 0, //不重置Effect的周期计时
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("ResetOnSuccessfulApplication - 每次apply成功后重置Effect的周期计时", Sirenix.OdinInspector.SdfIconType.HourglassTop)]
|
||||
#endif
|
||||
ResetOnSuccessfulApplication = 1//每次apply成功后重置Effect的周期计时
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GE过期的执行策略
|
||||
/// </summary>
|
||||
public enum EnumExpirationPolicy : byte
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("ClearEntireStack - 持续时间结束时, 清除所有层数", Sirenix.OdinInspector.SdfIconType.TrashFill)]
|
||||
#endif
|
||||
ClearEntireStack = 0, //持续时间结束时,清除所有层数
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("RemoveSingleStackAndRefreshDuration - 持续时间结束时减少一层,然后重新经历一个Duration", Sirenix.OdinInspector.SdfIconType.EraserFill)]
|
||||
#endif
|
||||
RemoveSingleStackAndRefreshDuration = 1, //持续时间结束时减少一层,然后重新经历一个Duration,一直持续到层数减为0
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("RefreshDuration - 持续时间结束时,再次刷新Duration", Sirenix.OdinInspector.SdfIconType.HourglassTop)]
|
||||
#endif
|
||||
RefreshDuration = 2//持续时间结束时,再次刷新Duration,这相当于无限Duration,
|
||||
//TODO :可以通过调用GameplayEffectsContainer的OnStackCountChange(GameplayEffect ActiveEffect, int OldStackCount, int NewStackCount)来处理层数,
|
||||
//TODO :可以达到Duration结束时减少两层并刷新Duration这样复杂的效果。
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 授予能力的激活策略
|
||||
/// </summary>
|
||||
public enum EnumGrantedAbilityActivationPolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// 不激活, 等待用户调用ASC激活
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("None - 不激活, 等待用户调用ASC激活", Sirenix.OdinInspector.SdfIconType.Joystick)]
|
||||
#endif
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 能力添加时激活(GE添加时激活)
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("WhenAdded - 能力添加时激活(GE添加时激活)", Sirenix.OdinInspector.SdfIconType.LightningChargeFill)]
|
||||
#endif
|
||||
WhenAdded = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 同步GE激活时激活
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("SyncWithEffect - 同步GE激活时激活", Sirenix.OdinInspector.SdfIconType.Robot)]
|
||||
#endif
|
||||
SyncWithEffect = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 授予能力的取消激活策略
|
||||
/// </summary>
|
||||
public enum EnumGrantedAbilityDeactivationPolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// 无相关取消激活逻辑, 需要用户调用ASC取消激活
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("None - 无相关取消激活逻辑, 需要用户调用ASC取消激活", Sirenix.OdinInspector.SdfIconType.Joystick)]
|
||||
#endif
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 同步GE,GE失活时取消激活
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("SyncWithEffect - 同步GE,GE失活时取消激活", Sirenix.OdinInspector.SdfIconType.Robot)]
|
||||
#endif
|
||||
SyncWithEffect = 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 授予能力的移除策略
|
||||
/// </summary>
|
||||
public enum EnumGrantedAbilityRemovePolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// 不移除
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("None - 不移除", Sirenix.OdinInspector.SdfIconType.Joystick)]
|
||||
#endif
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 同步GE,GE移除时移除
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("SyncWithEffect - 同步GE,GE移除时移除", Sirenix.OdinInspector.SdfIconType.Robot)]
|
||||
#endif
|
||||
SyncWithEffect = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 能力结束时自己移除
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("WhenEnd - 能力结束时自己移除", Sirenix.OdinInspector.SdfIconType.LightningChargeFill)]
|
||||
#endif
|
||||
WhenEnd = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 能力取消时自己移除
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("WhenCancel - 能力取消时自己移除", Sirenix.OdinInspector.SdfIconType.LightningChargeFill)]
|
||||
#endif
|
||||
WhenCancel = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 能力结束或取消时自己移除
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText("WhenCancelOrEnd - 能力结束或取消时自己移除", Sirenix.OdinInspector.SdfIconType.LightningChargeFill)]
|
||||
#endif
|
||||
WhenCancelOrEnd = 4,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GE的属性操作枚举
|
||||
/// </summary>
|
||||
public enum EnumGEOperation
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText(Sirenix.OdinInspector.SdfIconType.Plus, Text = "加法")]
|
||||
#endif
|
||||
Add = 0,
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText(Sirenix.OdinInspector.SdfIconType.X, Text = "乘法")]
|
||||
#endif
|
||||
Multiply = 1,
|
||||
#if UNITY_EDITOR
|
||||
[Sirenix.OdinInspector.LabelText(Sirenix.OdinInspector.SdfIconType.Pencil, Text = "覆写")]
|
||||
#endif
|
||||
Override = 2
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5eba2a774cae4daa9a640cb1a87156bc
|
||||
timeCreated: 1729528730
|
@@ -56,11 +56,11 @@ namespace GAS.Runtime
|
||||
{
|
||||
public string stackingCodeName; // 实际允许不会使用,而是使用stackingCodeName的hash值, 即stackingHashCode
|
||||
public int stackingHashCode;
|
||||
public StackingType stackingType;
|
||||
public EnumStackingType stackingType;
|
||||
public int limitCount;
|
||||
public DurationRefreshPolicy durationRefreshPolicy;
|
||||
public PeriodResetPolicy periodResetPolicy;
|
||||
public ExpirationPolicy expirationPolicy;
|
||||
public EnumDurationRefreshPolicy durationRefreshPolicy;
|
||||
public EnumPeriodResetPolicy periodResetPolicy;
|
||||
public EnumExpirationPolicy expirationPolicy;
|
||||
|
||||
// Overflow 溢出逻辑处理
|
||||
public bool denyOverflowApplication; //对应于StackDurationRefreshPolicy,如果为True则多余的Apply不会刷新Duration
|
||||
@@ -78,7 +78,7 @@ namespace GAS.Runtime
|
||||
this.stackingHashCode = stackingHashCode;
|
||||
}
|
||||
|
||||
public void SetStackingType(StackingType stackingType)
|
||||
public void SetStackingType(EnumStackingType stackingType)
|
||||
{
|
||||
this.stackingType = stackingType;
|
||||
}
|
||||
@@ -88,17 +88,17 @@ namespace GAS.Runtime
|
||||
this.limitCount = limitCount;
|
||||
}
|
||||
|
||||
public void SetDurationRefreshPolicy(DurationRefreshPolicy durationRefreshPolicy)
|
||||
public void SetDurationRefreshPolicy(EnumDurationRefreshPolicy durationRefreshPolicy)
|
||||
{
|
||||
this.durationRefreshPolicy = durationRefreshPolicy;
|
||||
}
|
||||
|
||||
public void SetPeriodResetPolicy(PeriodResetPolicy periodResetPolicy)
|
||||
public void SetPeriodResetPolicy(EnumPeriodResetPolicy periodResetPolicy)
|
||||
{
|
||||
this.periodResetPolicy = periodResetPolicy;
|
||||
}
|
||||
|
||||
public void SetExpirationPolicy(ExpirationPolicy expirationPolicy)
|
||||
public void SetExpirationPolicy(EnumExpirationPolicy expirationPolicy)
|
||||
{
|
||||
this.expirationPolicy = expirationPolicy;
|
||||
}
|
||||
@@ -107,6 +107,16 @@ namespace GAS.Runtime
|
||||
{
|
||||
this.overflowEffects = overflowEffects;
|
||||
}
|
||||
|
||||
public void SetOverflowEffects(LinkGEAsset[] overflowEffectAssets)
|
||||
{
|
||||
if (overflowEffectAssets is null || overflowEffectAssets.Length == 0) return;
|
||||
overflowEffects = new GameplayEffect[overflowEffectAssets.Length];
|
||||
for (var i = 0; i < overflowEffectAssets.Length; ++i)
|
||||
{
|
||||
overflowEffects[i] = new GameplayEffect(overflowEffectAssets[i].linkGE, overflowEffectAssets[i].valueId);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetOverflowEffects(GameplayEffectAsset[] overflowEffectAssets)
|
||||
{
|
||||
@@ -132,7 +142,7 @@ namespace GAS.Runtime
|
||||
get
|
||||
{
|
||||
var stack = new GameplayEffectStacking();
|
||||
stack.SetStackingType(StackingType.None);
|
||||
stack.SetStackingType(EnumStackingType.None);
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
@@ -147,7 +157,7 @@ namespace GAS.Runtime
|
||||
[VerticalGroup]
|
||||
[LabelText(GASTextDefine.LABEL_GE_STACKING_TYPE)]
|
||||
[EnumToggleButtons]
|
||||
public StackingType stackingType;
|
||||
public EnumStackingType stackingType;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[VerticalGroup]
|
||||
@@ -173,19 +183,19 @@ namespace GAS.Runtime
|
||||
[InfoBox(GASTextDefine.LABEL_GE_STACKING_DENY_OVERFLOW_APPLICATION+"为True时多余的Apply不会刷新Duration", InfoMessageType.None,
|
||||
VisibleIf =
|
||||
"@durationRefreshPolicy == DurationRefreshPolicy.RefreshOnSuccessfulApplication && denyOverflowApplication")]
|
||||
public DurationRefreshPolicy durationRefreshPolicy;
|
||||
public EnumDurationRefreshPolicy durationRefreshPolicy;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[VerticalGroup]
|
||||
[LabelText(GASTextDefine.LABEL_GE_STACKING_PERIOD_RESET_POLICY)]
|
||||
[HideIf("IsNoStacking")]
|
||||
public PeriodResetPolicy periodResetPolicy;
|
||||
public EnumPeriodResetPolicy periodResetPolicy;
|
||||
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
[VerticalGroup]
|
||||
[LabelText(GASTextDefine.LABEL_GE_STACKING_EXPIRATION_POLICY)]
|
||||
[HideIf("IsNoStacking")]
|
||||
public ExpirationPolicy expirationPolicy;
|
||||
public EnumExpirationPolicy expirationPolicy;
|
||||
|
||||
// Overflow 溢出逻辑处理
|
||||
[LabelWidth(LABEL_WIDTH)]
|
||||
|
@@ -117,34 +117,43 @@ namespace GAS.Runtime
|
||||
{
|
||||
public readonly AbstractAbility Ability;
|
||||
public readonly int AbilityLevel;
|
||||
public readonly GrantedAbilityActivationPolicy ActivationPolicy;
|
||||
public readonly GrantedAbilityDeactivationPolicy DeactivationPolicy;
|
||||
public readonly GrantedAbilityRemovePolicy RemovePolicy;
|
||||
public readonly EnumGrantedAbilityActivationPolicy ActivationPolicy;
|
||||
public readonly EnumGrantedAbilityDeactivationPolicy DeactivationPolicy;
|
||||
public readonly EnumGrantedAbilityRemovePolicy RemovePolicy;
|
||||
|
||||
public GrantedAbilityFromEffect(GrantedAbilityConfig config)
|
||||
public GrantedAbilityFromEffect(in GrantAbilityCfg config)
|
||||
{
|
||||
Ability =
|
||||
Activator.CreateInstance(config.AbilityAsset.AbilityType(), args: config.AbilityAsset) as
|
||||
AbstractAbility;
|
||||
AbilityLevel = config.AbilityLevel;
|
||||
ActivationPolicy = config.ActivationPolicy;
|
||||
DeactivationPolicy = config.DeactivationPolicy;
|
||||
RemovePolicy = config.RemovePolicy;
|
||||
Ability = new TimelineAbility(config.grantAbilityAsset);
|
||||
AbilityLevel = config.abilityLevel;
|
||||
ActivationPolicy = config.activationPolicy;
|
||||
DeactivationPolicy = config.deactivationPolicy;
|
||||
RemovePolicy = config.removePolicy;
|
||||
}
|
||||
|
||||
// public GrantedAbilityFromEffect(GrantedAbilityConfig config)
|
||||
// {
|
||||
// Ability =
|
||||
// Activator.CreateInstance(config.AbilityAsset.AbilityType(), args: config.AbilityAsset) as
|
||||
// AbstractAbility;
|
||||
// AbilityLevel = config.AbilityLevel;
|
||||
// ActivationPolicy = config.ActivationPolicy;
|
||||
// DeactivationPolicy = config.DeactivationPolicy;
|
||||
// RemovePolicy = config.RemovePolicy;
|
||||
// }
|
||||
|
||||
public GrantedAbilityFromEffect(
|
||||
AbstractAbility ability,
|
||||
int abilityLevel,
|
||||
GrantedAbilityActivationPolicy activationPolicy,
|
||||
GrantedAbilityDeactivationPolicy deactivationPolicy,
|
||||
GrantedAbilityRemovePolicy removePolicy)
|
||||
{
|
||||
Ability = ability;
|
||||
AbilityLevel = abilityLevel;
|
||||
ActivationPolicy = activationPolicy;
|
||||
DeactivationPolicy = deactivationPolicy;
|
||||
RemovePolicy = removePolicy;
|
||||
}
|
||||
// public GrantedAbilityFromEffect(
|
||||
// AbstractAbility ability,
|
||||
// int abilityLevel,
|
||||
// GrantedAbilityActivationPolicy activationPolicy,
|
||||
// GrantedAbilityDeactivationPolicy deactivationPolicy,
|
||||
// GrantedAbilityRemovePolicy removePolicy)
|
||||
// {
|
||||
// Ability = ability;
|
||||
// AbilityLevel = abilityLevel;
|
||||
// ActivationPolicy = activationPolicy;
|
||||
// DeactivationPolicy = deactivationPolicy;
|
||||
// RemovePolicy = removePolicy;
|
||||
// }
|
||||
|
||||
public GrantedAbilitySpecFromEffect CreateSpec(GameplayEffectSpec sourceEffectSpec)
|
||||
{
|
||||
@@ -164,9 +173,9 @@ namespace GAS.Runtime
|
||||
|
||||
public string AbilityName { get; private set; }
|
||||
public int AbilityLevel => GrantedAbility.AbilityLevel;
|
||||
public GrantedAbilityActivationPolicy ActivationPolicy => GrantedAbility.ActivationPolicy;
|
||||
public GrantedAbilityDeactivationPolicy DeactivationPolicy => GrantedAbility.DeactivationPolicy;
|
||||
public GrantedAbilityRemovePolicy RemovePolicy => GrantedAbility.RemovePolicy;
|
||||
public EnumGrantedAbilityActivationPolicy ActivationPolicy => GrantedAbility.ActivationPolicy;
|
||||
public EnumGrantedAbilityDeactivationPolicy DeactivationPolicy => GrantedAbility.DeactivationPolicy;
|
||||
public EnumGrantedAbilityRemovePolicy RemovePolicy => GrantedAbility.RemovePolicy;
|
||||
public AbilitySpec AbilitySpec => Owner.AbilityContainer.AbilitySpecs()[AbilityName];
|
||||
|
||||
public void Awake(GrantedAbilityFromEffect grantedAbility, GameplayEffectSpec sourceEffectSpec)
|
||||
@@ -185,20 +194,20 @@ namespace GAS.Runtime
|
||||
AbilitySpec.SetLevel(AbilityLevel);
|
||||
|
||||
// 是否添加时激活
|
||||
if (ActivationPolicy == GrantedAbilityActivationPolicy.WhenAdded)
|
||||
if (ActivationPolicy == EnumGrantedAbilityActivationPolicy.WhenAdded)
|
||||
{
|
||||
Owner.TryActivateAbility(AbilityName, sourceEffectSpec);
|
||||
}
|
||||
|
||||
switch (RemovePolicy)
|
||||
{
|
||||
case GrantedAbilityRemovePolicy.WhenEnd:
|
||||
case EnumGrantedAbilityRemovePolicy.WhenEnd:
|
||||
AbilitySpec.RegisterEndAbility(RemoveSelf);
|
||||
break;
|
||||
case GrantedAbilityRemovePolicy.WhenCancel:
|
||||
case EnumGrantedAbilityRemovePolicy.WhenCancel:
|
||||
AbilitySpec.RegisterCancelAbility(RemoveSelf);
|
||||
break;
|
||||
case GrantedAbilityRemovePolicy.WhenCancelOrEnd:
|
||||
case EnumGrantedAbilityRemovePolicy.WhenCancelOrEnd:
|
||||
AbilitySpec.RegisterEndAbility(RemoveSelf);
|
||||
AbilitySpec.RegisterCancelAbility(RemoveSelf);
|
||||
break;
|
||||
|
@@ -0,0 +1,26 @@
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// ASC组件预设
|
||||
/// </summary>
|
||||
public interface IAbilitySystemComponentPreset
|
||||
{
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 属性集
|
||||
/// </summary>
|
||||
string[] AttributeSets { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 固定的Tag
|
||||
/// </summary>
|
||||
GameplayTag[] BaseTags { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 附加的固定Ability
|
||||
/// </summary>
|
||||
string[] LinkAbilities { get; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e69a1a35dd34ca58e21f08aaf3ef4b2
|
||||
timeCreated: 1729527792
|
@@ -0,0 +1,32 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Timeline结构的Ability配置数据接口
|
||||
/// </summary>
|
||||
public interface ITimelineAbilityAsset : IAbilityAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 播放速率, 常用于加速或减速播放(例如基于攻击速度的技能, 播放速率随攻击速度变化)
|
||||
/// </summary>
|
||||
LFloat Speed { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否可手动结束技能
|
||||
/// </summary>
|
||||
bool ManualEndAbility { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Timeline的总帧数,即Ability的总持续时长
|
||||
/// </summary>
|
||||
int FrameCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Timeline结构配置
|
||||
/// </summary>
|
||||
TimelineInfo TimelineAbilityInfo { get; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da54882306814947916276f622ed9d3f
|
||||
timeCreated: 1729526364
|
@@ -0,0 +1,87 @@
|
||||
|
||||
using JNGame.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 纯净模式的ASC预制件配置
|
||||
/// </summary>
|
||||
public sealed class PureASCPresetAsset : ISerializable, IAbilitySystemComponentPreset
|
||||
{
|
||||
/// <summary>
|
||||
/// 唯一标识字符串
|
||||
/// </summary>
|
||||
private string m_Name;
|
||||
|
||||
/// <summary>
|
||||
/// 关联的属性集
|
||||
/// </summary>
|
||||
private string[] m_AttributeSets;
|
||||
|
||||
/// <summary>
|
||||
/// 固定Tag
|
||||
/// </summary>
|
||||
private GameplayTag[] m_BaseTags;
|
||||
|
||||
/// <summary>
|
||||
/// 关联的Ability
|
||||
/// </summary>
|
||||
private string[] m_LinkGEAssetLocations;
|
||||
|
||||
/// <summary>
|
||||
/// Get - 标识
|
||||
/// </summary>
|
||||
public string Name => m_Name;
|
||||
|
||||
/// <summary>
|
||||
/// Get - 属性集
|
||||
/// </summary>
|
||||
public string[] AttributeSets => m_AttributeSets;
|
||||
|
||||
/// <summary>
|
||||
/// Get - 固定Tag
|
||||
/// </summary>
|
||||
public GameplayTag[] BaseTags => m_BaseTags;
|
||||
|
||||
/// <summary>
|
||||
/// Get - 关联的Ability
|
||||
/// </summary>
|
||||
public string[] LinkAbilities => m_LinkGEAssetLocations;
|
||||
|
||||
public void Deserialize(Deserializer reader)
|
||||
{
|
||||
m_Name = reader.ReadString();
|
||||
ushort length = reader.ReadUInt16();
|
||||
m_AttributeSets = new string[length];
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
m_AttributeSets[i] = reader.ReadString();
|
||||
}
|
||||
m_BaseTags = reader.ReadArray(new GameplayTag());
|
||||
length = reader.ReadUInt16();
|
||||
m_LinkGEAssetLocations = new string[length];
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
m_LinkGEAssetLocations[i] = reader.ReadString();
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(Serializer writer)
|
||||
{
|
||||
writer.Write(m_Name);
|
||||
ushort length = (ushort)(m_AttributeSets == null ? 0 : m_AttributeSets.Length);
|
||||
writer.Write(length);
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
writer.Write(m_AttributeSets[i]);
|
||||
}
|
||||
writer.WriteArray(m_BaseTags);
|
||||
length = (ushort)(m_LinkGEAssetLocations == null ? 0 : m_LinkGEAssetLocations.Length);
|
||||
writer.Write(length);
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
writer.Write(m_LinkGEAssetLocations[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f709b7f4f5c46f5a62105e69bb48414
|
||||
timeCreated: 1729527772
|
@@ -34,11 +34,11 @@ namespace GAS.Runtime
|
||||
|
||||
public abstract Type AbilityType();
|
||||
|
||||
public void Serialize(Serializer writer)
|
||||
public virtual void Serialize(Serializer writer)
|
||||
{
|
||||
}
|
||||
|
||||
public void Deserialize(Deserializer reader)
|
||||
public virtual void Deserialize(Deserializer reader)
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,365 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 关联GE配置
|
||||
/// </summary>
|
||||
public partial struct LinkGEAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 关联的GE数据配置表ID
|
||||
/// </summary>
|
||||
public int valueId;
|
||||
|
||||
/// <summary>
|
||||
/// 关联的GE配置资源Location
|
||||
/// </summary>
|
||||
public string linkAssetLocation;
|
||||
|
||||
/// <summary>
|
||||
/// Get-关联的GE配置资源实例
|
||||
/// </summary>
|
||||
public IGameplayEffectData linkGE;
|
||||
}
|
||||
|
||||
public partial struct GrantAbilityCfg
|
||||
{
|
||||
/// <summary>
|
||||
/// 关联的技能资源地址
|
||||
/// </summary>
|
||||
public string abilityAssetLocation;
|
||||
|
||||
/// <summary>
|
||||
/// Ability等级
|
||||
/// </summary>
|
||||
public int abilityLevel;
|
||||
|
||||
/// <summary>
|
||||
/// 激活策略
|
||||
/// </summary>
|
||||
public EnumGrantedAbilityActivationPolicy activationPolicy;
|
||||
|
||||
/// <summary>
|
||||
/// 失活策略
|
||||
/// </summary>
|
||||
public EnumGrantedAbilityDeactivationPolicy deactivationPolicy;
|
||||
|
||||
/// <summary>
|
||||
/// 移除策略
|
||||
/// </summary>
|
||||
public EnumGrantedAbilityRemovePolicy removePolicy;
|
||||
|
||||
/// <summary>
|
||||
/// 关联的Ability配置,加载后绑定
|
||||
/// </summary>
|
||||
public PureTimelineAbilityAsset grantAbilityAsset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GE的属性修改器配置
|
||||
/// </summary>
|
||||
public struct GEModifierCfg
|
||||
{
|
||||
/// <summary>
|
||||
/// 属性名 - 完整
|
||||
/// </summary>
|
||||
public string attributeName;
|
||||
/// <summary>
|
||||
/// 属性名 - 最后
|
||||
/// </summary>
|
||||
public string attributeShortName;
|
||||
/// <summary>
|
||||
/// 归属的属性集
|
||||
/// </summary>
|
||||
public string attributeSetName;
|
||||
/// <summary>
|
||||
/// 修改参数值
|
||||
/// </summary>
|
||||
public LFloat modifierMagnitude;
|
||||
/// <summary>
|
||||
/// 属性修改操作
|
||||
/// </summary>
|
||||
public EnumGEOperation operation;
|
||||
|
||||
/// <summary>
|
||||
/// 属性规则计算器,资源加载后,通过Location字段绑定
|
||||
/// </summary>
|
||||
public PureModifierMagnitudeCalculation mmc;
|
||||
|
||||
public LFloat CalculateMagnitude(GameplayEffectSpec spec, LFloat modifierMagnitude)
|
||||
{
|
||||
return mmc == null ? modifierMagnitude : mmc.CalculateMagnitude(spec, modifierMagnitude);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 纯净模式的GE配置
|
||||
/// </summary>
|
||||
public partial class PureGameplayEffectAsset : IGameplayEffectData
|
||||
{
|
||||
/// <summary>
|
||||
/// GE名称,ScriptObjectable文件的name
|
||||
/// </summary>
|
||||
private string m_Name;
|
||||
public string Name => m_Name;
|
||||
|
||||
#region Policy相关的字段
|
||||
|
||||
/// <summary>
|
||||
/// GE持续策略
|
||||
/// </summary>
|
||||
private EffectsDurationPolicy m_DurationPolicy;
|
||||
public EffectsDurationPolicy DurationPolicy => m_DurationPolicy;
|
||||
|
||||
/// <summary>
|
||||
/// GE持续时长,限时持续策略GE生效,单位:毫秒
|
||||
/// </summary>
|
||||
private int m_Duration;
|
||||
public int Duration => m_Duration;
|
||||
|
||||
/// <summary>
|
||||
/// 间隔效果周期,非瞬时策略GE生效,单位:毫秒
|
||||
/// </summary>
|
||||
private int m_Period;
|
||||
public int Period => m_Period;
|
||||
|
||||
/// <summary>
|
||||
/// 间隔效果ID
|
||||
/// </summary>
|
||||
private int m_PeriodExecutionId;
|
||||
public int PeriodExecutionId => m_PeriodExecutionId;
|
||||
|
||||
/// <summary>
|
||||
/// 关联间隔效果配置资源的地址标识
|
||||
/// </summary>
|
||||
private string m_PeriodExcutionAssetLocation = "";
|
||||
|
||||
/// <summary>
|
||||
/// 关联间隔效果配置资源,运行时加载后,通过Location绑定加载后的内存实例
|
||||
/// </summary>
|
||||
private IGameplayEffectData m_PeriodExcutionAsset;
|
||||
public IGameplayEffectData PeriodExcutionAsset => m_PeriodExcutionAsset;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tag相关的字段
|
||||
|
||||
/// <summary>
|
||||
/// <para>标签用于描述[游戏效果]自身的特定属性,包括但不限于伤害、治疗、控制等效果类型。</para>
|
||||
/// <para>这些标签有助于区分和定义[游戏效果]的作用和表现。</para>
|
||||
/// <para>可配合RemoveGameplayEffectsWithTags食用。</para>
|
||||
/// </summary>
|
||||
private GameplayTag[] m_AssetTags;
|
||||
public GameplayTag[] AssetTags => m_AssetTags;
|
||||
|
||||
/// <summary>
|
||||
/// <para>当[游戏效果]生效时,标签会被添加到目标单位上,并在[游戏效果]失效时移除。</para>
|
||||
/// <para>该标签对即时型(Instant)[游戏效果]的无效。</para>
|
||||
/// </summary>
|
||||
private GameplayTag[] m_GrantedTags;
|
||||
public GameplayTag[] GrantedTags => m_GrantedTags;
|
||||
|
||||
/// <summary>
|
||||
/// <para>GE的目标单位必须具备【所有】这些标签才能应用于目标单位。</para>
|
||||
/// <para>如果想表达【任一】标签不可作用于目标,应该使用ApplicationImmunityTags标签。</para>
|
||||
/// </summary>
|
||||
private GameplayTag[] m_ApplicationRequiredTags;
|
||||
public GameplayTag[] ApplicationRequiredTags => m_ApplicationRequiredTags;
|
||||
|
||||
/// <summary>
|
||||
/// <para>GE的目标单位必须具备【全部】这些标签,否则该效果不会触发。</para>
|
||||
/// <para>一旦GE被施加,如果目标单位在效果持续期间标签发生变化,导致不再具备【全部】这些标签,效果将失效;反之,如果满足条件,效果将被激活。</para>
|
||||
/// <para>该标签对即时型(Instant)GE的无效。</para>
|
||||
/// </summary>
|
||||
private GameplayTag[] m_OngoingRequiredTags;
|
||||
public GameplayTag[] OngoingRequiredTags => m_OngoingRequiredTags;
|
||||
|
||||
/// <summary>
|
||||
/// GE的目标单位当前持有的所有GE中,其AssetTags或GrantedTags中具有【任一】这些标签的[游戏效果]将被移除。
|
||||
/// </summary>
|
||||
private GameplayTag[] m_RemoveGameplayEffectsWithTags;
|
||||
public GameplayTag[] RemoveGameplayEffectsWithTags => m_RemoveGameplayEffectsWithTags;
|
||||
|
||||
/// <summary>
|
||||
/// GE无法作用于拥有【任一】这些标签的目标单位
|
||||
/// </summary>
|
||||
private GameplayTag[] m_ApplicationImmunityTags;
|
||||
public GameplayTag[] ApplicationImmunityTags => m_ApplicationImmunityTags;
|
||||
|
||||
#endregion
|
||||
|
||||
#region GE堆叠相关的字段
|
||||
|
||||
/// <summary>
|
||||
/// 堆叠策略类型
|
||||
/// </summary>
|
||||
private EnumStackingType m_StackingType;
|
||||
// public EnumStackingType StackingType => m_StackingType;
|
||||
|
||||
/// <summary>
|
||||
/// 堆叠标识符
|
||||
/// </summary>
|
||||
private string m_StackingCodeName;
|
||||
// public string StackingCodeName => m_StackingCodeName;
|
||||
|
||||
/// <summary>
|
||||
/// 堆叠层数上限
|
||||
/// </summary>
|
||||
private int m_LimitCount;
|
||||
// public int LimitCount => m_LimitCount;
|
||||
|
||||
/// <summary>
|
||||
/// 持续时间刷新策略
|
||||
/// </summary>
|
||||
private EnumDurationRefreshPolicy m_DurationRefreshPolicy;
|
||||
// public EnumDurationRefreshPolicy DurationRefreshPolicy => m_DurationRefreshPolicy;
|
||||
|
||||
/// <summary>
|
||||
/// 周期重置策略
|
||||
/// </summary>
|
||||
private EnumPeriodResetPolicy m_PeriodResetPolicy;
|
||||
// public EnumPeriodResetPolicy PeriodResetPolicy => m_PeriodResetPolicy;
|
||||
|
||||
/// <summary>
|
||||
/// 持续时间结束策略
|
||||
/// </summary>
|
||||
private EnumExpirationPolicy m_ExpirationPolicy;
|
||||
// public EnumExpirationPolicy ExpirationPolicy => m_ExpirationPolicy;
|
||||
|
||||
/// <summary>
|
||||
/// 溢出时GE是否不生效
|
||||
/// </summary>
|
||||
private bool m_DenyOverflowApplication;
|
||||
// public bool DenyOverflowApplication => m_DenyOverflowApplication;
|
||||
|
||||
/// <summary>
|
||||
/// 溢出时是否清空堆叠
|
||||
/// </summary>
|
||||
private bool m_ClearStackOnOverflow;
|
||||
// public bool ClearStackOnOverflow => m_ClearStackOnOverflow;
|
||||
|
||||
/// <summary>
|
||||
/// 溢出时触发的GE
|
||||
/// </summary>
|
||||
private LinkGEAsset[] m_OverflowEffects;
|
||||
|
||||
public GameplayEffectStacking GetStackingRuntimeData()
|
||||
{
|
||||
var stack = new GameplayEffectStacking();
|
||||
stack.SetStackingCodeName(m_StackingCodeName);
|
||||
stack.SetStackingType(m_StackingType);
|
||||
stack.SetLimitCount(m_LimitCount);
|
||||
stack.SetDurationRefreshPolicy(m_DurationRefreshPolicy);
|
||||
stack.SetPeriodResetPolicy(m_PeriodResetPolicy);
|
||||
stack.SetExpirationPolicy(m_ExpirationPolicy);
|
||||
stack.SetOverflowEffects(m_OverflowEffects);
|
||||
stack.SetDenyOverflowApplication(m_DenyOverflowApplication);
|
||||
stack.SetClearStackOnOverflow(m_ClearStackOnOverflow);
|
||||
return stack;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 动态授予Ability相关的字段
|
||||
|
||||
private GrantAbilityCfg[] m_GrantAbilityCfgs;
|
||||
|
||||
public GrantedAbilityFromEffect[] GetGrantedAbilities()
|
||||
{
|
||||
var grantedAbilityList = new List<GrantedAbilityFromEffect>();
|
||||
foreach (var grantedAbilityConfig in m_GrantAbilityCfgs)
|
||||
{
|
||||
if (grantedAbilityConfig.grantAbilityAsset == null) continue;
|
||||
grantedAbilityList.Add(new GrantedAbilityFromEffect(grantedAbilityConfig));
|
||||
}
|
||||
|
||||
return grantedAbilityList.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Modifiers相关的字段
|
||||
|
||||
/// <summary>
|
||||
/// GE属性修改器配置
|
||||
/// </summary>
|
||||
private GEModifierCfg[] m_GEModifierCfg;
|
||||
public GEModifierCfg[] GEModifierCfg => m_GEModifierCfg;
|
||||
|
||||
#endregion
|
||||
|
||||
#region GameplayeCue相关字段
|
||||
|
||||
/// <summary>
|
||||
/// CueOnExecute - 执行时触发的CueAsset资源地址
|
||||
/// </summary>
|
||||
private string[] m_CueAssetLocationOnExcute;
|
||||
public string[] CueAssetOnExcute => m_CueAssetLocationOnExcute;
|
||||
/// <summary>
|
||||
/// CueDurational - 存在时持续触发的CueAsset资源地址
|
||||
/// </summary>
|
||||
private string[] m_CueAssetLocationOnDurational;
|
||||
public string[] CueAssetOnDurational => m_CueAssetLocationOnDurational;
|
||||
/// <summary>
|
||||
/// CueOnAdd - 添加时触发CueAsset资源地址
|
||||
/// </summary>
|
||||
private string[] m_CueAssetLocationOnAdd;
|
||||
public string[] CueAssetOnAdd => m_CueAssetLocationOnAdd;
|
||||
/// <summary>
|
||||
/// CueOnRemove - 移除时触发CueAsset资源地址
|
||||
/// </summary>
|
||||
private string[] m_CueAssetLocationOnRemove;
|
||||
public string[] CueAssetOnRemove => m_CueAssetLocationOnRemove;
|
||||
/// <summary>
|
||||
/// CueOnActivate - 激活时触发CueAsset资源地址
|
||||
/// </summary>
|
||||
private string[] m_CueAssetLocationOnActive;
|
||||
public string[] CueAssetOnActive => m_CueAssetLocationOnActive;
|
||||
/// <summary>
|
||||
/// CueOnDeactivate - 失活时触发CueAsset资源地址
|
||||
/// </summary>
|
||||
private string[] m_CueAssetLocationOnDeactive;
|
||||
public string[] CueAssetOnDeactive => m_CueAssetLocationOnDeactive;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Expiration相关字段
|
||||
|
||||
/// <summary>
|
||||
/// 过早到期施加的GE
|
||||
/// </summary>
|
||||
private LinkGEAsset[] m_PrematureExpirationEffect;
|
||||
public LinkGEAsset[] PrematureExpirationEffect => m_PrematureExpirationEffect;
|
||||
|
||||
/// <summary>
|
||||
/// 正常到期施加的GE
|
||||
/// </summary>
|
||||
private LinkGEAsset[] m_RoutineExpirationEffectClasses;
|
||||
public LinkGEAsset[] RoutineExpirationEffectClasses => m_RoutineExpirationEffectClasses;
|
||||
|
||||
#endregion
|
||||
|
||||
#region TickEventGE相关
|
||||
|
||||
/// <summary>
|
||||
/// 生效期间是否通过TickEvent触发效果
|
||||
/// </summary>
|
||||
private bool m_IsUseTickEventGE = false;
|
||||
public bool IsUseTickEventGE => m_IsUseTickEventGE;
|
||||
/// <summary>
|
||||
/// 触发需要的TickEvent
|
||||
/// </summary>
|
||||
private GameplayTag m_TickEventTag;
|
||||
public GameplayTag TickEventTag => m_TickEventTag;
|
||||
/// <summary>
|
||||
/// 触发的效果GE
|
||||
/// </summary>
|
||||
private LinkGEAsset[] m_TickEventEffect;
|
||||
public LinkGEAsset[] TickEventEffect => m_TickEventEffect;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5dfde87672da4b289e2d2dc6121a49ba
|
||||
timeCreated: 1729528615
|
@@ -0,0 +1,57 @@
|
||||
|
||||
|
||||
using System;
|
||||
using JNGame.Math;
|
||||
using JNGame.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 纯净模式的Ability配置资源
|
||||
/// </summary>
|
||||
public sealed partial class PureTimelineAbilityAsset : PureAbilityAsset, ITimelineAbilityAsset
|
||||
{
|
||||
private TimelineInfo m_TimelineInfo;
|
||||
|
||||
public TimelineInfo TimelineAbilityInfo => m_TimelineInfo;
|
||||
|
||||
public LFloat Speed => m_TimelineInfo.speed;
|
||||
|
||||
public bool ManualEndAbility => m_TimelineInfo.manualEndAbility;
|
||||
|
||||
public int FrameCount => m_TimelineInfo.frameCount;
|
||||
|
||||
public override Type AbilityType()
|
||||
{
|
||||
return typeof(TimelineAbility);
|
||||
}
|
||||
|
||||
public override void Serialize(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
m_TimelineInfo.Serialize(writer);
|
||||
}
|
||||
|
||||
public override void Deserialize(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
m_TimelineInfo = new TimelineInfo();
|
||||
m_TimelineInfo.Deserialize(reader);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public void SerializeForEditor(Serializer writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
m_TimelineInfo.SerializeForEditor(writer);
|
||||
}
|
||||
|
||||
public void DeserializeForEditor(Deserializer reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
m_TimelineInfo = new TimelineInfo();
|
||||
m_TimelineInfo.DeserializeForEditor(reader);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34bbcfe5d3ba4404b36636bad343445d
|
||||
timeCreated: 1729527624
|
@@ -0,0 +1,74 @@
|
||||
|
||||
using JNGame.Serialization;
|
||||
|
||||
namespace GAS.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 扩展序列化方法,用于GameplayTag Array的序列化
|
||||
/// </summary>
|
||||
public static class GameplayTagSerializationUtil
|
||||
{
|
||||
public static GameplayTag[] ReadArray(this Deserializer deserializer, GameplayTag _)
|
||||
{
|
||||
int length = deserializer.ReadUInt16();
|
||||
var lst = new GameplayTag[length];
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
lst[i].Deserialize(deserializer);
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
|
||||
public static void WriteArray(this Serializer serializer, GameplayTag[] gameplayTags)
|
||||
{
|
||||
serializer.Write((ushort)gameplayTags.Length);
|
||||
for (int i = 0; i < gameplayTags.Length; ++i)
|
||||
{
|
||||
gameplayTags[i].Serialize(serializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial struct GameplayTag : ISerializable
|
||||
{
|
||||
public readonly void Serialize(Serializer writer)
|
||||
{
|
||||
writer.Write(name);
|
||||
writer.Write(hashCode);
|
||||
writer.Write(shortName);
|
||||
writer.Write(ancestorHashCodes.Length);
|
||||
for (int i = 0; i < ancestorHashCodes.Length; ++i)
|
||||
{
|
||||
writer.Write(ancestorHashCodes[i]);
|
||||
}
|
||||
|
||||
writer.Write(ancestorNames.Length);
|
||||
for (int i = 0; i < ancestorNames.Length; ++i)
|
||||
{
|
||||
writer.Write(ancestorNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(Deserializer reader)
|
||||
{
|
||||
name = reader.ReadString();
|
||||
hashCode = reader.ReadInt32();
|
||||
shortName = reader.ReadString();
|
||||
|
||||
int size = reader.ReadInt32();
|
||||
ancestorHashCodes = new int[size];
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
int value = reader.ReadInt32();
|
||||
ancestorHashCodes[i] = value;
|
||||
}
|
||||
|
||||
size = reader.ReadInt32();
|
||||
ancestorNames = new string[size];
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
ancestorNames[i] = reader.ReadString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84a9bede3f9e4049a99e20324bcb4f88
|
||||
timeCreated: 1729527824
|
@@ -9,69 +9,64 @@ namespace GAS.Runtime
|
||||
/// </remarks>>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct GameplayTag : IEquatable<GameplayTag>
|
||||
public partial struct GameplayTag : IEquatable<GameplayTag>
|
||||
{
|
||||
[SerializeField]
|
||||
private string _name;
|
||||
public string name;
|
||||
|
||||
[SerializeField]
|
||||
private int _hashCode;
|
||||
public int hashCode;
|
||||
|
||||
[SerializeField]
|
||||
private string _shortName;
|
||||
public string shortName;
|
||||
|
||||
[SerializeField]
|
||||
private int[] _ancestorHashCodes;
|
||||
public int[] ancestorHashCodes;
|
||||
|
||||
[SerializeField]
|
||||
private string[] _ancestorNames;
|
||||
public string[] ancestorNames;
|
||||
|
||||
public GameplayTag(string name)
|
||||
{
|
||||
_name = name;
|
||||
_hashCode = name.GetHashCode();
|
||||
this.name = name;
|
||||
this.hashCode = name.GetHashCode();
|
||||
|
||||
var tags = name.Split('.');
|
||||
// if (tags.Length > GasDefine.GAS_TAG_MAX_GENERATIONS)
|
||||
// throw new Exception(
|
||||
// $"GameplayTag {name} has more than {GasDefine.GAS_TAG_MAX_GENERATIONS} generations");
|
||||
|
||||
_ancestorNames = new string[tags.Length - 1];
|
||||
_ancestorHashCodes = new int[tags.Length - 1];
|
||||
this.ancestorNames = new string[tags.Length - 1];
|
||||
this.ancestorHashCodes = new int[tags.Length - 1];
|
||||
var i = 0;
|
||||
var ancestorTag = "";
|
||||
while (i < tags.Length - 1)
|
||||
{
|
||||
ancestorTag += tags[i];
|
||||
_ancestorHashCodes[i] = ancestorTag.GetHashCode();
|
||||
_ancestorNames[i] = ancestorTag;
|
||||
this.ancestorHashCodes[i] = ancestorTag.GetHashCode();
|
||||
this.ancestorNames[i] = ancestorTag;
|
||||
ancestorTag += ".";
|
||||
i++;
|
||||
}
|
||||
|
||||
_shortName = tags[^1];
|
||||
this.shortName = tags[^1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Only For Show.
|
||||
/// </summary>
|
||||
public string Name => _name;
|
||||
public string Name => this.name;
|
||||
|
||||
/// <summary>
|
||||
/// Only For Show.
|
||||
/// </summary>
|
||||
public string ShortName => _shortName;
|
||||
public string ShortName => this.shortName;
|
||||
|
||||
/// <summary>
|
||||
/// Actually ,Use the hash code for compare.
|
||||
/// </summary>
|
||||
public int HashCode => _hashCode;
|
||||
public int HashCode => this.hashCode;
|
||||
|
||||
public string[] AncestorNames => _ancestorNames;
|
||||
public string[] AncestorNames => this.ancestorNames;
|
||||
|
||||
public bool Root => _ancestorHashCodes.Length == 0;
|
||||
public bool Root => this.ancestorHashCodes.Length == 0;
|
||||
|
||||
public int[] AncestorHashCodes => _ancestorHashCodes;
|
||||
public int[] AncestorHashCodes => this.ancestorHashCodes;
|
||||
|
||||
public bool IsDescendantOf(in GameplayTag other) => other.HasTag(this);
|
||||
|
||||
@@ -87,7 +82,7 @@ namespace GAS.Runtime
|
||||
|
||||
public readonly bool HasTag(in GameplayTag tag)
|
||||
{
|
||||
foreach (var ancestorHashCode in _ancestorHashCodes)
|
||||
foreach (var ancestorHashCode in this.ancestorHashCodes)
|
||||
if (ancestorHashCode == tag.HashCode)
|
||||
return true;
|
||||
|
||||
|
@@ -83,19 +83,4 @@ namespace GAS.Runtime
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public abstract class TimelineAbilityAssetT<T> : TimelineAbilityAssetBase where T : class
|
||||
{
|
||||
public sealed override Type AbilityType()
|
||||
{
|
||||
return typeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 这是一个最朴素的TimelineAbilityAsset实现, 如果要实现更复杂的TimelineAbilityAsset, 请用TimelineAbilityAssetBase或TimelineAbilityAssetT为基类
|
||||
/// </summary>
|
||||
public sealed class TimelineAbilityAsset : TimelineAbilityAssetT<TimelineAbility>
|
||||
{
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user