这是一个非常简单的容器,它允许将游戏标签复制为堆栈计数,用于武器弹药、库存物品计数、统计点等内容。

这是头文件:
USTRUCT(BlueprintType)
struct FKaosGameplayTagStack : public FFastArraySerializerItem
{
GENERATED_BODY()
FKaosGameplayTagStack()
{}
FKaosGameplayTagStack(FGameplayTag InTag, int32 InCount)
: Tag(InTag)
{
Tag = InTag;
Count = InCount;
}
private:
friend FKaosGameplayTagStackContainer;
UPROPERTY()
FGameplayTag Tag;
UPROPERTY()
int32 Count = 0;
};
USTRUCT(BlueprintType)
struct FKaosGameplayTagStackContainer : public FFastArraySerializer
{
GENERATED_BODY()
FKaosGameplayTagStackContainer() { }
public:
void PreReplicatedRemove(const TArrayView<int32> RemovedIndices, int32 FinalSize);
void PostReplicatedAdd(const TArrayView<int32> AddedIndices, int32 FinalSize);
void PostReplicatedChange(const TArrayView<int32> ChangedIndices, int32 FinalSize);
bool NetDeltaSerialize(FNetDeltaSerializeInfo& DeltaParms)
{
return FastArrayDeltaSerialize<FKaosGameplayTagStack, FKaosGameplayTagStackContainer>(Stacks, DeltaParms, *this);
}
/*
* 将计数添加到标签的堆栈中
*/
void AddStackCount(FGameplayTag Tag, int32 Count);
/*
* 从标签的堆栈中删除计数
*/
void RemoveStackCount(FGameplayTag Tag, int32 Count);
/*
* 如果堆栈中有一个或多个标签,则返回 true。
*/
bool HasTag(FGameplayTag Tag) const
{
return TagToCountMap.Contains(Tag);
}
/*
* 返回我们为提供的标签所拥有的堆栈数量
*/
int32 GetStackCount(FGameplayTag Tag) const
{
return TagToCountMap.FindRef(Tag);
}
private:
// 游戏标签堆栈列表,使用加速的 TagCountMap 来检查标签计数等。
UPROPERTY()
TArray<FKaosGameplayTagStack> Stacks;
// 查询的加速列表
TMap<FGameplayTag, int32> TagCountMap;
};
template<>
struct TStructOpsTypeTraits<FKaosGameplayTagStackContainer> : public TStructOpsTypeTraitsBase2<FKaosGameplayTagStackContainer>
{
enum
{
WithNetDeltaSerializer = true,
};
};
和 CPP 文件部分:
void FKaosGameplayTagStackContainer::AddStackCount(FGameplayTag Tag, int32 Count)
{
if (Count > 0)
{
for (FKaosGameplayTagStack& Stack : Stacks)
{
if (Stack.Tag == Tag)
{
const int32 NewCount = Stack.Count + Count;
Stack.Count = NewCount;
TagCountMap[Tag] = NewCount;
MarkItemDirty(Stack);
return;
}
}
FKaosGameplayTagStack& NewStack = Stacks.Emplace_GetRef(Tag, Count);
MarkItemDirty(NewStack);
TagCountMap.Add(Tag, Count);
}
}
void FKaosGameplayTagStackContainer::RemoveStackCount(FGameplayTag Tag, int32 Count)
{
if (Count > 0)
{
for (auto It = Stacks.CreateIterator(); It; ++It)
{
FKaosGameplayTagStack& Stack = *It;
if (Stack.Tag == Tag)
{
if (Stack.Count <= Count)
{
It.RemoveCurrent();
TagCountMap.Remove(Tag);
MarkArrayDirty();
}
else
{
const int32 NewCount = Stack.Count - Count;
Stack.Count = NewCount;
TagCountMap[Tag] = NewCount;
MarkItemDirty(Stack);
}
return;
}
}
}
}
void FKaosGameplayTagStackContainer::PreReplicatedRemove(const TArrayView<int32> RemovedIndices, int32 FinalSize)
{
for (const int32 Index : RemovedIndices)
{
const FGameplayTag Tag = Stacks[Index].Tag;
TagCountMap.Remove(Tag);
}
}
void FKaosGameplayTagStackContainer::PostReplicatedAdd(const TArrayView<int32> AddedIndices, int32 FinalSize)
{
for (const int32 Index : AddedIndices)
{
const FKaosGameplayTagStack& Stack = Stacks[Index];
TagCountMap.Add(Stack.Tag, Stack.Count);
}
}
void FKaosGameplayTagStackContainer::PostReplicatedChange(const TArrayView<int32> ChangedIndices, int32 FinalSize)
{
for (const int32 Index : ChangedIndices)
{
const FKaosGameplayTagStack& Stack = Stacks[Index];
TagCountMap[Stack.Tag] = Stack.Count;
}
}
要使用它,只需在某处添加一个复制属性:
属性使用标准的 C++ 变量语法声明,前面用 UPROPERTY 宏来定义属性元数据和变量说明符。
UPROPERTY(Replicated)
FKaosGameplayTagStackContainer GameplayStats;
可以这样类似使用它:
void AMyCharacter::AddStatTagCount(FGameplayTag Tag, int32 Count)
{
GameplayStats.AddStack(Tag, Count);
}
void AMyCharacter::RemoveStatTagCount(FGameplayTag Tag, int32 Count)
{
GameplayStats.RemoveStack(Tag, Count);
}
int32 AMyCharacter::GetStatTagStackCount(FGameplayTag Tag) const
{
return GameplayStats.GetStackCount(Tag);
}
bool AMyCharacter::HasStatTag(FGameplayTag Tag) const
{
return GameplayStats.ContainsTag(Tag);
}