Implement Friends using the Unreal Engine SDK
Overview
This topic is specific to the AccelByte Gaming Services (AGS) Shared Cloud tier.
The friends service is the part of AGS that allows players to connect socially with other players. For more information, refer to the Friends feature of the Social service.
Prerequisites
The examples in this document use AGS Shared Cloud UE SDK version 15.0.0. Any other version may not be compatible or may need different steps to implement.
This guide assumes that you have already implemented the Lobby service. Please make sure the player can successfully connect to the Lobby before continuing.
Quick Reference
References
Friend Notification Events
FRegistry::Lobby.SetOnFriendRequestAcceptedNotifDelegate(Api::Lobby::FAcceptFriendsNotif::CreateWeakLambda(this, [](const FAccelByteModelsAcceptFriendsNotif& Result)
{
// On friend request accepted
}));
FRegistry::Lobby.SetOnUnfriendNotifDelegate(Api::Lobby::FUnfriendNotif::CreateWeakLambda(this, [](const FAccelByteModelsUnfriendNotif& Result)
{
// On player is unfriended
}));
FRegistry::Lobby.SetOnCancelFriendsNotifDelegate(Api::Lobby::FCancelFriendsNotif::CreateWeakLambda(this, [](const FAccelByteModelsCancelFriendsNotif& Result)
{
// On friend request is canceled
}));
FRegistry::Lobby.SetOnRejectFriendsNotifDelegate(Api::Lobby::FRejectFriendsNotif::CreateWeakLambda(this, [](const FAccelByteModelsRejectFriendsNotif& Result)
{
// On friend request is rejected
}));
FRegistry::Lobby.SetOnIncomingRequestFriendsNotifDelegate(Api::Lobby::FRequestFriendsNotif::CreateWeakLambda(this, [](const FAccelByteModelsRequestFriendsNotif& Result)
{
// On player receive friend request
}));
Request Friend
// Response delegate
FRegistry::Lobby.SetRequestFriendsResponseDelegate(
Api::Lobby::FRequestFriendsResponse::CreateWeakLambda(this, [](const FAccelByteModelsRequestFriendsResponse& Result)
{
// On send friend Request success
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
// On send friend Request failed
}));
// Request
FRegistry::Lobby.RequestFriend("DesiredUserId");
Accept Friend Request
FRegistry::Lobby.SetAcceptFriendsResponseDelegate(
Api::Lobby::FAcceptFriendsResponse::CreateWeakLambda(this, [](const FAccelByteModelsAcceptFriendsResponse& Result)
{
// On success accepting the friend request
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
// On failed accepting the friend request
}));
FRegistry::Lobby.AcceptFriend("DesiredUserId");
Reject Friend Request
FRegistry::Lobby.SetRejectFriendsResponseDelegate(
Api::Lobby::FRejectFriendsResponse::CreateWeakLambda(this, [](const FAccelByteModelsRejectFriendsResponse& Result)
{
// On success rejecting the friend request
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
// On failed rejecting the friend request
}));
FRegistry::Lobby.RejectFriend("DesiredUserId");
Cancel Friend Request
FRegistry::Lobby.SetCancelFriendsResponseDelegate(
Api::Lobby::FCancelFriendsResponse::CreateWeakLambda(this, [](const FAccelByteModelsCancelFriendsResponse& Result)
{
// On success canceling the friend request
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
// On failed canceling the friend request
}));
FRegistry::Lobby.CancelFriendRequest("DesiredUserId");
Unfriend
// Response delegate
FRegistry::Lobby.SetUnfriendResponseDelegate(
Api::Lobby::FUnfriendResponse::CreateWeakLambda(this, [](const FAccelByteModelsUnfriendResponse& Result)
{
// On unfriend success
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
// On unfriend failed
}));
// Request
FRegistry::Lobby.Unfriend(UserData.UserId);
Load Friend List
// Response delegate
FRegistry::Lobby.SetLoadFriendListResponseDelegate(
Api::Lobby::FLoadFriendListResponse::CreateWeakLambda(this, [](const FAccelByteModelsLoadFriendListResponse& Result)
{
// On load friend list success
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
// On load friend list failed
}));
// Request
FRegistry::Lobby.LoadFriendsList();
List Incoming Friend Requests
// Response delegate
FRegistry::Lobby.SetListIncomingFriendsResponseDelegate(
Api::Lobby::FListIncomingFriendsResponse::CreateWeakLambda(this, [](const FAccelByteModelsListIncomingFriendsResponse& Result)
{
// On load incoming friend list invitation success
},
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
// On load incoming friend list invitation failed
})));
// Request
FRegistry::Lobby.ListIncomingFriends();
List Outgoing Friend Requests
// Response delegate
FRegistry::Lobby.SetListOutgoingFriendsResponseDelegate(
Api::Lobby::FListOutgoingFriendsResponse::CreateWeakLambda(this, [](const FAccelByteModelsListOutgoingFriendsResponse& Result)
{
// On load outgoing friend list invitation success
},
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
// On load outgoing friend list invitation failed
})));
// Request
FRegistry::Lobby.ListOutgoingFriends();
Search Users
FRegistry::User.SearchUsers(
"FriendName",
THandler<FPagedPublicUsersInfo>::CreateWeakLambda(this, [](const FPagedPublicUsersInfo& Result)
{
// On success search users
},
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
// On search users failed
})));
Get User data by ID
FRegistry::User.GetUserByUserId(
"UserId",
THandler<FSimpleUserData>::CreateWeakLambda(this, [](const FSimpleUserData& Result)
{
// On Get user data by id success
},
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
// On Get user data by id failed
})));
Get bulk User data
FRegistry::User.BulkGetUserInfo(
ArrayOfUsersId,
THandler<FListBulkUserInfo>::CreateWeakLambda(this, [](const FListBulkUserInfo& Result)
{
// On Get bulk user info success
},
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
// On Get bulk user info failed
})));
Quickstart
In this section, you will learn how to use AGS Shared Cloud Friends service.
This tutorial is more abstract than some others as the specifics of how each game implements the Friends service can vary dramatically.
There are a handful of data models and structs to familiarize yourself with.
(You can find most of these in the models folder inside the SDK plugin. In this case, the default path is .\Plugins\AccelByteUe4Sdk\Source\AccelByteUe4Sdk\Public\Models
.)
AccelByte's Game SDK uses a mixture of Websocket and HTTP requests, generally presented to you through a wrapper layer that uses callbacks and actions to return your data. Because of this, you must design your UI to accommodate delayed callbacks and, sometimes, several layers of callbacks (e.g., requesting a list of Friends > requesting specific data about friends > requesting the avatar of a friend).
The Lobby service Websocket API has two type functions for each functionality: Response delegate
- The delegate accesses the resulting response from the SDK's function
- Not necessary, but must be defined before you call the Request function Request function
- This function sends a request for services to the Websocket API
- Can be called separately from the Response delegate in a different function
Friend Logic
You will start by adding simple friend logic to your game.
Find Friends
You will focus on the Find Friends functionality first. Since this feature is usually separate from the main Friends Menu widget, you will need to:
Create a user widget C++ class called
AccelByteFindFriend
. In theAccelByteFindFriend
class, include the AccelByte header to ensure the SDK functions work correctly.- .cpp
- h
...
#include "Api/AccelByteLobbyApi.h"
#include "Api/AccelByteUserApi.h"...
#include "Core/AccelByteRegistry.h"For the Search a Friend feature, you can use the User SDK's
SearchUser()
function to return a list of search results with the desired player's display name as the parameter for the search query.Create a new function in the
AccelByteFindFriend
class, such as in the following:- .cpp
- h
void UAccelByteFindFriend::FindUsers(const FString& FriendName)
{
FRegistry::User.SearchUsers(
FriendName,
THandler<FPagedPublicUsersInfo>::CreateWeakLambda(this, [this](const FPagedPublicUsersInfo& Result)
{
UE_LOG(LogTemp, Log, TEXT("Success Find Friends"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Error SearchUsers, Error Code: %d Error Message: %s"), ErrorCode, *ErrorMessage);
}));
}/**
* @brief Find Friends functionality inside the callback.
*/
void FindUsers(const FString& FriendName);To send a friend request, you will need the desired player's User ID as the parameter. Use the
SearchUsers()
function to find the User ID.Since you will also need the response data from
SearchUsers()
, callRequestFriend()
right after theSearchUsers()
query in theFindFriends()
function of theAccelByteFindFriend
class.- .cpp
...
// SearchUser() OnSuccessDelegate
THandler<FPagedPublicUsersInfo>::CreateWeakLambda(this, [](const FPagedPublicUsersInfo& Result)
{
...
for (const FPublicUserInfo& UserData : Result.Data)
{
// 1. Set Response Delegate
FRegistry::Lobby.SetRequestFriendsResponseDelegate(
Api::Lobby::FRequestFriendsResponse::CreateWeakLambda(this, [](const FAccelByteModelsRequestFriendsResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Send Friend Request success"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Error RequestFriendsResponseDelegate, Error Code: %d Error Message: %s"), ErrorCode, *ErrorMessage);
}));
// 2. Send Request
FRegistry::Lobby.RequestFriend("DesiredUserId");
}
}),
...For functionality related to Friend Request, create a new user widget C++ class called
AccelByteFriendEntry
and include the following files at the top of the class and header files:- .cpp
...
#include "Api/AccelByteLobbyApi.h"
#include "Api/AccelByteUserApi.h"
#include "Core/AccelByteRegistry.h"
...In the
AccelByteFriendEntry
class, create some new functions for Friend Request functionality:
Accept an incoming friend request
- .cpp
- h
void UAccelByteFriendEntry::OnClickedAccept()
{
FRegistry::Lobby.SetAcceptFriendsResponseDelegate(
Api::Lobby::FAcceptFriendsResponse::CreateWeakLambda(this, [](const FAccelByteModelsAcceptFriendsResponse & Result)
{
UE_LOG(LogTemp, Log, TEXT("Successfully accept a friend request!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Failed to accept a friend request! Code: %d, Reason: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.AcceptFriend("DesiredUserId");
}
/**
* @brief Callback for Accept Button.
*/
UFUNCTION()
void OnClickedAccept();
Reject an incoming friend request
- .cpp
- h
void UAccelByteFriendEntry::OnClickedDecline()
{
FRegistry::Lobby.SetRejectFriendsResponseDelegate(
Api::Lobby::FRejectFriendsResponse::CreateWeakLambda(this, [](const FAccelByteModelsRejectFriendsResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Successfully reject the friend request!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Failed to reject the friend request! Code: %d, Reason: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.RejectFriend("DesiredUserId");
}
/**
* @brief Callback for Decline Button.
*/
UFUNCTION()
void OnClickedDecline();
Cancel an outgoing friend request
- .cpp
- h
void UAccelByteFriendEntry::OnClickedCancelRequest()
{
FRegistry::Lobby.SetCancelFriendsResponseDelegate(
Api::Lobby::FCancelFriendsResponse::CreateWeakLambda(this, [](const FAccelByteModelsCancelFriendsResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Successfully cancel the friend request!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Failed to cancel the friend request! Code: %d, Reason: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.CancelFriendRequest("DesiredUserId");
}
/**
* @brief Click callback to cancel request.
*/
UFUNCTION()
void OnClickedCancelRequest();
Unfriend
You can unfriend a player by using the SetUnfriendResponseDelegate()
function.
- .cpp
- h
void UAccelByteFriendEntry::OnClickedUnfriend()
{
FRegistry::Lobby.SetUnfriendResponseDelegate(
Api::Lobby::FUnfriendResponse::CreateWeakLambda(this, [](const FAccelByteModelsUnfriendResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Successfully unfriend a friend!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Failed to unfriend a friend! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.Unfriend("DesiredUserId");
}
/**
* @brief Functionality for Unfriend Button.
*/
UFUNCTION()
void OnClickedUnfriend();
Friend Menu Functionalities
The Friends menu functionality includes:
- Current friends list
- Outgoing friend list
- Incoming friend list
- Display the friend list
- Send notifications
Follow the steps below to use the Friends menu functionality:
Current friends list
Create a new user widget C++ class called
AccelByteFriends
to specify the flow between the functions when creating a Friend system.Add the AccelByte header in the
AccelByteFriends
class to ensure the functions work correctly for the Lobby services (as the Friends service is a part of the Lobby)..cpp
...
#include "Api/AccelByteLobbyApi.h"
#include "Core/AccelByteRegistry.h"
...You can display the friends list by using the
SetLoadFriendListResponseDelegate()
. To do this, create a new function in theAccelByteFriends
class.- .cpp
- h
void UAccelByteFriends::LoadFriendList()
{
FRegistry::Lobby.SetLoadFriendListResponseDelegate(
Api::Lobby::FLoadFriendListResponse::CreateWeakLambda(this, [](const FAccelByteModelsLoadFriendListResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Success Retrieve Load Friend List Response!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Error LoadFriendListResponseDelegate, Error Code: %d Error Message: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.LoadFriendsList();
}/**
* @brief Callback for Friend List.
*/
UFUNCTION()
void LoadFriendList();
Display incoming and outgoing friend requests
To display the User IDs for pending Incoming and Outgoing requests, use either
SetListIncomingFriendsResponseDelegate
orSetListOutgoingFriendsResponseDelegate
.To do this, create a new function for both the Incoming and Outgoing pending request lists in the
AccelByteFriends
class.- .cpp
- h
void UAccelByteFriends::LoadPendingIncomingList()
{
FRegistry::Lobby.SetListIncomingFriendsResponseDelegate(
Api::Lobby::FListIncomingFriendsResponse::CreateWeakLambda(this, [](const FAccelByteModelsListIncomingFriendsResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Success Retrieve List Incoming Friend Response!"));
},
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Unable to retrieve the list of incoming friend requests!"));
})));
FRegistry::Lobby.ListIncomingFriends();
}
void UAccelByteFriends::LoadPendingOutgoingList()
{
FRegistry::Lobby.SetListOutgoingFriendsResponseDelegate(
Api::Lobby::FListOutgoingFriendsResponse::CreateWeakLambda(this, [](const FAccelByteModelsListOutgoingFriendsResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Successfully Retrieved List Outgoing Friend Response"));
},
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Unable to retrieve the list of outgoing friend requests"));
})));
FRegistry::Lobby.ListOutgoingFriends();
}/**
* @brief Callback for Pending Incoming Friend List.
*/
UFUNCTION()
void LoadPendingIncomingList();
/**
* @brief Callback for Pending Outgoing Friend List.
*/
UFUNCTION()
void LoadPendingOutgoingList();
Notifications
Create a new function in the
AccelByteFriends
class calledSetNotificationDelegate()
to notify the player of the Friends Notification event and make your Friends List more responsive. The notification events are explained below:Delegates Usage `SetOnFriendRequestAcceptedNotifDelegate()` Receive notifications when a friend request from the sender is accepted by the receiver. `SetOnUnfriendNotifDelegate()` Receive notifications when the receiver is unfriended by the sender. `SetOnCancelFriendsNotifDelegate()` Receive notifications when a friend request from the sender is canceled by the sender. `SetOnRejectFriendsNotifDelegate()` Receive notifications when a friend request from the sender is rejected by the receiver. `SetOnIncomingRequestFriendsNotifDelegate()` Receive notifications when a player has an incoming friend request. - .cpp
- h
void UAccelByteFriends::SetNotificationDelegate()
{
FRegistry::Lobby.SetOnFriendRequestAcceptedNotifDelegate(Api::Lobby::FAcceptFriendsNotif::CreateWeakLambda(this, [](const FAccelByteModelsAcceptFriendsNotif& Result)
{
UE_LOG(LogTemp, Log, TEXT("On accepted a friend request from a player"));
}));
FRegistry::Lobby.SetOnUnfriendNotifDelegate(Api::Lobby::FUnfriendNotif::CreateWeakLambda(this, [](const FAccelByteModelsUnfriendNotif& Result)
{
UE_LOG(LogTemp, Log, TEXT("On unfriend by a friend"));
}));
FRegistry::Lobby.SetOnCancelFriendsNotifDelegate(Api::Lobby::FCancelFriendsNotif::CreateWeakLambda(this, [](const FAccelByteModelsCancelFriendsNotif& Result)
{
UE_LOG(LogTemp, Log, TEXT("On a friend request canceled by the sender"));
}));
FRegistry::Lobby.SetOnRejectFriendsNotifDelegate(Api::Lobby::FRejectFriendsNotif::CreateWeakLambda(this, [](const FAccelByteModelsRejectFriendsNotif& Result)
{
UE_LOG(LogTemp, Log, TEXT("On the friend request is rejected by another player"));
}));
FRegistry::Lobby.SetOnIncomingRequestFriendsNotifDelegate(Api::Lobby::FRequestFriendsNotif::CreateWeakLambda(this, [](const FAccelByteModelsRequestFriendsNotif& Result)
{
UE_LOG(LogTemp, Log, TEXT("On received a friend request"));
}));
}/**
* @brief Set Friend services notification delegates.
*/
void SetNotificationDelegate();
Additional friend functionalities
Get user data
To get user data, you need the user's Friend ID. To find this:
Modify
SetOnFriendRequestAcceptedNotifDelegate
.Add the call
GetUserData
after the friend request is accepted.- .cpp
...
FRegistry::Lobby.SetOnFriendRequestAcceptedNotifDelegate(Api::Lobby::FAcceptFriendsNotif::CreateWeakLambda(this, [this](const FAccelByteModelsAcceptFriendsNotif& Result)
{
...
FRegistry::User.GetUserByUserId(
Result.friendId,
THandler<FSimpleUserData>::CreateWeakLambda(this, [](const FSimpleUserData& Data)
{
UE_LOG(LogTemp, Log, TEXT("Get User By User Id Success. DisplayName: %s"), *Data.DisplayName);
},
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Get User by user id failed. Code: %d, Message: %s"), ErrorCode, *ErrorMessage);
})));
}));
...
Bulk get User data
To get user data in bulk, you will first need to load the Friends list.
The easiest way to do this is to add the call GetBulkUserInfo
into the LoadFriendList()
success response delegate in the SetLoadFriendListResponseDelegate
function.
<Tabs groupId="platforms">
<TabItem value="cpp" label=".cpp">
```cpp
...
void UAccelByteFriends::LoadFriendList()
{
FRegistry::Lobby.SetLoadFriendListResponseDelegate(
Api::Lobby::FLoadFriendListResponse::CreateWeakLambda(this, [](const FAccelByteModelsLoadFriendListResponse& Result)
{
...
FRegistry::User.BulkGetUserInfo(
Result.friendsId,
THandler<FListBulkUserInfo>::CreateWeakLambda(this, [](const FListBulkUserInfo& Data)
{
// On Get bulk user info success
for (FBaseUserInfo Info : Data.Data)
{
UE_LOG(LogTemp, Log, TEXT("Get Bulk User Info Success. DisplayName: %s"), *Info.DisplayName);
}
},
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Get Bulk User info failed. Code: %d, Message: %s"), ErrorCode, *ErrorMessage);
})));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
...
}));
...
}
...
```
</TabItem>
</Tabs>
Unbind events
Use the UnbindFriendNotifEvents
and UnbindFriendResponseEvents
delegates to unbind the Friends service.
<Tabs groupId="platforms">
<TabItem value="cpp" label=".cpp">
```cpp
...
FRegistry::Lobby.UnbindFriendNotifEvents();
FRegistry::Lobby.UnbindFriendResponseEvents();
...
```
</TabItem>
</Tabs>
After you have called this code remember to resubscribe all the notification and response delegates before you continue.
Congratulations! You have successfully implemented the basics of the Friends service.
Continue on for a step-by-step example of the UI and code implementation. Otherwise, you are now ready to move on to Party services.
Step-by-step guide
In this guide you will learn how to implement all the main Friends services, except the Block, Unblock, and Presence functionalities. Although you may mention these functions in the following sections, they are not required for the following implementation. You will explain them in detail later.
Implement the UI
Follow the steps below to implement the UI:
Create a widget blueprint class called
WB_FriendMenu
.Set its parent class to refer to the
AccelByteFriends
class.Add the following to the Friends menu:
- Text box for the header text.
- Text boxfor the total number of online friends.
- Button to go back to the previous page.
- Button to open the Find Friends widget.
- Four buttons: one each for Friends, Incoming Requests, Sent Requests, and Blocked tabs.
- Size box for the content list.
Create a widget blueprint class called WB_FriendEntry.
Set the
AccelByteFriendEntry
class as WB_FriendEntry's parent class.Include the following objects in the widget blueprint:
- Image for a friend's avatar image.
- Text box for a friend's display name.
- Text box for a friend's online status.
- Four buttons: one each for Chat, Unfriend, Send party invitation, and Block.
Create a widget blueprint class called
WB_FindFriend
.Set the
AccelByteFindFriend
class as theWB_FindFriend
parent class.Make sure the widget blueprint has the following objects:
- Editable text box to input the desired player's display name.
- Button to submit the search input.
(Optional) In this example, the Friends service is part of the Lobby, so you will need to open the
WB_LobbyMenu
.You will need to redirect the Friends service's widgets usage from the Lobby menu, so make sure it has the following objects:
- Text box for the header text.
- Button to go back to the Main menu.
- Button to open the Friends menu widget.
(Optional) To make it easier to move between pages (on the game side), create a new widget blueprint class called WB_MainMenu and make sure it has the following components:
- Button for the Lobby menu.
- Button for logging out.
Implement the main menu code
Follow the steps below to implement the code:
Create a user widget C++ class called
AccelByteMainMenu
and set the class as the parent class of your Main menu widget blueprint (in this case,WB_MainMenu
).Add the following code to the top of the
AccelByteMenu
class:- .cpp
- h
...
#include "Authentication/AccelByteAuth.h"
#include "Components/Button.h"
#include "TutorialProject/TutorialMenuHUD.h"...
class UButton;
class USizeBox;
class ATutorialMenuHUD;Add the
NativeConstruct()
override function to set up the Lobby button in the Main Menu.- .cpp
- h
void UAccelByteMainMenu::NativeConstruct()
{
Super::NativeConstruct();
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
check(TutorialMenuHUD);
Btn_Lobby->OnClicked.AddUniqueDynamic(TutorialMenuHUD, &ATutorialMenuHUD::OpenLobbyMenu);
}virtual void NativeConstruct() override;
/**
* @brief Button for Accessing Lobby Menu.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Lobby;
/**
* @brief A Tutorial Menu HUD to handle instantiating and casting to the HUD framework
*/
ATutorialMenuHUD* TutorialMenuHUD;Create a function in the
AccelByteMainMenu
class to bind theOnLogoutButtonClicked()
function from theAccelByteAuth
class with the Log Out button in the Main Menu.- .cpp
- h
void UAccelByteMainMenu::LogOut()
{
TutorialMenuHUD->GetLoginMenu()->OnLogoutButtonClicked();
}/**
* @brief Quit Game functionality.
*/
UFUNCTION()
void LogOut();Inside the
NativeConstruct()
function, set theLogOut()
function as the Logout button's callback function.- .cpp
- h
void UAccelByteMainMenu::NativeConstruct()
{
...
Btn_Logout->OnClicked.AddUniqueDynamic(this, &UAccelByteMainMenu::LogOut);
}/**
* @brief Button for Quit Game.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Logout;
Tutorial menu HUD
Prepare all of the Main Menu and Friends-related widgets so they are accessible to other classes via the TutorialMenuHUD
class.
Main menu widgets
To do this:
Add the related classes at the top of the class.
- .cpp
- h
...
#include "AccelByte/AccelByteMainMenu.h"
#include "AccelByte/Friends/AccelbyteFindFriend.h"
#include "AccelByte/Friends/AccelByteFriends.h"...
class UAccelByteMainMenu;
class UAccelByteFriends;
class UAccelByteFindFriend;In the
BeginPlay()
function, initialize pointers for the Main Menu, Friends Menu and Find Friends widget classes.- .cpp
- h
void ATutorialMenuHUD::BeginPlay()
{
...
check(MainMenuClass != nullptr);
check(FriendsMenuClass != nullptr);
check(FindFriendsMenuClass != nullptr);
...
MainMenu = CreateWidget<UAccelByteMainMenu>(PlayerController, MainMenuClass.Get());
FriendsMenu = CreateWidget<UAccelByteFriends>(PlayerController, FriendsMenuClass.Get());
FindFriendsMenu = CreateWidget<UAccelByteFindFriend>(PlayerController, FindFriendsMenuClass.Get());
...
}/**
* @brief Main Menu widget class
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteMainMenu> MainMenuClass;
/**
* @brief Friends Menu widget class
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteFriends> FriendsMenuClass;
/**
* @brief Find Friends Menu widget class
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteFindFriend> FindFriendsMenuClass;
/**
* @brief Main Menu widget pointer
*/
UPROPERTY()
UAccelByteMainMenu* MainMenu;
/**
* @brief Friends Menu widget pointer
*/
UPROPERTY()
UAccelByteFriends* FriendsMenu;
/**
* @brief Find Friends Menu widget pointer
*/
UPROPERTY()
UAccelByteFindFriend* FindFriendsMenu;Add the getter functions for Main Menu and each Friends widget pointer.
- h
/**
* @brief Getter for Main Menu widget
*/
UAccelByteMainMenu* GetMainMenu() const {return MainMenu; }
/**
* @brief Getter for Friends Menu widget
*/
UAccelByteFriends* GetFriendsMenu() const {return FriendsMenu; }
/**
* @brief Getter for Find Friends Menu widget
*/
UAccelByteFindFriend* GetFindFriendsMenu() const {return FindFriendsMenu; }Create new functions to open the Main Menu, Friends Menu, and Find Friends Menu widgets.
- .cpp
- h
void ATutorialMenuHUD::OpenMainMenu()
{
MainMenu->AddToViewport();
}
void ATutorialMenuHUD::OpenFriendsMenu()
{
if (!FriendsMenu->IsInViewport())
{
FriendsMenu->AddToViewport();
}
else
{
FriendsMenu->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
}
}
void ATutorialMenuHUD::OpenFindFriendsMenu()
{
FindFriendsMenu->AddToViewport();
}/**
* @brief Shows Main Menu on screen and destroys Login Menu
*/
void OpenMainMenu();
/**
* @brief Shows Friends Menu on screen
*/
void OpenFriendsMenu();
/**
* @brief Shows Find Friends Menu on screen
*/
void OpenFindFriendsMenu();Create other functions to close the Main Menu, Friends Menu, and Find Friends Menu widgets.
- .cpp
- h
void ATutorialMenuHUD::CloseMainMenu()
{
LoginMenu->AddToViewport();
MainMenu->RemoveFromViewport();
LobbyMenu->RemoveFromParent();
}
void ATutorialMenuHUD::CloseFriendMenu()
{
if (!LobbyMenu->IsInViewport())
{
LobbyMenu->AddToViewport();
}
FriendsMenu->RemoveFromParent();
}
void ATutorialMenuHUD::CloseFindFriendsMenu()
{
FindFriendsMenu->RemoveFromParent();
}/**
* @brief Destroys Main Menu widget
*/
void CloseMainMenu();
/**
* @brief Destroys Friend Menu widget
*/
void CloseFriendMenu();
/**
* @brief Destroys Find Friend Menu widget
*/
void CloseFindFriendsMenu();While still in the
TutorialMenuHUD
class, create a function to initialize the Main Menu widget state. Call theConnectToLobby()
function from this function.- .cpp
- h
void ATutorialMenuHUD::InitMainMenu()
{
// Add Lobby to Viewport and set its visibility as collapsed
LobbyMenu->AddToViewport();
LobbyMenu->ConnectToLobby();
LobbyMenu->SetVisibility(ESlateVisibility::Collapsed);
OpenMainMenu();
}/**
* @brief Init the construct function when the first time open main menu;
*/
void InitMainMenu();Now that you have the Main Menu, modify the
OpenLobbyMenu
andCloseLobbyMenu
functions as in the example below:- .cpp
void ATutorialMenuHUD::OpenLobbyMenu()
{
...
MainMenu->RemoveFromParent();
}
void ATutorialMenuHUD::CloseLobbyMenu()
{
MainMenu->AddToViewport();
...
}
Friend-related widgets
Open the
AccelByteFriendEntry
class and add the following AccelByte and widget classes to the top of the class:- .cpp
- h
...
#include "Components/Button.h"
#include "Components/TextBlock.h"
#include "Components/WidgetSwitcher.h"
#include "Components/Image.h"
#include "Components/ScaleBox.h"
#include "Components/HorizontalBox.h"
#include "TutorialProject/TutorialMenuHUD.h"...
#include "Models/AccelByteUserModels.h"
#include "Models/AccelByteLobbyModels.h"
#include "TutorialProject/TutorialMenuHUD.h"
...
class UTextBlock;
class UButton;
class UScaleBox;
class UHorizontalBox;
class UWidgetSwitcher;
...This Friend Entry widget will be used for displaying any friends-related lists. The layout inside may be slightly different depending on the required info for the list.
To make it easier to differentiate, create an enum to identify the desired mode list.
- h
/**
* Enumerator for Friend Entry widget modes.
*/
UENUM()
enum class EFriendEntryMode : uint8
{
Friend UMETA(DisplayName = "Friend"),
Incoming UMETA(DisplayName = "Incoming Request"),
Outgoing UMETA(DisplayName = "Outgoing Request"),
Search UMETA(DisplayName = "Search")
};Based on Friend Entry's mode, specify all the required widgets in the header file. The Default widgets and entry boxes for each entry mode are as follows:
- h
/**
* @brief Text Box for Friend Name (Will be replaced with friend name).
*/
UPROPERTY(meta = (BindWidget))
UTextBlock* Tb_FriendName;
/**
* @brief Text Box for Friend Status (i.e., Online, Offline, Away).
*/
UPROPERTY(meta = (BindWidget))
UTextBlock* Tb_Status;
/**
* @brief Widget Switcher to switch Entry Mode.
*/
UPROPERTY(meta = (BindWidget))
UWidgetSwitcher* Ws_EntryMode;
/**
* @brief Scale Box for User Image.
*/
UPROPERTY(meta = (BindWidget))
UScaleBox* Sb_Friend;
// Horizontal Boxes for Widget Switcher.
/**
* @brief Horizontal Box for Friend component.
*/
UPROPERTY(meta = (BindWidget))
UHorizontalBox* Hb_Friend;
/**
* @brief Horizontal Box for Incoming component.
*/
UPROPERTY(meta = (BindWidget))
UHorizontalBox* Hb_IncomingRequest;
/**
* @brief Horizontal Box for Outgoing component.
*/
UPROPERTY(meta = (BindWidget))
UHorizontalBox* Hb_OutgoingRequest;
/**
* @brief Horizontal Box for Search component.
*/
UPROPERTY(meta = (BindWidget))
UHorizontalBox* Hb_Search;Friend mode
A number of buttons (except the Unfriend button) are initialized here, but not explained in this sectionl. See the Full Code section for details.
// Friend Entry Type
/**
* @brief Button for Chat Friend.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Chat;
/**
* @brief Button for Invite Friend to Party.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_InviteParty;
/**
* @brief Button for Unfriend.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Unfriend;
/**
* @brief Button for Block Friend.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Block;- Incoming (Friend Request) mode
.h
// Incoming Entry Type
/**
* @brief Button for Accepting Friend Request.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Accept;
/**
* @brief Button for Decline Friend Request.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Decline;
/**
* @brief Button for Block User by Incoming Request.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Block_Request;- Outgoing (Friend Request) Mode
.h
// Outgoing Entry Type
/**
* @brief Button for canceling outgoing friend request.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_CancelRequest;- Search (Find Friend) Mode
.h
// Search Entry Type
/**
* @brief Button for Add Friend.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_AddFriend;Create a function that will initialize the Friend Entry data when the widget is created. Since this widget will be based on query results that contain
UserId
, use the SDK'sGetUserByUserId()
function to get the display name data..cpp
void UAccelByteFriendEntry::InitData(const EFriendEntryMode& EntryMode, const FString& UserId)
{
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
check(TutorialMenuHUD);
FRegistry::User.GetUserByUserId(
UserId,
THandler<FSimpleUserData>::CreateUObject(this, &UAccelByteFriendEntry::OnSuccessGetUserId),
FErrorHandler::CreateUObject(this, &UAccelByteFriendEntry::OnFailedGetUserId));
}.h
/**
* @brief Initialize entry data by getting User Data by User ID and selecting its entry Mode
* @param EntryMode Select entry mode based on the EFriendEntryMode enum
* @param UserId User ID needed to get User data.
*/
void InitData(const EFriendEntryMode& EntryMode, const FString& UserId);
/**
* @brief Callback for getting the user ID.
*/
void OnSuccessGetUserId(const FSimpleUserData& Data);
/**
* @brief Callback for getting user ID failure.
*/
void OnFailedGetUserId(int32 ErrorCode, const FString& ErrorMessage);
UPROPERTY()
ATutorialMenuHUD* TutorialMenuHUD;Define both of the
GetUser
response delegate functions you just declared to storeUserData
and update the Display Name's text widget if the query succeeds..cpp
void UAccelByteFriendEntry::OnSuccessGetUserId(const FSimpleUserData& Data)
{
UE_LOG(LogTemp, Log, TEXT("Success Get User By User ID!"));
UserData = Data;
Tb_FriendName->SetText(FText::FromString(UserData.DisplayName));
}
void UAccelByteFriendEntry::OnFailedGetUserId(int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT(" Get User by Id Failed : Code: %d, Reason: %s"), ErrorCode, *ErrorMessage);
}.h
/**
* @brief Models to store User Data contained in this entry.
*/
FSimpleUserData UserData;Once you have completed the previous steps, you will need to create some functions that will handle the on-click button events for the buttons you created earlier.
noteFor Friend Mode, leave the Chat, Invite Party, and Block button functions empty since they are related to other services.
.cpp
void UAccelByteFriendEntry::OnClickedChat()
{
// @TODO: will be covered in another service guide
}
void UAccelByteFriendEntry::OnClickedInviteParty()
{
// @TODO: will be covered in another service guide
}
void UAccelByteFriendEntry::OnClickedBlock()
{
// @TODO: will be covered in another service guide
}.h
// Functionality for Chat Button.
UFUNCTION()
void OnClickedChat();
// Functionality for Invite Party Button.
UFUNCTION()
void OnClickedInviteParty();
// Functionality for Block Friend Button.
UFUNCTION()
void OnClickedBlock();For the Unfriend button, modify the
OnClickedUnfriend()
function to get the desiredUserId
from the localUserData
variable you made earlier and to remove the entry upon a successful request..cpp
void UAccelByteFriendEntry::OnClickedUnfriend()
{
FRegistry::Lobby.SetUnfriendResponseDelegate(Api::Lobby::FUnfriendResponse::CreateWeakLambda(this, [this](const FAccelByteModelsUnfriendResponse& Result)
{
...
this->RemoveFromParent();
}),
...
FRegistry::Lobby.Unfriend(UserData.UserId);
}For the Incoming Mode button's functionality, modify the
OnClickAccept()
andOnClickDecline()
functions. You can useCreateWeakLambda
and define the result from the response delegate.For the Block button, use the same Block function you made earlier for Friend Mode.
.cpp
void UAccelByteFriendEntry::OnClickedAccept()
{
FRegistry::Lobby.SetAcceptFriendsResponseDelegate(
Api::Lobby::FAcceptFriendsResponse::CreateWeakLambda(this, [this](
FAccelByteModelsAcceptFriendsResponse Result)
{
this->RemoveFromParent();
...
}),
...
FRegistry::Lobby.AcceptFriend(UserData.UserId);
}
void UAccelByteFriendEntry::OnClickedDecline()
{
FRegistry::Lobby.SetRejectFriendsResponseDelegate(
Api::Lobby::FRejectFriendsResponse::CreateWeakLambda(this, [this](
FAccelByteModelsRejectFriendsResponse Result)
{
this->RemoveFromParent();
...
}),
...
FRegistry::Lobby.RejectFriend(UserData.UserId);
}
void UAccelByteFriendEntry::OnClickedCancelRequest()
{
FRegistry::Lobby.CancelFriendRequest(UserData.UserId);
this->RemoveFromParent();
}For Search Mode (that only has the Add Friend button), remove the SDK's
RequestFriends
functionality in theAccelByteFindFriend
class (in theFindFriend()
function).Next, create a new dedicated function.
.cpp
void UAccelByteFriendEntry::OnClickedAddFriend()
{
FRegistry::Lobby.SetRequestFriendsResponseDelegate(
Api::Lobby::FRequestFriendsResponse::CreateWeakLambda(this, [](
FAccelByteModelsRequestFriendsResponse Result)
{
UE_LOG(LogTemp, Log, TEXT("Successfully sent a friend request!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Error, TEXT("Failed to send a friend request! Code : %i , Message : %s"), Code, *Message);
}));
FRegistry::Lobby.RequestFriend(UserData.UserId);
Btn_AddFriend->SetIsEnabled(false);
}.h
/**
* @brief Functionality for Add Friend Button.
*/
UFUNCTION()
void OnClickedAddFriend();Now that you have prepared the functions for each button's widgets, create a new function to set the Friend Entry widget based on the entry mode's enum.
.cpp
void UAccelByteFriendEntry::SetEntryMode(const EFriendEntryMode& EntryMode) const
{
switch(EntryMode)
{
case EFriendEntryMode::Friend:
Sb_Friend->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
Tb_Status->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
Ws_EntryMode->SetActiveWidget(Hb_Friend);
Btn_Chat->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedChat);
Btn_InviteParty->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedInviteParty);
Btn_Unfriend->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedUnfriend);
Btn_Block->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedBlock);
return;
case EFriendEntryMode::Incoming:
Sb_Friend->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
Tb_Status->SetVisibility(ESlateVisibility::Collapsed);
Ws_EntryMode->SetActiveWidget(Hb_IncomingRequest);
Btn_Accept->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedAccept);
Btn_Decline->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedDecline);
Btn_Block_Request->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedBlock);
return;
case EFriendEntryMode::Outgoing:
Sb_Friend->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
Tb_Status->SetVisibility(ESlateVisibility::Collapsed);
Ws_EntryMode->SetActiveWidget(Hb_OutgoingRequest);
Btn_CancelRequest->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedCancelRequest);
return;
case EFriendEntryMode::Search:
Sb_Friend->SetVisibility(ESlateVisibility::Collapsed);
Tb_Status->SetVisibility(ESlateVisibility::Collapsed);
Ws_EntryMode->SetActiveWidget(Hb_Search);
Btn_AddFriend->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedAddFriend);
return;
default:
Sb_Friend->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
Tb_Status->SetVisibility(ESlateVisibility::Hidden);
Ws_EntryMode->SetActiveWidget(Hb_Friend);
Btn_Chat->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedChat);
Btn_InviteParty->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedInviteParty);
Btn_Unfriend->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedUnfriend);
Btn_Block->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedBlock);
}
}.h
/**
* @brief Set Mode settings for selected entry enumerator.
*/
void SetEntryMode(const EFriendEntryMode& EntryMode) const;Since you need this functionality when the Friend Entry widget is initialized, call
SetEntryMode()
in theInitData()
function..cpp
void UAccelByteFriendEntry::InitData(const EFriendEntryMode& EntryMode, const FString& UserId)
{
...
SetEntryMode(EntryMode);
}
Find Friends
Open the
AccelByteFindFriend
class and add the following widget-related classes to the top of the class:.cpp
...
#include "AccelByteFriends.h"
#include "Components/Button.h"
#include "Components/EditableTextBox.h"
#include "Components/ScrollBox.h"
#include "TutorialProject/TutorialMenuHUD.h".h
...
#include "AccelByteFriendEntry.h"
...
class UEditableTextBox;
class UButton;
class UScrollBox;
class ATutorialMenuHUD;Specify the Find Friends widget components in the header file.
.h
/**
* @brief Editable Text Box for Find Friend.
*/
UPROPERTY(meta = (BindWidget))
UEditableTextBox* Etb_FindFriend;
/**
* @brief Button to start searching Friend.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_FindFriend;
/**
* @brief Button to close Find Friend Widget.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Close;
/**
* @brief Scrollable Box for Friends List result.
*/
UPROPERTY(meta = (BindWidget))
UScrollBox* Sb_FriendList;You can reuse the Friend Entry widget to display player info based on the
SearchUser()
query result. To do this, declare theAccelByteFriendEntry
class in theAccelByteFindFriend
header file and prepare a new array to hold all the player information for players that are either friends or are listed in the Outgoing Friend Request list. This value will be set later..h
/**
* @brief Widget to spawn for friend Entry.
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteFriendEntry> FriendEntryClass;
/**
* @brief Container for all friend names copied from outgoing friend list.
*/
UPROPERTY()
TArray<FString> FriendSentRequestArray;Compile the entire project and then assign
WB_FriendEntry
as the reference forFriendEntryClass
in the Unreal editor.In the
FindFriends()
function, changeCreateWeakLambda()
toCreateUObject()
for theSearchUsers()
query response..cpp
void UAccelByteFindFriend::FindFriends(const FString& FriendName)
{
FRegistry::User.SearchUsers(
FriendName,
THandler<FPagedPublicUsersInfo>::CreateUObject(this, &UAccelByteFindFriend::OnSuccessFindFriends),
FErrorHandler::CreateUObject(this, &UAccelByteFindFriend::OnFailedFindFriends)
);
}.h
/**
* @brief Callback for Success Find Friends.
*/
void OnSuccessFindFriends(const FPagedPublicUsersInfo& Result);
/**
* @brief Callback for Failing Find Friends.
*/
void OnFailedFindFriends(int32 ErrorCode, const FString& ErrorMessage);Define both of the response delegate functions you just declared to update the players list widget based on the query result.
.cpp
void UAccelByteFindFriend::OnSuccessFindFriends(const FPagedPublicUsersInfo& Result)
{
UE_LOG(LogTemp, Log, TEXT("Success Find Friends"));
Sb_FriendList->ClearChildren();
for (const FPublicUserInfo& UserData : Result.Data)
{
if (UserData.UserId != FRegistry::Credentials.GetUserId())
{
const TWeakObjectPtr<UAccelByteFriendEntry> SearchFriendEntry = MakeWeakObjectPtr<UAccelByteFriendEntry>(
CreateWidget<UAccelByteFriendEntry>(this, FriendEntryClass.Get())
);
SearchFriendEntry->InitData(EFriendEntryMode::Search, UserData.UserId);
for (const FString& FriendSentRequest : FriendSentRequestArray)
{
if (UserData.UserId == FriendSentRequest)
{
SearchFriendEntry->EnableAddFriendButton(false);
}
}
Sb_FriendList->AddChild(SearchFriendEntry.Get());
}
}
}
void UAccelByteFindFriend::OnFailedFindFriends(int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Failed Find Friends : %d , %s"), ErrorCode, *ErrorMessage);
}To filter the results of Search User so that players won't be able to add those that have already been added as a friend or to whom they have already sent a friend request:
- Create a new function.
- Use the SDK's
LoadFriendList
andListOutgoingFriends
functions to get player lists. - Inside both functions, store the result data in
FriendSentRequestArray
(which you used to filter the Find Friend feature's result list).
.cpp
void UAccelByteFindFriend::FilterSearchEntryList()
{
FriendSentRequestArray.Empty();
FRegistry::Lobby.SetLoadFriendListResponseDelegate(
Api::Lobby::FLoadFriendListResponse::CreateWeakLambda(this, [this](
FAccelByteModelsLoadFriendListResponse Result)
{
FriendSentRequestArray = Result.friendsId;
FRegistry::Lobby.ListOutgoingFriends();
UE_LOG(LogTemp, Log, TEXT("On Load Friend List Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Error, TEXT("Unable to retrieve friends list! Code : %i , Message : %s"), Code, *Message);
}));
FRegistry::Lobby.SetListOutgoingFriendsResponseDelegate(
Api::Lobby::FListOutgoingFriendsResponse::CreateWeakLambda(this, [this](
FAccelByteModelsListOutgoingFriendsResponse Result)
{
FriendSentRequestArray.Append(Result.friendsId);
FindUsers(Etb_FindFriend->GetText().ToString());
UE_LOG(LogTemp, Log, TEXT("On List Outgoing Friends Success"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Error, TEXT("Unable to retrieve the list of outgoing/pending friend request! Code : %i , Message : %s"), Code, *Message);
}));
FRegistry::Lobby.LoadFriendsList();
}.h
/**
* @brief Filter search entry to disable the add button for users who are already in their friends list and outgoing requests list.
*/
void FilterSearchEntryList();Create two functions to be called when the Find Friend and Close buttons are clicked.
.cpp
void UAccelByteFindFriend::OnClickFindFriends()
{
Sb_FriendList->ClearChildren();
FilterSearchEntryList();
}
void UAccelByteFindFriend::OnClickCloseFindFriendWidget()
{
TutorialMenuHUD->CloseFindFriendsMenu();
}.h
/**
* @brief Find Friends button.
*/
UFUNCTION()
void OnClickFindFriends();
/**
* @brief Close Find Friend Widget.
*/
UFUNCTION()
void OnClickCloseFindFriendWidget();
/**
* @brief Tutorial Menu HUD pointer reference.
*/
UPROPERTY()
ATutorialMenuHUD* TutorialMenuHUD;Set up the widgets by adding the
NativeConstruct()
override function and initialize theTutorialMenuHUD
pointer reference..cpp
void UAccelByteFindFriend::NativeConstruct()
{
Super::NativeConstruct();
check (GetOwningPlayer() != nullptr);
check (GetOwningPlayer()->GetHUD() != nullptr);
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
Btn_FindFriend->OnClicked.AddUniqueDynamic(this, &UAccelByteFindFriend::OnClickFindFriends);
Btn_Close->OnClicked.AddUniqueDynamic(this, &UAccelByteFindFriend::OnClickCloseFindFriendWidget);
}.h
...
virtual void NativeConstruct() override;
Friends Menu
Open the
AccelByteFriends
class and include the following widget classes at the top:.cpp
...
#include "Components/Button.h"
#include "Components/ScrollBox.h"
#include "Components/TextBlock.h"
#include "TutorialProject/TutorialMenuHUD.h".h
...
#include "AccelByteFriendEntry.h"
#include "Models/AccelByteLobbyModels.h"
#include "TutorialProject/TutorialMenuHUD.h"
...
class UScrollBox;
class UButton;
class UTextBlock;
...Create an enum to determine the current Friends Menu's tab state.
.h
/**
* Enumerator to determine the current state
*/
UENUM()
enum class ECurrentStateFriend: uint8
{
FRIEND_LIST UMETA(DisplayName = "Friends List"),
INCOMING_LIST UMETA(DisplayName = "Incoming Requests List"),
OUTGOING_LIST UMETA(DisplayName = "Outgoing Requests List")
};Specify all of the Friends Menu widget components in the header file.
.h
/**
* @brief Button for opening Find Friend Menu pop up.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_FindFriend;
/**
* @brief Button for Friend List displaying.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_FriendList;
/**
* @brief Button for Pending Incoming Friend List.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_PendingIncomingList;
/**
* @brief Button for Pending Outgoing Friend List.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_PendingSentList;
/**
* @brief Button for Back to Main Menu.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Back;
/**
* @brief Scroll Box for content display of four functionality (FriendList, Incoming, Outgoing, Block).
*/
UPROPERTY(meta = (BindWidget))
UScrollBox* Sb_ContentList;
/**
* @brief Text Block to show how many player friends are currently online.
*/
UPROPERTY(meta = (BindWidget))
UTextBlock* T_FriendsOnline;Since you are mainly going to display Friends-related lists, initialize the
AccelByteFriendEntry
class and create a new function to make it easier to create the Friend Entry widget.When you have done that, create a local array to hold all of the Friend Entry widgets that have been created.
.cpp
void UAccelByteFriends::CreateEntryWidget(const EFriendEntryMode& EntryMode, const FString& FriendId)
{
const TWeakObjectPtr<UAccelByteFriendEntry> FriendEntryWidget = MakeWeakObjectPtr<UAccelByteFriendEntry>(CreateWidget<UAccelByteFriendEntry>(this, FriendEntryClass.Get()));
FriendListWidgets.Add(FriendEntryWidget);
FriendEntryWidget->InitData(EntryMode, FriendId);
Sb_ContentList->AddChild(FriendEntryWidget.Get());
}.h
/**
* @brief Creates Friend Entry Widget through weak object pointer.
* @param EntryMode Entry mode for the friend widget.
* @param FriendId Targeted Friend ID for the entry.
*/
void CreateEntryWidget(const EFriendEntryMode& EntryMode, const FString& FriendId);
/**
* @brief Reference to Friend Entry Class.
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteFriendEntry> FriendEntryClass;
/**
* @brief Array for Entry Widgets.
*/
TArray<TWeakObjectPtr<UAccelByteFriendEntry>> FriendListWidgets;To prepare the Friends Menu's button functionality, start by creating a new function for the Find Friend button. This will open the Find Friends Menu widget via
TutorialMenuHUD
..cpp
void UAccelByteFriends::OnClickedFindFriend()
{
TutorialMenuHUD->OpenFindFriendsMenu();
}.h
/**
* @brief Callback for Find Friend.
*/
UFUNCTION()
void OnClickedFindFriend();
/**
* @brief Tutorial Menu HUD pointer reference.
*/
UPROPERTY()
ATutorialMenuHUD* TutorialMenuHUD;Create a new function to go back to the Lobby page and bind it to the Back to Lobby button.
.cpp
void UAccelByteFriends::OnClickedBackToLobby()
{
TutorialMenuHUD->CloseFriendMenu();
}.h
/**
* @brief Callback for Back button to lobby.
*/
UFUNCTION()
void OnClickedBackToLobby();To make it easier to refresh the Friends List, create a new function in the
AccelByteFriends
class..cpp
void UAccelByteFriends::RefreshFriendsList()
{
switch (CurrentState)
{
case ECurrentStateFriend::FRIEND_LIST:
{
LoadFriendList();
break;
}
case ECurrentStateFriend::INCOMING_LIST:
{
LoadPendingIncomingList();
break;
}
case ECurrentStateFriend::OUTGOING_LIST:
{
LoadPendingOutgoingList();
break;
}
}
}.h
/**
* @brief Refresh friends list when open the friends menu
*/
void RefreshFriendsList();
/**
* @brief Current state of the menu.
*/
ECurrentStateFriend CurrentState;Create a new function to handle the widgets on the Friend List's tab button.
.cpp
void UAccelByteFriends::SwitchActiveButton(UButton* CurrentButton)
{
if (!CurrentActiveButton) CurrentActiveButton = CurrentButton;
CurrentActiveButton->SetBackgroundColor(FLinearColor::White);
CurrentActiveButton = CurrentButton;
FLinearColor SelectedTabGreyColor = FLinearColor(0.2f, 0.2f, 0.2f, 1.0f);
CurrentActiveButton->SetBackgroundColor(SelectedTabGreyColor);
}.h
/**
* @brief Switch the active button to the current button that player clicked before
* @param CurrentButton Current target active button
*/
void SwitchActiveButton(UButton* CurrentButton);
/**
* @brief Instantiate current active button
*/
UPROPERTY()
UButton* CurrentActiveButton;Start modifying the current Friends functionality, beginning with the
OnClickedFriendList()
function.Call the
CreateEntryWidget()
function to display the Friends List information.When you have finished, Once completed, store the current Friends tab type in a local enum variable to make it easier to create the correct Friend Entry widget.
.cpp
void UAccelByteFriends::LoadFriendList()
{
SwitchActiveButton(Btn_FriendList);
Sb_ContentList->ClearChildren();
CurrentState = ECurrentStateFriend::FRIEND_LIST;
FRegistry::Lobby.SetLoadFriendListResponseDelegate(
Api::Lobby::FLoadFriendListResponse::CreateWeakLambda(this, [this](const FAccelByteModelsLoadFriendListResponse& Result)
{
Sb_ContentList->ClearChildren();
FriendListWidgets.Empty();
for (const FString& FriendId : Result.friendsId)
{
CreateEntryWidget(EFriendEntryMode::Friend, FriendId);
}
UE_LOG(LogTemp, Log, TEXT("Success Retrieve Load Friend List Response!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Error LoadFriendListResponseDelegate, Error Code: %d Error Message: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.LoadFriendsList();
}.h
/**
* @brief Current state of the menu.
*/
ECurrentStateFriend CurrentState;Modify both the
OnClickedPendingIncomingList()
and theOnClickedPendingOutgoingList()
functions by adding functionality that will create the entry widget for each of the players listed, based on the query result..cpp
void UAccelByteFriends::LoadPendingIncomingList()
{
SwitchActiveButton(Btn_PendingIncomingList);
Sb_ContentList->ClearChildren();
CurrentState = ECurrentStateFriend::INCOMING_LIST;
FRegistry::Lobby.SetListIncomingFriendsResponseDelegate(
Api::Lobby::FListIncomingFriendsResponse::CreateWeakLambda(this, [this](
FAccelByteModelsListIncomingFriendsResponse Result)
{
Sb_ContentList->ClearChildren();
FriendListWidgets.Empty();
for (const FString& FriendId : Result.friendsId)
{
CreateEntryWidget(EFriendEntryMode::Incoming, FriendId);
}
UE_LOG(LogTemp, Log, TEXT("Success Retrieve List Incoming Friend Response!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Error, TEXT("Unable to retrieve the list of incoming friend requests! Code : %i , Message : %s"), Code, *Message);
}));
FRegistry::Lobby.ListIncomingFriends();
}
void UAccelByteFriends::LoadPendingOutgoingList()
{
SwitchActiveButton(Btn_PendingSentList);
Sb_ContentList->ClearChildren();
CurrentState = ECurrentStateFriend::OUTGOING_LIST;
FRegistry::Lobby.SetListOutgoingFriendsResponseDelegate(
Api::Lobby::FListOutgoingFriendsResponse::CreateWeakLambda(this, [this](
FAccelByteModelsListOutgoingFriendsResponse Result)
{
Sb_ContentList->ClearChildren();
FriendListWidgets.Empty();
for (const FString& FriendId : Result.friendsId)
{
CreateEntryWidget(EFriendEntryMode::Outgoing, FriendId);
}
UE_LOG(LogTemp, Log, TEXT("Success Retrieve List Outgoing Friend Response!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Error, TEXT("Unable to retrieve the list of outgoing friend requests! Code : %i , Message : %s"), Code, *Message);
}));
FRegistry::Lobby.ListOutgoingFriends();
}Now that you have prepared all the functions needed for the buttons:
- Add the
NativeConstruct()
override function. - Initialize the
TutorialMenuHUD
pointer. - Set up all of the Friend Menu buttons with the Friends Notif delegate.
.cpp
void UAccelByteFriends::NativeConstruct()
{
Super::NativeConstruct();
check (GetOwningPlayer() != nullptr);
check (GetOwningPlayer()->GetHUD() != nullptr);
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
Btn_FindFriend->OnClicked.AddUniqueDynamic(this, &UAccelByteFriends::OnClickedFindFriend);
Btn_FriendList->OnClicked.AddUniqueDynamic(this, &UAccelByteFriends::OnClickedFriendList);
Btn_PendingIncomingList->OnClicked.AddUniqueDynamic(this, &UAccelByteFriends::OnClickedPendingIncomingList);
Btn_PendingSentList->OnClicked.AddUniqueDynamic(this, &UAccelByteFriends::OnClickedPendingOutgoingList);
Btn_Back->OnClicked.AddUniqueDynamic(this, &UAccelByteFriends::OnClickedBackToLobby);
SetNotificationDelegate();
CurrentState = ECurrentStateFriend::FRIEND_LIST;
RefreshFriendsList();
}.h
...
virtual void NativeConstruct() override;
...- Add the
Modify the
SetNotificationDelegate()
delegate to checkCurrentState
and display its corresponding players, such as in the following example:.cpp
void UAccelByteFriends::SetNotificationDelegate()
{
FRegistry::Lobby.SetOnFriendRequestAcceptedNotifDelegate(
Api::Lobby::FAcceptFriendsNotif::CreateWeakLambda(this, [this](const FAccelByteModelsAcceptFriendsNotif& Result)
{
if (CurrentState == ECurrentStateFriend::FRIEND_LIST)
{
CreateEntryWidget(EFriendEntryMode::Friend, Result.friendId);
}
else if (CurrentState == ECurrentStateFriend::OUTGOING_LIST)
{
FRegistry::Lobby.ListOutgoingFriends();
}
}));
FRegistry::Lobby.SetOnUnfriendNotifDelegate(
Api::Lobby::FUnfriendNotif::CreateWeakLambda(this, [this](const FAccelByteModelsUnfriendNotif& Result)
{
if (CurrentState == ECurrentStateFriend::FRIEND_LIST)
{
FRegistry::Lobby.LoadFriendsList();
}
}));
FRegistry::Lobby.SetOnCancelFriendsNotifDelegate(
Api::Lobby::FCancelFriendsNotif::CreateWeakLambda(this, [this](const FAccelByteModelsCancelFriendsNotif& Result)
{
if (CurrentState == ECurrentStateFriend::INCOMING_LIST)
{
FRegistry::Lobby.ListIncomingFriends();
}
}));
FRegistry::Lobby.SetOnRejectFriendsNotifDelegate(
Api::Lobby::FRejectFriendsNotif::CreateWeakLambda(this, [this](const FAccelByteModelsRejectFriendsNotif& Result)
{
if (CurrentState == ECurrentStateFriend::OUTGOING_LIST)
{
FRegistry::Lobby.ListOutgoingFriends();
}
}));
FRegistry::Lobby.SetOnIncomingRequestFriendsNotifDelegate(
Api::Lobby::FRequestFriendsNotif::CreateWeakLambda(this, [this](const FAccelByteModelsRequestFriendsNotif& Result)
{
if (CurrentState == ECurrentStateFriend::INCOMING_LIST)
{
FRegistry::Lobby.ListIncomingFriends();
}
}));
}Open the
TutorialMenuHUD
class and call the Friends Menu'sRefreshFriendsList()
function inside the else condition of theOpenFriendsMenu()
function..cpp
void ATutorialMenuHUD::OpenFriendsMenu()
{
if (!FriendsMenu->IsInViewport())
...
else
{
...
FriendsMenu->RefreshFriendsList();
}
}
Implement Friend-Related Widgets
Open the
AccelByteLobby
class and include the following header:.cpp
...
#include "Components/Button.h"
#include "TutorialProject/TutorialMenuHUD.h"
....h
...
class ATutorialMenuHUD;
class UButton;
...Initialize the
TutorialMenuHUD
class in itsNativeConstruct()
function and set up the Leave Lobby button..cpp
void UAccelByteLobby::NativeConstruct()
{
Super::NativeConstruct();
check(GetOwningPlayer() != nullptr);
check(GetOwningPlayer()->GetHUD() != nullptr);
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
Btn_LeaveLobby->OnClicked.AddUniqueDynamic(TutorialMenuHUD, &ATutorialMenuHUD::CloseLobbyMenu);
}.h
virtual void NativeConstruct() override;
/**
* @brief Button for Leave Lobby and back to Main Menu.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_LeaveLobby;
/**
* @brief Tutorial Menu HUD pointer reference.
*/
UPROPERTY()
ATutorialMenuHUD* TutorialMenuHUD;Create a new function to prepare the Friends Management button in the Lobby menu.
.cpp
void UAccelByteLobby::OnClickedOpenFriendsManagement()
{
TutorialMenuHUD->OpenFriendsMenu();
}.h
/**
* @brief Button callback on Open Friends Management.
*/
UFUNCTION()
void OnClickedOpenFriendsManagement();Set up the Friends button with the callback function you created in the
NativeConstruct()
..cpp
void UAccelByteLobby::NativeConstruct()
{
...
Btn_FriendsManagement->OnClicked.AddUniqueDynamic(this, &UAccelByteLobby::OnClickedOpenFriendsManagement);
}.h
/**
* @brief Button for go to Friend Management Menu.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_FriendsManagement;Open your
AccelByteAuth
class. Under theLoginSuccess()
function, changeConnectToLobby()
toInitMainMenu()
..cpp
void UAccelByteAuth::LoginSuccess()
{
...
if(GetOwningPlayer() && GetOwningPlayer()->GetHUD())
{
TutorialMenuHUD->InitMainMenu();
}
}While still in the
AccelByteAuth
class, go to theLogoutSuccess()
function and call theTutorialMenuHUD
'sCloseMainMenu()
function..cpp
void UAccelByteAuth::LogoutSuccess()
{
...
if (TutorialMenuHUD == nullptr)
{
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
}
ensure(TutorialMenuHUD != nullptr);
TutorialMenuHUD->CloseMainMenu();
}
Congratulations! You have now fully implemented the Friends service.
Full code for reference
AccelByteFriends.h
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#pragma once
#include "CoreMinimal.h"
#include "AccelByteFriendEntry.h"
#include "Blueprint/UserWidget.h"
#include "Models/AccelByteLobbyModels.h"
#include "TutorialProject/TutorialMenuHUD.h"
#include "AccelByteFriends.generated.h"
/**
* Enumerator to determine the current state
* Available options:
* - FRIEND_LIST
* - INCOMING_LIST
* - OUTGOING_LIST
* - BLOCKED_LIST
*/
UENUM()
enum class ECurrentStateFriend: uint8
{
FRIEND_LIST UMETA(DisplayName = "Friends List"),
INCOMING_LIST UMETA(DisplayName = "Incoming Requests List"),
OUTGOING_LIST UMETA(DisplayName = "Outgoing Requests List"),
BLOCKED_LIST UMETA(DisplayName = "Blocked Users List")
};
class UScrollBox;
/**
* Component for to use AccelByte Friend services.
* This code covers AccelByte services including :
*
* - Friend List
* - List Outgoing Friend Request
* - List Incoming Friend Request
* - Block Friend List
*
*/
UCLASS()
class TUTORIALPROJECT_API UAccelByteFriends : public UUserWidget
{
GENERATED_BODY()
virtual void NativeConstruct() override;
public:
/**
* @brief Set Friend services notification delegates.
*/
void SetNotificationDelegate();
private:
/**
* @brief Button for opening Find Friend Menu pop up.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_FindFriend;
/**
* @brief Button for Friend List displaying.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_FriendList;
/**
* @brief Button for Pending Incoming Friend List.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_PendingIncomingList;
/**
* @brief Button for Pending Outgoing Friend List.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_PendingSentList;
/**
* @brief Button for Block Friend List.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_BlockList;
/**
* @brief Button for Back to Main Menu.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Back;
/**
* @brief Scroll Box for content display of four functionality (FriendList, Incoming, Outgoing, Block).
*/
UPROPERTY(meta = (BindWidget))
UScrollBox* Sb_ContentList;
/**
* @brief Callback for Find Friend.
*/
UFUNCTION()
void OnClickedFindFriend();
/**
* @brief Callback for Friend List.
*/
UFUNCTION()
void OnClickedFriendList();
/**
* @brief Callback for Pending Incoming Friend List.
*/
UFUNCTION()
void OnClickedPendingIncomingList();
/**
* @brief Callback for Pending Outgoing Friend List.
*/
UFUNCTION()
void OnClickedPendingOutgoingList();
/**
* @brief Callback for Block Friend List.
*/
UFUNCTION()
void OnClickedBlockList();
/**
* @brief Callback for Back button to lobby.
*/
UFUNCTION()
void OnClickedBackToLobby();
/**
* @brief Callback to get friends presence response.
* @param Result Model for user presence.
*/
void OnGetFriendsPresenceResponse(const FAccelByteModelsGetOnlineUsersResponse& Result);
/**
* @brief Get all the friend list data response here.
*/
void OnLoadFriendListResponse(const FAccelByteModelsLoadFriendListResponse& Result);
/**
* @brief Callback for list Incoming Friend response.
*/
void OnListIncomingFriendResponse(const FAccelByteModelsListIncomingFriendsResponse& Result);
/**
* @brief Callback for list Outgoing Friend response.
*/
void OnListOutgoingFriendResponse(const FAccelByteModelsListOutgoingFriendsResponse& Result);
/**
* @brief Callback for Successfully Get List Blocked User.
*/
void OnSuccessRetrieveListBlockedUser(const FAccelByteModelsListBlockedUserResponse& Result);
/**
* @brief Callback for Failed Get List Blocked User.
*/
void OnFailedRetrieveListBlockedUser(int32 ErrorCode, const FString& ErrorMessage);
/**
* @brief Creates Friend Entry Widget through weak object pointer.
* @param EntryMode Entry mode for the friend widget.
* @param FriendId Targeted Friend Id for the entry.
*/
void CreateEntryWidget(const EFriendEntryMode& EntryMode, const FString& FriendId);
/**
* @brief Sets the user presence of the entry.
* @param FriendEntry Pointer for Friend Entry Class.
* @param Availability User Presence Availability Code.
*/
void SetUserPresence(const TWeakObjectPtr<UAccelByteFriendEntry> FriendEntry, const FString& Availability) const;
/**
* @brief Reference to Friend Entry Class.
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteFriendEntry> FriendEntryClass;
/**
* @brief Tutorial Menu HUD pointer reference.
*/
UPROPERTY()
ATutorialMenuHUD* TutorialMenuHUD;
/**
* @brief Array for Entry Widgets.
*/
TArray<TWeakObjectPtr<UAccelByteFriendEntry>> FriendListWidgets;
/**
* @brief Current state of the menu.
*/
ECurrentStateFriend CurrentState;
};
AccelByteFriends.cpp
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#include "AccelByteFriends.h"
#include "Api/AccelByteLobbyApi.h"
#include "Api/AccelByteUserApi.h"
#include "Core/AccelByteRegistry.h"
#include "Components/Button.h"
#include "Components/ScrollBox.h"
#include "TutorialProject/TutorialMenuHUD.h"
void UAccelByteFriends::NativeConstruct()
{
Super::NativeConstruct();
check (GetOwningPlayer() != nullptr);
check (GetOwningPlayer()->GetHUD() != nullptr);
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
Btn_FindFriend->OnClicked.AddUniqueDynamic(this, &UAccelByteFriends::OnClickedFindFriend);
Btn_FriendList->OnClicked.AddUniqueDynamic(this, &UAccelByteFriends::LoadFriendList);
Btn_PendingIncomingList->OnClicked.AddUniqueDynamic(this, &UAccelByteFriends::LoadPendingIncomingList);
Btn_PendingSentList->OnClicked.AddUniqueDynamic(this, &UAccelByteFriends::LoadPendingOutgoingList);
Btn_Back->OnClicked.AddUniqueDynamic(this, &UAccelByteFriends::OnClickedBackToLobby);
SetNotificationDelegate();
CurrentState = ECurrentStateFriend::FRIEND_LIST;
RefreshFriendsList();
}
void UAccelByteFriends::SwitchActiveButton(UButton* CurrentButton)
{
if (!CurrentActiveButton) CurrentActiveButton = CurrentButton;
CurrentActiveButton->SetBackgroundColor(FLinearColor::White);
CurrentActiveButton = CurrentButton;
FLinearColor SelectedTabGreyColor = FLinearColor(0.2f, 0.2f, 0.2f, 1.0f);
CurrentActiveButton->SetBackgroundColor(SelectedTabGreyColor);
}
void UAccelByteFriends::SetNotificationDelegate()
{
FRegistry::Lobby.SetOnFriendRequestAcceptedNotifDelegate(
Api::Lobby::FAcceptFriendsNotif::CreateWeakLambda(this, [this](const FAccelByteModelsAcceptFriendsNotif& Result)
{
if (CurrentState == ECurrentStateFriend::FRIEND_LIST)
{
CreateEntryWidget(EFriendEntryMode::Friend, Result.friendId);
}
else if (CurrentState == ECurrentStateFriend::OUTGOING_LIST)
{
FRegistry::Lobby.ListOutgoingFriends();
}
}));
FRegistry::Lobby.SetOnUnfriendNotifDelegate(
Api::Lobby::FUnfriendNotif::CreateWeakLambda(this, [this](const FAccelByteModelsUnfriendNotif& Result)
{
if (CurrentState == ECurrentStateFriend::FRIEND_LIST)
{
FRegistry::Lobby.LoadFriendsList();
}
}));
FRegistry::Lobby.SetOnCancelFriendsNotifDelegate(
Api::Lobby::FCancelFriendsNotif::CreateWeakLambda(this, [this](const FAccelByteModelsCancelFriendsNotif& Result)
{
if (CurrentState == ECurrentStateFriend::INCOMING_LIST)
{
FRegistry::Lobby.ListIncomingFriends();
}
}));
FRegistry::Lobby.SetOnRejectFriendsNotifDelegate(
Api::Lobby::FRejectFriendsNotif::CreateWeakLambda(this, [this](const FAccelByteModelsRejectFriendsNotif& Result)
{
if (CurrentState == ECurrentStateFriend::OUTGOING_LIST)
{
FRegistry::Lobby.ListOutgoingFriends();
}
}));
FRegistry::Lobby.SetOnIncomingRequestFriendsNotifDelegate(
Api::Lobby::FRequestFriendsNotif::CreateWeakLambda(this, [this](const FAccelByteModelsRequestFriendsNotif& Result)
{
if (CurrentState == ECurrentStateFriend::INCOMING_LIST)
{
FRegistry::Lobby.ListIncomingFriends();
}
}));
}
void UAccelByteFriends::RefreshFriendsList()
{
switch (CurrentState)
{
case ECurrentStateFriend::FRIEND_LIST:
{
LoadFriendList();
break;
}
case ECurrentStateFriend::INCOMING_LIST:
{
LoadPendingIncomingList();
break;
}
case ECurrentStateFriend::OUTGOING_LIST:
{
LoadPendingOutgoingList();
break;
}
}
}
void UAccelByteFriends::OnClickedFindFriend()
{
TutorialMenuHUD->OpenFindFriendsMenu();
}
void UAccelByteFriends::LoadFriendList()
{
SwitchActiveButton(Btn_FriendList);
Sb_ContentList->ClearChildren();
CurrentState = ECurrentStateFriend::FRIEND_LIST;
FRegistry::Lobby.SetLoadFriendListResponseDelegate(
Api::Lobby::FLoadFriendListResponse::CreateWeakLambda(this, [this](const FAccelByteModelsLoadFriendListResponse& Result)
{
Sb_ContentList->ClearChildren();
FriendListWidgets.Empty();
for (const FString& FriendId : Result.friendsId)
{
CreateEntryWidget(EFriendEntryMode::Friend, FriendId);
}
UE_LOG(LogTemp, Log, TEXT("Success Retrieve Load Friend List Response!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Error LoadFriendListResponseDelegate, Error Code: %d Error Message: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.LoadFriendsList();
}
void UAccelByteFriends::LoadPendingIncomingList()
{
SwitchActiveButton(Btn_PendingIncomingList);
Sb_ContentList->ClearChildren();
CurrentState = ECurrentStateFriend::INCOMING_LIST;
FRegistry::Lobby.SetListIncomingFriendsResponseDelegate(
Api::Lobby::FListIncomingFriendsResponse::CreateWeakLambda(this, [this](
FAccelByteModelsListIncomingFriendsResponse Result)
{
Sb_ContentList->ClearChildren();
FriendListWidgets.Empty();
for (const FString& FriendId : Result.friendsId)
{
CreateEntryWidget(EFriendEntryMode::Incoming, FriendId);
}
UE_LOG(LogTemp, Log, TEXT("Success Retrieve List Incoming Friend Response!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Error, TEXT("Unable to retrieve the list of incoming friend requests! Code : %i , Message : %s"), Code, *Message);
}));
FRegistry::Lobby.ListIncomingFriends();
}
void UAccelByteFriends::LoadPendingOutgoingList()
{
SwitchActiveButton(Btn_PendingSentList);
Sb_ContentList->ClearChildren();
CurrentState = ECurrentStateFriend::OUTGOING_LIST;
FRegistry::Lobby.SetListOutgoingFriendsResponseDelegate(
Api::Lobby::FListOutgoingFriendsResponse::CreateWeakLambda(this, [this](
FAccelByteModelsListOutgoingFriendsResponse Result)
{
Sb_ContentList->ClearChildren();
FriendListWidgets.Empty();
for (const FString& FriendId : Result.friendsId)
{
CreateEntryWidget(EFriendEntryMode::Outgoing, FriendId);
}
UE_LOG(LogTemp, Log, TEXT("Success Retrieve List Outgoing Friend Response!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Error, TEXT("Unable to retrieve the list of outgoing friend requests! Code : %i , Message : %s"), Code, *Message);
}));
FRegistry::Lobby.ListOutgoingFriends();
}
void UAccelByteFriends::OnClickedBackToLobby()
{
TutorialMenuHUD->CloseFriendMenu();
}
void UAccelByteFriends::CreateEntryWidget(const EFriendEntryMode& EntryMode, const FString& FriendId)
{
const TWeakObjectPtr<UAccelByteFriendEntry> FriendEntryWidget = MakeWeakObjectPtr<UAccelByteFriendEntry>(CreateWidget<UAccelByteFriendEntry>(this, FriendEntryClass.Get()));
FriendListWidgets.Add(FriendEntryWidget);
FriendEntryWidget->InitData(EntryMode, FriendId);
Sb_ContentList->AddChild(FriendEntryWidget.Get());
}
AccelByteFindFriend.h
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#pragma once
#include "CoreMinimal.h"
#include "AccelByteFriendEntry.h"
#include "Models/AccelByteLobbyModels.h"
#include "TutorialProject/TutorialMenuHUD.h"
#include "AccelByteFriends.generated.h"
/**
* Enumerator to determine the current state
* Available options:
* - FRIEND_LIST
* - INCOMING_LIST
* - OUTGOING_LIST
* - BLOCKED_LIST
*/
UENUM()
enum class ECurrentStateFriend: uint8
{
FRIEND_LIST UMETA(DisplayName = "Friends List"),
INCOMING_LIST UMETA(DisplayName = "Incoming Requests List"),
OUTGOING_LIST UMETA(DisplayName = "Outgoing Requests List"),
BLOCKED_LIST UMETA(DisplayName = "Blocked Users List")
};
class UScrollBox;
class UButton;
/**
* Component for to use AccelByte Friend services.
* This code covers AccelByte services including :
*
* - Friend List
* - List Outgoing Friend Request
* - List Incoming Friend Request
* - Block Friend List
*
*/
UCLASS()
class TUTORIALPROJECT_API UAccelByteFriends : public UUserWidget
{
GENERATED_BODY()
virtual void NativeConstruct() override;
/**
* @brief Switch the active button to the current button that player clicked before
* @param CurrentButton Current target active button
*/
void SwitchActiveButton(UButton* CurrentButton);
/**
* @brief Instantiate current active button
*/
UPROPERTY()
UButton* CurrentActiveButton;
public:
/**
* @brief Set Friend services notification delegates.
*/
void SetNotificationDelegate();
/**
* @brief Refresh friends list when open the friends menu
*/
void RefreshFriendsList();
private:
/**
* @brief Button for opening Find Friend Menu pop up.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_FindFriend;
/**
* @brief Button for Friend List displaying.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_FriendList;
/**
* @brief Button for Pending Incoming Friend List.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_PendingIncomingList;
/**
* @brief Button for Pending Outgoing Friend List.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_PendingSentList;
/**
* @brief Button for Back to Main Menu.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Back;
/**
* @brief Scroll Box for content display of four functionality (FriendList, Incoming, Outgoing, Block).
*/
UPROPERTY(meta = (BindWidget))
UScrollBox* Sb_ContentList;
/**
* @brief Callback for Find Friend.
*/
UFUNCTION()
void OnClickedFindFriend();
/**
* @brief Callback for Friend List.
*/
UFUNCTION()
void LoadFriendList();
/**
* @brief Callback for Pending Incoming Friend List.
*/
UFUNCTION()
void LoadPendingIncomingList();
/**
* @brief Callback for Pending Outgoing Friend List.
*/
UFUNCTION()
void LoadPendingOutgoingList();
/**
* @brief Callback for Back button to lobby.
*/
UFUNCTION()
void OnClickedBackToLobby();
/**
* @brief Creates Friend Entry Widget through weak object pointer.
* @param EntryMode Entry mode for the friend widget.
* @param FriendId Targeted Friend Id for the entry.
*/
void CreateEntryWidget(const EFriendEntryMode& EntryMode, const FString& FriendId);
/**
* @brief Reference to Friend Entry Class.
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteFriendEntry> FriendEntryClass;
/**
* @brief Tutorial Menu HUD pointer reference.
*/
UPROPERTY()
ATutorialMenuHUD* TutorialMenuHUD;
/**
* @brief Array for Entry Widgets.
*/
TArray<TWeakObjectPtr<UAccelByteFriendEntry>> FriendListWidgets;
/**
* @brief Current state of the menu.
*/
ECurrentStateFriend CurrentState;
};
AccelByteFindFriend.cpp
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#include "AccelbyteFindFriend.h"
#include "AccelByteFriends.h"
// AccelByte Services
#include "Api/AccelByteLobbyApi.h"
#include "Api/AccelByteUserApi.h"
// Widget Components
#include "Components/Button.h"
#include "Components/EditableTextBox.h"
#include "Components/ScrollBox.h"
// Menu HUD
#include "TutorialProject/TutorialMenuHUD.h"
void UAccelbyteFindFriend::NativeConstruct()
{
Super::NativeConstruct();
check (GetOwningPlayer() != nullptr);
check (GetOwningPlayer()->GetHUD() != nullptr);
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
Btn_FindFriend->OnClicked.AddUniqueDynamic(this, &UAccelbyteFindFriend::OnClickFindFriends);
Btn_Close->OnClicked.AddUniqueDynamic(this, &UAccelbyteFindFriend::OnClickCloseFindFriendWidget);
}
void UAccelbyteFindFriend::OnClickFindFriends()
{
Sb_FriendList->ClearChildren();
FilterSearchEntryList();
}
void UAccelbyteFindFriend::OnClickCloseFindFriendWidget()
{
TutorialMenuHUD->CloseFindFriendsMenu();
}
void UAccelbyteFindFriend::FilterSearchEntryList()
{
FRegistry::Lobby.SetLoadFriendListResponseDelegate(Api::Lobby::FLoadFriendListResponse::CreateUObject(this, &UAccelbyteFindFriend::OnLoadFriendListResponse));
FRegistry::Lobby.SetListOutgoingFriendsResponseDelegate(Api::Lobby::FListOutgoingFriendsResponse::CreateUObject(this, &UAccelbyteFindFriend::OnListOutgoingFriendResponse));
// Filter users on Friends List.
FRegistry::Lobby.LoadFriendsList();
}
void UAccelbyteFindFriend::OnLoadFriendListResponse(const FAccelByteModelsLoadFriendListResponse& Result)
{
FriendSentRequestArray.Empty();
if (Result.Code == "0")
{
FriendSentRequestArray = Result.friendsId;
// Filter users on Outgoing Friends List.
FRegistry::Lobby.ListOutgoingFriends();
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Unable to retrieve friends list!"));
}
}
void UAccelbyteFindFriend::OnListOutgoingFriendResponse(const FAccelByteModelsListOutgoingFriendsResponse& Result)
{
if (Result.Code == "0")
{
FriendSentRequestArray.Append(Result.friendsId);
// Search friends after filtering users.
FindFriends(Etb_FindFriend->GetText().ToString());
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Unable to retrieve the list of outgoing/pending friend request!"));
}
}
void UAccelbyteFindFriend::FindFriends(const FString& FriendName)
{
FRegistry::User.SearchUsers(
FriendName,
THandler<FPagedPublicUsersInfo>::CreateUObject(this, &UAccelbyteFindFriend::OnSuccessFindFriends),
FErrorHandler::CreateUObject(this, &UAccelbyteFindFriend::OnFailedFindFriends)
);
}
void UAccelbyteFindFriend::OnSuccessFindFriends(const FPagedPublicUsersInfo& Result)
{
Sb_FriendList->ClearChildren();
for (const FPublicUserInfo& UserData : Result.Data)
{
// If search entry is not local player.
if (UserData.UserId != TutorialMenuHUD->PlayerInfo.UserId)
{
// Create friend entry.
const TWeakObjectPtr<UAccelByteFriendEntry> SearchFriendEntry = MakeWeakObjectPtr<UAccelByteFriendEntry>(
CreateWidget<UAccelByteFriendEntry>(this, FriendEntryClass.Get())
);
// Init entry data.
SearchFriendEntry->InitData(EFriendEntryMode::SEARCH_ENTRY, UserData.UserId);
// Disable add friend button when the request was already sent from our previous filtered array.
for (const FString& FriendSentRequest : FriendSentRequestArray)
{
if (UserData.UserId == FriendSentRequest)
{
SearchFriendEntry->EnableAddFriendButton(false);
}
}
// Add Entry to Scroll Box.
Sb_FriendList->AddChild(SearchFriendEntry.Get());
}
}
}
void UAccelbyteFindFriend::OnFailedFindFriends(int32 ErrorCode, const FString& ErrorMessage)
{
const FString DebugMessage = FString::Printf(TEXT("Failed Find Friends : %d , %s"), ErrorCode, *ErrorMessage);
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Cyan, DebugMessage);
UE_LOG(LogTemp, Warning, TEXT(" Failed Find Friends : Code: %d, Reason: %s"), ErrorCode, *ErrorMessage);
}
AccelByteFriendEntry.h
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Models/AccelByteUserModels.h"
#include "Models/AccelByteLobbyModels.h"
#include "AccelByteFriendEntry.generated.h"
class UTextBlock;
class UButton;
class UScaleBox;
class UHorizontalBox;
class UWidgetSwitcher;
/**
* Enumerator for Friend Entry widget modes.
* Available options:
* - Friend
* - Incoming Request
* - Outgoing Request
* - Blocked Users
* - Search User Entry
*/
UENUM()
enum class EFriendEntryMode : uint8
{
FRIEND_ENTRY UMETA(DisplayName = "Friend"),
INCOMING_ENTRY UMETA(DisplayName = "Incoming Request"),
OUTGOING_ENTRY UMETA(DisplayName = "Outgoing Request"),
BLOCKED_ENTRY UMETA(DisplayName = "Blocked"),
SEARCH_ENTRY UMETA(DisplayName = "Search")
};
/**
* Entry for Friend data.
* In this code you will use :
*
* - Get User by User ID
* - Chat with specific person
* - Unfriend specific person
* - Block specific person
*/
UCLASS()
class TUTORIALPROJECT_API UAccelByteFriendEntry : public UUserWidget
{
GENERATED_BODY()
public:
/**
* @brief Initialize Entry Data by getting User Data by User Id and selecting its Entry Mode
* @param EntryMode Select Entry Mode. Available modes: FRIEND, INCOMING, OUTGOING, BLOCKED, SEARCH.
* @param UserId User Id needed to get User Data.
*/
void InitData(const EFriendEntryMode& EntryMode, const FString& UserId);
/**
* @brief Set user presence text block.
* @param FriendPresence Replace this value with available user presences.
*/
void SetPresenceText(const FString& FriendPresence) const;
/**
* @brief Enable or Disable Add Friend button for search entry.
* @param bEnable Value to enable or disable the button.
*/
void EnableAddFriendButton(bool bEnable) const;
private:
// Friend Entry Type
/**
* @brief Button for Chat Friend.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Chat;
/**
* @brief Button for Invite Friend to Party.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_InviteParty;
/**
* @brief Button for Unfriend.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Unfriend;
/**
* @brief Button for Block Friend.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Block;
// Block Entry Type
/**
* @brief Button to Unblock User.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Unblock;
// Incoming Entry Type
/**
* @brief Button for Accepting Friend Request.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Accept;
/**
* @brief Button for Decline Friend Request.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Decline;
/**
* @brief Button for Block User by Incoming Request.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Block_Request;
// Outgoing Entry Type
/**
* @brief Button for canceling outgoing friend request.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_CancelRequest;
// Search Entry Type
/**
* @brief Button for Add Friend.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_AddFriend;
/**
* @brief Text Box for Friend Name (Will be replaced with friend name).
*/
UPROPERTY(meta = (BindWidget))
UTextBlock* Tb_FriendName;
/**
* @brief Text Box for Friend Status e.g., Online, Offline, or Away.
*/
UPROPERTY(meta = (BindWidget))
UTextBlock* Tb_Status;
/**
* @brief Widget Switcher to switch Entry Mode.
*/
UPROPERTY(meta = (BindWidget))
UWidgetSwitcher* Ws_EntryMode;
/**
* @brief Scale Box for User Image.
*/
UPROPERTY(meta = (BindWidget))
UScaleBox* Sb_Friend;
// Horizontal Boxes for Widget Switcher.
/**
* @brief Horizontal Box for Friend component.
*/
UPROPERTY(meta = (BindWidget))
UHorizontalBox* Hb_Friend;
/**
* @brief Horizontal Box for Incoming component.
*/
UPROPERTY(meta = (BindWidget))
UHorizontalBox* Hb_IncomingRequest;
/**
* @brief Horizontal Box for Outgoing component.
*/
UPROPERTY(meta = (BindWidget))
UHorizontalBox* Hb_OutgoingRequest;
/**
* @brief Horizontal Box for Blocked component.
*/
UPROPERTY(meta = (BindWidget))
UHorizontalBox* Hb_Blocked;
/**
* @brief Horizontal Box for Search component.
*/
UPROPERTY(meta = (BindWidget))
UHorizontalBox* Hb_Search;
/**
* @brief Functionality for Chat Button.
*/
UFUNCTION()
void OnClickedChat();
/**
* @brief Functionality for Invite Party Button.
*/
UFUNCTION()
void OnClickedInviteParty();
/**
* @brief Functionality for Unfriend Button.
*/
UFUNCTION()
void OnClickedUnfriend();
/**
* @brief Functionality for Block Friend Button.
*/
UFUNCTION()
void OnClickedBlock();
/**
* @brief Callback for Clicking Unblock button.
*/
UFUNCTION()
void OnClickedUnblock();
/**
* @brief Callback for Accept Button.
*/
UFUNCTION()
void OnClickedAccept();
/**
* @brief Callback for Decline Button.
*/
UFUNCTION()
void OnClickedDecline();
/**
* @brief Click callback to cancel request.
*/
UFUNCTION()
void OnClickedCancelRequest();
/**
* @brief Functionality for Add Friend Button.
*/
UFUNCTION()
void OnClickedAdd();
/**
* @brief Callback for successfully get the user ID.
*/
void OnSuccessGetUserId(const FSimpleUserData& Data);
/**
* @brief Callback for failed getting user ID.
*/
void OnFailedGetUserId(int32 ErrorCode, const FString& ErrorMessage);
/**
* @brief Callback for Unfriend.
*/
void OnUnfriendResponse(const FAccelByteModelsUnfriendResponse& Result);
/**
* @brief Callback for Block.
*/
void OnBlockPlayerResponse(const FAccelByteModelsBlockPlayerResponse& Result);
/**
* @brief Callback for when successfully unblock user.
*/
void OnUnblockPlayerResponse(const FAccelByteModelsUnblockPlayerResponse& Result);
/**
* @brief Response for Accepting Friend Request.
*/
void OnAcceptFriendResponse(const FAccelByteModelsAcceptFriendsResponse& Result);
/**
* @brief Response for Rejecting Friend Request.
*/
void OnRejectFriendResponse(const FAccelByteModelsRejectFriendsResponse& Result);
/**
* @brief Response for Friend Request.
*/
void OnRequestFriendResponse(const FAccelByteModelsRequestFriendsResponse& Result);
/**
* @brief Set Mode settings for selected entry enumerator.
*/
void SetEntryMode(const EFriendEntryMode& EntryMode) const;
public:
/**
* @brief Models to store User Data contained in this entry.
*/
FSimpleUserData UserData;
};
AccelByteFriendEntry.cpp
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#include "AccelByteFriendEntry.h"
#include "../Party/AccelByteParty.h"
// AccelByte Services
#include "Api/AccelByteLobbyApi.h"
#include "Api/AccelByteUserApi.h"
#include "Core/AccelByteRegistry.h"
// Widget Components
#include "Components/Button.h"
#include "Components/TextBlock.h"
#include "Components/WidgetSwitcher.h"
#include "Components/Image.h"
#include "Components/ScaleBox.h"
#include "Components/HorizontalBox.h"
// Menu HUD
#include "TutorialProject/TutorialMenuHUD.h"
void UAccelByteFriendEntry::InitData(const EFriendEntryMode& EntryMode, const FString& UserId)
{
FRegistry::User.GetUserByUserId(
UserId,
THandler<FSimpleUserData>::CreateUObject(this, &UAccelByteFriendEntry::OnSuccessGetUserId),
FErrorHandler::CreateUObject(this, &UAccelByteFriendEntry::OnFailedGetUserId));
SetEntryMode(EntryMode);
}
void UAccelByteFriendEntry::EnableAddFriendButton(bool bEnable) const
{
Btn_AddFriend->SetIsEnabled(bEnable);
}
void UAccelByteFriendEntry::OnClickedChat()
{
}
void UAccelByteFriendEntry::OnClickedInviteParty()
{
Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD())->GetPartyMenu()->OnClickedInviteParty(UserData.UserId);
}
void UAccelByteFriendEntry::OnClickedUnfriend()
{
FRegistry::Lobby.SetUnfriendResponseDelegate(Api::Lobby::FUnfriendResponse::CreateUObject(this, & UAccelByteFriendEntry::OnUnfriendResponse));
FRegistry::Lobby.Unfriend(UserData.UserId);
}
void UAccelByteFriendEntry::OnClickedBlock()
{
FRegistry::Lobby.SetBlockPlayerResponseDelegate(Api::Lobby::FBlockPlayerResponse::CreateUObject(this, &UAccelByteFriendEntry::OnBlockPlayerResponse));
FRegistry::Lobby.BlockPlayer(UserData.UserId);
}
void UAccelByteFriendEntry::OnClickedUnblock()
{
FRegistry::Lobby.SetUnblockPlayerResponseDelegate(Api::Lobby::FUnblockPlayerResponse::CreateUObject(this, &UAccelByteFriendEntry::OnUnblockPlayerResponse));
FRegistry::Lobby.UnblockPlayer(UserData.UserId);
}
void UAccelByteFriendEntry::OnClickedAccept()
{
FRegistry::Lobby.SetAcceptFriendsResponseDelegate(Api::Lobby::FAcceptFriendsResponse::CreateUObject(this, &UAccelByteFriendEntry::OnAcceptFriendResponse));
FRegistry::Lobby.AcceptFriend(UserData.UserId);
}
void UAccelByteFriendEntry::OnClickedDecline()
{
FRegistry::Lobby.SetRejectFriendsResponseDelegate(Api::Lobby::FRejectFriendsResponse::CreateUObject(this, &UAccelByteFriendEntry::OnRejectFriendResponse));
FRegistry::Lobby.RejectFriend(UserData.UserId);
}
void UAccelByteFriendEntry::OnClickedCancelRequest()
{
FRegistry::Lobby.CancelFriendRequest(UserData.UserId);
this->RemoveFromParent();
}
void UAccelByteFriendEntry::OnClickedAdd()
{
FRegistry::Lobby.SetRequestFriendsResponseDelegate(Api::Lobby::FRequestFriendsResponse::CreateUObject(this, &UAccelByteFriendEntry::OnRequestFriendResponse));
FRegistry::Lobby.RequestFriend(UserData.UserId);
Btn_AddFriend->SetIsEnabled(false);
}
void UAccelByteFriendEntry::OnSuccessGetUserId(const FSimpleUserData& Data)
{
UserData = Data;
Tb_FriendName->SetText(FText::FromString(UserData.DisplayName));
}
void UAccelByteFriendEntry::OnFailedGetUserId(int32 ErrorCode, const FString& ErrorMessage)
{
const FString DebugMessage = FString::Printf(TEXT("Get User Id Failed : %d , %s"), ErrorCode, *ErrorMessage);
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Cyan, DebugMessage);
UE_LOG(LogTemp, Warning, TEXT(" Get User Id Failed : Code: %d, Reason: %s"), ErrorCode, *ErrorMessage);
}
void UAccelByteFriendEntry::OnUnfriendResponse(const FAccelByteModelsUnfriendResponse& Result)
{
if (Result.Code == "0")
{
UE_LOG(LogTemp, Log, TEXT("Successfully unfriend a friend!"));
this->RemoveFromParent();
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Failed to unfriend a friend! Code: %s"), *Result.Code);
}
}
void UAccelByteFriendEntry::OnBlockPlayerResponse(const FAccelByteModelsBlockPlayerResponse& Result)
{
if (Result.Code == "0")
{
UE_LOG(LogTemp, Log, TEXT("Successfully block a friend!"));
this->RemoveFromParent();
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Failed to block a friend! Code: %s"), *Result.Code);
}
}
void UAccelByteFriendEntry::OnUnblockPlayerResponse(const FAccelByteModelsUnblockPlayerResponse& Result)
{
if (Result.Code == "0")
{
UE_LOG(LogTemp, Log, TEXT("Successfully Unblock User!"));
this->RemoveFromParent();
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Cannot retrieve the list of outgoing/pending friend request!"));
}
}
void UAccelByteFriendEntry::OnAcceptFriendResponse(const FAccelByteModelsAcceptFriendsResponse& Result)
{
if (Result.Code == "0")
{
UE_LOG(LogTemp, Log, TEXT("Successfully accept a friend request!"));
this->RemoveFromParent();
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Failed to accept a friend request! Code: %s"), *Result.Code);
}
}
void UAccelByteFriendEntry::OnRejectFriendResponse(const FAccelByteModelsRejectFriendsResponse& Result)
{
if (Result.Code == "0")
{
UE_LOG(LogTemp, Log, TEXT("Successfully reject a friend request!"));
this->RemoveFromParent();
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Failed to reject a friend request! Code: %s"), *Result.Code);
}
}
void UAccelByteFriendEntry::OnRequestFriendResponse(const FAccelByteModelsRequestFriendsResponse& Result)
{
if (Result.Code == "0")
{
UE_LOG(LogTemp, Log, TEXT("Successfully send a friend request!"));
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Failed to send a friend request! Code: %s"), *Result.Code);
}
}
void UAccelByteFriendEntry::SetEntryMode(const EFriendEntryMode& EntryMode) const
{
switch(EntryMode)
{
case EFriendEntryMode::FRIEND_ENTRY:
Sb_Friend->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
Tb_Status->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
Ws_EntryMode->SetActiveWidget(Hb_Friend);
Btn_Chat->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedChat);
Btn_InviteParty->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedInviteParty);
Btn_Unfriend->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedUnfriend);
Btn_Block->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedBlock);
return;
case EFriendEntryMode::INCOMING_ENTRY:
Sb_Friend->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
Tb_Status->SetVisibility(ESlateVisibility::Collapsed);
Ws_EntryMode->SetActiveWidget(Hb_IncomingRequest);
Btn_Accept->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedAccept);
Btn_Decline->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedDecline);
Btn_Block_Request->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedBlock);
return;
case EFriendEntryMode::OUTGOING_ENTRY:
Sb_Friend->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
Tb_Status->SetVisibility(ESlateVisibility::Collapsed);
Ws_EntryMode->SetActiveWidget(Hb_OutgoingRequest);
Btn_CancelRequest->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedCancelRequest);
return;
case EFriendEntryMode::BLOCKED_ENTRY:
Sb_Friend->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
Tb_Status->SetVisibility(ESlateVisibility::Collapsed);
Ws_EntryMode->SetActiveWidget(Hb_Blocked);
Btn_Unblock->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedUnblock);
return;
case EFriendEntryMode::SEARCH_ENTRY:
Sb_Friend->SetVisibility(ESlateVisibility::Collapsed);
Tb_Status->SetVisibility(ESlateVisibility::Collapsed);
Ws_EntryMode->SetActiveWidget(Hb_Search);
Btn_AddFriend->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedAdd);
return;
// FRIEND_ENTRY Default Entry Mode.
default:
Sb_Friend->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
Tb_Status->SetVisibility(ESlateVisibility::Hidden);
Ws_EntryMode->SetActiveWidget(Hb_Friend);
Btn_Chat->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedChat);
Btn_InviteParty->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedInviteParty);
Btn_Unfriend->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedUnfriend);
Btn_Block->OnClicked.AddUniqueDynamic(this, &UAccelByteFriendEntry::OnClickedBlock);
}
}
AccelByteMainMenu.h
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "AccelByteMainMenu.generated.h"
class UButton;
class UTextBlock;
class USizeBox;
class ATutorialMenuHUD;
/**
* Main Menu controller.
*/
UCLASS()
class TUTORIALPROJECT_API UAccelByteMainMenu : public UUserWidget
{
GENERATED_BODY()
protected:
virtual void NativeConstruct() override;
/**
* @brief Button for Accessing Lobby Menu.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_Lobby;
/**
* @brief A Tutorial Menu HUD to handle all instantiating and casting to the HUD framework
*/
ATutorialMenuHUD* TutorialMenuHUD;
};
AccelByteMainMenu.cpp
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#include "AccelByteMainMenu.h"
#include "Authentication/AccelByteAuth.h"
#include "Components/Button.h"
#include "TutorialProject/TutorialMenuHUD.h"
void UAccelByteMainMenu::NativeConstruct()
{
Super::NativeConstruct();
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
check(TutorialMenuHUD);
Btn_Lobby->OnClicked.AddUniqueDynamic(TutorialMenuHUD, &ATutorialMenuHUD::OpenLobbyMenu);
}
TutorialMenuHUD.h
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "TutorialMenuHUD.generated.h"
class UAccelByteAuth;
class UAccelByteLobby;
class UAccelByteFriends;
class UAccelByteFindFriend;
/**
* Menu Widget Controller. All Widget functionality controlled here.
*/
UCLASS()
class TUTORIALPROJECT_API ATutorialMenuHUD : public AHUD
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
public:
/**
* @brief Shows Login Menu on screen
*/
void OpenLoginMenu();
/**
* @brief Shows Main Menu on screen and destroys Login Menu
*/
void OpenMainMenu();
/**
* @brief Init the construct function when the first time open main menu;
*/
void InitMainMenu();
/**
* @brief Shows Lobby Menu which adds Party Menu in Sb_Party and destroys Main Menu
*/
UFUNCTION()
void OpenLobbyMenu();
/**
* @brief Shows Friends Menu on screen
*/
void OpenFriendsMenu();
/**
* @brief Shows Find Friends Menu on screen
*/
void OpenFindFriendsMenu();
/**
* @brief Destroys Main Menu widget
*/
void CloseMainMenu();
/**
* @brief Destroys Lobby Menu widget and shows Main Menu
*/
UFUNCTION()
void CloseLobbyMenu();
/**
* @brief Destroys Friend Menu widget
*/
void CloseFriendMenu();
/**
* @brief Destroys Find Friend Menu widget
*/
void CloseFindFriendsMenu();
protected:
/**
* @brief Login Menu widget class
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteAuth> LoginMenuClass;
/**
* @brief Lobby Menu widget class
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteLobby> LobbyMenuClass;
/**
* @brief Main Menu widget class
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteMainMenu> MainMenuClass;
/**
* @brief Friends Menu widget class
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteFriends> FriendsMenuClass;
/**
* @brief Find Friends Menu widget class
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteFindFriend> FindFriendsMenuClass;
public:
/**
* @brief Getter for Login Menu widget
*/
UAccelByteAuth* GetLoginMenu() const {return LoginMenu; }
/**
* @brief Getter for Main Menu widget
*/
UAccelByteMainMenu* GetMainMenu() const {return MainMenu; }
/**
* @brief Getter for Lobby Menu widget
*/
UAccelByteLobby* GetLobbyMenu() const {return LobbyMenu; }
/**
* @brief Getter for Friends Menu widget
*/
UAccelByteFriends* GetFriendsMenu() const {return FriendsMenu; }
/**
* @brief Getter for Find Friends Menu widget
*/
UAccelByteFindFriend* GetFindFriendsMenu() const {return FindFriendsMenu; }
private:
/**
* @brief Login Menu widget pointer
*/
UPROPERTY()
UAccelByteAuth* LoginMenu;
/**
* @brief Lobby Menu widget pointer
*/
UPROPERTY()
UAccelByteLobby* LobbyMenu;
/**
* @brief Main Menu widget pointer
*/
UPROPERTY()
UAccelByteMainMenu* MainMenu;
/**
* @brief Friends Menu widget pointer
*/
UPROPERTY()
UAccelByteFriends* FriendsMenu;
/**
* @brief Find Friends Menu widget pointer
*/
UPROPERTY()
UAccelByteFindFriend* FindFriendsMenu;
};
TutorialMenuHUD.cpp
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#include "TutorialMenuHUD.h"
#include "AccelByte/Authentication/AccelByteAuth.h"
#include "AccelByte/Lobby/AccelByteLobby.h"
#include "AccelByte/AccelByteMainMenu.h"
#include "AccelByte/Friends/AccelbyteFindFriend.h"
#include "AccelByte/Friends/AccelByteFriends.h"
void ATutorialMenuHUD::BeginPlay()
{
Super::BeginPlay();
APlayerController* PlayerController = GetOwningPlayerController();
check(LoginMenuClass != nullptr);
check(MainMenuClass != nullptr);
check(LobbyMenuClass != nullptr);
check(FriendsMenuClass != nullptr);
check(FindFriendsMenuClass != nullptr);
LoginMenu = CreateWidget<UAccelByteAuth>(PlayerController, LoginMenuClass.Get());
MainMenu = CreateWidget<UAccelByteMainMenu>(PlayerController, MainMenuClass.Get());
LobbyMenu = CreateWidget<UAccelByteLobby>(PlayerController, LobbyMenuClass.Get());
FriendsMenu = CreateWidget<UAccelByteFriends>(PlayerController, FriendsMenuClass.Get());
FindFriendsMenu = CreateWidget<UAccelByteFindFriend>(PlayerController, FindFriendsMenuClass.Get());
}
void ATutorialMenuHUD::OpenLoginMenu()
{
LoginMenu->AddToViewport();
}
void ATutorialMenuHUD::OpenMainMenu()
{
MainMenu->AddToViewport();
}
void ATutorialMenuHUD::InitMainMenu()
{
// Add Lobby to Viewport and set its visibility as collapsed
LobbyMenu->AddToViewport();
LobbyMenu->ConnectToLobby();
LobbyMenu->SetVisibility(ESlateVisibility::Collapsed);
OpenMainMenu();
}
void ATutorialMenuHUD::OpenLobbyMenu()
{
LobbyMenu->SetVisibility(ESlateVisibility::Visible);
MainMenu->RemoveFromParent();
}
void ATutorialMenuHUD::OpenFriendsMenu()
{
if (!FriendsMenu->IsInViewport())
{
FriendsMenu->AddToViewport();
}
else
{
FriendsMenu->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
FriendsMenu->RefreshFriendsList();
}
}
void ATutorialMenuHUD::OpenFindFriendsMenu()
{
FindFriendsMenu->AddToViewport();
}
void ATutorialMenuHUD::CloseMainMenu()
{
LoginMenu->AddToViewport();
MainMenu->RemoveFromViewport();
LobbyMenu->RemoveFromParent();
}
void ATutorialMenuHUD::CloseFindFriendsMenu()
{
FindFriendsMenu->RemoveFromParent();
}
void ATutorialMenuHUD::CloseLobbyMenu()
{
MainMenu->AddToViewport();
LobbyMenu->SetVisibility(ESlateVisibility::Collapsed);
}
void ATutorialMenuHUD::CloseFriendMenu()
{
if (!LobbyMenu->IsInViewport())
{
LobbyMenu->AddToViewport();
}
FriendsMenu->SetVisibility(ESlateVisibility::Collapsed);
}
AccelByteLobby.h
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#pragma once
#include "CoreMinimal.h"
#include "AccelByteLobby.generated.h"
class ATutorialMenuHUD;
class UButton;
/**
* Component for joining the AccelByte Lobby.
* This code covers AccelByte services including:
*
* - Join Lobby
* - Leave Lobby
*/
UCLASS()
class TUTORIALPROJECT_API UAccelByteLobby : public UUserWidget
{
GENERATED_BODY()
#pragma region Initialization
protected:
virtual void NativeConstruct() override;
#pragma endregion
#pragma region Widget Components
protected:
/**
* @brief Button for Leave Lobby and back to Main Menu.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_LeaveLobby;
/**
* @brief Button for go to Friend Management Menu.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_FriendsManagement;
#pragma endregion
#pragma region Widget Callbacks
private:
/**
* @brief Button callback on Open Friends Management.
*/
UFUNCTION()
void OnClickedOpenFriendsManagement();
#pragma endregion
#pragma region Utilities
public:
/**
* @brief Connect to AccelByte lobby.
*/
UFUNCTION()
void ConnectToLobby();
/**
* @brief Set Lobby services notification delegates.
*/
void SetLobbyNotificationDelegate();
private:
/**
* @brief Tutorial Menu HUD pointer reference.
*/
UPROPERTY()
ATutorialMenuHUD* TutorialMenuHUD;
#pragma endregion
};
AccelByteLobby.cpp
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#include "AccelByteLobby.h"
#include "Api/AccelByteLobbyApi.h"
#include "Core/AccelByteRegistry.h"
#include "Components/Button.h"
#include "TutorialProject/TutorialMenuHUD.h"
#pragma region Initialization
void UAccelByteLobby::NativeConstruct()
{
Super::NativeConstruct();
check(GetOwningPlayer() != nullptr);
check(GetOwningPlayer()->GetHUD() != nullptr);
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
Btn_LeaveLobby->OnClicked.AddUniqueDynamic(TutorialMenuHUD, &ATutorialMenuHUD::CloseLobbyMenu);
Btn_FriendsManagement->OnClicked.AddUniqueDynamic(this, &UAccelByteLobby::OnClickedOpenFriendsManagement);
}
#pragma endregion
#pragma region Widget Callbacks
void UAccelByteLobby::OnClickedOpenFriendsManagement()
{
TutorialMenuHUD->OpenFriendsMenu();
}
#pragma endregion
#pragma region Utilities
void UAccelByteLobby::ConnectToLobby()
{
SetLobbyNotificationDelegate();
FRegistry::Lobby.Connect();
}
void UAccelByteLobby::SetLobbyNotificationDelegate()
{
FRegistry::Lobby.SetConnectSuccessDelegate(FSimpleDelegate::CreateWeakLambda(this, [this]()
{
UE_LOG(LogTemp, Log, TEXT("Successfully Connected to Lobby"));
}));
FRegistry::Lobby.SetConnectFailedDelegate(FErrorHandler::CreateWeakLambda(this, [](int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Error, TEXT("Failed Connect to Lobby : Code: %d; Message: %s"), Code, *Message);
}));
FRegistry::Lobby.SetErrorNotifDelegate(FErrorHandler::CreateWeakLambda(this, [](int32 Code, const FString& Message)
{
UE_LOG(LogTemp, Error, TEXT("Error Connect to Lobby : Code: %d; Message: %s"), Code, *Message);
}));
FRegistry::Lobby.SetConnectionClosedDelegate(Api::Lobby::FConnectionClosed::CreateWeakLambda(this, [this](int32 StatusCode, const FString& Reason, bool bWasClean)
{
UE_LOG(LogTemp, Error, TEXT("Connection Closed, Code: %d Reason: %s Clean: %s"), StatusCode, *Reason, bWasClean ? TEXT("true") : TEXT("false"));
}));
FRegistry::Lobby.SetDisconnectNotifDelegate(Api::Lobby::FDisconnectNotif::CreateWeakLambda(this, [this](const FAccelByteModelsDisconnectNotif& Result)
{
UE_LOG(LogTemp, Log, TEXT("Disconnected from Lobby"));
}));
}
#pragma endregion
AccelByteAuth.cpp
// Copyright (c) 2024 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
#include "AccelByteAuth.h"
#include "Api/AccelByteUserApi.h"
#include "Core/AccelByteRegistry.h"
#include "Components/Button.h"
#include "Components/EditableTextBox.h"
#include "Components/TextBlock.h"
#include "TutorialProject/TutorialMenuHUD.h"
void UAccelByteAuth::NativeConstruct()
{
Super::NativeConstruct();
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetWorld()->GetFirstPlayerController()->GetHUD());
UE_LOG(LogTemp, Log, TEXT("Login with Username"));
T_LoginStatus->SetText(FText::FromString("Please Login"));
Btn_Login->OnClicked.AddUniqueDynamic(this, &UAccelByteAuth::OnLoginButtonClicked);
}
void UAccelByteAuth::OnLoginButtonClicked()
{
T_LoginStatus->SetText(FText::FromString("Logging in..."));
FRegistry::User.LoginWithUsername(
Etb_Username->GetText().ToString(),
Etb_Password->GetText().ToString(),
FVoidHandler::CreateUObject(this, &UAccelByteAuth::LoginSuccess),
FCustomErrorHandler::CreateUObject(this, &UAccelByteAuth::LoginFailed));
}
void UAccelByteAuth::OnLogoutButtonClicked()
{
FRegistry::User.Logout(
FVoidHandler::CreateUObject(this, &UAccelByteAuth::LogoutSuccess),
FErrorHandler::CreateUObject(this, &UAccelByteAuth::LogoutFailed));
if (FRegistry::Lobby.IsConnected())
{
FRegistry::Lobby.Disconnect();
}
}
void UAccelByteAuth::LoginSuccess()
{
UE_LOG(LogTemp, Log, TEXT("Login Success"));
T_LoginStatus->SetText(FText::FromString("Login successful"));
if(GetOwningPlayer() && GetOwningPlayer()->GetHUD())
{
TutorialMenuHUD->InitMainMenu();
this->RemoveFromParent();
}
}
void UAccelByteAuth::LoginFailed(int32 ErrorCode, const FString& ErrorMessage, const FJsonObject& ErrorJson)
{
UE_LOG(LogTemp, Error, TEXT("Login Failed : %d , %s"), ErrorCode, *ErrorMessage);
T_LoginStatus->SetText(FText::FromString(FString::Printf(TEXT("Login Failed : %d , %s"), ErrorCode, *ErrorMessage)));
}
void UAccelByteAuth::LogoutSuccess()
{
UE_LOG(LogTemp, Log, TEXT("Logout Success"));
if (TutorialMenuHUD == nullptr)
{
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
}
ensure(TutorialMenuHUD != nullptr);
TutorialMenuHUD->CloseMainMenu();
}
void UAccelByteAuth::LogoutFailed(int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Logout Failed : %d , %s"), ErrorCode, *ErrorMessage);
}