崩溃了呀

This commit is contained in:
DESKTOP-5RP3AKU\Jisol
2024-10-22 00:57:03 +08:00
parent e9c01842f0
commit 08d8f2ab5b
93 changed files with 11256 additions and 9311 deletions

View File

@@ -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;

View File

@@ -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)
{
}
}
}

View File

@@ -0,0 +1,23 @@
namespace GAS.Runtime
{
/// <summary>
/// Timeline运行时节点枚举
/// </summary>
public enum EnumRuntimeClipNode : ushort
{
InstantGE = 1, // 直接添加一个GE效果GE的时限效果由GE自己决定
DurationalGE, // 持续性GE效果Timeline控制其生命周期
InstantTask, // 瞬时的TaskTask可以理解为Condition+GE判断条件决定是否触发GE
DurationalTask, // 持续一段时间的TaskTimeline控制其生命周期
PassiveGE, // 被动GETimeline只负责添加不负责销毁外部手动控制
PassiveTask, // 被动TaskTimeline只负责添加不负责销毁外部手动控制
InstantCue, // 直接触发一个GameplayCue
DurationalCue, // 持续型GameplayCueTimeline控制其生命周期
EnumBuiltinCount = 100, // 内建行为树节点的类型上限,上层业务自行扩展的节点由此递增
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3e5fff7d0f654e88af64865debbcaf7c
timeCreated: 1729526089

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7f1af82c0b5748feb2aa43dd183fd279
timeCreated: 1729526102

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7137dd96f3d58434fa035d073b5881eb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b9d23e0917784dbba3773f52463eb252
timeCreated: 1729526102

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 68623f73aa1255d419c86dc8d08d246c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 73748f3e49399294c93c815c9bd90173
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ccc58d735ca245c4dbc2545104b20811
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7fa54cf9f74fa1c40be8ce5651dbab5d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 558296a0eeb98f843aa2149d21834cca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fcf8748d66384df458536a0246f1858f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5784d2561744253419d2cd63af70f7a7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b679e7a8b1b2e5f40925c990cd6d1c4f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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) { }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ad651df4e15d4a36a37f0f3df0ba5f79
timeCreated: 1729526089

View File

@@ -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
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 543a951e473f42f5b8a85dbef59b2e66
timeCreated: 1729525953

View File

@@ -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]();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 40797c0cb6a6439789f4a19cbca1b726
timeCreated: 1729526094

View File

@@ -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();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a708ca560d114d338204c891f7279de4
timeCreated: 1729525947

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 12ee977f578c48c0863340e8375d89f9
timeCreated: 1729526059

View File

@@ -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)
{
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c10a2c2836bd403192ab76376c74d63a
timeCreated: 1729527589

View File

@@ -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();

View File

@@ -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>
/// 同步GEGE失活时取消激活
/// </summary>
#if UNITY_EDITOR
[Sirenix.OdinInspector.LabelText("SyncWithEffect - 同步GEGE失活时取消激活", 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>
/// 同步GEGE移除时移除
/// </summary>
#if UNITY_EDITOR
[Sirenix.OdinInspector.LabelText("SyncWithEffect - 同步GEGE移除时移除", 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
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5eba2a774cae4daa9a640cb1a87156bc
timeCreated: 1729528730

View File

@@ -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)]

View File

@@ -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;

View File

@@ -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; }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3e69a1a35dd34ca58e21f08aaf3ef4b2
timeCreated: 1729527792

View File

@@ -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; }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: da54882306814947916276f622ed9d3f
timeCreated: 1729526364

View File

@@ -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]);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9f709b7f4f5c46f5a62105e69bb48414
timeCreated: 1729527772

View File

@@ -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)
{
}

View File

@@ -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>该标签对即时型InstantGE的无效。</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
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5dfde87672da4b289e2d2dc6121a49ba
timeCreated: 1729528615

View File

@@ -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
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 34bbcfe5d3ba4404b36636bad343445d
timeCreated: 1729527624

View File

@@ -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();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 84a9bede3f9e4049a99e20324bcb4f88
timeCreated: 1729527824

View File

@@ -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;

View File

@@ -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>
{
}
}