GameVersion

GameVersion

#Overview

name: GameVersion

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 17 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of GameVersion is to identify and manage different versions of the game within the Unreal Engine 5 pipeline cache system. This variable is used to ensure compatibility between cached pipeline state objects (PSOs) and the current game version.

GameVersion is primarily used in the RHI (Rendering Hardware Interface) subsystem, specifically within the pipeline file cache functionality. It’s also referenced in the ShaderPipelineCache module of the RenderCore system.

The value of GameVersion is typically set during the initialization of the PipelineFileCacheManager. By default, it uses the changelist number from the current engine version. However, this can be overridden by the game-specific code or configuration.

GameVersion interacts with other variables in the pipeline cache header, such as Magic, Version, Platform, and Guid. These variables collectively ensure that the cached PSOs are valid for the current game and engine version.

Developers must be aware that:

  1. Changing the GameVersion will invalidate existing pipeline caches, which can impact load times and performance until the cache is rebuilt.
  2. In editor builds, the GameVersion might be different from the current engine changelist to account for precompiled binaries.

Best practices when using this variable include:

  1. Incrementing GameVersion when making significant changes to shaders or rendering pipelines that would invalidate existing caches.
  2. Considering setting a custom GameVersion in the game’s configuration file (DefaultGame.ini) for more controlled versioning.
  3. Being cautious when merging pipeline caches from different game versions, as this can lead to incompatibilities.

By properly managing GameVersion, developers can ensure that the pipeline cache remains valid and optimized for their specific game version, balancing between performance benefits of caching and the need for up-to-date pipeline states.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseEngine.ini:2247, section: [OnlineSubsystemSteam]

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Plugins/Runtime/Steam/SteamShared/Source/SteamShared/Private/SteamSharedModule.cpp:339

Scope (from outer to inner):

file
function     FSteamServerInstanceHandler::FSteamServerInstanceHandler

Source code excerpt:


	// Set GameVersions
	FString GameVersion;
	GConfig->GetString(TEXT("OnlineSubsystemSteam"), TEXT("GameVersion"), GameVersion, GEngineIni);
	if (GameVersion.Len() == 0)
	{
		UE_LOG(LogSteamShared, Warning, TEXT("[OnlineSubsystemSteam].GameVersion is not set. Server advertising will fail"));
	}

	UE_LOG(LogSteamShared, Verbose, TEXT("Initializing Steam Game Server IP: 0x%08X Port: %d QueryPort: %d"), LocalServerIP, GamePort, QueryPort);

	if (SteamGameServer_Init(LocalServerIP, GamePort, QueryPort,
		(bVACEnabled ? eServerModeAuthenticationAndSecure : eServerModeAuthentication),
		TCHAR_TO_UTF8(*GameVersion)))
	{
		UE_LOG(LogSteamShared, Verbose, TEXT("Steam Dedicated Server API initialized."));
		bInitialized = true;
	}
	else
	{

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:226

Scope: file

Source code excerpt:

	uint64 Magic;			// Sanity check
	uint32 Version; 		// File version must match engine version, otherwise we ignore
	uint32 GameVersion; 	// Same as above but game specific code can invalidate
	TEnumAsByte<EShaderPlatform> Platform; // The shader platform for all referenced PSOs.
	FGuid Guid;				// Guid to identify the file uniquely
	uint64 TableOffset;		// absolute file offset to TOC
	int64 LastGCUnixTime;   // Last time that the cache was scanned to remove out of date elements.
	
	friend FArchive& operator<<(FArchive& Ar, FPipelineCacheFileFormatHeader& Info)

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:236

Scope (from outer to inner):

file
function     FArchive& operator<<

Source code excerpt:

		Ar << Info.Magic;
		Ar << Info.Version;
		Ar << Info.GameVersion;
		Ar << Info.Platform;
		Ar << Info.Guid;
		Ar << Info.TableOffset;

		if (Info.Version >= (uint32)EPipelineCacheFileFormatVersions::LastUsedTime)
		{

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:1861

Scope: file

Source code excerpt:

	EStatus CacheStatus = EStatus::Unknown;

	static uint32 GameVersion;

	FPipelineCacheFile()
	: TOCOffset(0)
	, AsyncFileHandle(nullptr)
	{
	}

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:1883

Scope (from outer to inner):

file
function     static bool OpenPipelineFileCache

Source code excerpt:

			FPipelineCacheFileFormatHeader Header = {};
			*FileReader << Header;
			if (Header.Magic == FPipelineCacheFileFormatMagic && Header.Version == FPipelineCacheFileFormatCurrentVersion && Header.GameVersion == GameVersion && Header.Platform == ShaderPlatform)
			{
				check(Header.TableOffset > 0);
				check(FileReader->TotalSize() > 0);
				
				UE_LOG(LogRHI, Log, TEXT("FPipelineCacheFile Header Game Version: %d"), Header.GameVersion);
				UE_LOG(LogRHI, Log, TEXT("FPipelineCacheFile Header Engine Data Version: %d"), Header.Version);
				UE_LOG(LogRHI, Log, TEXT("FPipelineCacheFile Header TOC Offset: %llu"), Header.TableOffset);
				UE_LOG(LogRHI, Log, TEXT("FPipelineCacheFile File Size: %lld Bytes"), FileReader->TotalSize());
				
				if(Header.TableOffset < (uint64)FileReader->TotalSize())
				{

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:1911

Scope (from outer to inner):

file
function     static bool OpenPipelineFileCache

Source code excerpt:

				bool bMagicMatch = (Header.Magic == FPipelineCacheFileFormatMagic);
				bool bVersionMatch = (Header.Version == FPipelineCacheFileFormatCurrentVersion);
				bool bGameVersionMatch = (Header.GameVersion == GameVersion);
				bool bSPMatch = (Header.Platform == ShaderPlatform);
				UE_LOG(LogRHI, Log, TEXT("FPipelineCacheFile: skipping %s (different %s%s%s%s)"), *FilePath,
					bMagicMatch ? TEXT("") : TEXT(" magic"),
					bVersionMatch ? TEXT("") : TEXT(" version"),
					bGameVersionMatch ? TEXT("") : TEXT(" gameversion"),
					bSPMatch ? TEXT("") : TEXT(" shaderplatform")

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:1986

Scope (from outer to inner):

file
function     void GarbageCollectUserCache

Source code excerpt:

		*FileReader << Header;

		if (!(Header.Magic == FPipelineCacheFileFormatMagic && Header.Version == FPipelineCacheFileFormatCurrentVersion && Header.GameVersion == GameVersion && Header.Platform == ShaderPlatform))
		{
			UE_LOG(LogRHI, Error, TEXT("File has invalid or out of date header"));
			return;
		}

		FTimespan GCPeriod = FTimespan::FromDays(GCPeriodInDays);

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:2384

Scope: file

Source code excerpt:

					Header.Magic = FPipelineCacheFileFormatMagic;
					Header.Version = FPipelineCacheFileFormatCurrentVersion;
					Header.GameVersion = GameVersion;
					Header.Platform = ShaderPlatform;
					Header.Guid = FileGuid;
					Header.TableOffset = 0;
					Header.LastGCUnixTime = UnixTime;

					*JournalWriter << Header;

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:2492

Scope: file

Source code excerpt:

						Header.Magic = FPipelineCacheFileFormatMagic;
						Header.Version = FPipelineCacheFileFormatCurrentVersion;
						Header.GameVersion = GameVersion;
						Header.Platform = ShaderPlatform;
						Header.Guid = FileGuid;
						Header.TableOffset = 0;
						Header.LastGCUnixTime = UnixTime;
		 
						*FileWriter << Header;

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:3006

Scope: file

Source code excerpt:

	}
};
uint32 FPipelineCacheFile::GameVersion = 0;

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:3107

Scope (from outer to inner):

file
function     void FPipelineFileCacheManager::Initialize

Source code excerpt:

	// Make enabled explicit on a flag not the existence of "FileCache" object as we are using that behind a lock and in Open / Close operations
	FileCacheEnabled = ShouldEnableFileCache();
	FPipelineCacheFile::GameVersion = InGameVersion;
	if (FPipelineCacheFile::GameVersion == 0)
	{
		// Defaulting the CL is fine though
		FPipelineCacheFile::GameVersion = (uint32)FEngineVersion::Current().GetChangelist();
	}

	SET_MEMORY_STAT(STAT_NewCachedPSOMemory, 0);
	SET_MEMORY_STAT(STAT_PSOStatMemory, 0);
}

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:4034

Scope (from outer to inner):

file
function     bool FPipelineFileCacheManager::SavePipelineFileCacheFrom

Source code excerpt:

}

bool FPipelineFileCacheManager::SavePipelineFileCacheFrom(uint32 GameVersion, EShaderPlatform Platform, FString const& Path, const TSet<FPipelineCacheFileFormatPSO>& PSOs)
{
	FPipelineCacheFileData Output;
	Output.Header.Magic = FPipelineCacheFileFormatMagic;
	Output.Header.Version = FPipelineCacheFileFormatCurrentVersion;
	Output.Header.GameVersion = GameVersion;
	Output.Header.Platform = Platform;
	Output.Header.TableOffset = 0;
	Output.Header.Guid = FGuid::NewGuid();

	Output.TOC.MetaData.Reserve(PSOs.Num());

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:4159

Scope (from outer to inner):

file
function     bool FPipelineFileCacheManager::MergePipelineFileCaches

Source code excerpt:

	FPipelineCacheFileData B = FPipelineCacheFileData::Open(PathB);
	
	if (A.Header.Magic == FPipelineCacheFileFormatMagic && B.Header.Magic == FPipelineCacheFileFormatMagic && A.Header.GameVersion == B.Header.GameVersion && A.Header.Platform == B.Header.Platform && A.Header.Version == FPipelineCacheFileFormatCurrentVersion && B.Header.Version == FPipelineCacheFileFormatCurrentVersion)
	{
		FPipelineCacheFileData Output;
		Output.Header.Magic = FPipelineCacheFileFormatMagic;
		Output.Header.Version = FPipelineCacheFileFormatCurrentVersion;
		Output.Header.GameVersion = A.Header.GameVersion;
		Output.Header.Platform = A.Header.Platform;
		Output.Header.TableOffset = 0;
		Output.Header.Guid = FGuid::NewGuid();
		
		uint32 MergeCount = 0;
		for (auto const& Entry : A.TOC.MetaData)

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Private/PipelineFileCache.cpp:4277

Scope (from outer to inner):

file
function     bool FPipelineFileCacheManager::MergePipelineFileCaches

Source code excerpt:

        }
	}
    else if (A.Header.GameVersion != B.Header.GameVersion)
    {
        UE_LOG(LogRHI, Error, TEXT("Incompatible game versions: %u vs. %u."), A.Header.GameVersion, B.Header.GameVersion);
    }
    else if (A.Header.Platform != B.Header.Platform)
    {
        UE_LOG(LogRHI, Error, TEXT("Incompatible shader platforms: %s vs. %s."), *LegacyShaderPlatformToShaderFormat(A.Header.Platform).ToString(), *LegacyShaderPlatformToShaderFormat(B.Header.Platform).ToString());
    }
    else if (A.Header.Version != B.Header.Version)

#Loc: <Workspace>/Engine/Source/Runtime/RHI/Public/PipelineFileCache.h:323

Scope (from outer to inner):

file
class        class FPipelineFileCacheManager

Source code excerpt:

public:
	
	RHI_API static void Initialize(uint32 GameVersion);
	RHI_API static void Shutdown();
	
	RHI_API static bool LoadPipelineFileCacheInto(FString const& Path, TSet<FPipelineCacheFileFormatPSO>& PSOs);
	RHI_API static bool SavePipelineFileCacheFrom(uint32 GameVersion, EShaderPlatform Platform, FString const& Path, const TSet<FPipelineCacheFileFormatPSO>& PSOs);
	RHI_API static bool MergePipelineFileCaches(FString const& PathA, FString const& PathB, FPipelineFileCacheManager::PSOOrder Order, FString const& OutputPath);
																				
	/* Open the pipeline file cache for the specfied name and platform. If successful, the GUID of the game file will be returned in OutGameFileGuid */
	RHI_API static bool OpenPipelineFileCache(const FString& Key, const FString& CacheName, EShaderPlatform Platform, FGuid& OutGameFileGuid);

	/* Open the user pipeline file cache for the specified name and platform. The user cache is always created even if the file was not present when opened.

#Loc: <Workspace>/Engine/Source/Runtime/RenderCore/Private/ShaderPipelineCache.cpp:635

Scope (from outer to inner):

file
function     int32 FShaderPipelineCache::GetGameVersionForPSOFileCache

Source code excerpt:

int32 FShaderPipelineCache::GetGameVersionForPSOFileCache()
{
	int32 GameVersion = (int32)FEngineVersion::Current().GetChangelist();
#if WITH_EDITOR
	// We might be using the editor built at a different (older) CL than the current sync (think precompiled binaries synced via UGS) when packaging.
	// As such, don't use the current CL as it does not reflect the state of the content.
	FBuildVersion BuildVersion;
	if (FBuildVersion::TryRead(FBuildVersion::GetDefaultFileName(), BuildVersion))
	{

#Loc: <Workspace>/Engine/Source/Runtime/RenderCore/Private/ShaderPipelineCache.cpp:648

Scope (from outer to inner):

file
function     int32 FShaderPipelineCache::GetGameVersionForPSOFileCache

Source code excerpt:

		if (FEngineVersion::Current().GetChangelist() >= (uint32)BuildVersion.CompatibleChangelist)
		{
			GameVersion = BuildVersion.Changelist;
		}
	}
#endif
	GConfig->GetInt(FShaderPipelineCacheConstants::SectionHeading, FShaderPipelineCacheConstants::GameVersionKey, GameVersion, *GGameIni);
	return GameVersion;
}

bool FShaderPipelineCache::SetGameUsageMaskWithComparison(uint64 InMask, FPSOMaskComparisonFn InComparisonFnPtr)
{
	static bool bMaskChanged = false;