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

775 lines
22 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "OnlineSubsystemSteam.h"
#include "HAL/FileManager.h"
#include "HAL/RunnableThread.h"
#include "Interfaces/IPluginManager.h"
#include "Misc/StringBuilder.h"
#include "OnlineSessionInterfaceSteam.h"
#include "OnlineIdentityInterfaceSteam.h"
#include "OnlinePresenceInterfaceSteam.h"
#include "OnlineFriendsInterfaceSteam.h"
#include "OnlineSharedCloudInterfaceSteam.h"
#include "OnlineLeaderboardInterfaceSteam.h"
#include "VoiceInterfaceSteam.h"
#include "OnlineExternalUIInterfaceSteam.h"
#include "OnlineAchievementsInterfaceSteam.h"
#include "OnlineAuthInterfaceSteam.h"
#include "OnlineAuthInterfaceUtilsSteam.h"
#include "OnlineEncryptedAppTicketInterfaceSteam.h"
#include "OnlinePurchaseInterfaceSteam.h"
#include "OnlineStoreInterfaceSteam.h"
#include "VoiceInterfaceSteam.h"
#include "SteamSharedModule.h"
#include <steam/isteamapps.h>
#include <steam/isteamgameserverstats.h>
/* Specify this define in your Target.cs for your project
*
* This helps the SteamAPI find your project on shipping builds
* if your game is launched outside of Steam.
*/
#ifndef UE_PROJECT_STEAMSHIPPINGID
#define UE_PROJECT_STEAMSHIPPINGID 0
#endif
namespace FNetworkProtocolTypes
{
const FLazyName Steam(TEXT("Steam"));
}
namespace OSSConsoleVariables
{
TAutoConsoleVariable<int32> CVarSteamInitServerOnClient(
TEXT("OSS.SteamInitServerOnClient"),
0,
TEXT("Whether or not to initialize the Steam server interface on clients (default false)"),
ECVF_Default | ECVF_Cheat);
#if !UE_BUILD_SHIPPING
/** CVar used by NetcodeUnitTest, to force-enable Steam within the unit test commandlet */
TAutoConsoleVariable<int32> CVarSteamUnitTest(
TEXT("OSS.SteamUnitTest"),
0,
TEXT("Whether or not Steam is being force-enabled by NetcodeUnitTest"),
ECVF_Default);
#endif
}
extern "C"
{
static void __cdecl SteamworksWarningMessageHook(int Severity, const char *Message);
static void __cdecl SteamworksWarningMessageHookNoOp(int Severity, const char *Message);
}
/**
* Callback function into Steam error messaging system
* @param Severity - error level
* @param Message - message from Steam
*/
static void __cdecl SteamworksWarningMessageHook(int Severity, const char *Message)
{
const TCHAR *MessageType;
switch (Severity)
{
case 0: MessageType = TEXT("message"); break;
case 1: MessageType = TEXT("warning"); break;
default: MessageType = TEXT("notification"); break; // Unknown severity; new SDK?
}
UE_LOG_ONLINE(Warning, TEXT("Steamworks SDK %s: %s"), MessageType, UTF8_TO_TCHAR(Message));
}
/**
* Callback function into Steam error messaging system that outputs nothing
* @param Severity - error level
* @param Message - message from Steam
*/
static void __cdecl SteamworksWarningMessageHookNoOp(int Severity, const char *Message)
{
// no-op.
}
/**
* Get relaunch settings from OnlineSubsystemSteam configuration
*
* @param RequireRelaunch enforce the Steam client running precondition
* @param RelaunchAppId appid to launch when the Steam client is loaded
*
* @return if this sequence completed without any serious errors
*/
bool GetRelaunchSettings(bool& RequireRelaunch, int32& RelaunchAppId)
{
#if !UE_BUILD_SHIPPING && !UE_BUILD_SHIPPING_WITH_EDITOR
// Get SteamDevAppId and set it as RelaunchAppId
if (!GConfig->GetInt(TEXT("OnlineSubsystemSteam"), TEXT("SteamDevAppId"), RelaunchAppId, GEngineIni))
{
UE_LOG_ONLINE(Warning, TEXT("Missing SteamDevAppId key in OnlineSubsystemSteam of DefaultEngine.ini"));
return false;
}
// Should the game force a relaunch in Steam if the client isn't already loaded
if (!GConfig->GetBool(TEXT("OnlineSubsystemSteam"), TEXT("bRelaunchInSteam"), RequireRelaunch, GEngineIni))
{
UE_LOG_ONLINE(Warning, TEXT("Missing bRelaunchInSteam key in OnlineSubsystemSteam of DefaultEngine.ini"));
}
#else
// Always check against the Steam client when shipping
RequireRelaunch = true;
RelaunchAppId = UE_PROJECT_STEAMSHIPPINGID;
#endif
return true;
}
FOnlineAuthSteamPtr FOnlineSubsystemSteam::GetAuthInterface() const
{
return AuthInterface;
}
FOnlineAuthSteamUtilsPtr FOnlineSubsystemSteam::GetAuthInterfaceUtils() const
{
return AuthInterfaceUtils;
}
FOnlinePingSteamPtr FOnlineSubsystemSteam::GetPingInterface() const
{
return PingInterface;
}
void FOnlineSubsystemSteam::SetPingInterface(FOnlinePingSteamPtr InPingInterface)
{
PingInterface = InPingInterface;
}
FOnlineEncryptedAppTicketSteamPtr FOnlineSubsystemSteam::GetEncryptedAppTicketInterface() const
{
return EncryptedAppTicketInterface;
}
IOnlineSessionPtr FOnlineSubsystemSteam::GetSessionInterface() const
{
return SessionInterface;
}
IOnlineFriendsPtr FOnlineSubsystemSteam::GetFriendsInterface() const
{
return FriendInterface;
}
IOnlineGroupsPtr FOnlineSubsystemSteam::GetGroupsInterface() const
{
return nullptr;
}
IOnlinePartyPtr FOnlineSubsystemSteam::GetPartyInterface() const
{
return nullptr;
}
IOnlineSharedCloudPtr FOnlineSubsystemSteam::GetSharedCloudInterface() const
{
return SharedCloudInterface;
}
IOnlineUserCloudPtr FOnlineSubsystemSteam::GetUserCloudInterface() const
{
return UserCloudInterface;
}
IOnlineLeaderboardsPtr FOnlineSubsystemSteam::GetLeaderboardsInterface() const
{
return LeaderboardsInterface;
}
IOnlineVoicePtr FOnlineSubsystemSteam::GetVoiceInterface() const
{
#if WITH_ENGINE
if (VoiceInterface.IsValid() && !bVoiceInterfaceInitialized)
{
if (!VoiceInterface->Init())
{
VoiceInterface = nullptr;
}
bVoiceInterfaceInitialized = true;
}
#endif //WITH_ENGINE
return VoiceInterface;
}
IOnlineExternalUIPtr FOnlineSubsystemSteam::GetExternalUIInterface() const
{
return ExternalUIInterface;
}
IOnlineTimePtr FOnlineSubsystemSteam::GetTimeInterface() const
{
return nullptr;
}
IOnlineIdentityPtr FOnlineSubsystemSteam::GetIdentityInterface() const
{
return IdentityInterface;
}
IOnlineTitleFilePtr FOnlineSubsystemSteam::GetTitleFileInterface() const
{
return nullptr;
}
IOnlineEntitlementsPtr FOnlineSubsystemSteam::GetEntitlementsInterface() const
{
return nullptr;
}
IOnlineEventsPtr FOnlineSubsystemSteam::GetEventsInterface() const
{
return nullptr;
}
IOnlineAchievementsPtr FOnlineSubsystemSteam::GetAchievementsInterface() const
{
return AchievementsInterface;
}
IOnlineSharingPtr FOnlineSubsystemSteam::GetSharingInterface() const
{
return nullptr;
}
IOnlineUserPtr FOnlineSubsystemSteam::GetUserInterface() const
{
return nullptr;
}
IOnlineMessagePtr FOnlineSubsystemSteam::GetMessageInterface() const
{
return nullptr;
}
IOnlinePresencePtr FOnlineSubsystemSteam::GetPresenceInterface() const
{
return PresenceInterface;
}
IOnlinePurchasePtr FOnlineSubsystemSteam::GetPurchaseInterface() const
{
return PurchaseInterface;
}
IOnlineStoreV2Ptr FOnlineSubsystemSteam::GetStoreV2Interface() const
{
return StoreInterface;
}
IOnlineChatPtr FOnlineSubsystemSteam::GetChatInterface() const
{
return nullptr;
}
IOnlineStatsPtr FOnlineSubsystemSteam::GetStatsInterface() const
{
return nullptr;
}
IOnlineTurnBasedPtr FOnlineSubsystemSteam::GetTurnBasedInterface() const
{
return nullptr;
}
IOnlineTournamentPtr FOnlineSubsystemSteam::GetTournamentInterface() const
{
return nullptr;
}
void FOnlineSubsystemSteam::QueueAsyncTask(FOnlineAsyncTask* AsyncTask)
{
check(OnlineAsyncTaskThreadRunnable);
OnlineAsyncTaskThreadRunnable->AddToInQueue(AsyncTask);
}
void FOnlineSubsystemSteam::QueueAsyncOutgoingItem(FOnlineAsyncItem* AsyncItem)
{
check(OnlineAsyncTaskThreadRunnable);
OnlineAsyncTaskThreadRunnable->AddToOutQueue(AsyncItem);
}
bool FOnlineSubsystemSteam::Tick(float DeltaTime)
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_FOnlineSubsystemSteam_Tick);
if (!FOnlineSubsystemImpl::Tick(DeltaTime))
{
return false;
}
if (OnlineAsyncTaskThreadRunnable)
{
OnlineAsyncTaskThreadRunnable->GameTick();
}
if (SessionInterface.IsValid())
{
SessionInterface->Tick(DeltaTime);
}
#if WITH_ENGINE
if (VoiceInterface.IsValid() && bVoiceInterfaceInitialized)
{
VoiceInterface->Tick(DeltaTime);
}
#endif //WITH_ENGINE
if (AuthInterface.IsValid())
{
AuthInterface->Tick(DeltaTime);
}
return true;
}
bool FOnlineSubsystemSteam::Init()
{
bool bRelaunchInSteam = false;
int RelaunchAppId = 0;
if (!GetRelaunchSettings(bRelaunchInSteam, RelaunchAppId))
{
UE_LOG_ONLINE(Warning, TEXT("Could not set up the steam environment! Falling back to another OSS."));
return false;
}
const bool bIsServer = IsRunningDedicatedServer();
bool bInitServerOnClient = false;
GConfig->GetBool(TEXT("OnlineSubsystemSteam"), TEXT("bInitServerOnClient"), bInitServerOnClient, GEngineIni);
bool bAttemptServerInit = bIsServer || !!OSSConsoleVariables::CVarSteamInitServerOnClient.GetValueOnGameThread() || bInitServerOnClient;
UE_LOG_ONLINE(Verbose, TEXT("Steam: Starting SteamWorks. Client [%d] Server [%d]"), !bIsServer, bAttemptServerInit);
// Don't initialize the Steam Client API if we are launching as a server
bool bClientInitSuccess = !bIsServer ? InitSteamworksClient(bRelaunchInSteam, RelaunchAppId) : true;
// Initialize the Steam Server API if this is a dedicated server or servers should initialize on clients
bool bServerInitSuccess = bAttemptServerInit ? (InitSteamworksServer()) : true;
if (bClientInitSuccess && bServerInitSuccess)
{
// Create the online async task thread
OnlineAsyncTaskThreadRunnable = new FOnlineAsyncTaskManagerSteam(this);
check(OnlineAsyncTaskThreadRunnable);
OnlineAsyncTaskThread = FRunnableThread::Create(OnlineAsyncTaskThreadRunnable, *FString::Printf(TEXT("OnlineAsyncTaskThreadSteam %s"), *InstanceName.ToString()), 128 * 1024, TPri_Normal);
check(OnlineAsyncTaskThread);
UE_LOG_ONLINE(Verbose, TEXT("Created thread (ID:%d)."), OnlineAsyncTaskThread->GetThreadID() );
SessionInterface = MakeShareable(new FOnlineSessionSteam(this));
SessionInterface->CheckPendingSessionInvite();
IdentityInterface = MakeShareable(new FOnlineIdentitySteam(this));
PresenceInterface = MakeShareable(new FOnlinePresenceSteam(this));
AuthInterfaceUtils = MakeShareable(new FOnlineAuthUtilsSteam());
AuthInterface = MakeShareable(new FOnlineAuthSteam(this, AuthInterfaceUtils));
if (!bIsServer)
{
FriendInterface = MakeShareable(new FOnlineFriendsSteam(this));
UserCloudInterface = MakeShareable(new FOnlineUserCloudSteam(this));
SharedCloudInterface = MakeShareable(new FOnlineSharedCloudSteam(this));
LeaderboardsInterface = MakeShareable(new FOnlineLeaderboardsSteam(this));
#if WITH_ENGINE
VoiceInterface = MakeShareable(new FOnlineVoiceSteam(this));
#endif //WITH_ENGINE
ExternalUIInterface = MakeShareable(new FOnlineExternalUISteam(this));
AchievementsInterface = MakeShareable(new FOnlineAchievementsSteam(this));
EncryptedAppTicketInterface = MakeShareable(new FOnlineEncryptedAppTicketSteam(this));
PurchaseInterface = MakeShareable(new FOnlinePurchaseSteam(this));
StoreInterface = MakeShareable(new FOnlineStoreSteam(this));
}
else
{
#if WITH_ENGINE
// Need a voice interface here to serialize packets but NOT add to VoiceData.RemotePackets
VoiceInterface = MakeShareable(new FOnlineVoiceSteam(this));
#endif //WITH_ENGINE
}
}
else
{
// If the client succeeded, but the server didn't, this could be because there's a server and client running on the same machine - inform the user
if (bClientInitSuccess)
{
UE_LOG_ONLINE(Warning, TEXT("Failed to initialize Steam, this could be due to a Steam server and client running on the same machine. Try running with -NOSTEAM on the cmdline to disable."));
}
Shutdown();
}
return bClientInitSuccess && bServerInitSuccess;
}
bool FOnlineSubsystemSteam::Shutdown()
{
UE_LOG_ONLINE(Display, TEXT("OnlineSubsystemSteam::Shutdown()"));
FOnlineSubsystemImpl::Shutdown();
if (OnlineAsyncTaskThread)
{
// Destroy the online async task thread
delete OnlineAsyncTaskThread;
OnlineAsyncTaskThread = nullptr;
}
if (OnlineAsyncTaskThreadRunnable)
{
delete OnlineAsyncTaskThreadRunnable;
OnlineAsyncTaskThreadRunnable = nullptr;
}
#if WITH_ENGINE
if (VoiceInterface.IsValid() && bVoiceInterfaceInitialized) {
VoiceInterface->Shutdown();
}
#endif //WITH_ENGINE
#define DESTRUCT_INTERFACE(Interface) \
if (Interface.IsValid()) \
{ \
ensure(Interface.IsUnique()); \
Interface = nullptr; \
}
// Destruct the interfaces
DESTRUCT_INTERFACE(EncryptedAppTicketInterface);
DESTRUCT_INTERFACE(AchievementsInterface);
DESTRUCT_INTERFACE(ExternalUIInterface);
DESTRUCT_INTERFACE(VoiceInterface);
DESTRUCT_INTERFACE(LeaderboardsInterface);
DESTRUCT_INTERFACE(SharedCloudInterface);
DESTRUCT_INTERFACE(UserCloudInterface);
DESTRUCT_INTERFACE(FriendInterface);
DESTRUCT_INTERFACE(IdentityInterface);
DESTRUCT_INTERFACE(AuthInterface);
DESTRUCT_INTERFACE(AuthInterfaceUtils);
DESTRUCT_INTERFACE(PingInterface);
DESTRUCT_INTERFACE(SessionInterface);
DESTRUCT_INTERFACE(PresenceInterface);
DESTRUCT_INTERFACE(StoreInterface);
DESTRUCT_INTERFACE(PurchaseInterface);
#undef DESTRUCT_INTERFACE
ClearUserCloudFiles();
ShutdownSteamworks();
return true;
}
bool FOnlineSubsystemSteam::IsEnabled() const
{
if (bSteamworksClientInitialized || bSteamworksGameServerInitialized)
{
return true;
}
// Check the ini for disabling Steam
bool bEnableSteam = FOnlineSubsystemImpl::IsEnabled();
if (bEnableSteam)
{
#if UE_EDITOR
if (bEnableSteam)
{
bEnableSteam = IsRunningDedicatedServer() || IsRunningGame();
}
#endif
#if !UE_BUILD_SHIPPING
// Force-enable Steam for NetcodeUnitTest
if (!!OSSConsoleVariables::CVarSteamUnitTest.GetValueOnGameThread())
{
bEnableSteam = true;
}
#endif
}
return bEnableSteam;
}
bool FOnlineSubsystemSteam::InitSteamworksClient(bool bRelaunchInSteam, int32 SteamAppId)
{
bSteamworksClientInitialized = false;
// If the game was not launched from within Steam, but is supposed to, trigger a Steam launch and exit
if (bRelaunchInSteam && SteamAppId != 0 && SteamAPI_RestartAppIfNecessary(SteamAppId))
{
if (FPlatformProperties::IsGameOnly() || FPlatformProperties::IsServerOnly())
{
UE_LOG_ONLINE(Log, TEXT("Game restarting within Steam client, exiting"));
FPlatformMisc::RequestExit(false);
}
return bSteamworksClientInitialized;
}
// Otherwise initialize as normal
else
{
SteamAPIClientHandle = FSteamSharedModule::Get().ObtainSteamClientInstanceHandle();
// Steamworks needs to initialize as close to start as possible, so it can hook its overlay into Direct3D, etc.
bSteamworksClientInitialized = (SteamAPIClientHandle.IsValid() ? true : false);
// Test all the Steam interfaces
#define GET_STEAMWORKS_INTERFACE(Interface) \
if (Interface() == nullptr) \
{ \
UE_LOG_ONLINE(Warning, TEXT("Steamworks: %s() failed!"), TEXT(#Interface)); \
bSteamworksClientInitialized = false; \
} \
// GSteamUtils
GET_STEAMWORKS_INTERFACE(SteamUtils);
// GSteamUser
GET_STEAMWORKS_INTERFACE(SteamUser);
// GSteamFriends
GET_STEAMWORKS_INTERFACE(SteamFriends);
// GSteamRemoteStorage
GET_STEAMWORKS_INTERFACE(SteamRemoteStorage);
// GSteamUserStats
GET_STEAMWORKS_INTERFACE(SteamUserStats);
// GSteamMatchmakingServers
GET_STEAMWORKS_INTERFACE(SteamMatchmakingServers);
// GSteamApps
GET_STEAMWORKS_INTERFACE(SteamApps);
// GSteamNetworking
GET_STEAMWORKS_INTERFACE(SteamNetworking);
// GSteamMatchmaking
GET_STEAMWORKS_INTERFACE(SteamMatchmaking);
#undef GET_STEAMWORKS_INTERFACE
}
if (bSteamworksClientInitialized)
{
GameServerGamePort = SteamAPIClientHandle->GetGamePort();
bool bIsSubscribed = true;
if (FPlatformProperties::IsGameOnly() || FPlatformProperties::IsServerOnly())
{
bIsSubscribed = SteamApps()->BIsSubscribed();
}
// Make sure the Steam user has valid access to the game
if (bIsSubscribed)
{
UE_LOG_ONLINE(Log, TEXT("Steam User is subscribed %i"), bSteamworksClientInitialized);
if (SteamUtils())
{
SteamAppID = SteamUtils()->GetAppID();
SteamUtils()->SetWarningMessageHook(SteamworksWarningMessageHook);
}
}
else
{
UE_LOG_ONLINE(Error, TEXT("Steam User is NOT subscribed, exiting."));
bSteamworksClientInitialized = false;
FPlatformMisc::RequestExit(false);
}
}
UE_LOG_ONLINE(Log, TEXT("[AppId: %d] Client API initialized %i"), GetSteamAppId(), bSteamworksClientInitialized);
return bSteamworksClientInitialized;
}
bool FOnlineSubsystemSteam::InitSteamworksServer()
{
SteamAPIServerHandle = FSteamSharedModule::Get().ObtainSteamServerInstanceHandle();
bSteamworksGameServerInitialized = (SteamAPIServerHandle.IsValid());
if (bSteamworksGameServerInitialized)
{
// Grab the port values so that we save them.
GameServerGamePort = SteamAPIServerHandle->GetGamePort();
GameServerQueryPort = SteamAPIServerHandle->GetQueryPort();
// Test all the Steam interfaces
#define GET_STEAMWORKS_INTERFACE(Interface) \
if (Interface() == nullptr) \
{ \
UE_LOG_ONLINE(Warning, TEXT("Steamworks: %s() failed!"), TEXT(#Interface)); \
bSteamworksGameServerInitialized = false; \
} \
// NOTE: It's not possible for >some< of the interfaces to initialize, and others fail; it's all or none
GET_STEAMWORKS_INTERFACE(SteamGameServer);
GET_STEAMWORKS_INTERFACE(SteamGameServerStats);
GET_STEAMWORKS_INTERFACE(SteamGameServerNetworking);
GET_STEAMWORKS_INTERFACE(SteamGameServerUtils);
#undef GET_STEAMWORKS_INTERFACE
}
if (SteamGameServerUtils() != nullptr)
{
SteamAppID = SteamGameServerUtils()->GetAppID();
SteamGameServerUtils()->SetWarningMessageHook(SteamworksWarningMessageHook);
}
UE_LOG_ONLINE(Log, TEXT("[AppId: %d] Game Server API initialized %i"), GetSteamAppId(), bSteamworksGameServerInitialized);
return bSteamworksGameServerInitialized;
}
void FOnlineSubsystemSteam::ShutdownSteamworks()
{
if (bSteamworksGameServerInitialized)
{
SteamAPIServerHandle.Reset();
if (SessionInterface.IsValid())
{
SessionInterface->GameServerSteamId = nullptr;
SessionInterface->bSteamworksGameServerConnected = false;
}
bSteamworksGameServerInitialized = false;
}
if (bSteamworksClientInitialized)
{
SteamAPIClientHandle.Reset();
bSteamworksClientInitialized = false;
}
}
bool FOnlineSubsystemSteam::IsLocalPlayer(const FUniqueNetId& UniqueId) const
{
ISteamUser* SteamUserPtr = SteamUser();
return SteamUserPtr && SteamUserPtr->GetSteamID() == (const FUniqueNetIdSteam&)UniqueId;
}
FOnlineLeaderboardsSteam * FOnlineSubsystemSteam::GetInternalLeaderboardsInterface()
{
return LeaderboardsInterface.Get();
}
FSteamUserCloudData* FOnlineSubsystemSteam::GetUserCloudEntry(const FUniqueNetId& UserId)
{
FScopeLock ScopeLock(&UserCloudDataLock);
for (int32 UserIdx = 0; UserIdx < UserCloudData.Num(); UserIdx++)
{
FSteamUserCloudData* UserMetadata = UserCloudData[UserIdx];
if (*UserMetadata->UserId == UserId)
{
return UserMetadata;
}
}
// Always create a new one if it doesn't exist
const FUniqueNetIdSteam& SteamUserId = FUniqueNetIdSteam::Cast(UserId);
FSteamUserCloudData* NewItem = new FSteamUserCloudData(SteamUserId);
int32 UserIdx = UserCloudData.Add(NewItem);
return UserCloudData[UserIdx];
}
bool FOnlineSubsystemSteam::ClearUserCloudMetadata(const FUniqueNetId& UserId, const FString& FileName)
{
if (FileName.Len() > 0)
{
FScopeLock ScopeLock(&UserCloudDataLock);
// Search for the specified file
FSteamUserCloudData* UserCloud = GetUserCloudEntry(UserId);
if (UserCloud)
{
UserCloud->ClearMetadata(FileName);
}
}
return true;
}
void FOnlineSubsystemSteam::ClearUserCloudFiles()
{
FScopeLock ScopeLock(&UserCloudDataLock);
for (int32 UserIdx = 0; UserIdx < UserCloudData.Num(); UserIdx++)
{
FSteamUserCloudData* UserCloud = UserCloudData[UserIdx];
delete UserCloud;
}
UserCloudData.Empty();
}
static FDelegateHandle GOnEnumerateUserFilesCompleteDelegateHandle;
TMap<IOnlineUserCloud*, FDelegateHandle> GPerCloudDeleteFromEnumerateUserFilesCompleteDelegateHandles;
static void DeleteFromEnumerateUserFilesComplete(bool bWasSuccessful, const FUniqueNetId& UserId)
{
IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get();
check(OnlineSub);
IOnlineUserCloudPtr UserCloud = OnlineSub->GetUserCloudInterface();
UserCloud->ClearOnEnumerateUserFilesCompleteDelegate_Handle(GOnEnumerateUserFilesCompleteDelegateHandle);
GPerCloudDeleteFromEnumerateUserFilesCompleteDelegateHandles.Remove(UserCloud.Get());
if (bWasSuccessful)
{
TArray<FCloudFileHeader> UserFiles;
UserCloud->GetUserFileList(UserId, UserFiles);
for (int32 Idx = 0; Idx < UserFiles.Num(); Idx++)
{
UserCloud->DeleteUserFile(UserId, UserFiles[Idx].FileName, true, true);
}
}
}
bool FOnlineSubsystemSteam::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar)
{
if (FOnlineSubsystemImpl::Exec(InWorld, Cmd, Ar))
{
return true;
}
bool bWasHandled = false;
if (FParse::Command(&Cmd, TEXT("DELETECLOUDFILES")))
{
IOnlineUserCloudPtr UserCloud = GetUserCloudInterface();
FUniqueNetIdSteamRef SteamId = FUniqueNetIdSteam::Create(SteamUser()->GetSteamID());
FOnEnumerateUserFilesCompleteDelegate Delegate = FOnEnumerateUserFilesCompleteDelegate::CreateStatic(&DeleteFromEnumerateUserFilesComplete);
GPerCloudDeleteFromEnumerateUserFilesCompleteDelegateHandles.Add(UserCloud.Get(), UserCloud->AddOnEnumerateUserFilesCompleteDelegate_Handle(Delegate));
UserCloud->EnumerateUserFiles(*SteamId);
bWasHandled = true;
}
else if (FParse::Command(&Cmd, TEXT("SYNCLOBBIES")))
{
if (SessionInterface.IsValid())
{
SessionInterface->SyncLobbies();
bWasHandled = true;
}
}
else if (FParse::Command(&Cmd, TEXT("AUTH")))
{
if (AuthInterface.IsValid())
{
bWasHandled = AuthInterface->Exec(Cmd);
}
}
return bWasHandled;
}
FString FOnlineSubsystemSteam::GetAppId() const
{
return FString::Printf(TEXT("%d"),GetSteamAppId());
}
FText FOnlineSubsystemSteam::GetOnlineServiceName() const
{
return NSLOCTEXT("OnlineSubsystemSteam", "OnlineServiceName", "Steam");
}