Files
UnrealEngine/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSharedCloudInterfaceSteam.cpp
2025-05-18 13:04:45 +08:00

313 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "OnlineSharedCloudInterfaceSteam.h"
#include "OnlineSubsystemSteam.h"
FString FOnlineAsyncTaskSteamReadSharedFile::ToString() const
{
return FString::Printf(TEXT("FOnlineAsyncTaskSteamReadSharedFile bWasSuccessful: %d Handle: %s"), WasSuccessful(), *SharedHandle.ToDebugString());
}
void FOnlineAsyncTaskSteamReadSharedFile::Tick()
{
ISteamUtils* SteamUtilsPtr = SteamUtils();
check(SteamUtilsPtr);
if (!bInit)
{
if (SteamRemoteStorage() && SharedHandle.IsValid())
{
if (SteamUser()->BLoggedOn())
{
// Actual request to download the file from Steam
CallbackHandle = SteamRemoteStorage()->UGCDownload(*(UGCHandle_t*)SharedHandle.GetBytes(), 0);
}
else
{
UE_LOG_ONLINE_CLOUD(Warning, TEXT("Steam user not logged in."));
}
}
else
{
UE_LOG_ONLINE_CLOUD(Warning, TEXT("Steam remote storage API disabled."));
}
bInit = true;
}
if (CallbackHandle != k_uAPICallInvalid)
{
bool bFailedCall = false;
// Poll for completion status
bIsComplete = SteamUtilsPtr->IsAPICallCompleted(CallbackHandle, &bFailedCall) ? true : false;
if (bIsComplete)
{
bool bFailedResult;
// Retrieve the callback data from the request
bool bSuccessCallResult = SteamUtilsPtr->GetAPICallResult(CallbackHandle, &CallbackResults, sizeof(CallbackResults), CallbackResults.k_iCallback, &bFailedResult);
bWasSuccessful = (bSuccessCallResult ? true : false) &&
(!bFailedCall ? true : false) &&
(!bFailedResult ? true : false) &&
((CallbackResults.m_eResult == k_EResultOK) ? true : false);
}
}
else
{
// Invalid API call
bIsComplete = true;
bWasSuccessful = false;
}
}
void FOnlineAsyncTaskSteamReadSharedFile::Finalize()
{
FOnlineAsyncTaskSteam::Finalize();
FOnlineSharedCloudSteamPtr SharedCloud = StaticCastSharedPtr<FOnlineSharedCloudSteam>(Subsystem->GetSharedCloudInterface());
FCloudFileSteam* SharedFile = SharedCloud->GetSharedCloudFile(SharedHandle);
if (SharedFile)
{
if (bWasSuccessful)
{
// Currently don't support greater than 1 chunk (we read everything in at once)
if (FSharedContentHandleSteam(CallbackResults.m_hFile) == SharedHandle && CallbackResults.m_nSizeInBytes > 0 && CallbackResults.m_nSizeInBytes <= k_unMaxCloudFileChunkSize)
{
SharedFile->Data.Empty(CallbackResults.m_nSizeInBytes);
SharedFile->Data.AddUninitialized(CallbackResults.m_nSizeInBytes);
uint32 FileOffset = 0;
// This call only works once per call to UGCDownload()
if (SteamRemoteStorage()->UGCRead(CallbackResults.m_hFile, SharedFile->Data.GetData(), SharedFile->Data.Num(), FileOffset, k_EUGCRead_ContinueReadingUntilFinished) != CallbackResults.m_nSizeInBytes)
{
// Failed to read the data from disk
SharedFile->Data.Empty();
bWasSuccessful = false;
}
}
else
{
// Bad handle or bad filesize
bWasSuccessful = false;
}
}
SharedFile->AsyncState = bWasSuccessful ? EOnlineAsyncTaskState::Done : EOnlineAsyncTaskState::Failed;
}
else
{
// No file found
bWasSuccessful = false;
}
}
void FOnlineAsyncTaskSteamReadSharedFile::TriggerDelegates()
{
FOnlineAsyncTaskSteam::TriggerDelegates();
IOnlineSharedCloudPtr SharedCloudInterface = Subsystem->GetSharedCloudInterface();
SharedCloudInterface->TriggerOnReadSharedFileCompleteDelegates(bWasSuccessful, SharedHandle);
}
FString FOnlineAsyncTaskSteamWriteSharedFile::ToString() const
{
return FString::Printf(TEXT("FOnlineAsyncTaskSteamWriteSharedFile bWasSuccessful:%d UserId:%s FileName:%s Handle:%s"),
WasSuccessful(), *UserId->ToDebugString(), *FileName, *FSharedContentHandleSteam(CallbackResults.m_hFile).ToDebugString());
}
void FOnlineAsyncTaskSteamWriteSharedFile::Tick()
{
ISteamUtils* SteamUtilsPtr = SteamUtils();
check(SteamUtilsPtr);
if (!bInit)
{
if (WriteUserFile(*UserId, FileName, Contents))
{
// Simply mark the file as shared, will trigger a delegate when upload is complete
CallbackHandle = SteamRemoteStorage()->FileShare(TCHAR_TO_UTF8(*FileName));
}
bInit = true;
}
if (CallbackHandle != k_uAPICallInvalid)
{
bool bFailedCall = false;
// Poll for completion status
bIsComplete = SteamUtilsPtr->IsAPICallCompleted(CallbackHandle, &bFailedCall) ? true : false;
if (bIsComplete)
{
bool bFailedResult;
// Retrieve the callback data from the request
bool bSuccessCallResult = SteamUtilsPtr->GetAPICallResult(CallbackHandle, &CallbackResults, sizeof(CallbackResults), CallbackResults.k_iCallback, &bFailedResult);
bWasSuccessful = (bSuccessCallResult ? true : false) &&
(!bFailedCall ? true : false) &&
(!bFailedResult ? true : false) &&
((CallbackResults.m_eResult == k_EResultOK) ? true : false);
}
}
else
{
// Invalid API call
bIsComplete = true;
bWasSuccessful = false;
}
}
void FOnlineAsyncTaskSteamWriteSharedFile::Finalize()
{
FOnlineAsyncTaskSteam::Finalize();
if (bWasSuccessful)
{
// If the task failed, we'll have no "handle" to associate with the done state
FOnlineSharedCloudSteamPtr SharedCloud = StaticCastSharedPtr<FOnlineSharedCloudSteam>(Subsystem->GetSharedCloudInterface());
FSharedContentHandleSteam SharedHandle(CallbackResults.m_hFile);
// Create the entry to hold the data
FCloudFileSteam* SharedFile = SharedCloud->GetSharedCloudFile(SharedHandle);
if (SharedFile)
{
SharedFile->Data = Contents;
SharedFile->AsyncState = EOnlineAsyncTaskState::Done;
}
}
// Done with this copy of the data regardless
Contents.Empty();
}
void FOnlineAsyncTaskSteamWriteSharedFile::TriggerDelegates()
{
FOnlineAsyncTaskSteam::TriggerDelegates();
IOnlineSharedCloudPtr SharedCloudInterface = Subsystem->GetSharedCloudInterface();
UGCHandle_t NewHandle = bWasSuccessful ? CallbackResults.m_hFile : k_UGCHandleInvalid;
TSharedRef<FSharedContentHandle> SharedHandle = MakeShareable(new FSharedContentHandleSteam(NewHandle));
SharedCloudInterface->TriggerOnWriteSharedFileCompleteDelegates(bWasSuccessful, *UserId, FileName, SharedHandle);
}
FCloudFileSteam* FOnlineSharedCloudSteam::GetSharedCloudFile(const FSharedContentHandle& SharedHandle)
{
for (int32 FileIdx=0; FileIdx < SharedFileCache.Num(); FileIdx++)
{
FCloudFileSteam* SharedFile = SharedFileCache[FileIdx];
if (SharedFile->SharedHandle == *(FSharedContentHandleSteam*)&SharedHandle)
{
return SharedFile;
}
}
// Always create a new one if it doesn't exist
FCloudFileSteam* NewItem = new FCloudFileSteam(*(FSharedContentHandleSteam*)&SharedHandle);
int32 FileIdx = SharedFileCache.Add(NewItem);
return SharedFileCache[FileIdx];
}
bool FOnlineSharedCloudSteam::GetSharedFileContents(const FSharedContentHandle& SharedHandle, TArray<uint8>& FileContents)
{
FCloudFileSteam* SharedFile = GetSharedCloudFile(SharedHandle);
if (SharedFile && SharedFile->AsyncState == EOnlineAsyncTaskState::Done && SharedFile->Data.Num() > 0)
{
FileContents = SharedFile->Data;
return true;
}
else
{
FileContents.Empty();
}
return false;
}
bool FOnlineSharedCloudSteam::ClearSharedFiles()
{
for (int32 FileIdx=0; FileIdx < SharedFileCache.Num(); FileIdx++)
{
const FCloudFileSteam* SharedFile = SharedFileCache[FileIdx];
// If there is an async task outstanding, fail to empty
if (SharedFile->AsyncState == EOnlineAsyncTaskState::InProgress)
{
return false;
}
}
for (int32 FileIdx=0; FileIdx < SharedFileCache.Num(); FileIdx++)
{
FCloudFileSteam* SharedFile = SharedFileCache[FileIdx];
delete SharedFile;
}
SharedFileCache.Empty();
return true;
}
bool FOnlineSharedCloudSteam::ClearSharedFile(const FSharedContentHandle& SharedHandle)
{
for (int32 FileIdx=0; FileIdx < SharedFileCache.Num(); FileIdx++)
{
const FCloudFileSteam* SharedFile = SharedFileCache[FileIdx];
if (SharedFile->SharedHandle == *(FSharedContentHandleSteam*)&SharedHandle)
{
// If there is an async task outstanding, fail to empty
if (SharedFile->AsyncState != EOnlineAsyncTaskState::InProgress)
{
SharedFileCache.RemoveAtSwap(FileIdx);
delete SharedFile;
return true;
}
break;
}
}
return false;
}
bool FOnlineSharedCloudSteam::ReadSharedFile(const FSharedContentHandle& SharedHandle)
{
bool bSuccess = false;
// Create the entry to hold the data
FCloudFileSteam* SharedFile = GetSharedCloudFile(SharedHandle);
if (SharedFile)
{
SharedFile->AsyncState = EOnlineAsyncTaskState::InProgress;
SteamSubsystem->QueueAsyncTask(new FOnlineAsyncTaskSteamReadSharedFile(SteamSubsystem, *(FSharedContentHandleSteam*)&SharedHandle));
bSuccess = true;
}
return bSuccess;
}
bool FOnlineSharedCloudSteam::WriteSharedFile(const FUniqueNetId& UserId, const FString& FileName, TArray<uint8>& FileContents)
{
SteamSubsystem->QueueAsyncTask(new FOnlineAsyncTaskSteamWriteSharedFile(SteamSubsystem, FUniqueNetIdSteam::Cast(UserId), FileName, FileContents));
return true;
}
void FOnlineSharedCloudSteam::GetDummySharedHandlesForTest(TArray< TSharedRef<FSharedContentHandle> > & OutHandles)
{
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766135714)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766136144)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766136543)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766137039)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766137499)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766137928)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766138377)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766138784)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766139217)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766139630)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766140275)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766140713)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766141131)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766141899)));
OutHandles.Add(MakeShareable(new FSharedContentHandleSteam(594715184766142348)));
}