gpt4 book ai didi

c++ - 如何在客户端获取 GameplayAbility 属性的增量值(属性值更改后)?

转载 作者:行者123 更新时间:2023-11-28 04:26:38 25 4
gpt4 key购买 nike

在我的虚幻引擎项目中,它使用 GameplayAbilitySystem和默认的服务器-> 客户端架构,客户端会收到服务器上发生的属性值更改的通知。

此外,我不仅要获取新值,还要获取值更改的量(delta = 新值 - 旧值)。这应该可以使用 attribute value change delegate ,因为它包含 FOnAttributeChangeData 及其成员 NewValueOldValue

在服务器上,两个值都是正确的。但是,在客户端上,FOnAttributeChangeData::NewValue == FOnAttributeChangeData::OldValue 和两者的值都与服务器上的 NewValue 相同。

这是因为委托(delegate)在复制发生后被调用...

UPROPERTY(ReplicatedUsing=OnRep_MyAttribute)
FGameplayAttributeData MyAttribute;

void UAttributeSetBase::OnRep_MyAttribute()
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MyAttribute);
}

(这是 ActionRPG 的默认 GAS 设置)

...所以客户端不知道它在复制之前的值。

  1. 如何获取服务器更新之前的属性值?
  2. 如何将此值转发给委托(delegate)人?

最佳答案

获取旧值(问题1)

UnrealEngine OnRep 函数提供复制变量的先前状态作为 OnRep 函数中的第一个参数。所以添加参数

void UAttributeSetBase::OnRep_MyAttribute(const FGameplayAttributeData& Previous)
{
const auto PreviousValue = Previous.GetCurrentValue(); // See below for possible usage.
GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MyAttribute);
}

感谢 Unreal GAS discord channel 的@Dan。

将值转发给委托(delegate)人(问题2)

想法

当您的目标是不修改 UE4 源代码时,一种可能是在属性集中缓存以前的值,这样您就可以从外部访问它。

  1. 在属性集 OnRep 函数中缓存每个属性的值。
  2. 在委托(delegate)中使用缓存的值,但仅当它有效时。由于该值是在 OnRep 函数中分配的,因此它不会存在于服务器上。这非常好,因为我们希望保留服务器上的行为,它使用 FOnAttributeChangeData::OldValue(仅在服务器上具有正确的值)。

示例实现

缓存之前的值

AttributeSetBase.h:

// Wrapper for a TMap. If you need thread safety, use another container or allocator.
class CachePreviousDataFromReplication
{
TMap<FName, FGameplayAttributeData> CachedPreviousData;
public:
void Add(const FName, const FGameplayAttributeData&);
auto Find(const FName) const -> const FGameplayAttributeData*;
};
class YOUR_API UAttributeSetBase : public UAttributeSet
{
// ...
private:
UFUNCTION() void OnRep_MyAttribute(const FGameplayAttributeData& Previous);
// ...
private:
CachePreviousDataFromReplication CachedDataFromReplication;
public:
// \param[in] AttributeName Use GET_MEMBER_NAME_CHECKED() to retrieve the name.
auto GetPreviousDataFromReplication(const FName AttributeName) const -> const FGameplayAttributeData*;
}

AttributeSetBase.cpp:

void CachePreviousDataFromReplication::Add(const FName AttributeName, const FGameplayAttributeData& AttributeData)
{
this->CachedPreviousData.Add(AttributeName, AttributeData);
}

auto CachePreviousDataFromReplication::Find(const FName AttributeName) const -> const FGameplayAttributeData*
{
return CachedPreviousData.Find(AttributeName);
}

void UAttributeSetBase::OnRep_MyAttribute(const FGameplayAttributeData& Previous)
{
CachedDataFromReplication.Add(GET_MEMBER_NAME_CHECKED(UAttributeSetBase, MyAttribute), Previous); // Add this to every OnRep function.
GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MyAttribute);
}

auto UAttributeSetBase::GetPreviousDataFromReplication(const FName AttributeName) const -> const FGameplayAttributeData*
{
return CachedDataFromReplication.Find(AttributeName);
}

访问委托(delegate)中的先前值

ACharacterBase.h:

class YOUR_API ACharacterBase : public ACharacter, public IAbilitySystemInterface
{
// ...
void OnMyAttributeValueChange(const FOnAttributeChangeData& Data); // The callback to be registered within GAS.
// ...
}

ACharacterBase.cpp:

void ACharacterBase::OnMyAttributeValueChange(const FOnAttributeChangeData& Data)
{
// This delegate is fired either from
// 1. `SetBaseAttributeValueFromReplication` or from
// 2. `InternalUpdateNumericalAttribute`
// #1 is called on clients, after the attribute has changed its value. This implies,
// that the previous value is not present on the client anymore. Therefore, the
// value of `Data.OldValue` is erroneously identical to `Data.NewValue`.
// In that case (and only in that case), the previous value is retrieved from a cache
// in the AttributeSet. This cache will be only present on client, after it had
// received an update from replication.
auto deltaValue = 0.f;
if (Data.NewValue == Data.OldValue)
{
const auto attributeName = GET_MEMBER_NAME_CHECKED(UAttributeSetBase, MyAttribute);
if (auto previousData = AttributeSetComponent->GetPreviousDataFromReplication(attributeName))
{
// This will be called on the client, when coming from replication.
deltaValue = Data.NewValue - previousData->GetCurrentValue();
}
}
else
{
// This might be called on the server or clients, when coming from
// `InternalUpdateNumericalAttribute`.
deltaValue = Data.NewValue - Data.OldValue;
}
// Use deltaValue as you like.
}

关于c++ - 如何在客户端获取 GameplayAbility 属性的增量值(属性值更改后)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54170464/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com