Skip to main content

Manage friend requests with the OSS - Add friends - (Unreal Engine module)

Last updated on October 24, 2024

What's in the Starter Pack

In the Search for players module, you implemented some friend functionalities in the FriendSubsystem_Starter subsystem class. You will continue to use that class to follow this tutorial.

Before you start, several delegates have been prepared for you in the /Source/AccelByteWars/TutorialModules/Social/FriendsEssentials/FriendsEssentialsModels.h file that you will use along with this tutorial.

  • Delegates to be used as a callback when cached friends data is updated.

    DECLARE_DELEGATE_ThreeParams(FOnGetCacheFriendListComplete, bool /*bWasSuccessful*/, TArray<TSharedRef<FOnlineFriend>>& /*CachedFriendList*/, const FString& /*ErrorMessage*/);
    DECLARE_DELEGATE(FOnCachedFriendsDataUpdated);
  • Delegates to be used as a callback when getting received and sent friend requests completes.

    // ...
    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 used as a callback when accept, reject, and cancel friend requests complete.

    // ...
    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.

  1. You previously created a function named CacheFriendList() in the FriendsSubsystem_Starter that is used to get and cache the friend list which also includes the received friend requests. Therefore, to get the received friend requests, you only need to filter that cached friend list.

  2. Open the FriendsSubsystem_Starter class Header file and create the following function declarations:

    public:
    // ...
    void GetInboundFriendRequestList(const APlayerController* PC, const FOnGetInboundFriendRequestListComplete& OnComplete = FOnGetInboundFriendRequestListComplete());
    note

    "Inbound" friend requests is an alternate term for "received" friend requests.

  3. Create the definition for the function above. Open the FriendsSubsystem_Starter class CPP file and add the code below. 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.
    const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
    GetCacheFriendList(LocalUserNum, 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);
    }
    }));
    }

Implement Get Sent Friend Requests

In this section, you will implement functionalities to get the sent friend requests list.

  1. Open the FriendsSubsystem_Starter class Header file and create the following function declarations:

    public:
    // ...
    void GetOutboundFriendRequestList(const APlayerController* PC, const FOnGetOutboundFriendRequestListComplete& OnComplete = FOnGetOutboundFriendRequestListComplete());
    note

    "Outbound" friend requests is an alternate term for "sent" friend requests.

  2. Create the definition for the function above. Open the FriendsSubsystem_Starter class CPP file and add the code below. Similar to getting received friend requests, to get sent friend requests, 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.
    const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
    GetCacheFriendList(LocalUserNum, 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);
    }
    }));
    }

Implement Accept Received Friend Request

In this section, you will implement functionalities to accept a received friend request.

  1. 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());
  2. You also need to create a callback function to handle when the accepting friend request process completes:

    protected:
    // ...
    void OnAcceptFriendRequestComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& FriendId, const FString& ListName, const FString& ErrorStr, const FOnAcceptFriendRequestComplete OnComplete);
  3. Define the functions above. Open the FriendsSubsystem_Starter class CPP file and define the AcceptFriendRequest() function. This function will accept a friend request and call the OnAcceptFriendRequestComplete() 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));
    }
  4. Define the OnAcceptFriendRequestComplete() function that will be called upon the accept friend request process completing. This function prints a log to show whether the accept received friend request process was successful or not, triggers the callback delegate, and shows a pop-up message telling the player the status of their request. Do note that PromptSubsystem is Byte Wars-specific, so 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);
    }
    }

Implement Reject Received Friend Request

In this section, you will implement functionalities to reject a received a friend request.

  1. 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());
  2. You also need to create a callback function to handle when rejecting a friend request process completes.

    protected:
    // ...
    void OnRejectFriendRequestComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& FriendId, const FString& ListName, const FString& ErrorStr, const FOnRejectFriendRequestComplete OnComplete);
  3. Define the functions above. Open the FriendsSubsystem_Starter class CPP file and define the RejectFriendRequest() function. This function will reject a friend request and call the OnRejectFriendRequestComplete() 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(""));
    }
  4. Define the OnRejectFriendRequestComplete() function that will be called upon the reject friend request process completing. This function prints a log to show whether the reject received friend request process was successful or not, triggers 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);
    }
    }

Implement Cancel Sent Friend Request

In this section, you will implement functionality to cancel a sent friend request.

  1. 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());
  2. You also need to create a callback function to handle when a canceling the sent friend request process completes.

    protected:
    // ...
    void OnCancelFriendRequestComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& FriendId, const FString& ListName, const FString& ErrorStr, const FOnCancelFriendRequestComplete OnComplete);
  3. Define the functions above. Open the FriendsSubsystem_Starter class CPP file and define the CancelFriendRequest() function. This function will cancel a sent friend request and call the OnCancelFriendRequestComplete() 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(""));
    }
  4. Define the OnCancelFriendRequestComplete() function that will be called upon the cancel sent friend request process completing. This function simply prints a log to show whether the cancel sent friend request process was successful or not and triggers 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);
    }
    }

Listen On Friend List Updated

When the players accept, reject, or cancel friend requests, the cached friend list will be updated automatically by AccelByte Gaming Services (AGS) Online Subsystem (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.

  1. 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);
  2. Open the FriendsSubsystem_Starter class CPP file and create the definitions for the functions above. Start with the BindOnCachedFriendsDataUpdated() 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(); })));
    }
  3. 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);
    }
    }
  4. Take a moment to understand the idea behind those functions. Essentially, 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 the UnbindOnCachedFriendsDataUpdated() function. You will use these functions to update the displayed entries widgets in the next tutorial.

Resources