UE学习日志#8 GAS--ASC源码简要分析5 GameplayEffects: Primary outward facing API for other systems P2

注:1.这个分类是按照源码里的注释分类的

2.本篇是通读并给出一些注释形式的,并不涉及结构性的分析

3.看之前要对UE的GAS系统的定义有初步了解

4.因为都是接口函数,有些没细看的研究那一部分的时候会细看

8 OnPredictiveGameplayCueCatchup

Call预测性添加的GC,移除标签并尝试InvokeGC事件ByTag

/** Called for predictively added gameplay cue. Needs to remove tag count and possible invoke OnRemove event if misprediction */
	virtual void OnPredictiveGameplayCueCatchup(FGameplayTag Tag);

 实现:

void UAbilitySystemComponent::OnPredictiveGameplayCueCatchup(FGameplayTag Tag)
{
	// Remove it
	RemoveLooseGameplayTag(Tag);

	if (HasMatchingGameplayTag(Tag) == 0)
	{
		// Invoke Removed event if we no longer have this tag (probably a mispredict)
		InvokeGameplayCueEvent(Tag, EGameplayCueEvent::Removed);
	}
}

9 GetGameplayEffectDuration

声明:

输入Handle,返回

/** Returns the total duration of a gameplay effect */
	float GetGameplayEffectDuration(FActiveGameplayEffectHandle Handle) const;

实现:

调用FActiveGameplayEffectsContainer类型的GetGameplayEffectStartTimeAndDuration

float UAbilitySystemComponent::GetGameplayEffectDuration(FActiveGameplayEffectHandle Handle) const
{
	float StartEffectTime = 0.0f;
	float Duration = 0.0f;
	ActiveGameplayEffects.GetGameplayEffectStartTimeAndDuration(Handle, StartEffectTime, Duration);

	return Duration;
}

 到了GetGameplayEffectStartTimeAndDuration中匹配Handle,然后调用下边这个获取

EffectStartTime = ActiveEffect.StartWorldTime;
EffectDuration = ActiveEffect.GetDuration();

10 RecomputeGameplayEffectStartTimes

通过游戏状态同步服务器时间的时候调用,来保持冷却时间与服务器的同步

/** Called whenever the server time replicates via the game state to keep our cooldown timers in sync with the server */
	virtual void RecomputeGameplayEffectStartTimes(const float WorldTime, const float ServerWorldTime);

 调用FActiveGameplayEffectsContainer类型的RecomputeStartWorldTimes

void UAbilitySystemComponent::RecomputeGameplayEffectStartTimes(const float WorldTime, const float ServerWorldTime)
{
	ActiveGameplayEffects.RecomputeStartWorldTimes(WorldTime, ServerWorldTime);
}

 他的声明和实现:

/** Recomputes the start time for all active abilities */
	void RecomputeStartWorldTimes(const float WorldTime, const float ServerWorldTime);
void FActiveGameplayEffectsContainer::RecomputeStartWorldTimes(const float WorldTime, const float ServerWorldTime)
{
	for (FActiveGameplayEffect& ActiveEffect : this)
	{
		ActiveEffect.RecomputeStartWorldTime(WorldTime, ServerWorldTime);
	}
}

还是被我找到核心了,就是把服务器端的StartWorldTime同步到客户端 

void FActiveGameplayEffect::RecomputeStartWorldTime(const float WorldTime, const float ServerWorldTime)
{
	StartWorldTime = WorldTime - (ServerWorldTime - StartServerWorldTime);
}

11 GetGameplayEffectStartTimeAndDuration

一个接口,调用前面说过的FActiveGameplayEffectsContainer类型里的GetGameplayEffectStartTimeAndDuration

void UAbilitySystemComponent::GetGameplayEffectStartTimeAndDuration(FActiveGameplayEffectHandle Handle, float& StartEffectTime, float& Duration) const
{
	return ActiveGameplayEffects.GetGameplayEffectStartTimeAndDuration(Handle, StartEffectTime, Duration);
}

12 UpdateActiveGameplayEffectSetByCallerMagnitude/s

声明://某些GE修改参数的幅值是SetByCaller的,也就是由调用者设置

/** Dynamically update the set-by-caller magnitude for an active gameplay effect */
	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = GameplayEffects)
	virtual void UpdateActiveGameplayEffectSetByCallerMagnitude(FActiveGameplayEffectHandle ActiveHandle, UPARAM(meta=(Categories = "SetByCaller"))FGameplayTag SetByCallerTag, float NewValue);

	/** Dynamically update multiple set-by-caller magnitudes for an active gameplay effect */
	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = GameplayEffects)
	virtual void UpdateActiveGameplayEffectSetByCallerMagnitudes(FActiveGameplayEffectHandle ActiveHandle, const TMap& NewSetByCallerValues);

实现://接口继续调用FActiveGameplayEffectsContainer类型里的

void UAbilitySystemComponent::UpdateActiveGameplayEffectSetByCallerMagnitude(FActiveGameplayEffectHandle ActiveHandle, FGameplayTag SetByCallerTag, float NewValue)
{
	ActiveGameplayEffects.UpdateActiveGameplayEffectSetByCallerMagnitude(ActiveHandle, SetByCallerTag, NewValue);
}

 更新指定Handle的SetByCallerMagnitude,调用标签版本的,下边会贴一下

然后是计算Modifier

UpdateAllAggregatorModMagnitudes把要更新的加入一个堆AttributesToUpdate,然后调用UpdateAggregatorModMagnitudes(AttributesToUpdate, ActiveEffect);

void FActiveGameplayEffectsContainer::UpdateActiveGameplayEffectSetByCallerMagnitude(FActiveGameplayEffectHandle ActiveHandle, const FGameplayTag& SetByCallerTag, float NewValue)
{
	if (FActiveGameplayEffect* Effect = GetActiveGameplayEffect(ActiveHandle))
	{
		Effect->Spec.SetSetByCallerMagnitude(SetByCallerTag, NewValue);
		Effect->Spec.CalculateModifierMagnitudes();
		MarkItemDirty(*Effect);

		UpdateAllAggregatorModMagnitudes(*Effect);
	}
}
void FGameplayEffectSpec::SetSetByCallerMagnitude(FName DataName, float Magnitude)
{
	if (DataName != NAME_None)
	{
		SetByCallerNameMagnitudes.FindOrAdd(DataName) = Magnitude;
	}
}

void FGameplayEffectSpec::SetSetByCallerMagnitude(FGameplayTag DataTag, float Magnitude)
{
	if (DataTag.IsValid())
	{
		SetByCallerTagMagnitudes.FindOrAdd(DataTag) = Magnitude;
	}
}

 UpdateAggregatorModMagnitudes的实现:

void FActiveGameplayEffectsContainer::UpdateAggregatorModMagnitudes(const TSet& AttributesToUpdate, FActiveGameplayEffect& ActiveEffect)
{
	const FGameplayEffectSpec& Spec = ActiveEffect.Spec;
	for (const FGameplayAttribute& Attribute : AttributesToUpdate)
	{
		// skip over any modifiers for attributes that we don't have
		if (!Owner || Owner->HasAttributeSetForAttribute(Attribute) == false)
		{
			continue;
		}

		FAggregator* Aggregator = FindOrCreateAttributeAggregator(Attribute).Get();
		check(Aggregator);

		// Update the aggregator Mods.
		Aggregator->UpdateAggregatorMod(ActiveEffect.Handle, Attribute, Spec, ActiveEffect.PredictionKey.WasLocallyGenerated(), ActiveEffect.Handle);
	}
}

UpdateActiveGameplayEffectSetByCallerMagnitudes就不贴了,逻辑上就是多了一步遍历调用UpdateActiveGameplayEffectSetByCallerMagnitude

13 SetActiveGameplayEffectLevel/UsingQuery

声明:

/** Updates the level of an already applied gameplay effect. The intention is that this is 'seemless' and doesnt behave like removing/reapplying */
	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = GameplayEffects)
	virtual void SetActiveGameplayEffectLevel(FActiveGameplayEffectHandle ActiveHandle, int32 NewLevel);

追溯过程同理,这里直接贴最后调用的GE里的核心代码:

可以看到重新计算了Modifier

Effect.Spec.SetLevel(NewLevel);
MarkItemDirty(Effect);
			
Effect.Spec.CalculateModifierMagnitudes();
UpdateAllAggregatorModMagnitudes(Effect);

UsingQuery版本多了一步查询:

TArray ActiveGameplayEffectHandles = ActiveGameplayEffects.GetActiveEffects(Query);

14 InhibitActiveGameplayEffect/SetActiveGameplayEffectInhibit

约束(Inhibit)激活的GE使其无效但没有被移除

/** Inhibit an active gameplay effect so that it is disabled, but not removed */
	UE_DEPRECATED(5.4, "Use SetActiveGameplayEffectInhibit with a MoveTemp(ActiveGEHandle) so it's clear the Handle is no longer valid. Check (then use) the returned FActiveGameplayEffectHandle to continue your operation.")
	virtual void InhibitActiveGameplayEffect(FActiveGameplayEffectHandle ActiveGEHandle, bool bInhibit, bool bInvokeGameplayCueEvents);

 这行比较关键,调用了SetActiveGameplayEffectInhibit

FActiveGameplayEffectHandle ContinuationHandle = SetActiveGameplayEffectInhibit(MoveTemp(ActiveGEHandle), bInhibit, bInvokeGameplayCueEvents);

 SetActiveGameplayEffectInhibit的实现:

检查有效性

保证线程的安全性

更新约束状态

处理标签和修改器

处理状态变化的回调

FActiveGameplayEffectHandle UAbilitySystemComponent::SetActiveGameplayEffectInhibit(FActiveGameplayEffectHandle&& ActiveGEHandle, bool bInhibit, bool bInvokeGameplayCueEvents)
{
	FActiveGameplayEffect* ActiveGE = ActiveGameplayEffects.GetActiveGameplayEffect(ActiveGEHandle);
	if (!ActiveGE)
	{
		ABILITY_LOG(Error, TEXT("%s received bad Active GameplayEffect Handle: %s"), ANSI_TO_TCHAR(__func__), *ActiveGEHandle.ToString());
		return FActiveGameplayEffectHandle();
	}

	if (ActiveGE->bIsInhibited != bInhibit)
	{
		ActiveGE->bIsInhibited = bInhibit;

		// It's possible the adding or removing of the tags can invalidate the ActiveGE.  As such,
		// let's make sure we hold on to that memory until this function is done.
		FScopedActiveGameplayEffectLock ScopeLockActiveGameplayEffects(ActiveGameplayEffects);

		// All OnDirty callbacks must be inhibited until we update this entire GameplayEffect.
		FScopedAggregatorOnDirtyBatch	AggregatorOnDirtyBatcher;
		if (bInhibit)
		{
			// Remove our ActiveGameplayEffects modifiers with our Attribute Aggregators
			ActiveGameplayEffects.RemoveActiveGameplayEffectGrantedTagsAndModifiers(*ActiveGE, bInvokeGameplayCueEvents);
		}
		else
		{
			ActiveGameplayEffects.AddActiveGameplayEffectGrantedTagsAndModifiers(*ActiveGE, bInvokeGameplayCueEvents);
		}

		// The act of executing anything on the ActiveGE can invalidate it.  So we need to recheck if we can continue to execute the callbacks.
		if (!ActiveGE->IsPendingRemove)
		{
			ActiveGE->EventSet.OnInhibitionChanged.Broadcast(ActiveGEHandle, ActiveGE->bIsInhibited);
		}

		// We lost that it was active somewhere along the way, let the caller know
		if (ActiveGE->IsPendingRemove)
		{
			return FActiveGameplayEffectHandle();
		}
	}

你可能感兴趣的:(UE学习日志,学习,游戏引擎)