Unreal Engine Module - Add a Friend - Use the Online Subsystem to manage friend requests
What's in the Starter Pack
In Module: Search Player, you implemented some friend functionalities in the FriendSubsystem_Starter
subsystem class. You will continue to use that class to follow this section.
Before you start, we have prepared several delegates in the /Source/AccelByteWars/TutorialModules/Social/FriendsEssentials/FriendsEssentialsModels.h
file that you will use along with this tutorial.
Delegates to be can be used as callback when cached friends data is updated.
DECLARE_DELEGATE(FOnCachedFriendsDataUpdated);
Delegates to be can be used as callback when getting received and sent friend requests completed.
DECLARE_DELEGATE_ThreeParams(FOnGetInboundFriendRequestListComplete, bool /*bWasSuccessful*/, TArray<UFriendData*> /*FriendRequests*/, const FString& /*ErrorMessage*/);
DECLARE_DELEGATE_ThreeParams(FOnGetOutboundFriendRequestListComplete, bool /*bWasSuccessful*/, TArray<UFriendData*> /*FriendRequests*/, const FString& /*ErrorMessage*/);Delegates to be can be used as callback when accept, reject, and cancel friend requests are completed.
DECLARE_DELEGATE_TwoParams(FOnAcceptFriendRequestComplete, bool /*bWasSuccessful*/, const FString& /*ErrorMessage*/);
DECLARE_DELEGATE_TwoParams(FOnRejectFriendRequestComplete, bool /*bWasSuccessful*/, const FString& /*ErrorMessage*/);
DECLARE_DELEGATE_TwoParams(FOnCancelFriendRequestComplete, bool /*bWasSuccessful*/, const FString& /*ErrorMessage*/);
Implement Get Received Friend Requests
In this section, you will implement functionalities to get the received friend requests list.
In the previous tutorial, you have created a function namely
CacheFriendList()
in theFriendsSubsystem_Starter
that is used to get and cache the friend list which also includes the received friends requests. Therefore, to get the received friend requests, you only need to filter that cached friend list.Open the
FriendsSubsystem_Starter
class header file and create the following function declarations. The inbound friend request is an alternative term for received friend request which should not be confused.public:
void GetInboundFriendRequestList(const APlayerController* PC, const FOnGetInboundFriendRequestListComplete& OnComplete= FOnGetInboundFriendRequestListComplete());Next, let's create the definition for the function above. Open the
FriendsSubsystem_Starter
class CPP file and add the following code. This function will filter the cached friend list to get the received friend requests.void UFriendsSubsystem_Starter::GetInboundFriendRequestList(const APlayerController* PC, const FOnGetInboundFriendRequestListComplete& OnComplete)
{
if (!ensure(FriendsInterface))
{
UE_LOG_FRIENDS_ESSENTIALS(Warning, TEXT("Cannot query friend request list. Friends Interface is not valid."));
return;
}
// Get friend inbound request list from cache.
GetCacheFriendList(PC, FOnGetCacheFriendListComplete::CreateWeakLambda(this, [this, OnComplete](bool bWasSuccessful, TArray<TSharedRef<FOnlineFriend>>& CachedFriendList, const FString& ErrorMessage)
{
if (bWasSuccessful)
{
// Filter pending inbound friend requests.
CachedFriendList = CachedFriendList.FilterByPredicate([](const TSharedRef<FOnlineFriend>& Friend)
{
return Friend->GetInviteStatus() == EInviteStatus::PendingInbound;
});
TArray<UFriendData*> InboundFriendRequestList;
for (const TSharedRef<FOnlineFriend>& TempData : CachedFriendList)
{
InboundFriendRequestList.Add(UFriendData::ConvertToFriendData(TempData));
}
OnComplete.ExecuteIfBound(true, InboundFriendRequestList, TEXT(""));
}
else
{
OnComplete.ExecuteIfBound(false, TArray<UFriendData*>(), ErrorMessage);
}
}));
}Congratulations! Your get received friend requests list functionalities are completed.
Implement Get Sent Friend Requests
In this section, you will implement functionalities to get the sent friend requests list.
Open the
FriendsSubsystem_Starter
class header file and create the following function declarations. The outbound friend request is an alternative term for received friend request which should not be confused.public:
void GetOutboundFriendRequestList(const APlayerController* PC, const FOnGetOutboundFriendRequestListComplete& OnComplete = FOnGetOutboundFriendRequestListComplete());Next, let's create the definition for the function above. Open the
FriendsSubsystem_Starter
class CPP file and add the following code. Similar to getting received friend request, to get sent friend request you only need to filter the cached friend list.void UFriendsSubsystem_Starter::GetOutboundFriendRequestList(const APlayerController* PC, const FOnGetOutboundFriendRequestListComplete& OnComplete)
{
if (!ensure(FriendsInterface))
{
UE_LOG_FRIENDS_ESSENTIALS(Warning, TEXT("Cannot query friend request list. Friends Interface is not valid."));
return;
}
// Get friend outbound request list from cache.
GetCacheFriendList(PC, FOnGetCacheFriendListComplete::CreateWeakLambda(this, [this, OnComplete](bool bWasSuccessful, TArray<TSharedRef<FOnlineFriend>>& CachedFriendList, const FString& ErrorMessage)
{
if (bWasSuccessful)
{
// Filter pending outbound friend requests.
CachedFriendList = CachedFriendList.FilterByPredicate([](const TSharedRef<FOnlineFriend>& Friend)
{
return Friend->GetInviteStatus() == EInviteStatus::PendingOutbound;
});
TArray<UFriendData*> OutbondFriendRequestList;
for (const TSharedRef<FOnlineFriend>& TempData : CachedFriendList)
{
OutbondFriendRequestList.Add(UFriendData::ConvertToFriendData(TempData));
}
OnComplete.ExecuteIfBound(true, OutbondFriendRequestList, TEXT(""));
}
else
{
OnComplete.ExecuteIfBound(false, TArray<UFriendData*>(), ErrorMessage);
}
}));
}Congratulations! Your get sent friend requests list functionalities are completed.
Implement Accept Received Friend Request
In this section, you will implement functionalities to accept a received friend request.
Open the
FriendsSubsystem_Starter
class header file and declare the following function.public:
void AcceptFriendRequest(const APlayerController* PC, const FUniqueNetIdRepl FriendUserId, const FOnAcceptFriendRequestComplete& OnComplete = FOnAcceptFriendRequestComplete());You also need to create a callback function to handle when the accepting friend request process is completed.
protected:
void OnAcceptFriendRequestComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& FriendId, const FString& ListName, const FString& ErrorStr, const FOnAcceptFriendRequestComplete OnComplete);Now, let's define the functions above. Open the
FriendsSubsystem_Starter
class CPP file and define theAcceptFriendRequest()
function. This function will accept a friend request and call theOnAcceptFriendRequestComplete()
function to handle the callback.void UFriendsSubsystem_Starter::AcceptFriendRequest(const APlayerController* PC, const FUniqueNetIdRepl FriendUserId, const FOnAcceptFriendRequestComplete& OnComplete)
{
if (!ensure(FriendsInterface) || !ensure(PromptSubsystem))
{
UE_LOG_FRIENDS_ESSENTIALS(Warning, TEXT("Cannot accept friend request. Friends Interface or Prompt Subsystem is not valid."));
return;
}
PromptSubsystem->ShowLoading(ACCEPT_FRIEND_REQUEST_MESSAGE);
const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
FriendsInterface->AcceptInvite(LocalUserNum, FriendUserId.GetUniqueNetId().ToSharedRef().Get(), TEXT(""), FOnAcceptInviteComplete::CreateUObject(this, &ThisClass::OnAcceptFriendRequestComplete, OnComplete));
}Finally, define the
OnAcceptFriendRequestComplete()
function that will be called upon the accept friend request process is completed. This function prints a log to show whether the accept received friend request process was successful or not, trigger the callback delegate, and show a pop-up message telling the player the status of their request. Do note thatPromptSubsystem
is Byte Wars specifics, you won't find that exact object in a blank project.void UFriendsSubsystem_Starter::OnAcceptFriendRequestComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& FriendId, const FString& ListName, const FString& ErrorStr, const FOnAcceptFriendRequestComplete OnComplete)
{
PromptSubsystem->HideLoading();
if (bWasSuccessful)
{
UE_LOG_FRIENDS_ESSENTIALS(Warning, TEXT("Success to accept a friend request."));
PromptSubsystem->ShowMessagePopUp(MESSAGE_PROMPT_TEXT, SUCCESS_ACCEPT_FRIEND_REQUEST);
OnComplete.ExecuteIfBound(true, TEXT(""));
}
else
{
UE_LOG_FRIENDS_ESSENTIALS(Warning, TEXT("Failed to accept a friend request. Error: %s"), *ErrorStr);
PromptSubsystem->ShowMessagePopUp(ERROR_PROMPT_TEXT, FText::FromString(ErrorStr));
OnComplete.ExecuteIfBound(false, ErrorStr);
}
}Congratulations! Your accept friend request functionalities are completed.
Implement Reject Received Friend Request
In this section, you will implement functionalities to reject received a friend request.
Open the
FriendsSubsystem_Starter
class header file and declare the following function.public:
void RejectFriendRequest(const APlayerController* PC, const FUniqueNetIdRepl FriendUserId, const FOnRejectFriendRequestComplete& OnComplete = FOnRejectFriendRequestComplete());You also need to create a callback function to handle when rejecting friend request process is completed.
protected:
void OnRejectFriendRequestComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& FriendId, const FString& ListName, const FString& ErrorStr, const FOnRejectFriendRequestComplete OnComplete);Now, let's define the functions above. Open the
FriendsSubsystem_Starter
class CPP file and define theRejectFriendRequest()
function. This function will reject a friend request and call theOnRejectFriendRequestComplete()
function to handle the callback.void UFriendsSubsystem_Starter::RejectFriendRequest(const APlayerController* PC, const FUniqueNetIdRepl FriendUserId, const FOnRejectFriendRequestComplete& OnComplete)
{
if (!ensure(FriendsInterface) || !ensure(PromptSubsystem))
{
UE_LOG_FRIENDS_ESSENTIALS(Warning, TEXT("Cannot reject friend request. Friends Interface or Prompt Subsystem is not valid."));
return;
}
PromptSubsystem->ShowLoading(REJECT_FRIEND_REQUEST_MESSAGE);
const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
OnRejectFriendRequestCompleteDelegateHandle = FriendsInterface->AddOnRejectInviteCompleteDelegate_Handle(LocalUserNum, FOnRejectInviteCompleteDelegate::CreateUObject(this, &ThisClass::OnRejectFriendRequestComplete, OnComplete));
FriendsInterface->RejectInvite(LocalUserNum, FriendUserId.GetUniqueNetId().ToSharedRef().Get(), TEXT(""));
}Finally, define the
OnRejectFriendRequestComplete()
function that will be called upon the reject friend request process is completed. This function prints a log to show whether the reject received friend request process was successful or not, trigger the callback delegate, and shows a pop-up telling the player the status of their request.void UFriendsSubsystem_Starter::OnRejectFriendRequestComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& FriendId, const FString& ListName, const FString& ErrorStr, const FOnRejectFriendRequestComplete OnComplete)
{
PromptSubsystem->HideLoading();
FriendsInterface->ClearOnRejectInviteCompleteDelegate_Handle(LocalUserNum, OnRejectFriendRequestCompleteDelegateHandle);
if (bWasSuccessful)
{
UE_LOG_FRIENDS_ESSENTIALS(Warning, TEXT("Success to reject a friend request."));
PromptSubsystem->ShowMessagePopUp(MESSAGE_PROMPT_TEXT, SUCCESS_REJECT_FRIEND_REQUEST);
OnComplete.ExecuteIfBound(true, TEXT(""));
}
else
{
UE_LOG_FRIENDS_ESSENTIALS(Warning, TEXT("Failed to reject a friend request. Error: %s"), *ErrorStr);
PromptSubsystem->ShowMessagePopUp(ERROR_PROMPT_TEXT, FText::FromString(ErrorStr));
OnComplete.ExecuteIfBound(false, ErrorStr);
}
}Congratulations! Your reject friend request functionalities are completed.
Implement Cancel Sent Friend Request
In this section, you will implement functionality to cancel a sent friend request.
Open the
FriendsSubsystem_Starter
class header file and declare the following function.public:
void CancelFriendRequest(const APlayerController* PC, const FUniqueNetIdRepl FriendUserId, const FOnCancelFriendRequestComplete& OnComplete = FOnCancelFriendRequestComplete());You also need to create a callback function to handle when canceling the sent friend request process is completed.
protected:
void OnCancelFriendRequestComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& FriendId, const FString& ListName, const FString& ErrorStr, const FOnCancelFriendRequestComplete OnComplete);Now, let's define the functions above. Open the
FriendsSubsystem_Starter
class CPP file and define theCancelFriendRequest()
function. This function will cancel a sent friend request and call theOnCancelFriendRequestComplete()
function to handle the callback.void UFriendsSubsystem_Starter::CancelFriendRequest(const APlayerController* PC, const FUniqueNetIdRepl FriendUserId, const FOnCancelFriendRequestComplete& OnComplete)
{
if (!ensure(FriendsInterface) || !ensure(PromptSubsystem))
{
UE_LOG_FRIENDS_ESSENTIALS(Warning, TEXT("Cannot cancel friend request. Friends Interface or Prompt Subsystem is not valid."));
return;
}
PromptSubsystem->ShowLoading(CANCEL_FRIEND_REQUEST_MESSAGE);
const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
OnCancelFriendRequestCompleteDelegateHandle = FriendsInterface->AddOnDeleteFriendCompleteDelegate_Handle(LocalUserNum, FOnDeleteFriendCompleteDelegate::CreateUObject(this, &ThisClass::OnCancelFriendRequestComplete, OnComplete));
FriendsInterface->DeleteFriend(LocalUserNum, FriendUserId.GetUniqueNetId().ToSharedRef().Get(), TEXT(""));
}Finally, define the
OnCancelFriendRequestComplete()
function that will be called upon the cancel sent friend request process is completed. This function simply prints a log to show whether the cancel sent friend request process was successful or not and trigger the callback delegate.void UFriendsSubsystem_Starter::OnCancelFriendRequestComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& FriendId, const FString& ListName, const FString& ErrorStr, const FOnCancelFriendRequestComplete OnComplete)
{
PromptSubsystem->HideLoading();
FriendsInterface->ClearOnDeleteFriendCompleteDelegate_Handle(LocalUserNum, OnCancelFriendRequestCompleteDelegateHandle);
if (bWasSuccessful)
{
UE_LOG_FRIENDS_ESSENTIALS(Warning, TEXT("Success to cancel a friend request."));
PromptSubsystem->ShowMessagePopUp(MESSAGE_PROMPT_TEXT, SUCCESS_CANCEL_FRIEND_REQUEST);
OnComplete.ExecuteIfBound(true, TEXT(""));
}
else
{
UE_LOG_FRIENDS_ESSENTIALS(Warning, TEXT("Failed to cancel a friend request. Error: %s"), *ErrorStr);
PromptSubsystem->ShowMessagePopUp(ERROR_PROMPT_TEXT, FText::FromString(ErrorStr));
OnComplete.ExecuteIfBound(false, ErrorStr);
}
}Congratulations! Your cancel sent friend request functionality is completed.
Listen On Friend List Updated
When the players accept, reject, or cancel friend requests, the cached friend list will be updated automatically by AccelByte OSS. In this section, you will learn how to bind a delegate to be executed when the friend list is updated. It will be useful when you need to update the displayed entries widgets later.
Open the
FriendsSubsystem_Starter
class header file and create the following function declarations.public:
void BindOnCachedFriendsDataUpdated(const APlayerController* PC, const FOnCachedFriendsDataUpdated& Delegate);
void UnbindOnCachedFriendsDataUpdated(const APlayerController* PC);Then, open the
FriendsSubsystem_Starter
class CPP file and create the definitions for the functions above. Let's start with theBindOnCachedFriendsDataUpdated()
function.void UFriendsSubsystem_Starter::BindOnCachedFriendsDataUpdated(const APlayerController* PC, const FOnCachedFriendsDataUpdated& Delegate)
{
ensure(FriendsInterface);
const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
// Add on friends changed delegate.
OnFriendsChangeDelegateHandles.Add(LocalUserNum, FriendsInterface->AddOnFriendsChangeDelegate_Handle(LocalUserNum, FOnFriendsChangeDelegate::CreateWeakLambda(this, [Delegate]() { Delegate.ExecuteIfBound(); })));
}Next, create the definition for the
UnbindOnCachedFriendsDataUpdated()
function.void UFriendsSubsystem_Starter::UnbindOnCachedFriendsDataUpdated(const APlayerController* PC)
{
ensure(FriendsInterface);
const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
// Clear on friends changed delegate.
FDelegateHandle TempHandle = OnFriendsChangeDelegateHandles[LocalUserNum];
if (TempHandle.IsValid())
{
FriendsInterface->ClearOnFriendsChangeDelegate_Handle(LocalUserNum, TempHandle);
}
}Now let's understand the idea behind those functions. So basically, you can bind a delegate to be executed when the friend list is updated by using the
BindOnCachedFriendsDataUpdated()
function. To unbind that delegate, you can use theUnbindOnCachedFriendsDataUpdated()
function. You will use these functions to update displayed entries widgets in the next section.
Resources
- The files used in this tutorial section are available in the Byte Wars GitHub repository.