Files
UnrealEngine/Engine/Source/Runtime/Online/BuildPatchServices/Private/BuildPatchProgress.cpp
2025-05-18 13:04:45 +08:00

255 lines
6.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
BuildPatchProgress.cpp: Implements classes involved with tracking the patch
progress information.
=============================================================================*/
#include "BuildPatchProgress.h"
#include "Misc/ScopeLock.h"
#include "HAL/PlatformTime.h"
#include "HAL/PlatformProcess.h"
namespace BuildPatchServices
{
/* FBuildPatchProgress implementation
*****************************************************************************/
FBuildPatchProgress::FBuildPatchProgress()
{
TotalWeight = 0.0f;
CurrentState = EBuildPatchState::Queued;
CurrentProgress = 0.0f;
bIsDownloading = false;
bShouldAbort = false;
// Initialize array data
for (uint32 idx = 0; idx < static_cast<uint32>(EBuildPatchState::NUM_PROGRESS_STATES); ++idx)
{
StateProgressValues[idx] = 0.0f;
StateProgressWeights[idx] = 1.0f;
}
// Update for initial values
UpdateCachedValues();
UpdateProgressInfo();
}
void FBuildPatchProgress::SetPaused(bool bIsPaused)
{
FScopeLock ScopeLock(&ThreadLock);
if (GetPauseState() != bIsPaused)
{
TogglePauseState();
}
}
void FBuildPatchProgress::Abort()
{
bShouldAbort = true;
}
void FBuildPatchProgress::SetStateProgress(const EBuildPatchState& State, const float& Value)
{
check(!FMath::IsNaN(Value));
FScopeLock ScopeLock(&ThreadLock);
if (StateProgressValues[static_cast<uint32>(State)] != Value)
{
StateProgressValues[static_cast<uint32>(State)] = Value;
UpdateProgressInfo();
}
}
void FBuildPatchProgress::SetStateWeight(const EBuildPatchState& State, const float& Value)
{
check(!FMath::IsNaN(Value));
FScopeLock ScopeLock(&ThreadLock);
if (bCountsTowardsProgress[static_cast<uint32>(State)])
{
TotalWeight += Value - StateProgressWeights[static_cast<uint32>(State)];
StateProgressWeights[static_cast<uint32>(State)] = Value;
}
}
EBuildPatchState FBuildPatchProgress::GetState() const
{
FScopeLock ScopeLock(&ThreadLock);
return CurrentState;
}
float FBuildPatchProgress::GetProgress() const
{
FScopeLock ScopeLock(&ThreadLock);
if (bHasProgressValue[static_cast<uint32>(CurrentState)])
{
return CurrentProgress;
}
// We return -1.0f to indicate a marquee style progress should be displayed
return -1.0f;
}
float FBuildPatchProgress::GetProgressNoMarquee() const
{
FScopeLock ScopeLock(&ThreadLock);
return CurrentProgress;
}
float FBuildPatchProgress::GetStateProgress(const EBuildPatchState& State) const
{
FScopeLock ScopeLock(&ThreadLock);
return StateProgressValues[static_cast<uint32>(State)];
}
float FBuildPatchProgress::GetStateWeight(const EBuildPatchState& State) const
{
FScopeLock ScopeLock(&ThreadLock);
return StateProgressWeights[static_cast<uint32>(State)];
}
bool FBuildPatchProgress::TogglePauseState()
{
FScopeLock ScopeLock(&ThreadLock);
// If in pause state revert to no state and recalculate progress
if (CurrentState == EBuildPatchState::Paused)
{
CurrentState = EBuildPatchState::NUM_PROGRESS_STATES;
UpdateProgressInfo();
return false;
}
else
{
// Else we just set paused
CurrentState = EBuildPatchState::Paused;
return true;
}
}
bool FBuildPatchProgress::GetPauseState() const
{
FScopeLock ScopeLock(&ThreadLock);
return CurrentState == EBuildPatchState::Paused;
}
double FBuildPatchProgress::WaitWhilePaused() const
{
// Pause if necessary
const double PrePauseTime = FPlatformTime::Seconds();
double PostPauseTime = PrePauseTime;
while (GetPauseState())
{
FPlatformProcess::Sleep(0.1f);
PostPauseTime = FPlatformTime::Seconds();
}
// Return pause time
return PostPauseTime - PrePauseTime;
}
void FBuildPatchProgress::SetIsDownloading(bool bInIsDownloading)
{
FScopeLock ScopeLock(&ThreadLock);
if (bIsDownloading != bInIsDownloading)
{
bIsDownloading = bInIsDownloading;
UpdateProgressInfo();
}
}
void FBuildPatchProgress::CancelAbort()
{
bShouldAbort = false;
}
void FBuildPatchProgress::UpdateProgressInfo()
{
FScopeLock ScopeLock(&ThreadLock);
// If we are paused or there's an error, we don't change the state or progress value
if (bShouldAbort || CurrentState == EBuildPatchState::Paused)
{
return;
}
// Reset values
CurrentState = EBuildPatchState::NUM_PROGRESS_STATES;
CurrentProgress = 0.0f;
// Loop through each progress value to find total progress and current state
for (uint32 idx = 0; idx < static_cast<uint32>(EBuildPatchState::NUM_PROGRESS_STATES); ++idx)
{
// Is this the current state
if ((CurrentState == EBuildPatchState::NUM_PROGRESS_STATES) && StateProgressValues[idx] < 1.0f)
{
CurrentState = static_cast<EBuildPatchState>(idx);
}
// Do we count the progress
if (bCountsTowardsProgress[idx])
{
const float StateProgress = StateProgressValues[idx] * (StateProgressWeights[idx] / TotalWeight);
CurrentProgress += StateProgress;
check(!FMath::IsNaN(CurrentProgress));
}
}
// Ensure Sanity
CurrentProgress = FMath::Clamp(CurrentProgress, 0.0f, 1.0f);
// Switch between Downloading and Installing depending on bIsDownloading
// This avoids reporting a Downloading state while the download system is idle during long periods of
// mainly hard disk activity, before all downloadable chunks have been required.
if (CurrentState == EBuildPatchState::Downloading && !bIsDownloading)
{
CurrentState = EBuildPatchState::Installing;
}
}
void FBuildPatchProgress::UpdateCachedValues()
{
TotalWeight = 0.0f;
for (uint32 idx = 0; idx < static_cast<uint32>(EBuildPatchState::NUM_PROGRESS_STATES); ++idx)
{
if (bCountsTowardsProgress[idx])
{
TotalWeight += StateProgressWeights[idx];
}
}
// If you assert here you're going to cause a divide by 0.0f
check(TotalWeight != 0.0f);
}
/* FBuildPatchProgress static constants
*****************************************************************************/
const bool FBuildPatchProgress::bHasProgressValue[static_cast<int32>(EBuildPatchState::NUM_PROGRESS_STATES)] =
{
false, // Queued
false, // Initializing
true, // Resuming
true, // Downloading
true, // Installing
true, // MovingToInstall
true, // SettingAttributes
true, // BuildVerification
false, // CleanUp
false, // PrerequisitesInstall
false, // Completed
true // Paused
};
const bool FBuildPatchProgress::bCountsTowardsProgress[static_cast<int32>(EBuildPatchState::NUM_PROGRESS_STATES)] =
{
false, // Queued
false, // Initializing
false, // Resuming
true, // Downloading
true, // Installing
true, // MovingToInstall
true, // SettingAttributes
true, // BuildVerification
false, // CleanUp
false, // PrerequisitesInstall
false, // Completed
false // Paused
};
}