diff --git a/Source/AdvancedSessions/Classes/FindSessionsCallbackProxyAdvanced.h b/Source/AdvancedSessions/Classes/FindSessionsCallbackProxyAdvanced.h index 6b09526..4d12ca8 100644 --- a/Source/AdvancedSessions/Classes/FindSessionsCallbackProxyAdvanced.h +++ b/Source/AdvancedSessions/Classes/FindSessionsCallbackProxyAdvanced.h @@ -51,6 +51,10 @@ private: // Internal callback when the session search completes, calls out to the public success/failure callbacks void OnCompleted(bool bSuccess); + bool bRunSecondSearch; + + TArray SessionSearchResults; + private: // The player controller triggering things TWeakObjectPtr PlayerControllerWeakPtr; @@ -63,6 +67,7 @@ private: // Object to track search results TSharedPtr SearchObject; + TSharedPtr SearchObjectDedicated; // Whether or not to search LAN bool bUseLAN; diff --git a/Source/AdvancedSessions/Classes/SteamFuncs/AdvancedSteamWorkshopLibrary.h b/Source/AdvancedSessions/Classes/SteamFuncs/AdvancedSteamWorkshopLibrary.h new file mode 100644 index 0000000..635d223 --- /dev/null +++ b/Source/AdvancedSessions/Classes/SteamFuncs/AdvancedSteamWorkshopLibrary.h @@ -0,0 +1,297 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once +#include "OnlineSubSystemHeader.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "Online.h" +#include "OnlineSubsystem.h" +#include "OnlineSessionInterface.h" + +// @todo Steam: Steam headers trigger secure-C-runtime warnings in Visual C++. Rather than mess with _CRT_SECURE_NO_WARNINGS, we'll just +// disable the warnings locally. Remove when this is fixed in the SDK +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4996) +#endif + +#if PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX + +#pragma push_macro("ARRAY_COUNT") +#undef ARRAY_COUNT + +#include + +#pragma pop_macro("ARRAY_COUNT") + +#endif + +// @todo Steam: See above +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + +#include "AdvancedSteamWorkshopLibrary.generated.h" + + +//General Advanced Sessions Log +DECLARE_LOG_CATEGORY_EXTERN(AdvancedSteamWorkshopLog, Log, All); + + +// Using a custom struct because uint32 isn't blueprint supported and I don't want to cast to int32 +// due to the size of the workshop it could end up overflowing? +USTRUCT(BlueprintType) +struct FBPSteamWorkshopID +{ + GENERATED_USTRUCT_BODY() + +public: + + uint32 SteamWorkshopID; + + FBPSteamWorkshopID() + { + + } + + FBPSteamWorkshopID(uint32 ID) + { + SteamWorkshopID = ID; + } +}; + + +// General result codes - Copying steams version over +// Check these to future proof +UENUM(BlueprintType) +enum class FBPSteamResult : uint8 +{ + k_EResultOK = 1, // success + k_EResultFail = 2, // generic failure + k_EResultNoConnection = 3, // no/failed network connection + // k_EResultNoConnectionRetry = 4, // OBSOLETE - removed + k_EResultInvalidPassword = 5, // password/ticket is invalid + k_EResultLoggedInElsewhere = 6, // same user logged in elsewhere + k_EResultInvalidProtocolVer = 7, // protocol version is incorrect + k_EResultInvalidParam = 8, // a parameter is incorrect + k_EResultFileNotFound = 9, // file was not found + k_EResultBusy = 10, // called method busy - action not taken + k_EResultInvalidState = 11, // called object was in an invalid state + k_EResultInvalidName = 12, // name is invalid + k_EResultInvalidEmail = 13, // email is invalid + k_EResultDuplicateName = 14, // name is not unique + k_EResultAccessDenied = 15, // access is denied + k_EResultTimeout = 16, // operation timed out + k_EResultBanned = 17, // VAC2 banned + k_EResultAccountNotFound = 18, // account not found + k_EResultInvalidSteamID = 19, // steamID is invalid + k_EResultServiceUnavailable = 20, // The requested service is currently unavailable + k_EResultNotLoggedOn = 21, // The user is not logged on + k_EResultPending = 22, // Request is pending (may be in process, or waiting on third party) + k_EResultEncryptionFailure = 23, // Encryption or Decryption failed + k_EResultInsufficientPrivilege = 24, // Insufficient privilege + k_EResultLimitExceeded = 25, // Too much of a good thing + k_EResultRevoked = 26, // Access has been revoked (used for revoked guest passes) + k_EResultExpired = 27, // License/Guest pass the user is trying to access is expired + k_EResultAlreadyRedeemed = 28, // Guest pass has already been redeemed by account, cannot be acked again + k_EResultDuplicateRequest = 29, // The request is a duplicate and the action has already occurred in the past, ignored this time + k_EResultAlreadyOwned = 30, // All the games in this guest pass redemption request are already owned by the user + k_EResultIPNotFound = 31, // IP address not found + k_EResultPersistFailed = 32, // failed to write change to the data store + k_EResultLockingFailed = 33, // failed to acquire access lock for this operation + k_EResultLogonSessionReplaced = 34, + k_EResultConnectFailed = 35, + k_EResultHandshakeFailed = 36, + k_EResultIOFailure = 37, + k_EResultRemoteDisconnect = 38, + k_EResultShoppingCartNotFound = 39, // failed to find the shopping cart requested + k_EResultBlocked = 40, // a user didn't allow it + k_EResultIgnored = 41, // target is ignoring sender + k_EResultNoMatch = 42, // nothing matching the request found + k_EResultAccountDisabled = 43, + k_EResultServiceReadOnly = 44, // this service is not accepting content changes right now + k_EResultAccountNotFeatured = 45, // account doesn't have value, so this feature isn't available + k_EResultAdministratorOK = 46, // allowed to take this action, but only because requester is admin + k_EResultContentVersion = 47, // A Version mismatch in content transmitted within the Steam protocol. + k_EResultTryAnotherCM = 48, // The current CM can't service the user making a request, user should try another. + k_EResultPasswordRequiredToKickSession = 49,// You are already logged in elsewhere, this cached credential login has failed. + k_EResultAlreadyLoggedInElsewhere = 50, // You are already logged in elsewhere, you must wait + k_EResultSuspended = 51, // Long running operation (content download) suspended/paused + k_EResultCancelled = 52, // Operation canceled (typically by user: content download) + k_EResultDataCorruption = 53, // Operation canceled because data is ill formed or unrecoverable + k_EResultDiskFull = 54, // Operation canceled - not enough disk space. + k_EResultRemoteCallFailed = 55, // an remote call or IPC call failed + k_EResultPasswordUnset = 56, // Password could not be verified as it's unset server side + k_EResultExternalAccountUnlinked = 57, // External account (PSN, Facebook...) is not linked to a Steam account + k_EResultPSNTicketInvalid = 58, // PSN ticket was invalid + k_EResultExternalAccountAlreadyLinked = 59, // External account (PSN, Facebook...) is already linked to some other account, must explicitly request to replace/delete the link first + k_EResultRemoteFileConflict = 60, // The sync cannot resume due to a conflict between the local and remote files + k_EResultIllegalPassword = 61, // The requested new password is not legal + k_EResultSameAsPreviousValue = 62, // new value is the same as the old one ( secret question and answer ) + k_EResultAccountLogonDenied = 63, // account login denied due to 2nd factor authentication failure + k_EResultCannotUseOldPassword = 64, // The requested new password is not legal + k_EResultInvalidLoginAuthCode = 65, // account login denied due to auth code invalid + k_EResultAccountLogonDeniedNoMail = 66, // account login denied due to 2nd factor auth failure - and no mail has been sent + k_EResultHardwareNotCapableOfIPT = 67, // + k_EResultIPTInitError = 68, // + k_EResultParentalControlRestricted = 69, // operation failed due to parental control restrictions for current user + k_EResultFacebookQueryError = 70, // Facebook query returned an error + k_EResultExpiredLoginAuthCode = 71, // account login denied due to auth code expired + k_EResultIPLoginRestrictionFailed = 72, + k_EResultAccountLockedDown = 73, + k_EResultAccountLogonDeniedVerifiedEmailRequired = 74, + k_EResultNoMatchingURL = 75, + k_EResultBadResponse = 76, // parse failure, missing field, etc. + k_EResultRequirePasswordReEntry = 77, // The user cannot complete the action until they re-enter their password + k_EResultValueOutOfRange = 78, // the value entered is outside the acceptable range + k_EResultUnexpectedError = 79, // something happened that we didn't expect to ever happen + k_EResultDisabled = 80, // The requested service has been configured to be unavailable + k_EResultInvalidCEGSubmission = 81, // The set of files submitted to the CEG server are not valid ! + k_EResultRestrictedDevice = 82, // The device being used is not allowed to perform this action + k_EResultRegionLocked = 83, // The action could not be complete because it is region restricted + k_EResultRateLimitExceeded = 84, // Temporary rate limit exceeded, try again later, different from k_EResultLimitExceeded which may be permanent + k_EResultAccountLoginDeniedNeedTwoFactor = 85, // Need two-factor code to login + k_EResultItemDeleted = 86, // The thing we're trying to access has been deleted + k_EResultAccountLoginDeniedThrottle = 87, // login attempt failed, try to throttle response to possible attacker + k_EResultTwoFactorCodeMismatch = 88, // two factor code mismatch + k_EResultTwoFactorActivationCodeMismatch = 89, // activation code for two-factor didn't match + k_EResultAccountAssociatedToMultiplePartners = 90, // account has been associated with multiple partners + k_EResultNotModified = 91, // data not modified +}; + +// Check these to future proof +UENUM(BlueprintType) +enum class FBPWorkshopFileType : uint8 +{ + k_EWorkshopFileTypeCommunity = 0, + k_EWorkshopFileTypeMicrotransaction = 1, + k_EWorkshopFileTypeCollection = 2, + k_EWorkshopFileTypeArt = 3, + k_EWorkshopFileTypeVideo = 4, + k_EWorkshopFileTypeScreenshot = 5, + k_EWorkshopFileTypeGame = 6, + k_EWorkshopFileTypeSoftware = 7, + k_EWorkshopFileTypeConcept = 8, + k_EWorkshopFileTypeWebGuide = 9, + k_EWorkshopFileTypeIntegratedGuide = 10, + k_EWorkshopFileTypeMerch = 11, + k_EWorkshopFileTypeControllerBinding = 12, + k_EWorkshopFileTypeSteamworksAccessInvite = 13, + k_EWorkshopFileTypeSteamVideo = 14, + + // Update k_EWorkshopFileTypeMax if you add values. + k_EWorkshopFileTypeMax = 15 +}; + +// WorkshopItemDetails Struct +USTRUCT(BlueprintType) +struct FBPSteamWorkshopItemDetails +{ + GENERATED_USTRUCT_BODY() + +public: + FBPSteamWorkshopItemDetails() + { + + } + + FBPSteamWorkshopItemDetails(SteamUGCDetails_t &hUGCDetails) + { + ResultOfRequest = (FBPSteamResult)hUGCDetails.m_eResult; + FileType = (FBPWorkshopFileType)hUGCDetails.m_eFileType; + CreatorAppID = (int32)hUGCDetails.m_nCreatorAppID; + ConsumerAppID = (int32)hUGCDetails.m_nConsumerAppID; + Title = FString(hUGCDetails.m_rgchTitle, k_cchPublishedDocumentTitleMax); + Description = FString(hUGCDetails.m_rgchDescription, k_cchPublishedDocumentDescriptionMax); + ItemUrl = FString(hUGCDetails.m_rgchURL, k_cchPublishedFileURLMax); + VotesUp = (int32)hUGCDetails.m_unVotesUp; + VotesDown = (int32)hUGCDetails.m_unVotesDown; + CalculatedScore = hUGCDetails.m_flScore; + bBanned = hUGCDetails.m_bBanned; + bAcceptedForUse = hUGCDetails.m_bAcceptedForUse; + bTagsTruncated = hUGCDetails.m_bTagsTruncated; + } + + // Result of obtaining the details + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + FBPSteamResult ResultOfRequest; + + // Type of file + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + FBPWorkshopFileType FileType; + + // These two are listed as baked to an int, but is stored as a uint, think its safe to keep int + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + int32 CreatorAppID; + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + int32 ConsumerAppID; + + // Title of item + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + FString Title; + + // Description of item + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + FString Description; + + //Url for a video of website + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + FString ItemUrl; + + // Votes will be unlikely to go above signed limited + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + int32 VotesUp; + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + int32 VotesDown; + + // Calculated score + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + float CalculatedScore; + + // whether the file was banned + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + bool bBanned; + + // developer has specifically flagged this item as accepted in the Workshop + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + bool bAcceptedForUse; + + // whether the list of tags was too long to be returned in the provided buffer + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Online|AdvancedSteamWorkshop") + bool bTagsTruncated; + + /* + PublishedFileId_t m_nPublishedFileId; + uint64 m_ulSteamIDOwner; // Steam ID of the user who created this content. + uint32 m_rtimeCreated; // time when the published file was created + uint32 m_rtimeUpdated; // time when the published file was last updated + uint32 m_rtimeAddedToUserList; // time when the user added the published file to their list (not always applicable) + ERemoteStoragePublishedFileVisibility m_eVisibility; // visibility + char m_rgchTags[k_cchTagListMax]; // comma separated list of all tags associated with this file + // file/url information + UGCHandle_t m_hFile; // The handle of the primary file + UGCHandle_t m_hPreviewFile; // The handle of the preview file + char m_pchFileName[k_cchFilenameMax]; // The cloud filename of the primary file + int32 m_nFileSize; // Size of the primary file + int32 m_nPreviewFileSize; // Size of the preview file + uint32 m_unNumChildren; // if m_eFileType == k_EWorkshopFileTypeCollection, then this number will be the number of children contained within the collection + */ + +}; + +UCLASS() +class UAdvancedSteamWorkshopLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() +public: + + //********* Steam Functions *************// + + // Returns IDs for subscribed workshop items, TArray length dictates how many + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSteamWorkshop") + static TArray GetSubscribedWorkshopItems(int32 & NumberOfItems); + + UFUNCTION(BlueprintCallable, Category = "Online|AdvancedSteamWorkshop") + static void GetNumSubscribedWorkshopItems(int32 & NumberOfItems); + +}; diff --git a/Source/AdvancedSessions/Classes/SteamFuncs/SteamWSRequestUGCDetailsCallbackProxy.h b/Source/AdvancedSessions/Classes/SteamFuncs/SteamWSRequestUGCDetailsCallbackProxy.h new file mode 100644 index 0000000..bdbe618 --- /dev/null +++ b/Source/AdvancedSessions/Classes/SteamFuncs/SteamWSRequestUGCDetailsCallbackProxy.h @@ -0,0 +1,72 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +#pragma once + +// This is taken directly from UE4 - OnlineSubsystemSteamPrivatePCH.h as a fix for the array_count macro + +// @todo Steam: Steam headers trigger secure-C-runtime warnings in Visual C++. Rather than mess with _CRT_SECURE_NO_WARNINGS, we'll just +// disable the warnings locally. Remove when this is fixed in the SDK +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4996) +#endif + +#if PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX + +#pragma push_macro("ARRAY_COUNT") +#undef ARRAY_COUNT + +#include + +#pragma pop_macro("ARRAY_COUNT") + +#endif + +// @todo Steam: See above +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "SteamWSRequestUGCDetailsCallbackProxy.generated.h" + + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBlueprintWorkshopDetailsDelegate, const FBPSteamWorkshopItemDetails&, WorkShopDetails); + +UCLASS(MinimalAPI) +class USteamWSRequestUGCDetailsCallbackProxy : public UOnlineBlueprintCallProxyBase +{ + GENERATED_UCLASS_BODY() + + // Called when there is a successful results return + UPROPERTY(BlueprintAssignable) + FBlueprintWorkshopDetailsDelegate OnSuccess; + + // Called when there is an unsuccessful results return + UPROPERTY(BlueprintAssignable) + FBlueprintWorkshopDetailsDelegate OnFailure; + + // Ends the current session + UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly = "true", WorldContext="WorldContextObject"), Category = "Online|AdvancedSteamWorkshop") + static USteamWSRequestUGCDetailsCallbackProxy* GetWorkshopItemDetails(UObject* WorldContextObject, FBPSteamWorkshopID WorkShopID, int32 NumSecondsBeforeTimeout); + + // UOnlineBlueprintCallProxyBase interface + virtual void Activate() override; + // End of UOnlineBlueprintCallProxyBase interface + +private: + +#if PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX + // Internal callback when the operation completes, calls out to the public success/failure callbacks + /* Steam UGC details */ + //STEAM_CALLBACK(USteamWSRequestUGCDetailsCallbackProxy, OnUGCRequestUGCDetails, SteamUGCRequestUGCDetailsResult_t, OnUGCRequestUGCDetailsCallback); + void OnUGCRequestUGCDetails(SteamUGCRequestUGCDetailsResult_t *pResult, bool bIOFailure); + CCallResult m_callResultUGCRequestDetails; +#endif + +private: + + FBPSteamWorkshopID WorkShopID; + + int32 NumSecondsBeforeTimeout; + + UObject* WorldContextObject; +}; diff --git a/Source/AdvancedSessions/Private/AdvancedFriendsLibrary.cpp b/Source/AdvancedSessions/Private/AdvancedFriendsLibrary.cpp index 7d9844f..7c2ca94 100644 --- a/Source/AdvancedSessions/Private/AdvancedFriendsLibrary.cpp +++ b/Source/AdvancedSessions/Private/AdvancedFriendsLibrary.cpp @@ -115,6 +115,8 @@ UTexture2D * UAdvancedFriendsLibrary::GetSteamFriendAvatar(const FBPUniqueNetId SteamUtils()->GetImageSize(Picture, &Width, &Height); // STOLEN FROM ANSWERHUB :p, then fixed because answerhub wasn't releasing the memory O.o + // Also fixed image pixel format and switched to a memcpy instead of manual iteration. + // At some point I should probably reply to that answerhub post with these fixes to prevent people killing their games..... if (Width > 0 && Height > 0) { diff --git a/Source/AdvancedSessions/Private/FindSessionsCallbackProxyAdvanced.cpp b/Source/AdvancedSessions/Private/FindSessionsCallbackProxyAdvanced.cpp index d4e68fd..302bbdb 100644 --- a/Source/AdvancedSessions/Private/FindSessionsCallbackProxyAdvanced.cpp +++ b/Source/AdvancedSessions/Private/FindSessionsCallbackProxyAdvanced.cpp @@ -12,6 +12,7 @@ UFindSessionsCallbackProxyAdvanced::UFindSessionsCallbackProxyAdvanced(const FOb , Delegate(FOnFindSessionsCompleteDelegate::CreateUObject(this, &ThisClass::OnCompleted)) , bUseLAN(false) { + bRunSecondSearch = false; } UFindSessionsCallbackProxyAdvanced* UFindSessionsCallbackProxyAdvanced::FindSessionsAdvanced(UObject* WorldContextObject, class APlayerController* PlayerController, int MaxResults, bool bUseLAN, EBPServerPresenceSearchType ServerTypeToSearch, const TArray &Filters, bool bEmptyServersOnly, bool bNonEmptyServersOnly, bool bSecureServersOnly, int MinSlotsAvailable) @@ -40,6 +41,9 @@ void UFindSessionsCallbackProxyAdvanced::Activate() auto Sessions = Helper.OnlineSub->GetSessionInterface(); if (Sessions.IsValid()) { + // Re-initialize here, otherwise I think there might be issues with people re-calling search for some reason before it is destroyed + bRunSecondSearch = false; + DelegateHandle = Sessions->AddOnFindSessionsCompleteDelegate_Handle(Delegate); SearchObject = MakeShareable(new FOnlineSessionSearch); @@ -81,6 +85,18 @@ void UFindSessionsCallbackProxyAdvanced::Activate() if (MinSlotsAvailable != 0) tem.Set(SEARCH_MINSLOTSAVAILABLE, MinSlotsAvailable, EOnlineComparisonOp::GreaterThanEquals); + + + // Filter results + if (SearchSettings.Num() > 0) + { + for (int i = 0; i < SearchSettings.Num(); i++) + { + // Function that was added to make directly adding a FVariant possible + tem.HardSet(SearchSettings[i].PropertyKeyPair.Key, SearchSettings[i].PropertyKeyPair.Data, SearchSettings[i].ComparisonOp); + } + } + switch (ServerSearchType) { @@ -99,28 +115,26 @@ void UFindSessionsCallbackProxyAdvanced::Activate() case EBPServerPresenceSearchType::AllServers: default: { - // tem.Set(SEARCH_DEDICATED_ONLY, false, EOnlineComparisonOp::Equals); - // tem.Set(SEARCH_PRESENCE, false, EOnlineComparisonOp::Equals); + bRunSecondSearch = true; + + SearchObjectDedicated = MakeShareable(new FOnlineSessionSearch); + SearchObjectDedicated->MaxSearchResults = MaxResults; + SearchObjectDedicated->bIsLanQuery = bUseLAN; + + FOnlineSearchSettingsEx DedicatedOnly = tem; + tem.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals); + + DedicatedOnly.Set(SEARCH_DEDICATED_ONLY, true, EOnlineComparisonOp::Equals); + SearchObjectDedicated->QuerySettings = DedicatedOnly; } break; - - } - - // Filter results - if (SearchSettings.Num() > 0) - { - for (int i = 0; i < SearchSettings.Num(); i++) - { - // Function that was added to make directly adding a FVariant possible - tem.HardSet(SearchSettings[i].PropertyKeyPair.Key, SearchSettings[i].PropertyKeyPair.Data, SearchSettings[i].ComparisonOp); - } } // Copy the derived temp variable over to it's base class SearchObject->QuerySettings = tem; Sessions->FindSessions(*Helper.UserID, SearchObject.ToSharedRef()); - + // OnQueryCompleted will get called, nothing more to do now return; } @@ -131,8 +145,7 @@ void UFindSessionsCallbackProxyAdvanced::Activate() } // Fail immediately - TArray Results; - OnFailure.Broadcast(Results); + OnFailure.Broadcast(SessionSearchResults); } void UFindSessionsCallbackProxyAdvanced::OnCompleted(bool bSuccess) @@ -140,7 +153,7 @@ void UFindSessionsCallbackProxyAdvanced::OnCompleted(bool bSuccess) FOnlineSubsystemBPCallHelperAdvanced Helper(TEXT("FindSessionsCallback"), GEngine->GetWorldFromContextObject(WorldContextObject)); Helper.QueryIDFromPlayerController(PlayerControllerWeakPtr.Get()); - if (Helper.IsValid()) + if (!bRunSecondSearch && Helper.IsValid()) { auto Sessions = Helper.OnlineSub->GetSessionInterface(); if (Sessions.IsValid()) @@ -149,51 +162,43 @@ void UFindSessionsCallbackProxyAdvanced::OnCompleted(bool bSuccess) } } - TArray Results; - if (bSuccess && SearchObject.IsValid()) { // Just log the results for now, will need to add a blueprint-compatible search result struct for (auto& Result : SearchObject->SearchResults) { - /* bool bAddResult = true; + FString ResultText = FString::Printf(TEXT("Found a session. Ping is %d"), Result.PingInMs); - // Filter results - if (SearchSettings.Num() > 0) - { - FOnlineSessionSetting * setting; - for (int i = 0; i < SearchSettings.Num(); i++) - { - setting = Result.Session.SessionSettings.Settings.Find(SearchSettings[i].PropertyKeyPair.Key); + FFrame::KismetExecutionMessage(*ResultText, ELogVerbosity::Log); - // Couldn't find this key - if (!setting) - continue; - - if (!CompareVariants(setting->Data, SearchSettings[i].PropertyKeyPair.Data, SearchSettings[i].ComparisonOp)) - { - bAddResult = false; - break; - } - } - }*/ - - //if (bAddResult) - //{ - FString ResultText = FString::Printf(TEXT("Found a session. Ping is %d"), Result.PingInMs); - - FFrame::KismetExecutionMessage(*ResultText, ELogVerbosity::Log); - - FBlueprintSessionResult BPResult; - BPResult.OnlineResult = Result; - Results.Add(BPResult); - //} + FBlueprintSessionResult BPResult; + BPResult.OnlineResult = Result; + SessionSearchResults.Add(BPResult); + } + if (!bRunSecondSearch) + { + OnSuccess.Broadcast(SessionSearchResults); + return; } - OnSuccess.Broadcast(Results); } else { - OnFailure.Broadcast(Results); + if (!bRunSecondSearch) + { + // Need to account for only one of the searches failing + if(SessionSearchResults.Num() > 0) + OnSuccess.Broadcast(SessionSearchResults); + else + OnFailure.Broadcast(SessionSearchResults); + return; + } + } + + if (bRunSecondSearch && ServerSearchType == EBPServerPresenceSearchType::AllServers) + { + bRunSecondSearch = false; + auto Sessions = Helper.OnlineSub->GetSessionInterface(); + Sessions->FindSessions(*Helper.UserID, SearchObjectDedicated.ToSharedRef()); } } diff --git a/Source/AdvancedSessions/Private/SteamFuncs/AdvancedSteamWorkshopLibrary.cpp b/Source/AdvancedSessions/Private/SteamFuncs/AdvancedSteamWorkshopLibrary.cpp new file mode 100644 index 0000000..cb59c47 --- /dev/null +++ b/Source/AdvancedSessions/Private/SteamFuncs/AdvancedSteamWorkshopLibrary.cpp @@ -0,0 +1,69 @@ +// Fill out your copyright notice in the Description page of Project Settings. +#include "OnlineSubSystemHeader.h" +#include "SteamFuncs/AdvancedSteamWorkshopLibrary.h" +//General Log +DEFINE_LOG_CATEGORY(AdvancedSteamWorkshopLog); + + +void UAdvancedSteamWorkshopLibrary::GetNumSubscribedWorkshopItems(int32 & NumberOfItems) +{ + NumberOfItems = 0; +#if PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX + + if (SteamAPI_Init()) + { + NumberOfItems = SteamUGC()->GetNumSubscribedItems(); + return; + } + else + { + UE_LOG(AdvancedSteamWorkshopLog, Warning, TEXT("Error in GetNumSubscribedWorkshopItemCount : SteamAPI is not Inited!")); + return; + } +#endif + + UE_LOG(AdvancedSteamWorkshopLog, Warning, TEXT("Error in GetNumSubscribedWorkshopItemCount : Called on an incompatible platform")); + return; +} + +TArray UAdvancedSteamWorkshopLibrary::GetSubscribedWorkshopItems(int32 & NumberOfItems) +{ + TArray outArray; + NumberOfItems = 0; + +#if PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX + + if (SteamAPI_Init()) + { + uint32 NumItems = SteamUGC()->GetNumSubscribedItems(); + + if (NumItems == 0) + return outArray; + + // Not using the actual variable above in case someone somehow goes past int32 limits + // Don't want to go negative on the iteration. + NumberOfItems = NumItems; + + PublishedFileId_t *fileIds = new PublishedFileId_t[NumItems]; + + uint32 subItems = SteamUGC()->GetSubscribedItems(fileIds, NumItems); + + for (uint32 i = 0; i < subItems; ++i) + { + outArray.Add(FBPSteamWorkshopID(fileIds[i])); + } + + delete fileIds; + + return outArray; + } + else + { + UE_LOG(AdvancedSteamWorkshopLog, Warning, TEXT("Error in GetSubscribedWorkshopItemCount : SteamAPI is not Inited!")); + return outArray; + } +#endif + + UE_LOG(AdvancedSteamWorkshopLog, Warning, TEXT("Error in GetSubscribedWorkshopItemCount : Called on an incompatible platform")); + return outArray; +} diff --git a/Source/AdvancedSessions/Private/SteamFuncs/SteamWSRequestUGCDetailsCallbackProxy.cpp b/Source/AdvancedSessions/Private/SteamFuncs/SteamWSRequestUGCDetailsCallbackProxy.cpp new file mode 100644 index 0000000..e3c7035 --- /dev/null +++ b/Source/AdvancedSessions/Private/SteamFuncs/SteamWSRequestUGCDetailsCallbackProxy.cpp @@ -0,0 +1,54 @@ +// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. + +#include "OnlineSubSystemHeader.h" +#include "SteamFuncs/SteamWSRequestUGCDetailsCallbackProxy.h" + +////////////////////////////////////////////////////////////////////////// +// UEndSessionCallbackProxy + +USteamWSRequestUGCDetailsCallbackProxy::USteamWSRequestUGCDetailsCallbackProxy(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + NumSecondsBeforeTimeout = 4.0f; +} + + +USteamWSRequestUGCDetailsCallbackProxy* USteamWSRequestUGCDetailsCallbackProxy::GetWorkshopItemDetails(UObject* WorldContextObject, FBPSteamWorkshopID WorkShopID, int32 NumSecondsBeforeTimeout) +{ + USteamWSRequestUGCDetailsCallbackProxy* Proxy = NewObject(); + + Proxy->WorkShopID = WorkShopID; + Proxy->NumSecondsBeforeTimeout = NumSecondsBeforeTimeout; + return Proxy; +} + +void USteamWSRequestUGCDetailsCallbackProxy::Activate() +{ +#if PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX + if (SteamAPI_Init()) + { + SteamAPICall_t hSteamAPICall = SteamUGC()->RequestUGCDetails(WorkShopID.SteamWorkshopID, NumSecondsBeforeTimeout); + m_callResultUGCRequestDetails.Set(hSteamAPICall, this, &USteamWSRequestUGCDetailsCallbackProxy::OnUGCRequestUGCDetails); + return; + } +#endif + OnFailure.Broadcast(FBPSteamWorkshopItemDetails()); +} + +void USteamWSRequestUGCDetailsCallbackProxy::OnUGCRequestUGCDetails(SteamUGCRequestUGCDetailsResult_t *pResult, bool bIOFailure) +{ +#if PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX + + if (bIOFailure || !pResult) + { + OnFailure.Broadcast(FBPSteamWorkshopItemDetails()); + return; + } + + OnSuccess.Broadcast(FBPSteamWorkshopItemDetails(pResult->m_details)); + return; +#endif + + OnFailure.Broadcast(FBPSteamWorkshopItemDetails()); +} +