嘿我跟您说这坑一点也不大,AbilitySystemComponent.h也就两千行,.cpp也就三千多,乐
凡事要一点点来,我也就按每天的进度分p了。
1 类的继承关系和修饰符
先看这两行,为了方便看我加了换行
UCLASS(ClassGroup=AbilitySystem,
hidecategories=(Object,LOD,Lighting,Transform,Sockets,TextureStreaming),
editinlinenew,
meta=(BlueprintSpawnableComponent))
class GAMEPLAYABILITIES_API UAbilitySystemComponent :
public UGameplayTasksComponent,
public IGameplayTagAssetInterface,
public IAbilitySystemReplicationProxyInterface
1.1 UCLASS里的说明符
1.ClassGroup
这里是官方文档里的说明,看说明是用来方便视图分类的,但是我找了半天这个GroupView硬是没找到,希望有知道的大佬为我解惑
2.hidecategories
隐藏指定Category的属性,这里隐藏的都是些渲染和Transform等属性,作为处理中心ASC当然用不到这些。
3.editinlinenew
可以直接在编辑器中创建该类的对象,会传递给所有子类,可以用NotEditInlineNew重载覆盖。
4.meta=(BlueprintSpawnableComponent)
可以在蓝图中生成
1.2 继承关系
继承UGameplayTasksComponent,用于管理任务相关的操作,例如某些异步任务,找了下源文件UGameplayTasksComponent就是继承UActorComponent的
实现IGameplayTagAssetInterface接口,使支持标签的管理
实现IAbilitySystemReplicationProxyInterface,使支持网络同步和复制
2 继承自原生组件的接口
在海量的代码里无从下手的情况下,我选择先去看UE自带的一些关于生命周期的接口,.h里也把他们都写在一起了:
// ----------------------------------------------------------------------------------------------------------------
// Component overrides
// ----------------------------------------------------------------------------------------------------------------
virtual void InitializeComponent() override;
virtual void UninitializeComponent() override;
virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override;
virtual bool GetShouldTick() const override;
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
virtual void GetSubobjectsWithStableNamesForNetworking(TArray<UObject*>& Objs) override;
virtual bool ReplicateSubobjects(class UActorChannel *Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags) override;
/** Force owning actor to update it's replication, to make sure that gameplay cues get sent down quickly. Override to change how aggressive this is */
virtual void ForceReplication() override;
virtual void PreNetReceive() override;
virtual void PostNetReceive() override;
virtual void OnRegister() override;
virtual void OnUnregister() override;
virtual void ReadyForReplication() override;
virtual void BeginPlay() override;
这里除了网络相关的几个其他的都是继承自UActorComponent里的,顺序大概是这样:
OnRegister()-->
InitializeComponent()-->
BeginPlay()-->
TickComponent()-->
UninitializeComponent()-->
OnUnregister()-->
OnComponentDestroyed()
2.1 OnRegister
总的来说就是处理GA、GE、GC要注册的东西,根据数据表初始化AS
void UAbilitySystemComponent::OnRegister()
{
Super::OnRegister();
// Cached off netrole to avoid constant checking on owning actor
//缓存网络角色避免持续检测owning actor
CacheIsNetSimulated();
// Init starting data
//就是实现用数据表初始化AS
for (int32 i=0; i < DefaultStartingData.Num(); ++i)
{
if (DefaultStartingData[i].Attributes && DefaultStartingData[i].DefaultStartingTable)
{
UAttributeSet* Attributes = const_cast<UAttributeSet*>(GetOrCreateAttributeSubobject(DefaultStartingData[i].Attributes));
Attributes->InitFromMetaDataTable(DefaultStartingData[i].DefaultStartingTable);
}
}
//ActiveGameplayEffects是FActiveGameplayEffectsContainer类型的
//用Owner注册
ActiveGameplayEffects.RegisterWithOwner(this);
ActiveGameplayEffects.SetIsUsingReplicationCondition(bUseReplicationConditionForActiveGameplayEffects);
//FGameplayAbilitySpecContainer ActivatableAbilities
ActivatableAbilities.RegisterWithOwner(this);
//FActiveGameplayCueContainer ActiveGameplayCues
ActiveGameplayCues.bMinimalReplication = false;
ActiveGameplayCues.SetOwner(this);
/** Replicated gameplaycues when in minimal replication mode. These are cues that would come normally come from ActiveGameplayEffects (but since we do not replicate AGE in minimal mode, they must be replicated through here)
UPROPERTY(Replicated)
FActiveGameplayCueContainer MinimalReplicationGameplayCues;*/
MinimalReplicationGameplayCues.bMinimalReplication = true;
MinimalReplicationGameplayCues.SetOwner(this);
UpdateActiveGameplayEffectsReplicationCondition();
UpdateMinimalReplicationGameplayCuesCondition();
PRAGMA_DISABLE_DEPRECATION_WARNINGS
// This field is not replicated (MinimalReplicationTags has a custom serializer),
// so we don't need to mark it dirty.
MinimalReplicationTags.Owner = this;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
ReplicatedLooseTags.Owner = this;
/** Allocate an AbilityActorInfo. Note: this goes through a global function and is a SharedPtr so projects can make their own AbilityActorInfo */
// 分配一个 AbilityActorInfo 实例。这个实例通过全局函数创建,并且是一个共享指针,允许项目自 //定义 AbilityActorInfo。
// 如果 AbilityActorInfo 无效(即未创建过),则创建一个新的实例
if(!AbilityActorInfo.IsValid())
{
AbilityActorInfo = TSharedPtr<FGameplayAbilityActorInfo>(UAbilitySystemGlobals::Get().AllocAbilityActorInfo());
}
// Ensure bDestroyActiveStateInitiated is clear in case component is re-entering play
bDestroyActiveStateInitiated = false;
}
2.2 InitializeComponent
(1.19补充)先贴在这,大概就是处理一些AS相关的初始化,之后看了AS部分会细化
void UAbilitySystemComponent::InitializeComponent()
{
Super::InitializeComponent();
// Look for DSO AttributeSets (note we are currently requiring all attribute sets to be subobjects of the same owner. This doesn't *have* to be the case forever.
AActor *Owner = GetOwner();
InitAbilityActorInfo(Owner, Owner); // Default init to our outer owner
// cleanup any bad data that may have gotten into SpawnedAttributes
for (int32 Idx = SpawnedAttributes.Num()-1; Idx >= 0; --Idx)
{
if (SpawnedAttributes[Idx] == nullptr)
{
SpawnedAttributes.RemoveAt(Idx);
}
}
TArray<UObject*> ChildObjects;
GetObjectsWithOuter(Owner, ChildObjects, false, RF_NoFlags, EInternalObjectFlags::Garbage);
for (UObject* Obj : ChildObjects)
{
UAttributeSet* Set = Cast<UAttributeSet>(Obj);
if (Set)
{
SpawnedAttributes.AddUnique(Set);
}
}
SetSpawnedAttributesListDirty();
}
2.3 BeginPlay
void UAbilitySystemComponent::BeginPlay()
{
Super::BeginPlay();
// Cache net role here as well since for map-placed actors on clients, the Role may not be set correctly yet in OnRegister.
// 缓存网络角色因为对于在客户端放置的地图Actor
// 其角色可能尚未在 OnRegister 中正确设置,因此我们在 BeginPlay 中再做一次缓存
CacheIsNetSimulated();
}
2.4 TickComponent
大概是这样:
1.更新动画蒙太奇的数据
2.调用父类TickComponent
3.Tick实现了ITickableAttributeSetInterface的AS
void UAbilitySystemComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
SCOPE_CYCLE_COUNTER(STAT_TickAbilityTasks);
CSV_SCOPED_TIMING_STAT_EXCLUSIVE(AbilityTasks);
if (IsOwnerActorAuthoritative())
{
AnimMontage_UpdateReplicatedData();
}
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
for (UAttributeSet* AttributeSet : GetSpawnedAttributes())
{
ITickableAttributeSetInterface* TickableSet = Cast<ITickableAttributeSetInterface>(AttributeSet);
if (TickableSet && TickableSet->ShouldTick())
{
TickableSet->Tick(DeltaTime);
}
}
}
值得一提的是开发者好像打算用另一种定时器机制来管理Tick
PrimaryComponentTick.bStartWithTickEnabled = true; // FIXME! Just temp until timer manager figured out
2.5 UninitializeComponent
多在父类基础上多调用了一行这个:
ActiveGameplayEffects.Uninitialize();
GE相关的Uninitialize
2.6 OnUnregister
void UAbilitySystemComponent::OnUnregister()
{
Super::OnUnregister();
DestroyActiveState();
//取消所有能力并销毁任何剩余的实例化能力
}
2.7 OnComponentDestroyed
核心是调用DestroyActiveState,这个函数的具体解析后边的文章里写了,然后就是AS的销毁,是为了防止移除并重新添加level的时候直接uninit并且re-init但没有销毁。
void UAbilitySystemComponent::OnComponentDestroyed(bool bDestroyingHierarchy)
{
DestroyActiveState();
// The MarkPendingKill on these attribute sets used to be done in UninitializeComponent,
// but it was moved here instead since it's possible for the component to be uninitialized,
// and later re-initialized, without being destroyed - and the attribute sets need to be preserved
// in this case. This can happen when the owning actor's level is removed and later re-added
// to the world, since EndPlay (and therefore UninitializeComponents) will be called on
// the owning actor when its level is removed.
for (UAttributeSet* Set : GetSpawnedAttributes())
{
if (Set)
{
Set->MarkAsGarbage();
}
}
// Call the super at the end, after we've done what we needed to do
Super::OnComponentDestroyed(bDestroyingHierarchy);
}