bool FOnlineSessionNull::GetResolvedConnectString(const class FOnlineSessionSearchResult& SearchResult, FName PortType, FString& ConnectInfo) { bool bSuccess = false; if (SearchResult.Session.SessionInfo.IsValid()) { TSharedPtr<FOnlineSessionInfoNull> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoNull>(SearchResult.Session.SessionInfo); if (PortType == BeaconPort) { int32 BeaconListenPort = 15000; if (SearchResult.Session.SessionSettings.Get(SETTING_BEACONPORT, BeaconListenPort) && BeaconListenPort > 0) { bSuccess = GetConnectStringFromSessionInfo(SessionInfo, ConnectInfo, BeaconListenPort); } } else if (PortType == GamePort) { bSuccess = GetConnectStringFromSessionInfo(SessionInfo, ConnectInfo); } } if (!bSuccess || ConnectInfo.IsEmpty()) { UE_LOG_ONLINE(Warning, TEXT("Invalid session info in search result to GetResolvedConnectString()")); } return bSuccess; }
bool APartyBeaconClient::RequestReservation(const FString& ConnectInfoStr, const FString& InSessionId, const FUniqueNetIdRepl& RequestingPartyLeader, const TArray<FPlayerReservation>& PartyMembers) { bool bSuccess = false; FURL ConnectURL(NULL, *ConnectInfoStr, TRAVEL_Absolute); if (InitClient(ConnectURL)) { DestSessionId = InSessionId; PendingReservation.PartyLeader = RequestingPartyLeader; PendingReservation.PartyMembers = PartyMembers; bPendingReservationSent = false; RequestType = EClientRequestType::ExistingSessionReservation; bSuccess = true; } else { UE_LOG_ONLINE(Warning, TEXT("RequestReservation: Failure to init client beacon with %s."), *ConnectURL.ToString()); RequestType = EClientRequestType::NonePending; } if (!bSuccess) { OnFailure(); } return bSuccess; }
/** * Write out the steam app id to the steam_appid.txt file before initializing the API * @param SteamAppId id assigned to the application by Steam */ static void WriteSteamAppIdToDisk(int32 SteamAppId) { if (SteamAppId > 0) { // Turn off sandbox temporarily to make sure file is where it's always expected FScopeSandboxContext ScopedSandbox(false); // Access the physical file writer directly so that we still write next to the executable in CotF builds. FString SteamAppIdFilename = GetSteamAppIdFilename(); IFileHandle* Handle = IPlatformFile::GetPlatformPhysical().OpenWrite(*SteamAppIdFilename, false, false); if (!Handle) { UE_LOG_ONLINE(Fatal, TEXT("Failed to create file: %s"), *SteamAppIdFilename); } else { FString AppId = FString::Printf(TEXT("%d"), SteamAppId); FBufferArchive Archive; Archive.Serialize((void*)TCHAR_TO_ANSI(*AppId), AppId.Len()); Handle->Write(Archive.GetData(), Archive.Num()); delete Handle; Handle = nullptr; } } }
bool FOnlineSessionNull::CancelFindSessions() { uint32 Return = E_FAIL; if (CurrentSessionSearch->SearchState == EOnlineAsyncTaskState::InProgress) { // Make sure it's the right type Return = ERROR_SUCCESS; FinalizeLANSearch(); CurrentSessionSearch->SearchState = EOnlineAsyncTaskState::Failed; CurrentSessionSearch = NULL; } else { UE_LOG_ONLINE(Warning, TEXT("Can't cancel a search that isn't in progress")); } if (Return != ERROR_IO_PENDING) { TriggerOnCancelFindSessionsCompleteDelegates(true); } return Return == ERROR_SUCCESS || Return == ERROR_IO_PENDING; }
void FOnlineSubsystemSteamModule::StartupModule() { bool bSuccess = false; // Load the Steam modules before first call to API LoadSteamModules(); if (AreSteamDllsLoaded()) { // Create and register our singleton factory with the main online subsystem for easy access SteamFactory = new FOnlineFactorySteam(); FOnlineSubsystemModule& OSS = FModuleManager::GetModuleChecked<FOnlineSubsystemModule>("OnlineSubsystem"); OSS.RegisterPlatformService(STEAM_SUBSYSTEM, SteamFactory); bSuccess = true; } else { UE_LOG_ONLINE(Warning, TEXT("Steam SDK %s libraries not present at %s or failed to load!"), STEAM_SDK_VER, *GetSteamModulePath()); } if (!bSuccess) { UnloadSteamModules(); } }
bool FOnlineSessionNull::FindSessions(int32 SearchingPlayerNum, const TSharedRef<FOnlineSessionSearch>& SearchSettings) { uint32 Return = E_FAIL; // Don't start another search while one is in progress if (!CurrentSessionSearch.IsValid() && SearchSettings->SearchState != EOnlineAsyncTaskState::InProgress) { // Free up previous results SearchSettings->SearchResults.Empty(); // Copy the search pointer so we can keep it around CurrentSessionSearch = SearchSettings; // remember the time at which we started search, as this will be used for a "good enough" ping estimation SessionSearchStartInSeconds = FPlatformTime::Seconds(); // Check if its a LAN query Return = FindLANSession(); if (Return == ERROR_IO_PENDING) { SearchSettings->SearchState = EOnlineAsyncTaskState::InProgress; } } else { UE_LOG_ONLINE(Warning, TEXT("Ignoring game search request while one is pending")); Return = ERROR_IO_PENDING; } return Return == ERROR_SUCCESS || Return == ERROR_IO_PENDING; }
void FOnlineSubsystemSteamModule::LoadSteamModules() { UE_LOG_ONLINE(Display, TEXT("Loading Steam SDK %s"), STEAM_SDK_VER); #if PLATFORM_WINDOWS #if PLATFORM_64BITS FString RootSteamPath = GetSteamModulePath(); FPlatformProcess::PushDllDirectory(*RootSteamPath); SteamDLLHandle = FPlatformProcess::GetDllHandle(*(RootSteamPath + "steam_api64.dll")); #if 0 //64 bit not supported well at present, use Steam Client dlls // Load the Steam dedicated server dlls (assumes no Steam Client running) if (IsRunningDedicatedServer()) { SteamServerDLLHandle = FPlatformProcess::GetDllHandle(*(RootSteamPath + "steamclient64.dll")); } #endif FPlatformProcess::PopDllDirectory(*RootSteamPath); #else //PLATFORM_64BITS FString RootSteamPath = GetSteamModulePath(); FPlatformProcess::PushDllDirectory(*RootSteamPath); SteamDLLHandle = FPlatformProcess::GetDllHandle(*(RootSteamPath + "steam_api.dll")); if (IsRunningDedicatedServer()) { SteamServerDLLHandle = FPlatformProcess::GetDllHandle(*(RootSteamPath + "steamclient.dll")); } FPlatformProcess::PopDllDirectory(*RootSteamPath); #endif //PLATFORM_64BITS #elif PLATFORM_MAC SteamDLLHandle = FPlatformProcess::GetDllHandle(TEXT("libsteam_api.dylib")); #endif //PLATFORM_WINDOWS }
/** * ** INTERNAL ** * Called by an async task after completing an achievement read. * * @param PlayerId - id of a player we were making read for * @param bReadSuccessfully - whether the read completed successfully */ void FOnlineAchievementsSteam::UpdateAchievementsForUser(const FUniqueNetIdSteam& PlayerId, bool bReadSuccessfully) { // shouldn't get this far if no achievements are configured check(bHaveConfiguredAchievements); ISteamUserStats* SteamUserStatsPtr = SteamUserStats(); check(SteamUserStatsPtr); CSteamID SteamUserId = PlayerId; // new array TArray<FOnlineAchievement> AchievementsForPlayer; const int32 AchNum = Achievements.Num(); for (int32 AchIdx = 0; AchIdx < AchNum; ++AchIdx) { // get the info bool bUnlocked; uint32 UnlockUnixTime; if (!SteamUserStatsPtr->GetAchievementAndUnlockTime(TCHAR_TO_UTF8(*Achievements[AchIdx].Id), &bUnlocked, &UnlockUnixTime)) { UE_LOG_ONLINE(Warning, TEXT("GetAchievementAndUnlockTime() failed for achievement '%s'"), *Achievements[AchIdx].Id); // skip this achievement continue; } FOnlineAchievementSteam NewAch = Achievements[ AchIdx ]; NewAch.bReadFromSteam = true; NewAch.Progress = bUnlocked ? 100.0 : 0.0; // TODO: we may want to support more fine-grained progress based on associated stat and min/max, // although we can only map it one-way (i.e. when reading, but not when writing) NewAch.UnlockTime = FDateTime::FromUnixTimestamp(UnlockUnixTime); NewAch.Title = FText::FromString( UTF8_TO_TCHAR( SteamUserStatsPtr->GetAchievementDisplayAttribute(TCHAR_TO_UTF8(*Achievements[AchIdx].Id), "name") ) ); NewAch.LockedDesc = FText::FromString( UTF8_TO_TCHAR( SteamUserStatsPtr->GetAchievementDisplayAttribute(TCHAR_TO_UTF8(*Achievements[AchIdx].Id), "desc") ) ); NewAch.UnlockedDesc = NewAch.LockedDesc; NewAch.bIsHidden = FCString::Atoi( UTF8_TO_TCHAR( SteamUserStatsPtr->GetAchievementDisplayAttribute(TCHAR_TO_UTF8(*Achievements[AchIdx].Id), "desc") ) ) != 0; UE_LOG_ONLINE(Verbose, TEXT("Read achievement %d: %s"), AchIdx, *NewAch.ToDebugString()); AchievementsForPlayer.Add( NewAch ); // add mapping (should replace any existing one) AchievementDescriptions.Add(NewAch.Id, NewAch); } // should replace any already existing values PlayerAchievements.Add(PlayerId, AchievementsForPlayer); }
void FOnlineSessionNull::AppendSessionSettingsToPacket(FNboSerializeToBufferNull& Packet, FOnlineSessionSettings* SessionSettings) { #if DEBUG_LAN_BEACON UE_LOG_ONLINE(Verbose, TEXT("Sending session settings to client")); #endif // Members of the session settings class Packet << SessionSettings->NumPublicConnections << SessionSettings->NumPrivateConnections << (uint8)SessionSettings->bShouldAdvertise << (uint8)SessionSettings->bIsLANMatch << (uint8)SessionSettings->bIsDedicated << (uint8)SessionSettings->bUsesStats << (uint8)SessionSettings->bAllowJoinInProgress << (uint8)SessionSettings->bAllowInvites << (uint8)SessionSettings->bUsesPresence << (uint8)SessionSettings->bAllowJoinViaPresence << (uint8)SessionSettings->bAllowJoinViaPresenceFriendsOnly << (uint8)SessionSettings->bAntiCheatProtected << SessionSettings->BuildUniqueId; // First count number of advertised keys int32 NumAdvertisedProperties = 0; for (FSessionSettings::TConstIterator It(SessionSettings->Settings); It; ++It) { const FOnlineSessionSetting& Setting = It.Value(); if (Setting.AdvertisementType >= EOnlineDataAdvertisementType::ViaOnlineService) { NumAdvertisedProperties++; } } // Add count of advertised keys and the data Packet << (int32)NumAdvertisedProperties; for (FSessionSettings::TConstIterator It(SessionSettings->Settings); It; ++It) { const FOnlineSessionSetting& Setting = It.Value(); if (Setting.AdvertisementType >= EOnlineDataAdvertisementType::ViaOnlineService) { Packet << It.Key(); Packet << Setting; #if DEBUG_LAN_BEACON UE_LOG_ONLINE(Verbose, TEXT("%s"), *Setting.ToString()); #endif } } }
bool FOnlineIdentityLeet::Login(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials) { UE_LOG_ONLINE(Display, TEXT("FOnlineIdentityLeet::Login")); FString ErrorStr; if (bHasLoginOutstanding) { ErrorStr = FString::Printf(TEXT("Registration already pending for user %d"), LocalUserNumPendingLogin); } else if (!(LoginUrl.Len() && LoginRedirectUrl.Len() && ClientId.Len())) { ErrorStr = FString::Printf(TEXT("OnlineSubsystemLeet is improperly configured in DefaultEngine.ini LeetEndpoint=%s RedirectUrl=%s ClientId=%s"), *LoginUrl, *LoginRedirectUrl, *ClientId); } else { // random number to represent client generated state for verification on login State = FString::FromInt(FMath::Rand() % 100000); // auth url to spawn in browser const FString& Command = FString::Printf(TEXT("%s?redirect_uri=%s&client_id=%s&state=%s&response_type=token"), *LoginUrl, *LoginRedirectUrl, *ClientId, *State); UE_LOG_ONLINE(Display, TEXT("FOnlineIdentityLeet::Login - %s"), *LoginUrl); // This should open the browser with the command as the URL if (FPlatformMisc::OsExecute(TEXT("open"), *Command)) { // keep track of local user requesting registration LocalUserNumPendingLogin = LocalUserNum; bHasLoginOutstanding = true; } else { ErrorStr = FString::Printf(TEXT("Failed to execute command %s"), *Command); } } if (!ErrorStr.IsEmpty()) { UE_LOG(LogOnline, Error, TEXT("RegisterUser() failed: %s"), *ErrorStr); TriggerOnLoginCompleteDelegates(LocalUserNum, false, FUniqueNetIdString(TEXT("")), ErrorStr); return false; } return true; }
void FOnlineAsyncTaskSteamDeleteUserFile::Tick() { bWasSuccessful = false; if (SteamRemoteStorage() && FileName.Len() > 0) { CSteamID SteamId(*(uint64*)UserId.GetBytes()); if (SteamUser()->BLoggedOn() && SteamUser()->GetSteamID() == SteamId) { bool bCloudDeleteSuccess = true; if (bShouldCloudDelete) { // Remove the cloud flag, the file remains safely available on the local machine bCloudDeleteSuccess = SteamRemoteStorage()->FileForget(TCHAR_TO_UTF8(*FileName)); } bool bLocalDeleteSuccess = true; if (bShouldLocallyDelete) { bLocalDeleteSuccess = false; // Only clear the tables if we're permanently deleting the file // Need to make sure nothing async is happening first (this is a formality as nothing in Steam actually is) IOnlineUserCloudPtr UserCloud = Subsystem->GetUserCloudInterface(); if (UserCloud->ClearFile(UserId, FileName)) { // Permanent delete bLocalDeleteSuccess = SteamRemoteStorage()->FileDelete(TCHAR_TO_UTF8(*FileName)); Subsystem->ClearUserCloudMetadata(UserId, FileName); } } bWasSuccessful = bCloudDeleteSuccess && bLocalDeleteSuccess; } else { UE_LOG_ONLINE(Warning, TEXT("Can only delete cloud files for logged in user.")); } } else { UE_LOG_ONLINE(Warning, TEXT("Steam remote storage API disabled.")); } bIsComplete = true; }
bool FOnlineUserCloudOculus::DeleteUserFile(const FUniqueNetId& UserId, const FString& FileName, bool bShouldCloudDelete, bool bShouldLocallyDelete) { auto LoggedInPlayerId = OculusSubsystem.GetIdentityInterface()->GetUniquePlayerId(0); if (!LoggedInPlayerId.IsValid() || UserId != *LoggedInPlayerId) { UE_LOG_ONLINE(Warning, TEXT("Can only save data for logged in player")); return false; } if (bShouldLocallyDelete && ReadCache.Contains(FileName)) { ReadCache.FindAndRemoveChecked(FileName); } if (bShouldCloudDelete) { FString BucketName; FString Key; if (!(FileName.Split(SEPARATOR, &BucketName, &Key))) { BucketName = DefaultBucket; Key = FileName; } auto DelegateLambda = FOculusMessageOnCompleteDelegate::CreateLambda([this, BucketName, Key, LoggedInPlayerId, FileName](ovrMessageHandle Message, bool bIsError) { if (bIsError) { UE_LOG_ONLINE(Warning, TEXT("Failed to Delete: %s%s%s"), *BucketName, *SEPARATOR, *Key); } TriggerOnDeleteUserFileCompleteDelegates(!bIsError, *LoggedInPlayerId, FileName); }); OculusSubsystem.AddRequestDelegate( ovr_CloudStorage_Delete(TCHAR_TO_UTF8(*BucketName), TCHAR_TO_UTF8(*Key)), std::move(DelegateLambda)); } else { TriggerOnDeleteUserFileCompleteDelegates(false, *LoggedInPlayerId, FileName); } return true; }
bool FOnlineUserCloudOculus::GetFileContents(const FUniqueNetId& UserId, const FString& FileName, TArray<uint8>& FileContents) { auto LoggedInPlayerId = OculusSubsystem.GetIdentityInterface()->GetUniquePlayerId(0); if (!LoggedInPlayerId.IsValid() || UserId != *LoggedInPlayerId) { UE_LOG_ONLINE(Warning, TEXT("Can only read data for logged in player")); return false; } if (!ReadCache.Contains(FileName)) { UE_LOG_ONLINE(Warning, TEXT("No data from ReadUserFile for: %s"), *FileName); return false; } FileContents = ReadCache.FindAndRemoveChecked(FileName); return true; }
/** * Give the async task a chance to marshal its data back to the game thread * Can only be called on the game thread by the async task manager */ void FOnlineAsyncEventSteamInviteAccepted::Finalize() { FOnlineSessionSteamPtr SessionInt = StaticCastSharedPtr<FOnlineSessionSteam>(Subsystem->GetSessionInterface()); if (SessionInt.IsValid() && !SessionInt->CurrentSessionSearch.IsValid()) { // Create a search settings object TSharedRef<FOnlineSessionSearch> SearchSettings = MakeShareable(new FOnlineSessionSearch()); SessionInt->CurrentSessionSearch = SearchSettings; SessionInt->CurrentSessionSearch->SearchState = EOnlineAsyncTaskState::InProgress; TCHAR ParsedURL[1024]; if (!FParse::Value(*ConnectionURL, TEXT("SteamConnectIP="), ParsedURL, ARRAY_COUNT(ParsedURL))) { UE_LOG_ONLINE(Warning, TEXT("FOnlineAsyncEventSteamInviteAccepted: Failed to parse connection URL")); return; } // Determine the port int32 Port = 0; TCHAR* PortToken = FCString::Strchr(ParsedURL, ':'); if (PortToken) { Port = FCString::Atoi(PortToken+1); PortToken[0] = '\0'; } Port = (Port > 0) ? Port : Subsystem->GetGameServerGamePort(); // Parse the address bool bIsValid; TSharedRef<FInternetAddr> IpAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); IpAddr->SetIp(ParsedURL, bIsValid); if (bIsValid) { SessionInt->CurrentSessionSearch->QuerySettings.Set(FName(SEARCH_STEAM_HOSTIP), IpAddr->ToString(false), EOnlineComparisonOp::Equals); FOnlineAsyncTaskSteamFindServer* NewTask = new FOnlineAsyncTaskSteamFindServer(Subsystem, SearchSettings, LocalUserNum, SessionInt->OnSessionUserInviteAcceptedDelegates); Subsystem->QueueAsyncTask(NewTask); } } else { UE_LOG_ONLINE(Warning, TEXT("Invalid session or search already in progress when accepting invite. Ignoring invite request.")); } }
bool FOnlineUserCloudOculus::ReadUserFile(const FUniqueNetId& UserId, const FString& FileName) { auto LoggedInPlayerId = OculusSubsystem.GetIdentityInterface()->GetUniquePlayerId(0); if (!LoggedInPlayerId.IsValid() || UserId != *LoggedInPlayerId) { UE_LOG_ONLINE(Warning, TEXT("Can only read data for logged in player")); return false; } FString BucketName; FString Key; if (!(FileName.Split(SEPARATOR, &BucketName, &Key))) { BucketName = DefaultBucket; Key = FileName; } OculusSubsystem.AddRequestDelegate( ovr_CloudStorage_Load(TCHAR_TO_UTF8(*BucketName), TCHAR_TO_UTF8(*Key)), FOculusMessageOnCompleteDelegate::CreateLambda([this, BucketName, Key, LoggedInPlayerId, FileName](ovrMessageHandle Message, bool bIsError) { ovrCloudStorageDataHandle response = ovr_Message_GetCloudStorageData(Message); check(BucketName == UTF8_TO_TCHAR(ovr_CloudStorageData_GetBucket(response))); check(Key == UTF8_TO_TCHAR(ovr_CloudStorageData_GetKey(response))); if (bIsError) { UE_LOG_ONLINE(Warning, TEXT("Failed to Load: %s%s%s"), *BucketName, *SEPARATOR, *Key); } else { int64 BlobSize = ovr_CloudStorageData_GetDataSize(response); const void* RawBlob = ovr_CloudStorageData_GetData(response); TArray<uint8> Blob; Blob.Insert(static_cast<const uint8 *>(RawBlob), BlobSize, 0); ReadCache.Add(FileName, MoveTemp(Blob)); } TriggerOnReadUserFileCompleteDelegates(!bIsError, *LoggedInPlayerId, FileName); })); return true; }
void FOnlineUserCloudOculus::RequestEnumeratePagedBuckets(TSharedPtr<const FUniqueNetId> UserId, ovrCloudStorageMetadataArrayHandle previousPage) { auto Delegate = FOculusMessageOnCompleteDelegate::CreateLambda([this, UserId](ovrMessageHandle Message, bool bIsError) { const FString& BucketName(Buckets[EnumerateBucketsCounter]); if (bIsError) { // NOTE: this may be too harsh. depending on the error we might be able to keep going. // check when better error handling is enabled in t11136437 UE_LOG_ONLINE(Warning, TEXT("Failed to Enumerate bucket: %s"), *BucketName); EnumerateBucketsCounter = -1; EnumerateCache.Reset(); TriggerOnEnumerateUserFilesCompleteDelegates(false, *UserId); return; } ovrCloudStorageMetadataArrayHandle response = ovr_Message_GetCloudStorageMetadataArray(Message); // adds all the keys to the cache in the format: BucketName / Key for (size_t i = 0; i < ovr_CloudStorageMetadataArray_GetSize(response); i++) { ovrCloudStorageMetadataHandle Metadatum = ovr_CloudStorageMetadataArray_GetElement(response, i); FString Key = ovr_CloudStorageMetadata_GetKey(Metadatum); FString Filename = FString::Printf(TEXT("%s%s%s"), *BucketName, *SEPARATOR, *Key); unsigned int Size = ovr_CloudStorageMetadata_GetDataSize(Metadatum); EnumerateCache.Add(FCloudFileHeader("", Filename, Size)); } // First check to see if we need to get another page of entires for this Bucket if (ovr_CloudStorageMetadataArray_HasNextPage(response)) { RequestEnumeratePagedBuckets(UserId, response); } // see if we need to move on to the next bucket else if (EnumerateBucketsCounter < (Buckets.Num() - 1)) { EnumerateBucketsCounter++; RequestEnumeratePagedBuckets(UserId, nullptr); } // Otherwise we are done - notify the App else { EnumerateBucketsCounter = -1; TriggerOnEnumerateUserFilesCompleteDelegates(true, *UserId); } }); if (previousPage) { OculusSubsystem.AddRequestDelegate(ovr_CloudStorage_GetNextCloudStorageMetadataArrayPage(previousPage), std::move(Delegate)); } else { OculusSubsystem.AddRequestDelegate(ovr_CloudStorage_LoadBucketMetadata(TCHAR_TO_UTF8(*Buckets[EnumerateBucketsCounter])), std::move(Delegate)); } }
void FOnlineSubsystemOculusModule::ShutdownModule() { UE_LOG_ONLINE(Log, TEXT("Oculus Shutdown!")); FOnlineSubsystemModule& OSS = FModuleManager::GetModuleChecked<FOnlineSubsystemModule>("OnlineSubsystem"); OSS.UnregisterPlatformService(OCULUS_SUBSYSTEM); delete OculusFactory; OculusFactory = nullptr; }
bool FOnlineSessionNull::UnregisterPlayers(FName SessionName, const TArray< TSharedRef<const FUniqueNetId> >& Players) { bool bSuccess = true; FNamedOnlineSession* Session = GetNamedSession(SessionName); if (Session) { for (int32 PlayerIdx=0; PlayerIdx < Players.Num(); PlayerIdx++) { const TSharedRef<const FUniqueNetId>& PlayerId = Players[PlayerIdx]; FUniqueNetIdMatcher PlayerMatch(*PlayerId); int32 RegistrantIndex = Session->RegisteredPlayers.IndexOfByPredicate(PlayerMatch); if (RegistrantIndex != INDEX_NONE) { Session->RegisteredPlayers.RemoveAtSwap(RegistrantIndex); UnregisterVoice(*PlayerId); // update number of open connections if (Session->NumOpenPublicConnections < Session->SessionSettings.NumPublicConnections) { Session->NumOpenPublicConnections++; } else if (Session->NumOpenPrivateConnections < Session->SessionSettings.NumPrivateConnections) { Session->NumOpenPrivateConnections++; } } else { UE_LOG_ONLINE(Warning, TEXT("Player %s is not part of session (%s)"), *PlayerId->ToDebugString(), *SessionName.ToString()); } } } else { UE_LOG_ONLINE(Warning, TEXT("No game present to leave for session (%s)"), *SessionName.ToString()); bSuccess = false; } TriggerOnUnregisterPlayersCompleteDelegates(SessionName, Players, bSuccess); return bSuccess; }
bool FOnlineSessionNull::RegisterPlayers(FName SessionName, const TArray< TSharedRef<const FUniqueNetId> >& Players, bool bWasInvited) { bool bSuccess = false; FNamedOnlineSession* Session = GetNamedSession(SessionName); if (Session) { bSuccess = true; for (int32 PlayerIdx=0; PlayerIdx<Players.Num(); PlayerIdx++) { const TSharedRef<const FUniqueNetId>& PlayerId = Players[PlayerIdx]; FUniqueNetIdMatcher PlayerMatch(*PlayerId); if (Session->RegisteredPlayers.IndexOfByPredicate(PlayerMatch) == INDEX_NONE) { Session->RegisteredPlayers.Add(PlayerId); RegisterVoice(*PlayerId); // update number of open connections if (Session->NumOpenPublicConnections > 0) { Session->NumOpenPublicConnections--; } else if (Session->NumOpenPrivateConnections > 0) { Session->NumOpenPrivateConnections--; } } else { RegisterVoice(*PlayerId); UE_LOG_ONLINE(Log, TEXT("Player %s already registered in session %s"), *PlayerId->ToDebugString(), *SessionName.ToString()); } } } else { UE_LOG_ONLINE(Warning, TEXT("No game present to join for session (%s)"), *SessionName.ToString()); } TriggerOnRegisterPlayersCompleteDelegates(SessionName, Players, bSuccess); return bSuccess; }
void FOnlineSubsystemOculusModule::StartupModule() { UE_LOG_ONLINE(Log, TEXT("Oculus Startup!")); OculusFactory = new FOnlineFactoryOculus(); // Create and register our singleton factory with the main online subsystem for easy access FOnlineSubsystemModule& OSS = FModuleManager::GetModuleChecked<FOnlineSubsystemModule>("OnlineSubsystem"); OSS.RegisterPlatformService(OCULUS_SUBSYSTEM, OculusFactory); }
void FOnlineSubsystemImpl::OnNamedInterfaceCleanup() { if (NamedInterfaces) { UE_LOG_ONLINE(Display, TEXT("Removing %d named interfaces"), NamedInterfaces->GetNumInterfaces()); NamedInterfaces->RemoveFromRoot(); NamedInterfaces->OnCleanup().RemoveAll(this); NamedInterfaces = nullptr; } }
void FOnlineAsyncTaskSteamEnumerateUserFiles::Tick() { bIsComplete = true; bWasSuccessful = false; if (SteamRemoteStorage()) { CSteamID SteamId(*(uint64*)UserId.GetBytes()); if (SteamUser()->BLoggedOn() && SteamUser()->GetSteamID() == SteamId) { //SteamSubsystem->GetUserCloudInterface()->DumpCloudState(UserId); FScopeLock ScopeLock(&Subsystem->UserCloudDataLock); // Get or create the user metadata entry and empty it FSteamUserCloudData* UserMetadata = Subsystem->GetUserCloudEntry(UserId); UserMetadata->CloudMetadata.Empty(); // Fill in the metadata entries const int32 FileCount = (int32) SteamRemoteStorage()->GetFileCount(); for (int32 FileIdx = 0; FileIdx < FileCount; FileIdx++) { int32 FileSize = 0; const char *FileName = SteamRemoteStorage()->GetFileNameAndSize(FileIdx, &FileSize); new (UserMetadata->CloudMetadata) FCloudFileHeader(UTF8_TO_TCHAR(FileName), UTF8_TO_TCHAR(FileName), int32(FileSize)); //SteamSubsystem->GetUserCloudInterface()->DumpCloudFileState(UserId, FileName); } bWasSuccessful = true; } else { UE_LOG_ONLINE(Warning, TEXT("Can only enumerate cloud files for logged in user.")); } } else { UE_LOG_ONLINE(Warning, TEXT("Steam remote storage API disabled.")); } }
EOnlineCachedResult::Type FOnlineAchievementsSteam::GetCachedAchievements(const FUniqueNetId& PlayerId, TArray<FOnlineAchievement> & OutAchievements) { if (!bHaveConfiguredAchievements) { // we don't have achievements UE_LOG_ONLINE(Warning, TEXT("Steam achievements have not been configured in .ini")); return EOnlineCachedResult::NotFound; } const TArray<FOnlineAchievement> * PlayerAch = PlayerAchievements.Find(FUniqueNetIdSteam (PlayerId)); if (NULL == PlayerAch) { // achievements haven't been read for a player UE_LOG_ONLINE(Warning, TEXT("Steam achievements have not been read for player %s"), *PlayerId.ToString()); return EOnlineCachedResult::NotFound; } OutAchievements = *PlayerAch; return EOnlineCachedResult::Success; };
void FOnlineUserCloudOculus::GetUserFileList(const FUniqueNetId& UserId, TArray<FCloudFileHeader>& UserFiles) { auto LoggedInPlayerId = OculusSubsystem.GetIdentityInterface()->GetUniquePlayerId(0); if (!LoggedInPlayerId.IsValid() || UserId != *LoggedInPlayerId) { UE_LOG_ONLINE(Warning, TEXT("Can get file list for logged in player")); return; } UserFiles = MoveTemp(EnumerateCache); }
/** * 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)); }
bool FOnlineSessionNull::EndSession(FName SessionName) { uint32 Result = E_FAIL; // Grab the session information by name FNamedOnlineSession* Session = GetNamedSession(SessionName); if (Session) { // Can't end a match that isn't in progress if (Session->SessionState == EOnlineSessionState::InProgress) { Session->SessionState = EOnlineSessionState::Ended; // If the session should be advertised and the lan beacon was destroyed, recreate Result = UpdateLANStatus(); } else { UE_LOG_ONLINE(Warning, TEXT("Can't end session (%s) in state %s"), *SessionName.ToString(), EOnlineSessionState::ToString(Session->SessionState)); } } else { UE_LOG_ONLINE(Warning, TEXT("Can't end an online game for session (%s) that hasn't been created"), *SessionName.ToString()); } if (Result != ERROR_IO_PENDING) { if (Session) { Session->SessionState = EOnlineSessionState::Ended; } TriggerOnEndSessionCompleteDelegates(SessionName, (Result == ERROR_SUCCESS) ? true : false); } return Result == ERROR_SUCCESS || Result == ERROR_IO_PENDING; }
bool FOnlineUserCloudOculus::ClearFiles(const FUniqueNetId& UserId) { auto LoggedInPlayerId = OculusSubsystem.GetIdentityInterface()->GetUniquePlayerId(0); if (!LoggedInPlayerId.IsValid() || UserId != *LoggedInPlayerId) { UE_LOG_ONLINE(Warning, TEXT("Can only clear data for logged in player")); return false; } ReadCache.Reset(); return true; }
virtual IOnlineSubsystemPtr CreateSubsystem(FName InstanceName) { FOnlineSubsystemNullPtr OnlineSub = MakeShareable(new FOnlineSubsystemNull(InstanceName)); if (OnlineSub->IsEnabled()) { if(!OnlineSub->Init()) { UE_LOG_ONLINE(Warning, TEXT("Null API failed to initialize!")); OnlineSub->Shutdown(); OnlineSub = NULL; } } else { UE_LOG_ONLINE(Warning, TEXT("Null API disabled!")); OnlineSub->Shutdown(); OnlineSub = NULL; } return OnlineSub; }
bool FOnlineUserCloudOculus::WriteUserFile(const FUniqueNetId& UserId, const FString& FileName, TArray<uint8>& FileContents) { auto LoggedInPlayerId = OculusSubsystem.GetIdentityInterface()->GetUniquePlayerId(0); if (!LoggedInPlayerId.IsValid() || UserId != *LoggedInPlayerId) { UE_LOG_ONLINE(Warning, TEXT("Can only save data for logged in player")); return false; } FString BucketName; FString Key; if (!(FileName.Split(SEPARATOR, &BucketName, &Key))) { BucketName = DefaultBucket; Key = FileName; } // store the save data in a temporary buffer until the Oculus Platform threadpool can process the request TArray<uint8> *TmpBuffer = new TArray<uint8>(MoveTemp(FileContents)); auto DelegateLambda = FOculusMessageOnCompleteDelegate::CreateLambda([this, BucketName, Key, LoggedInPlayerId, FileName, TmpBuffer](ovrMessageHandle Message, bool bIsError) { check(BucketName == UTF8_TO_TCHAR(ovr_CloudStorageUpdateResponse_GetBucket(ovr_Message_GetCloudStorageUpdateResponse(Message)))); check(Key == UTF8_TO_TCHAR(ovr_CloudStorageUpdateResponse_GetKey(ovr_Message_GetCloudStorageUpdateResponse(Message)))); if (bIsError) { UE_LOG_ONLINE(Warning, TEXT("Failed to Save: %s%s%s"), *BucketName, *SEPARATOR, *Key); } delete TmpBuffer; TriggerOnWriteUserFileCompleteDelegates(!bIsError, *LoggedInPlayerId, FileName); }); OculusSubsystem.AddRequestDelegate( ovr_CloudStorage_Save(TCHAR_TO_UTF8(*BucketName), TCHAR_TO_UTF8(*Key), TmpBuffer->GetData(), TmpBuffer->Num(), 0, nullptr), std::move(DelegateLambda)); return true; }
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; } #define DESTRUCT_INTERFACE(Interface) \ if (Interface.IsValid()) \ { \ ensure(Interface.IsUnique()); \ Interface = nullptr; \ } // Destruct the interfaces 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(SessionInterface); #undef DESTRUCT_INTERFACE ClearUserCloudFiles(); DestroySteamSocketSubsystem(); ShutdownSteamworks(); #if !UE_BUILD_SHIPPING && !UE_BUILD_SHIPPING_WITH_EDITOR DeleteSteamAppIdFromDisk(); #endif // !UE_BUILD_SHIPPING && !UE_BUILD_SHIPPING_WITH_EDITOR return true; }