NumBitsForContainerSize
NumBitsForContainerSize
#Overview
name: NumBitsForContainerSize
The value of this variable can be defined or overridden in .ini config files. 1
.ini config file referencing this setting variable.
It is referenced in 8
C++ source files.
#Summary
#Usage in the C++ source code
The purpose of NumBitsForContainerSize is to define the number of bits used for replicating the size of a gameplay tag container in Unreal Engine’s networking system. This variable is primarily used for optimizing network traffic when sending gameplay tag containers between server and clients.
NumBitsForContainerSize is mainly used by the Gameplay Tags system, which is a core component of Unreal Engine’s gameplay framework. It’s specifically utilized in the GameplayTags module, as evidenced by its presence in GameplayTagsManager and GameplayTagsSettings classes.
The value of this variable is set in multiple places:
- It’s initialized in the UGameplayTagsManager constructor.
- It can be configured in the GameplayTagsSettings, as indicated by the UPROPERTY macro in GameplayTagsSettings.h.
- It’s updated in the UGameplayTagsManager::ConstructGameplayTagTree() function based on the value from GameplayTagsSettings.
This variable interacts closely with other networking-related variables in the Gameplay Tags system, such as NetIndexFirstBitSegment.
Developers should be aware that:
- This variable directly affects the maximum size of gameplay tag containers that can be replicated. The maximum size is (2^NumBitsForContainerSize) - 1.
- Changing this value affects network performance and compatibility. Increasing it allows for larger containers but uses more bandwidth.
- It’s validated in the FGameplayTagContainerNetSerializer to ensure it’s between 1 and 31 bits.
Best practices when using this variable include:
- Set it based on the typical size of your gameplay tag containers to optimize network usage.
- Avoid frequent changes, especially in live games, as it could cause network incompatibility.
- Consider the trade-off between supporting larger containers and network efficiency.
- Ensure all connected clients and servers use the same value to prevent replication issues.
#Setting Variables
#References In INI files
Location: <Workspace>/Projects/Lyra/Config/DefaultGameplayTags.ini:9, section: [/Script/GameplayTags.GameplayTagsSettings]
- INI Section:
/Script/GameplayTags.GameplayTagsSettings
- Raw value:
6
- Is Array:
False
#References in C++ code
#Callsites
This variable is referenced in the following C++ source code:
#Loc: <Workspace>/Engine/Source/Runtime/GameplayTags/Classes/GameplayTagsManager.h:612
Scope (from outer to inner):
file
class class UGameplayTagsManager : public UObject
Source code excerpt:
/** Numbers of bits to use for replicating container size. This can be set via config. */
int32 NumBitsForContainerSize;
GAMEPLAYTAGS_API void PushDeferOnGameplayTagTreeChangedBroadcast();
GAMEPLAYTAGS_API void PopDeferOnGameplayTagTreeChangedBroadcast();
private:
/** Cached number of bits we need to replicate tags. That is, Log2(Number of Tags). Will always be <= 16. */
#Loc: <Workspace>/Engine/Source/Runtime/GameplayTags/Classes/GameplayTagsSettings.h:146
Scope (from outer to inner):
file
class class UGameplayTagsSettings : public UGameplayTagsList
Source code excerpt:
/** Numbers of bits to use for replicating container size, set this based on how large your containers tend to be */
UPROPERTY(config, EditAnywhere, Category = "Advanced Replication")
int32 NumBitsForContainerSize;
/** The length in bits of the first segment when net serializing tags. We will serialize NetIndexFirstBitSegment + 1 bit to indicate "more", which is slower to replicate */
UPROPERTY(config, EditAnywhere, Category= "Advanced Replication")
int32 NetIndexFirstBitSegment;
/** A list of .ini files used to store restricted gameplay tags. */
#Loc: <Workspace>/Engine/Source/Runtime/GameplayTags/Private/GameplayTagContainer.cpp:944
Scope (from outer to inner):
file
function bool FGameplayTagContainer::NetSerialize
Source code excerpt:
// -------------------------------------------------------
const int32 NumBitsForContainerSize = UGameplayTagsManager::Get().NumBitsForContainerSize;
if (Ar.IsSaving())
{
uint8 NumTags = IntCastChecked<uint8, int32>(GameplayTags.Num());
uint8 MaxSize = (1 << NumBitsForContainerSize) - 1;
if (!ensureMsgf(NumTags <= MaxSize, TEXT("TagContainer has %d elements when max is %d! Tags: %s"), NumTags, MaxSize, *ToStringSimple()))
{
NumTags = MaxSize;
}
Ar.SerializeBits(&NumTags, NumBitsForContainerSize);
for (int32 idx=0; idx < NumTags;++idx)
{
FGameplayTag& Tag = GameplayTags[idx];
Tag.NetSerialize_Packed(Ar, Map, bOutSuccess);
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
#Loc: <Workspace>/Engine/Source/Runtime/GameplayTags/Private/GameplayTagContainer.cpp:970
Scope (from outer to inner):
file
function bool FGameplayTagContainer::NetSerialize
Source code excerpt:
// No Common Container tags, just replicate this like normal
uint8 NumTags = 0;
Ar.SerializeBits(&NumTags, NumBitsForContainerSize);
GameplayTags.Empty(NumTags);
GameplayTags.AddDefaulted(NumTags);
for (uint8 idx = 0; idx < NumTags; ++idx)
{
GameplayTags[idx].NetSerialize_Packed(Ar, Map, bOutSuccess);
#Loc: <Workspace>/Engine/Source/Runtime/GameplayTags/Private/GameplayTagContainerNetSerializer.cpp:184
Scope (from outer to inner):
file
namespace UE::Net
function bool FGameplayTagContainerNetSerializer::Validate
Source code excerpt:
const SourceType& SourceValue = *reinterpret_cast<const SourceType*>(Args.Source);
const int32 NumBitsForContainerSize = UGameplayTagsManager::Get().NumBitsForContainerSize;
// More than 31 bits would result in undefined behavior for shifting and more than 32 bits is more than the bitstream API supports in a single call.
if (NumBitsForContainerSize <= 0 || NumBitsForContainerSize > 31)
{
// This is worthy of a check as not even a zero sized container can be sent with zero bits.
checkf(NumBitsForContainerSize > 0, TEXT("Incorrectly configured GameplayTagsManager with %d bits for container size."), NumBitsForContainerSize);
return false;
}
const uint32 NumTags = static_cast<uint32>(SourceValue.GetGameplayTags().Num());
const uint32 MaxSize = (1U << static_cast<uint32>(NumBitsForContainerSize)) - 1U;
if (NumTags > MaxSize)
{
return false;
}
FGameplayTagContainerNetSerializerSerializationHelper IntermediateValue;
#Loc: <Workspace>/Engine/Source/Runtime/GameplayTags/Private/GameplayTagsManager.cpp:184
Scope (from outer to inner):
file
function UGameplayTagsManager::UGameplayTagsManager
Source code excerpt:
NetIndexFirstBitSegment = 16;
NetIndexTrueBitNum = 16;
NumBitsForContainerSize = 6;
NetworkGameplayTagNodeIndexHash = 0;
}
// Enable to turn on detailed startup logging
#define GAMEPLAYTAGS_VERBOSE 0
#Loc: <Workspace>/Engine/Source/Runtime/GameplayTags/Private/GameplayTagsManager.cpp:560
Scope (from outer to inner):
file
function void UGameplayTagsManager::ConstructGameplayTagTree
Source code excerpt:
bShouldWarnOnInvalidTags = MutableDefault->WarnOnInvalidTags;
bShouldClearInvalidTags = MutableDefault->ClearInvalidTags;
NumBitsForContainerSize = MutableDefault->NumBitsForContainerSize;
NetIndexFirstBitSegment = MutableDefault->NetIndexFirstBitSegment;
#if WITH_EDITOR
if (GIsEditor)
{
bShouldAllowUnloadingTags = MutableDefault->AllowEditorTagUnloading;
#Loc: <Workspace>/Engine/Source/Runtime/GameplayTags/Private/GameplayTagsSettings.cpp:68
Scope (from outer to inner):
file
function UGameplayTagsSettings::UGameplayTagsSettings
Source code excerpt:
AllowGameTagUnloading = false;
InvalidTagCharacters = ("\"',");
NumBitsForContainerSize = 6;
NetIndexFirstBitSegment = 16;
}
#if WITH_EDITOR
void UGameplayTagsSettings::PreEditChange(FProperty* PropertyThatWillChange)
{