Unreal Engine SDK を使用してパーティサービスを実装する
Introduction
This topic is specific to the AccelByte Gaming Services (AGS) Shared Cloud tier.
The Party service is part of the AGS that allows you to create a Party with other players. This service is described in detail in the Party documentation.
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 and Friends services. Please make sure a player can successfully connect to the Lobby and invite their friends before proceeding with this guide.
Lobby has two function types:
- Response delegate: The delegate accesses the result response from the SDK's functions. Not necessary, but, if used, must be defined before calling 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.
Since party implementation can vary for each game, you can familiarize yourself with other concepts and classes in the AccelByteLobbyModels
header file inside the plugin SDK. For some implementations, you don't even need to implement the Friends service first, since party invitations only require user IDs.
Quick reference
References
#include "Api/AccelByteLobbyApi.h"
#include "Core/AccelByteRegistry.h"
#include "Models/AccelByteLobbyModels.h"
Party notification events
FRegistry::Lobby.SetPartyGetInvitedNotifDelegate(Api::Lobby::FPartyGetInvitedNotif::CreateWeakLambda(this, [](const FAccelByteModelsPartyGetInvitedNotice& Result)
{
// On get invited to a party
}));
FRegistry::Lobby.SetPartyKickNotifDelegate(Api::Lobby::FPartyKickNotif::CreateWeakLambda(this, [](const FAccelByteModelsGotKickedFromPartyNotice& Result)
{
// On player kicked from party
}));
FRegistry::Lobby.SetPartyMemberLeaveNotifDelegate(Api::Lobby::FPartyMemberLeaveNotif::CreateWeakLambda(this, [](const FAccelByteModelsLeavePartyNotice& Result)
{
// On a member left the party
}));
FRegistry::Lobby.SetPartyJoinNotifDelegate(Api::Lobby::FPartyJoinNotif::CreateWeakLambda(this, [](const FAccelByteModelsPartyJoinNotice& Result)
{
// On party join
}));
FRegistry::Lobby.SetPartyInvitationRejectedNotifDelegate(Api::Lobby::FPartyRejectNotif::CreateWeakLambda(this, [](const FAccelByteModelsPartyRejectNotice& Result)
{
// On party invitation rejected
}));
FRegistry::Lobby.SetPartyDataUpdateNotifDelegate(Api::Lobby::FPartyDataUpdateNotif::CreateWeakLambda(this, [](const FAccelByteModelsPartyDataNotif& Result)
{
// On party data update
}));
FRegistry::Lobby.SetPartyMemberConnectNotifDelegate(Api::Lobby::FPartyMemberConnectNotif::CreateWeakLambda(this, [](const FAccelByteModelsPartyMemberConnectionNotice& Result)
{
// On party member reconnecting to the lobby
}));
FRegistry::Lobby.SetPartyMemberDisconnectNotifDelegate(Api::Lobby::FPartyMemberDisconnectNotif::CreateWeakLambda(this, [](const FAccelByteModelsPartyMemberConnectionNotice& Result)
{
// On party member disconnected from the lobby
}));
Create Party
FRegistry::Lobby.SetCreatePartyResponseDelegate(
Api::Lobby::FPartyCreateResponse::CreateWeakLambda(this, [](const FAccelByteModelsCreatePartyResponse Result)
{
UE_LOG(LogTemp, Log, TEXT("Create Party Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Create Party Error! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendCreatePartyRequest();
Invite to Party
FRegistry::Lobby.SetInvitePartyResponseDelegate(
Api::Lobby::FPartyInviteResponse::CreateWeakLambda(this, [](const FAccelByteModelsPartyInviteResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Invite Party Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Log, TEXT("Invite Party Failed! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendInviteToPartyRequest("DesiredUserId");
Leave Party
FRegistry::Lobby.SetLeavePartyResponseDelegate(
Api::Lobby::FPartyLeaveResponse::CreateWeakLambda(this, [](const FAccelByteModelsLeavePartyResponse& Result)
{
UE_LOG(LogTemp, Error, TEXT("Leave Party Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Log, TEXT("Leave Party Failed! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendLeavePartyRequest();
Promote to Party leader
FRegistry::Lobby.SetPartyPromoteLeaderResponseDelegate(
Api::Lobby::FPartyPromoteLeaderResponse::CreateWeakLambda(this, [](const FAccelByteModelsPartyPromoteLeaderResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Promote Party Leader Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Promote Party Leader Failed! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendPartyPromoteLeaderRequest("MemberUserId");
Kick from Party
FRegistry::Lobby.SetInvitePartyKickMemberResponseDelegate(
Api::Lobby::FPartyKickResponse::CreateWeakLambda(this, [](const FAccelByteModelsKickPartyMemberResponse& result)
{
UE_LOG(LogTemp, Log, TEXT("Kick Party Member Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Kick Party Member Failed! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendKickPartyMemberRequest("MemberUserId");
Join Party
FRegistry::Lobby.SetInvitePartyJoinResponseDelegate(
Api::Lobby::FPartyJoinResponse::CreateWeakLambda(this, [](const FAccelByteModelsPartyJoinResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Accept Party Success! Member : %d"), Result.Members.Num());
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Accept Party Error! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendAcceptInvitationRequest("DesiredPartyId", "PartyInvitationToken");
Reject Party invitation
FRegistry::Lobby.SetInvitePartyRejectResponseDelegate(
Api::Lobby::FPartyRejectResponse::CreateWeakLambda(this, [](const FAccelByteModelsPartyRejectResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Reject Party Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Reject Party Error! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendRejectInvitationRequest("DesiredPartyId", "PartyInvitationToken");
Get current Party info
FRegistry::Lobby.SendInfoPartyRequest(
Api::Lobby::FPartyInfoResponse::CreateWeakLambda(this, [](const FAccelByteModelsInfoPartyResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Get Current party info success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Get current party info Error! %d: %s"), ErrorCode, *ErrorMessage);
}));
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
Create a party implementation
Follow the steps below to get started:
Set the Maximum Party Member value and Auto kick on disconnect features from Party Configurations in the Admin Portal.
Create a User Widget C++ class called
AccelByteParty
to accommodate the functions for the Party Menu widget.Add the following header to ensure the functions work correctly for the Lobby services:
.cpp
...
#include "Api/AccelByteLobbyApi.h"
#include "Core/AccelByteRegistry.h"
...Add some basic Party functions in the
AccelByteParty
class so you can call these later from your widgets:
Create a Party
This function returns a result from the FAccelByteModelsCreatePartyResponse
class type which contains Party data such as:
PartyId
LeaderId
, the leader'suserId
- Members, array of the party members'
userIds
- Invitees, array of the invitees'
userIds
InvitationToken
, the party invitation's token
- .cpp
- h
void UAccelByteParty::OnClickedCreateParty()
{
FRegistry::Lobby.SetCreatePartyResponseDelegate(
Api::Lobby::FPartyCreateResponse::CreateWeakLambda(this, [](const FAccelByteModelsCreatePartyResponse Result)
{
UE_LOG(LogTemp, Log, TEXT("Create Party Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Create Party Error! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendCreatePartyRequest();
}
/**
* @brief Callback when creating Party.
*/
UFUNCTION()
void OnClickedCreateParty();
Invite friend to a Party
To send an invitation, you need the UserID
of the player you want to invite, so add inviteeUserId
as the function's parameter. Other party members can also invite people to the party.
- .cpp
- h
void UAccelByteParty::OnClickedInviteParty()
{
FRegistry::Lobby.SetInvitePartyResponseDelegate(
Api::Lobby::FPartyInviteResponse::CreateWeakLambda(this, [](const FAccelByteModelsPartyInviteResponse Result)
{
UE_LOG(LogTemp, Log, TEXT("Invite Party Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Log, TEXT("Invite Party Failed! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendInviteToPartyRequest("DesiredUserId");
}
/**
* @brief Callback when inviting to Party.
* @param UserId user ID to invited.
*/
UFUNCTION()
void OnClickedInviteParty(const FString& UserId);
Leave a Party
Use this function to leave a Party.
- .cpp
- h
void UAccelByteParty::OnClickedLeaveParty()
{
FRegistry::Lobby.SetLeavePartyResponseDelegate(
Api::Lobby::FPartyLeaveResponse::CreateWeakLambda(this, [](FAccelByteModelsLeavePartyResponse Result)
{
UE_LOG(LogTemp, Error, TEXT("Leave Party Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Log, TEXT("Leave Party Failed! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendLeavePartyRequest();
}
/**
* @brief Callback when leaving Party.
*/
UFUNCTION()
void OnClickedLeaveParty();
Promote a friend to Party leader
You need the UserID
of the Party member you want to promote to Party leader.
- .cpp
- h
void UAccelByteParty::OnClickedPartyLeader()
{
FRegistry::Lobby.SetPartyPromoteLeaderResponseDelegate(
Api::Lobby::FPartyPromoteLeaderResponse::CreateWeakLambda(this, [](const FAccelByteModelsPartyPromoteLeaderResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Promote Party Leader Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Promote Party Leader Failed! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendPartyPromoteLeaderRequest("MemberUserId");
}
/**
* @brief Callback for OnClicked Party Leader Button.
*/
UFUNCTION()
void OnClickedPartyLeader();
Kick a friend from a Party
You need the UserID
of the Party member you want to kick from the Party.
- .cpp
- h
void UAccelByteParty::OnClickedKickParty()
{
FRegistry::Lobby.SetInvitePartyKickMemberResponseDelegate(
Api::Lobby::FPartyKickResponse::CreateWeakLambda(this, [](FAccelByteModelsKickPartyMemberResponse result)
{
UE_LOG(LogTemp, Log, TEXT("Kick Party Member Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Kick Party Member Failed! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendKickPartyMemberRequest("MemberUserId");
}
```csharp
/**
* @brief Callback for OnClicked Kick Party.
*/
UFUNCTION()
void OnClickedKickParty();
```
Most of the Party Invitation UIs will be spawnable widgets. Create a new user widget class called
AccelBytePartyInvitationPopUp
and add the following header on the top:.cpp
...
#include "Api/AccelByteLobbyApi.h"
#include "Core/AccelByteRegistry.h"
...This class will hold functions that handle events related to the Party Invitation. You can parent this class to your Party Invitation widget later on.
Add the following functions to handle party invitations in the
AccelBytePartyInvitationPopUp
class:
Handle Party invitations
Accept Party invitation (join Party)
This function requires partyId
and invitationToken
which are contained in a PartyInvitation
object.
- .cpp
- h
void UAccelBytePartyInvitationPopUp::OnClickedAcceptPartyInvitation()
{
FRegistry::Lobby.SetInvitePartyJoinResponseDelegate(
Api::Lobby::FPartyJoinResponse::CreateWeakLambda(this, [](const FAccelByteModelsPartyJoinResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Accept Party Success! Member : %d"), Result.Members.Num());
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Accept Party Error! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendAcceptInvitationRequest("DesiredPartyId", "PartyInvitationToken");
}
/**
* @brief Callback for accepting Party invitation.
*/
UFUNCTION()
void OnClickedAcceptPartyInvitation();
Reject Party invitation
This function requires partyId
and invitationToken
which are contained in a PartyInvitation
object.
- .cpp
- h
void UAccelBytePartyInvitationPopUp::OnClickedRejectPartyInvitation()
{
FRegistry::Lobby.SetInvitePartyRejectResponseDelegate(
Api::Lobby::FPartyRejectResponse::CreateWeakLambda(this, [](const FAccelByteModelsPartyRejectResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Reject Party Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Reject Party Error! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendRejectInvitationRequest("DesiredPartyId", "PartyInvitationToken");
}
/**
* @brief Callback for rejecting Party invitation.
*/
UFUNCTION()
void OnClickedRejectPartyInvitation();
Use the result value from the
Lobby.SetPartyGetInvitedNotifDelegate()
event for theFAccelByteModelsPartyGetInvitedNotice
value.To send a notification to a player on any activity related to the current party, go back to the
AccelByteParty
class and create a new function to get all Party Notification Events with Lobby service.Add a log for each event:
- .cpp
- h
void UAccelByteParty::SetNotificationDelegate()
{
FRegistry::Lobby.SetPartyGetInvitedNotifDelegate(Api::Lobby::FPartyGetInvitedNotif::CreateWeakLambda(this, [](const FAccelByteModelsPartyGetInvitedNotice& Result)
{
UE_LOG(LogTemp, Log, TEXT("On Get Invite to Party Notice!"));
}));
FRegistry::Lobby.SetPartyKickNotifDelegate(Api::Lobby::FPartyKickNotif::CreateWeakLambda(this, [](const FAccelByteModelsGotKickedFromPartyNotice& Result)
{
UE_LOG(LogTemp, Log, TEXT("You have been kicked from the party!"));
}));
FRegistry::Lobby.SetPartyMemberLeaveNotifDelegate(Api::Lobby::FPartyMemberLeaveNotif::CreateWeakLambda(this, [](const FAccelByteModelsLeavePartyNotice& Result)
{
UE_LOG(LogTemp, Log, TEXT("On a member left the party!"));
}));
FRegistry::Lobby.SetPartyMemberConnectNotifDelegate(Api::Lobby::FPartyMemberConnectNotif::CreateWeakLambda(this, [](const FAccelByteModelsPartyMemberConnectionNotice& Result)
{
UE_LOG(LogTemp, Log, TEXT("On a member reconnect to the party!"));
}));
FRegistry::Lobby.SetPartyMemberDisconnectNotifDelegate(Api::Lobby::FPartyMemberDisconnectNotif::CreateWeakLambda(this, [](const FAccelByteModelsPartyMemberConnectionNotice& Result)
{
UE_LOG(LogTemp, Log, TEXT("On a member disconnected from the party!"));
}));
}
/**
* @brief Function where all the notifications are being set.
*/
void SetNotificationDelegate();
You may wish to retrieve Party data. There are a few ways you can do this:
SetPartyDataUpdateNotifDelegate()
Add this lobby's notification event to retrieve Party data every time the data is updated. This will return a result with the class type
FAccelByteModelsPartyDataNotif
and contain data such as:PartyId
: the current player's Party ID.Namespace: the current project's namespace.
Leader: the party leader's user ID.
Members: a list of the party members' user IDs.
Invitees: a list of the invited players' user IDs.
Custom_attribute,
FJsonObjectWrapper
: holds custom information.UpdatedAt
: timestamp of the party data update..cpp
void UAccelByteParty::SetNotificationDelegate()
{
...
FRegistry::Lobby.SetPartyDataUpdateNotifDelegate(Api::Lobby::FPartyDataUpdateNotif::CreateWeakLambda(this, [](const FAccelByteModelsPartyDataNotif& Result)
{
UE_LOG(LogTemp, Log, TEXT("On any party data update"));
}));
}SendInfoPartyRequest()
You can also retrieve Party data using the
SendInfoPartyRequest()
function. This will return a result with the class typeFAccelByteModelsInfoPartyResponse
and contain data such as:PartyID
: the Party's unique ID.LeaderID
: the Party leader's user ID.- Members (
userIDs
): a list of the Party members' user IDs. - Invitees (
userIDs
): a list of the invited players' user IDs. InvitationToken
: the token of the latest Party invitation sent.
.cpp
FRegistry::Lobby.SendInfoPartyRequest(Api::Lobby::FPartyInfoResponse::CreateWeakLambda(this, [](const FAccelByteModelsInfoPartyResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Get information about current party success"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Log, TEXT("Get information about current party failed"));
}));You may wish to unbind Party services. You can do this with the delegates
UnbindPartyNotifEvents
andUnbindPartyResponseEvents
..cpp
...
FRegistry::Lobby.UnbindPartyNotifEvents();
FRegistry::Lobby.UnbindPartyResponseEvents();
...After you call this code, you need to resubscribe all the notification and response delegates in both party services.
Congratulations! You have successfully learned how to use the Party service.
Step-by-Step guide
Implement the UI
Create a widget blueprint class called
WB_Party
and re-parent theWB_Party
widget blueprint to theAccelByteParty
C++ class.Add the following objects to the Party widget blueprint:
- Text box for Party Id.
- Button to create a party.
- Any box for the party members list.
- Button to leave the party.
To display a Party member's information, create a widget blueprint class called
WB_PartyPlayerEntry
.Add the following objects to the
WB_PartyPlayerEntry
widget blueprint:- Text box to display the player's username.
- Button to promote a party leader.
- Button to kick a player from the party.
- Image for the party leader icon.
To send a Party invitation, you will need a spawnable widget.
Create a widget blueprint class called
WB_InvitationParty
.Re-parent the
WB_InvitationParty
widget blueprint to theAccelBytePartyInvitationPopUp
C++ class.Add the following objects to the Party Invitation PopUp widget blueprint:
- Text box for invitation text.
- Button to accept the party invitation.
- Button to reject the party invitation.
To prepare the Notification Box widget, start by creating a new widget blueprint class called
WB_LobbyNotificationEntry
.Add a text box for the notification text to the
WB_LobbyNotificationEntry
widget blueprint.Create another widget blueprint class called
WB_Notification
.Add the following objects to the
WB_Notification
widget blueprint:- Text box for the subheader text.
- List view to add the Lobby Notification entry dynamically.
注記Don't forget to set the Entry Widget Class under the List Entries component with
WB_LobbyNotificationEntry
.Since the Party service is part of the Lobby Menu in this example, add the following object components in
WB_LobbyMenu
:- Scroll box to add the
WB_PartyMenu
. - Border for the Notification Box widget blueprint to display the notification update to players.
- Scroll box to add the
Implement the code
Tutorial menu HUD
Before you move on, prepare all of the Party-related widgets so they are accessible to other classes via the TutorialMenuHUD
class.
Do this by adding all of the Party-related classes to the top of the
TutorialMenuHUD
class.- .cpp
- h
...
#include "AccelByte/Party/AccelByteParty.h"
......
class UAccelByteParty;
...Initialize the pointer to refer to the Party widget classes in the
BeginPlay()
function.- .cpp
- h
void ATutorialMenuHUD::BeginPlay()
{
...
check(PartyClass != nullptr);
...
PartyMenu = CreateWidget<UAccelByteParty>(PlayerController, PartyClass.Get());
...
}/**
* @brief Party Menu widget class
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteParty> PartyClass;
/**
* @brief Party Menu widget pointer
*/
UPROPERTY()
UAccelByteParty* PartyMenu;Add a getter function for the Party Menu widgets' pointer.
- h
/**
* @brief Getter for Party Menu widget
*/
UAccelByteParty* GetPartyMenu() const {return PartyMenu; }
Party's player entry
Create a user widget C++ class named
AccelBytePartyPlayerEntry
and set the class as the parent class of your Party Player Entry widget blueprint (in this case,WB_PartyPlayerEntry
).Open the
AccelBytePartyPlayerEntry
class and add the following to the the top of the class:- .cpp
- h
...
#include "AccelByteParty.h"
#include "Api/AccelByteLobbyApi.h"
#include "Api/AccelByteUserApi.h"
#include "Core/AccelByteRegistry.h"
#include "Components/Image.h"
#include "Components/TextBlock.h"
#include "Components/Button.h"
......
#include "Models/AccelByteLobbyModels.h"
#include "Models/AccelByteUserModels.h"
...
class UImage;
class UTextBlock;
class UButton;
...- Specify all the widget components in the
AccelBytePartyPlayerEntry
header file.
- h
/**
* @brief Image to display leader status.
*/
UPROPERTY(meta = (BindWidget))
UImage* Img_LeaderIcon;
/**
* @brief Text Box for Player Username.
*/
UPROPERTY(meta = (BindWidget))
UTextBlock* Tb_PlayerUsername;
/**
* @brief Button for Promoting Party Leader.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_PartyLeader;
/**
* @brief Button for Kick Party Member.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_KickPlayer;Create a variable called
UserData
to store the user data required by the Party functionalities. To getUserData
from other scripts, create a function that will return the variable.- .cpp
- h
FSimpleUserData UAccelBytePartyPlayerEntry::GetUserData() const
{
return UserData;
}/**
* @brief Get User Data stored in this entry.
*/
FSimpleUserData GetUserData() const;
/**
* @brief Models to store User Data contained in this entry.
*/
FSimpleUserData UserData;Move the
OnClickedPartyLeader()
function and theOnClickedKickParty()
function fromAccelByteParty
to theAccelBytePartyPlayerEntry
class.Once you have done that, modify both functions using
CreateUObject()
instead ofCreateWeakLambda()
for better readability.- .cpp
- h
void UAccelBytePartyPlayerEntry::OnClickedPartyLeader()
{
FRegistry::Lobby.SetPartyPromoteLeaderResponseDelegate(
Api::Lobby::FPartyPromoteLeaderResponse::CreateWeakLambda(this, [](const FAccelByteModelsPartyPromoteLeaderResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Promote Party Leader Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Promote Party Leader Failed! %d: %s"), ErrorCode, *ErrorMessage);
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Cyan, "Unable to Promote Party Leader!");
}));
FRegistry::Lobby.SendPartyPromoteLeaderRequest(UserData.UserId);
}
void UAccelBytePartyPlayerEntry::OnClickedKickParty()
{
FRegistry::Lobby.SetInvitePartyKickMemberResponseDelegate(
Api::Lobby::FPartyKickResponse::CreateWeakLambda(this, [](FAccelByteModelsKickPartyMemberResponse result)
{
UE_LOG(LogTemp, Log, TEXT("Kick Party Member Success!"));
}),
FErrorHandler::CreateWeakLambda(this, [](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Kick Party Member Failed! %d: %s"), ErrorCode, *ErrorMessage);
}));
FRegistry::Lobby.SendKickPartyMemberRequest(UserData.UserId);
}/**
* @brief Callback for OnClicked Party Leader Button.
*/
UFUNCTION()
void OnClickedPartyLeader();
/**
* @brief Callback for OnClicked Kick Party.
*/
UFUNCTION()
void OnClickedKickParty();- Add the
NativeConstruct()
override function and set up the button widgets to be called by their functions on the button clicked.
- .cpp
- h
void UAccelBytePartyPlayerEntry::NativeConstruct()
{
Super::NativeConstruct();
Btn_PartyLeader->OnClicked.AddUniqueDynamic(this, &UAccelBytePartyPlayerEntry::OnClickedPartyLeader);
Btn_KickPlayer->OnClicked.AddUniqueDynamic(this, &UAccelBytePartyPlayerEntry::OnClickedKickParty);
}...
virtual void NativeConstruct() override;Create a function to display the player's display name when the party's Player Entry initializes. Use the User SDK's
GetUserByUserId()
function to get the display name data.- .cpp
- h
void UAccelBytePartyPlayerEntry::InitData(const FString& PlayerId)
{
UserData.UserId = PlayerId;
FRegistry::User.GetUserByUserId(
PlayerId,
THandler<FSimpleUserData>::CreateUObject(this, &UAccelBytePartyPlayerEntry::OnSuccessGetUserId),
FErrorHandler::CreateUObject(this, &UAccelBytePartyPlayerEntry::OnFailedGetUserId));
}/**
* @brief Initialize User ID and converted to FSimpleUserData in here.
*/
void InitData(const FString& PlayerId);
/**
* @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);Define what to do after the
GetUserByUserId()
query result is received in both of the response functions you declared earlier.- .cpp
void UAccelBytePartyPlayerEntry::OnSuccessGetUserId(const FSimpleUserData& Data)
{
UserData = Data;
Tb_PlayerUsername->SetText(FText::FromString(UserData.DisplayName));
}
void UAccelBytePartyPlayerEntry::OnFailedGetUserId(int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Get User Id Failed : %d , %s"), ErrorCode, *ErrorMessage);
}Create a function to enable visibility of the Promote Leader and Kick Party Member buttons if the player is the party leader.
- .cpp
- h
void UAccelBytePartyPlayerEntry::EnableAllComponents(bool bIsEnable) const
{
if (bEnable)
{
Btn_KickPlayer->SetVisibility(ESlateVisibility::Visible);
Btn_PartyLeader->SetVisibility(ESlateVisibility::Visible);
}
else
{
Btn_KickPlayer->SetVisibility(ESlateVisibility::Hidden);
Btn_PartyLeader->SetVisibility(ESlateVisibility::Hidden);
}
}/**
* @brief Enabling button Promote Leader and Kick Party member.
* @param bEnable Enable all button components.
*/
void EnableAllComponents(bool bIsEnable) const;Create a function that will show the Party leader's icon image.
- .cpp
- h
void UAccelBytePartyPlayerEntry::SetImageIconLeader(bool bIsLeader) const
{
if (bIsLeader)
{
Img_LeaderIcon->SetVisibility(ESlateVisibility::Visible);
}
else
{
Img_LeaderIcon->SetVisibility(ESlateVisibility::Hidden);
}
}/**
* @brief Set Image Icon to Party Member.
* @param bIsLeader Checks if the player is the leader of the Party.
*/
void SetImageIconLeader(bool bIsLeader) const;
Party menu
Open the
AccelByteParty
header and class, then add the following includes at the top of the header and class:- .cpp
- h
#include "AccelBytePartyPlayerEntry.h"
#include "Components/ScrollBox.h"
#include "Components/Button.h"
#include "Components/Image.h"
#include "Components/TextBlock.h"
#include "TutorialProject/TutorialMenuHUD.h"#include "AccelBytePartyInvitationPopUp.h"
...
class UAccelBytePartyPlayerEntry;
class UScrollBox;
class UButton;
class UTextBlock;
class ATutorialMenuHUD;- Specify all the widgets components in the
AccelByteParty
header file.
- h
/**
* @brief Scroll Box to spawn the player entry.
*/
UPROPERTY(meta = (BindWidget))
UScrollBox* Sb_Player;
/**
* @brief Button for Create Party.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_CreateParty;
/**
* @brief Button for Leave Party.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_LeaveParty;
/**
* @brief Text Block for displaying Party ID.
*/
UPROPERTY(meta = (BindWidget))
UTextBlock* Tb_PartyID;
Declare a
NativeConstruct()
override function to initialize the widget components and theTotalPartyMember
based on your Max Party Member configuration in Admin Portal.- .cpp
- h
void UAccelByteParty::NativeConstruct()
{
Super::NativeConstruct();
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
Btn_CreateParty->OnClicked.AddUniqueDynamic(this, &UAccelByteParty::OnClickedCreateParty);
Btn_LeaveParty->OnClicked.AddUniqueDynamic(this, &UAccelByteParty::OnClickedLeaveParty);
TotalPartyMember = 4;
SetNotificationDelegate();
}...
virtual void NativeConstruct() override;
/**
* @brief Tutorial Menu HUD to handle all functionality of the UI.
*/
ATutorialMenuHUD* TutorialMenuHUD;
/**
* @brief Define maximum party member allowed.
*/
UPROPERTY()
int TotalPartyMember;Create a new function to enable and disable the Create Party button and the Leave Party button depending on the situation.
- .cpp
- h
void UAccelByteParty::SetCreatePartyButtonEnabled(bool bIsCreateParty) const
{
Btn_CreateParty->SetIsEnabled(bIsCreateParty);
Btn_LeaveParty->SetIsEnabled(!bIsCreateParty);
}/**
* @brief Set enabled / disabled state of the Create Party & Leave Party button.
*/
void SetCreatePartyButtonEnabled(bool bIsCreateParty) const;Also create a function to display the Leader Icon if the player's a Party member. To check on each player in the Party, create an array that will hold our Party's player entry data.
- .cpp
- h
void UAccelByteParty::SetUpdateLeaderIcon(const FString& LeaderId) const
{
for (const TWeakObjectPtr<UAccelBytePartyPlayerEntry>& PlayerEntry : PartyPlayerEntryWidgetArray)
{
// Leader Entry
if (LeaderId == PlayerEntry->GetUserData().UserId)
{
PlayerEntry->SetImageIconLeader(true);
PlayerEntry->EnableAllComponents(false);
}
// Other entries when local player is leader
else if (LeaderId == FRegistry::Credentials.GetUserId())
{
PlayerEntry->SetImageIconLeader(false);
if (PlayerEntry->GetUserData().UserId.IsEmpty())
{
PlayerEntry->EnableAllComponents(false);
}
else
{
PlayerEntry->EnableAllComponents(true);
}
}
// Other entries when local player is not leader
else
{
PlayerEntry->SetImageIconLeader(false);
PlayerEntry->EnableAllComponents(false);
}
}
}/**
* @brief Update the leader icon.
* @param LeaderId The ID of the current party leader.
*/
void SetUpdateLeaderIcon(const FString& LeaderId) const;
/**
* @brief Copy Array of player entry.
*/
TArray<TWeakObjectPtr<UAccelBytePartyPlayerEntry>> PartyPlayerEntryWidgetArray;Prepare a new function to refresh the Party's Player Entry list. Since you are also going to add the Party Player Entry widget, create a class reference to the
WB_PartyPlayerEntry
's class.- .cpp
- h
void UAccelByteParty::RefreshPartyList()
{
Sb_Player->ClearChildren();
PartyPlayerEntryWidgetArray.Empty();
if (PartyInfo.PartyId.IsEmpty())
{
return;
}
for (int i = 0; i < TotalPartyMember; ++i)
{
TWeakObjectPtr<UAccelBytePartyPlayerEntry> PlayerEntry = MakeWeakObjectPtr<UAccelBytePartyPlayerEntry>(CreateWidget<UAccelBytePartyPlayerEntry>(this, PartyPlayerEntryClass.Get()));
PlayerEntry->EnableAllComponents(false);
PartyPlayerEntryWidgetArray.Add(PlayerEntry);
if (i < PartyInfo.Members.Num())
{
PlayerEntry->InitData(PartyInfo.Members[i]);
}
Sb_Player->AddChild(PlayerEntry.Get());
}
Tb_PartyID->SetText(FText::FromString(PartyInfo.PartyId));
SetCreatePartyButtonEnabled(false);
SetUpdateLeaderIcon(PartyInfo.Leader);
}/**
* @brief Create an Empty Party List with UMG.
*/
void RefreshPartyList();
/**
* @brief Reference to Party Player Entry Class.
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelBytePartyPlayerEntry> PartyPlayerEntryClass;
/**
* @brief Current Party Information
*/
FAccelByteModelsPartyDataNotif PartyInfo;Then, create a new function that will refresh all of the Party Widgets state.
- .cpp
- h
void UAccelByteParty::RefreshPartyEntries()
{
Tb_PartyID->SetText(FText::FromString("##############"));
SetCreatePartyButtonEnabled(true);
RefreshPartyList();
}/**
* @brief Refresh party entries.
*/
void RefreshPartyEntries();Also prepare a new function that will reset the current stored Party Info.
- .cpp
- h
void UAccelByteParty::ResetPartyInfo()
{
const FAccelByteModelsPartyDataNotif EmptyData;
PartyInfo = EmptyData;
bIsInParty = false;
RefreshPartyEntries();
}/**
* @brief Reset current PartyInfo class variable and refresh current party entries.
*/
void ResetPartyInfo();
bool bIsInParty;Remove
SetCreatePartyResponseDelegate
,SetLeavePartyResponseDelegate
, andSetInvitePartyResponseDelegate
from their current function.You are going to put them in the
SetNotificationDelegate()
function instead.Also, modify the
SetNotificationDelegate()
function by changing theCreateWeakLambda
withCreateUObject
for readability.- .cpp
- h
void UAccelByteParty::OnClickedCreateParty()
{
FRegistry::Lobby.SendCreatePartyRequest();
}
void UAccelByteParty::OnClickedLeaveParty()
{
FRegistry::Lobby.SendLeavePartyRequest();
}
void UAccelByteParty::OnClickedInviteParty(const FString& UserId)
{
FRegistry::Lobby.SendInviteToPartyRequest(UserId);
}
void UAccelByteParty::SetNotificationDelegate()
{
FRegistry::Lobby.SetCreatePartyResponseDelegate(Api::Lobby::FPartyCreateResponse::CreateUObject(this, &UAccelByteParty::OnCreatePartyResponse),
FErrorHandler::CreateUObject(this, &UAccelByteParty::OnCreatePartyFailed));
FRegistry::Lobby.SetLeavePartyResponseDelegate(Api::Lobby::FPartyLeaveResponse::CreateUObject(this, &UAccelByteParty::OnLeavePartyResponse),
FErrorHandler::CreateUObject(this, &UAccelByteParty::OnLeavePartyFailed));
FRegistry::Lobby.SetInvitePartyResponseDelegate(Api::Lobby::FPartyInviteResponse::CreateUObject(this, &UAccelByteParty::OnInvitePartyResponse),
FErrorHandler::CreateUObject(this, &UAccelByteParty::OnInvitePartyFailed));
FRegistry::Lobby.SetPartyGetInvitedNotifDelegate(Api::Lobby::FPartyGetInvitedNotif::CreateUObject(this, &UAccelByteParty::OnInvitePartyGetInviteNotice));
FRegistry::Lobby.SetPartyKickNotifDelegate(Api::Lobby::FPartyKickNotif::CreateUObject(this, &UAccelByteParty::OnInvitePartyKickedNotice));
FRegistry::Lobby.SetPartyMemberLeaveNotifDelegate(Api::Lobby::FPartyMemberLeaveNotif::CreateUObject(this, &UAccelByteParty::OnLeavePartyNotice));
FRegistry::Lobby.SetPartyDataUpdateNotifDelegate
(Api::Lobby::FPartyDataUpdateNotif::CreateUObject(this, &UAccelByteParty::OnPartyDataUpdateResponse));
}// Response for creating party.
void OnCreatePartyResponse(const FAccelByteModelsCreatePartyResponse& Result);
// Response for failing create party.
void OnCreatePartyFailed(int32 ErrorCode, const FString& ErrorMessage);
// Response for leaving party.
void OnLeavePartyResponse(const FAccelByteModelsLeavePartyResponse& Result);
// Response for failing leaving party.
void OnLeavePartyFailed(int32 ErrorCode, const FString& ErrorMessage);
// Response for inviting friend to party.
void OnInvitePartyResponse(const FAccelByteModelsPartyInviteResponse& Result);
// Response for failing inviting friend to party.
void OnInvitePartyFailed(int32 ErrorCode, const FString& ErrorMessage);
// Response for get notification for invitation party.
void OnInvitePartyGetInviteNotice(const FAccelByteModelsPartyGetInvitedNotice& Result);
// Response for notification when someone kicked in the party.
void OnInvitePartyKickedNotice(const FAccelByteModelsGotKickedFromPartyNotice& Result);
// Response for notification when someone leave party.
void OnLeavePartyNotice(const FAccelByteModelsLeavePartyNotice& Result);
// Response for updating party data when someone do some action regarding to party.
void OnPartyDataUpdateResponse(const FAccelByteModelsPartyDataNotif& Result);Now, define the response delegate functions you declared earlier for each Create Party, Leave Party, and Invite Party response query.
Create Party's Success and Failed Response
- .cpp
void UAccelByteParty::OnCreatePartyResponse(const FAccelByteModelsCreatePartyResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Create Party Success!"));
}
void UAccelByteParty::OnCreatePartyFailed(int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Create Party Failed : %d , %s"), ErrorCode, *ErrorMessage);
}Leave Party's Success and Failed Response
- .cpp
void UAccelByteParty::OnLeavePartyResponse(const FAccelByteModelsLeavePartyResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Leave Party Success!"));
ResetPartyInfo();
}
void UAccelByteParty::OnLeavePartyFailed(int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Leave Party Failed : %d , %s"), ErrorCode, *ErrorMessage);
}Invite to Party's Success and Failed Response
- .cpp
void UAccelByteParty::OnInvitePartyResponse(const FAccelByteModelsPartyInviteResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Invite Party Success!"));
}
void UAccelByteParty::OnInvitePartyFailed(int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Invite Party Failed : %d , %s"), ErrorCode, *ErrorMessage);
}Define the notification events' callback functions to update your widgets based on each event updates:
OnInvitePartyGetInviteNotice()
- .cpp
void UAccelByteParty::OnInvitePartyGetInviteNotice(const FAccelByteModelsPartyGetInvitedNotice& Result)
{
UE_LOG(LogTemp, Log, TEXT("On Get Invite to Party Notice!"));
}OnInvitePartyKickedNotice()
- .cpp
void UAccelByteParty::OnInvitePartyKickedNotice(const FAccelByteModelsGotKickedFromPartyNotice& Result)
{
UE_LOG(LogTemp, Log, TEXT("You have been kicked from the party!"));
ResetPartyInfo();
}OnLeavePartyNotice()
- .cpp
void UAccelByteParty::OnLeavePartyNotice(const FAccelByteModelsLeavePartyNotice& Result)
{
UE_LOG(LogTemp, Log, TEXT("On Some Player Leaved Notice!"));
}OnPartyDataUpdateResponse()
- .cpp
void UAccelByteParty::OnPartyDataUpdateResponse(const FAccelByteModelsPartyDataNotif& Result)
{
UE_LOG(LogTemp, Log, TEXT("On Party Data Update Response!"));
PartyInfo = Result;
RefreshPartyList();
}
Party invitation pop-up
Open the
AccelBytePartyInvitationPopUp
class and add the widget-related header at the top of the class- .cpp
- h
...
#include "Components/Button.h"
#include "TutorialProject/TutorialMenuHUD.h"
#include "TutorialProject/TutorialProjectUtilities.h"...
#include "AccelByteParty.h"
#include "Models/AccelByteLobbyModels.h"
...
class ATutorialMenuHUD;
class UTextBlock;
class UButton;
Specify all the widget components in the
AccelBytePartyInvitationPopUp
header file.- h
/**
* @brief Text Box displaying Invitation.
*/
UPROPERTY(meta = (BindWidget))
UTextBlock* Tb_InvitationText;
/**
* @brief Button for Accepting Party Invitation.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_AcceptParty;
/**
* @brief Button for Rejecting Party Invitation.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_RejectParty;
Add the
NativeConstruct()
override function to initialize theTutorialMenuHUD
object and widgets.- .cpp
- h
void UAccelBytePartyInvitationPopUp::NativeConstruct()
{
Super::NativeConstruct();
Btn_AcceptParty->SetIsEnabled(true);
Btn_RejectParty->SetIsEnabled(true);
TutorialMenuHUD = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD());
Btn_AcceptParty->OnClicked.AddUniqueDynamic(this, &UAccelBytePartyInvitationPopUp::OnClickedAcceptPartyInvitation);
Btn_RejectParty->OnClicked.AddUniqueDynamic(this, &UAccelBytePartyInvitationPopUp::OnClickedRejectPartyInvitation);
}...
virtual void NativeConstruct() override;
...
/**
* @brief Tutorial Menu HUD to handle all functionality of the UI.
*/
ATutorialMenuHUD* TutorialMenuHUD;Create a function that initializes the local
InvitationData
you created in the QuickStart section. If you haven't created a new local variable.- .cpp
- h
void UAccelBytePartyInvitationPopUp::InitData(const FAccelByteModelsPartyGetInvitedNotice& Result)
{
InvitationData = Result;
}/**
* @brief Initialize ResultInvited data to get player response to party host.
*/
void InitData(const FAccelByteModelsPartyGetInvitedNotice& Result);
...
/**
* @brief Get Invitation notice data to pass player accepting / rejecting
* party invitation request.
*/
FAccelByteModelsPartyGetInvitedNotice InvitationData;Modify the
OnClickedAcceptPartyInvitation()
function by adding code to disable the button after clicking it.- .cpp
void UAccelBytePartyInvitationPopUp::OnClickedAcceptPartyInvitation()
{
Btn_AcceptParty->SetIsEnabled(false);
FRegistry::Lobby.SetInvitePartyJoinResponseDelegate(Api::Lobby::FPartyJoinResponse::CreateWeakLambda(this, [this](const FAccelByteModelsPartyJoinResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Accept Party Success! Member : %d"), Result.Members.Num());
RemoveFromParent();
}),
FErrorHandler::CreateWeakLambda(this, [this](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Accept Party Error! %d: %s"), ErrorCode, *ErrorMessage);
TutorialMenuHUD->GetPartyMenu()->ResetPartyInfo();
RemoveFromParent();
}));
FRegistry::Lobby.SendAcceptInvitationRequest(InvitationData.PartyId, InvitationData.InvitationToken);
}Modify the
OnClickedRejectPartyInvitation()
function by adding widget implementation.- .cpp
void UAccelBytePartyInvitationPopUp::OnClickedRejectPartyInvitation()
{
Btn_RejectParty->SetIsEnabled(false);
FRegistry::Lobby.SetInvitePartyRejectResponseDelegate(Api::Lobby::FPartyRejectResponse::CreateWeakLambda(this, [this](const FAccelByteModelsPartyRejectResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Reject Party Success!"));
RemoveFromParent();
}),
FErrorHandler::CreateWeakLambda(this, [this](const int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Reject Party Error! %d: %s"), ErrorCode, *ErrorMessage);
RemoveFromParent();
}));
FRegistry::Lobby.SendRejectInvitationRequest(InvitationData.PartyId, InvitationData.InvitationToken);
}Open the
AccelByteParty
class, create a reference to the Party Invitation pop-up class and set theAccelBytePartyInvitationPopUp
class as the reference.Also, in the
OnInvitePartyGetInviteNotice()
function, add the code to create a new Party Invitation pop-up widget.- .cpp
- h
void UAccelByteParty::OnInvitePartyGetInviteNotice(const FAccelByteModelsPartyGetInvitedNotice& Result)
{
...
const TWeakObjectPtr<UAccelBytePartyInvitationPopUp> InvitationPopUpWidget = MakeWeakObjectPtr<UAccelBytePartyInvitationPopUp>(
CreateWidget<UAccelBytePartyInvitationPopUp>(this, PartyInvitationPopUpClass.Get()));
InvitationPopUpWidget.Get()->InitData(Result);
InvitationPopUpWidget->AddToViewport();
}/**
* @brief Reference to Party Invitation Pop Up Class.
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelBytePartyInvitationPopUp> PartyInvitationPopUpClass;
Party-related widget implementation
Now that you have the Party service implemented:
Open your
AccelByteFriendEntry
class and add the following code inside theOnClickedInviteParty()
function. Make sure theTutorialMenuHUD
pointer andUserData
exist.- .cpp
...
#include "../Party/AccelByteParty.h"
...
UAccelByteFriendEntry::OnClickedInviteParty()
{
TutorialMenuHUD->GetPartyMenu()->OnClickedInviteParty(UserData.UserId);
}Next, open the
AccelByteLobby
header class and include theAccelByteParty
header file.- .cpp
- h
...
#include "../Party/AccelByteParty.h"
...
class UScrollBox;Still in the
AccelByteLobby
class, in theSetLobbyNotificationDelegate()
function, under the Lobby'sSetConnectSuccessDelegate()
lambda, add some code to prepare the Party Widgets in Lobby Page.- .cpp
void UAccelByteLobby::SetLobbyNotificationDelegate()
{
FRegistry::Lobby.SetConnectSuccessDelegate(FSimpleDelegate::CreateWeakLambda(this, [this]()
{
...
TutorialMenuHUD->GetPartyMenu()->SetCreatePartyButtonEnabled(true);
TutorialMenuHUD->GetPartyMenu()->RefreshPartyEntries();
}));
...
}Specify the Party's box widget in
AccelByteLobby
class, then create a function to spawn the Party Widget to Lobby Page.- .cpp
- h
void UAccelByteLobby::AddPartyChild(UAccelByteParty* PartyMenu)
{
Sb_Party->AddChild(PartyMenu);
}/**
* @brief Scroll Box to spawn Party Widget.
*/
UPROPERTY(meta = (BindWidget))
UScrollBox* Sb_Party;
/**
* @brief Add new Party Menu to the party scroll box widget child.
* @param PartyMenu Party Menu that is going to be added to the party scroll box widget child.
*/
UFUNCTION()
void AddPartyChild(UAccelByteParty* PartyMenu);Open the
TutorialMenuHUD
class, then call the Lobby'sAddPartyChild()
function in theInitMainMenu()
function.- .cpp
void ATutorialMenuHUD::InitMainMenu()
{
...
LobbyMenu->AddPartyChild(PartyMenu);
...
}In the
TutorialMenuHUD
class, refresh the Party list when opening the Lobby Menu.- .cpp
void ATutorialMenuHUD::OpenLobbyMenu()
{
...
PartyMenu->RefreshPartyList();
}Also, in the
TutorialMenuHUD
class, create a new function to refresh the Party Entries on closing the Lobby Menu.- .cpp
- h
void ATutorialMenuHUD::OnCloseLobbyMenu()
{
PartyMenu->RefreshPartyEntries();
CloseLobbyMenu();
}/**
* @brief Refreshes Party entries and close lobby menu
*/
void OnCloseLobbyMenu();Back to the
AccelByteLobby.cpp
, call theOnCloseLobbyMenu()
you created earlier inside the Lobby's notification delegate on the connection closed and disconnected.- .cpp
void UAccelByteLobby::SetLobbyNotificationDelegate()
{
...
FRegistry::Lobby.SetConnectionClosedDelegate(Api::Lobby::FConnectionClosed::CreateWeakLambda(this, [this](int32 StatusCode, const FString& Reason, bool bWasClean)
{
...
TutorialMenuHUD->OnCloseLobbyMenu();
}));
FRegistry::Lobby.SetDisconnectNotifDelegate(Api::Lobby::FDisconnectNotif::CreateWeakLambda(this, [this](const FAccelByteModelsDisconnectNotif& Result)
{
...
TutorialMenuHUD->OnCloseLobbyMenu();
}));
...
}
Congratulations! You have now fully implemented the Party service.
Full code for reference
AccelBytePartyInvitationPopup.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/AccelByteLobbyModels.h"
#include "AccelBytePartyInvitationPopUp.generated.h"
class UTextBlock;
class UButton;
/**
* Pop-up window when the player gets a party invitation from a friend.
* This code covers AccelByte services including:
*
* - Get User Data by User ID
* - Accept Party Invitation
* - Reject Party Invitation
*/
UCLASS()
class TUTORIALPROJECT_API UAccelBytePartyInvitationPopUp : public UUserWidget
{
GENERATED_BODY()
virtual void NativeConstruct() override;
/**
* @brief Text Box displaying Invitation.
*/
UPROPERTY(meta = (BindWidget))
UTextBlock* Tb_InvitationText;
/**
* @brief Button for Accepting Party Invitation.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_AcceptParty;
/**
* @brief Button for Rejecting Party Invitation.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_RejectParty;
public:
/**
* @brief Initialize ResultInvited data to get player response to party host.
*/
UFUNCTION()
void InitData(const FAccelByteModelsPartyGetInvitedNotice& Result);
/**
* @brief Callback for accepting party invitation.
*/
UFUNCTION()
void OnClickedAcceptPartyInvitation();
/**
* @brief Callback for rejecting party invitation.
*/
UFUNCTION()
void OnClickedRejectPartyInvitation();
/**
* @brief Response when Accepting party invitation.
*/
void OnInvitePartyJoinResponse(const FAccelByteModelsPartyJoinResponse& Result);
/**
* @brief Response when Declining party invitation.
*/
void OnInvitePartyRejectResponse(const FAccelByteModelsPartyRejectResponse& Result);
/**
* @brief Get Invitation notice data to pass player accepting / rejecting
* party invitation request.
*/
FAccelByteModelsPartyGetInvitedNotice InvitationData;
};
AccelBytePartyInvitationPopup.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 "AccelBytePartyInvitationPopUp.h"
// AccelByte Services
#include "Api/AccelByteLobbyApi.h"
#include "Core/AccelByteRegistry.h"
// Widget Components
#include "Components/Button.h"
void UAccelBytePartyInvitationPopUp::NativeConstruct()
{
Super::NativeConstruct();
Btn_AcceptParty->OnClicked.AddUniqueDynamic(this, &UAccelBytePartyInvitationPopUp::OnClickedAcceptPartyInvitation);
Btn_RejectParty->OnClicked.AddUniqueDynamic(this, &UAccelBytePartyInvitationPopUp::OnClickedRejectPartyInvitation);
}
void UAccelBytePartyInvitationPopUp::InitData(const FAccelByteModelsPartyGetInvitedNotice& Result)
{
InvitationData = Result;
}
void UAccelBytePartyInvitationPopUp::OnClickedAcceptPartyInvitation()
{
FRegistry::Lobby.SetInvitePartyJoinResponseDelegate(Api::Lobby::FPartyJoinResponse::CreateUObject(this, &UAccelBytePartyInvitationPopUp::OnInvitePartyJoinResponse));
FRegistry::Lobby.SendAcceptInvitationRequest(*InvitationData.PartyId, *InvitationData.InvitationToken);
}
void UAccelBytePartyInvitationPopUp::OnClickedRejectPartyInvitation()
{
FRegistry::Lobby.SetInvitePartyRejectResponseDelegate(Api::Lobby::FPartyRejectResponse::CreateUObject(this, &UAccelBytePartyInvitationPopUp::OnInvitePartyRejectResponse));
FRegistry::Lobby.SendRejectInvitationRequest(*InvitationData.PartyId, *InvitationData.InvitationToken);
}
void UAccelBytePartyInvitationPopUp::OnInvitePartyJoinResponse(const FAccelByteModelsPartyJoinReponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Join Party Success! Member : %d"), Result.Members.Num());
if (Result.Code != "0")
{
UE_LOG(LogTemp, Warning, TEXT("Join Party Failed!"));
}
this->RemoveFromParent();
}
void UAccelBytePartyInvitationPopUp::OnInvitePartyRejectResponse(const FAccelByteModelsPartyRejectResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Reject Party Success!"));
if (Result.Code != "0")
{
UE_LOG(LogTemp, Warning, TEXT("Reject Party Failed!"));
}
this->RemoveFromParent();
}
AccelBytePartyPlayerEntry.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/AccelByteLobbyModels.h"
#include "Models/AccelByteUserModels.h"
#include "AccelBytePartyPlayerEntry.generated.h"
class UImage;
class UTextBlock;
class UButton;
/**
* Party Player entry. This will hold individual data searched from Party member.
* This code covers AccelByte services including :
*
* - Get User by User ID
* - Kick Player
* - Promote Leader
*/
UCLASS()
class TUTORIALPROJECT_API UAccelBytePartyPlayerEntry : public UUserWidget
{
GENERATED_BODY()
virtual void NativeConstruct() override;
public:
/**
* @brief Initialize User ID and converted to FSimpleUserData in here.
*/
void InitData(const FString& PlayerId);
/**
* @brief Enabling button Promote Leader and Kick Party member.
* @param bEnable Enable all button components.
*/
void EnableAllComponents(bool bIsEnable) const;
/**
* @brief Set Image Icon to Party Member.
* @param bIsLeader Checks if the player is the leader of the party.
*/
void SetImageIconLeader(bool bIsLeader) const;
/**
* @brief Get User Data stored in this entry.
*/
FSimpleUserData GetUserData() const;
private:
/**
* @brief Image to display leader status.
*/
UPROPERTY(meta = (BindWidget))
UImage* Img_LeaderIcon;
/**
* @brief Text Box for Player Username.
*/
UPROPERTY(meta = (BindWidget))
UTextBlock* Tb_PlayerUsername;
/**
* @brief Button for Promoting Party Leader.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_PartyLeader;
/**
* @brief Button for Kick Party Member.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_KickPlayer;
/**
* @brief Callback for OnClicked Party Leader Button.
*/
UFUNCTION()
void OnClickedPartyLeader();
/**
* @brief Callback for OnClicked Kick Party.
*/
UFUNCTION()
void OnClickedKickParty();
/**
* @brief Response when party promoted to leader.
*/
void OnPartyPromoteLeaderResponse(const FAccelByteModelsPartyPromoteLeaderResponse& Result);
/**
* @brief Response when party kicked.
*/
void OnInvitePartyKickMemberResponse(const FAccelByteModelsKickPartyMemberResponse& Result);
/**
* @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 Models to store User Data contained in this entry.
*/
FSimpleUserData UserData;
};
AccelBytePartyPlayerEntry.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 "AccelBytePartyPlayerEntry.h"
#include "AccelByteParty.h"
// AccelByte Services
#include "Api/AccelByteLobbyApi.h"
#include "Api/AccelByteUserApi.h"
#include "Core/AccelByteRegistry.h"
// Widget Components
#include "Components/Image.h"
#include "Components/TextBlock.h"
#include "Components/Button.h"
// Menu HUD
#include "TutorialProject/TutorialMenuHUD.h"
void UAccelBytePartyPlayerEntry::NativeConstruct()
{
Super::NativeConstruct();
Btn_PartyLeader->OnClicked.AddUniqueDynamic(this, &UAccelBytePartyPlayerEntry::OnClickedPartyLeader);
Btn_KickPlayer->OnClicked.AddUniqueDynamic(this, &UAccelBytePartyPlayerEntry::OnClickedKickParty);
}
void UAccelBytePartyPlayerEntry::InitData(const FString& PlayerId)
{
UserData.UserId = PlayerId;
FRegistry::User.GetUserByUserId(
PlayerId,
THandler<FSimpleUserData>::CreateUObject(this, &UAccelBytePartyPlayerEntry::OnSuccessGetUserId),
FErrorHandler::CreateUObject(this, &UAccelBytePartyPlayerEntry::OnFailedGetUserId));
}
void UAccelBytePartyPlayerEntry::EnableAllComponents(bool bIsEnable) const
{
if (bEnable)
{
Btn_KickPlayer->SetVisibility(ESlateVisibility::Visible);
Btn_PartyLeader->SetVisibility(ESlateVisibility::Visible);
}
else
{
Btn_KickPlayer->SetVisibility(ESlateVisibility::Hidden);
Btn_PartyLeader->SetVisibility(ESlateVisibility::Hidden);
}
}
void UAccelBytePartyPlayerEntry::SetImageIconLeader(bool bIsLeader) const
{
if (bIsLeader)
{
Img_LeaderIcon->SetColorAndOpacity(FLinearColor::Yellow);
}
else
{
Img_LeaderIcon->SetColorAndOpacity(FLinearColor::White);
}
}
FSimpleUserData UAccelBytePartyPlayerEntry::GetUserData() const
{
return UserData;
}
void UAccelBytePartyPlayerEntry::OnClickedPartyLeader()
{
FRegistry::Lobby.SetPartyPromoteLeaderResponseDelegate(Api::Lobby::FPartyPromoteLeaderResponse::CreateUObject(this, &UAccelBytePartyPlayerEntry::OnPartyPromoteLeaderResponse));
FRegistry::Lobby.SendPartyPromoteLeaderRequest(UserData.UserId);
}
void UAccelBytePartyPlayerEntry::OnClickedKickParty()
{
FRegistry::Lobby.SetInvitePartyKickMemberResponseDelegate(Api::Lobby::FPartyKickResponse::CreateUObject(this, &UAccelBytePartyPlayerEntry::OnInvitePartyKickMemberResponse));
FRegistry::Lobby.SendKickPartyMemberRequest(UserData.UserId);
}
void UAccelBytePartyPlayerEntry::OnPartyPromoteLeaderResponse(const FAccelByteModelsPartyPromoteLeaderResponse& Result)
{
if (Result.Code == "0")
{
UE_LOG(LogTemp, Log, TEXT("Promote Party Leader Success!"));
SetImageIconLeader(true);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Promote Party Leader Failed!"));
}
}
void UAccelBytePartyPlayerEntry::OnInvitePartyKickMemberResponse(const FAccelByteModelsKickPartyMemberResponse& Result)
{
if (Result.Code == "0")
{
UE_LOG(LogTemp, Log, TEXT("Kick Party Member Success!"));
Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD())->GetPartyMenu()->CreatePartyList();
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Kick Party Member Failed!"));
}
}
void UAccelBytePartyPlayerEntry::OnSuccessGetUserId(const FSimpleUserData& Data)
{
UserData = Data;
Tb_PlayerUsername->SetText(FText::FromString(UserData.DisplayName));
}
void UAccelBytePartyPlayerEntry::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; Message: %s"), ErrorCode, *ErrorMessage);
}
AccelByteParty.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 "AccelBytePartyInvitationPopUp.h"
#include "Blueprint/UserWidget.h"
#include "Models/AccelByteLobbyModels.h"
#include "AccelByteParty.generated.h"
class UAccelBytePartyPlayerEntry;
class UScrollBox;
class UButton;
class UTextBlock;
/**
* Party setup
* This code covers AccelByte services including :
*
* - Create Party
* - Leave Party
* - Invite Party
* - Get Notification when leave party
* - Get Notification when join party
* - Get Notification when someone kicked from party
* - Get Notification when someone promoted to be a party leader
* - Update party data
*/
UCLASS()
class TUTORIALPROJECT_API UAccelByteParty : public UUserWidget
{
GENERATED_BODY()
private:
virtual void NativeConstruct() override;
private:
/**
* @brief Scroll Box to spawn the player entry.
*/
UPROPERTY(meta = (BindWidget))
UScrollBox* Sb_Player;
/**
* @brief Button for Create Party.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_CreateParty;
/**
* @brief Button for Leave Party.
*/
UPROPERTY(meta = (BindWidget))
UButton* Btn_LeaveParty;
/**
* @brief Text Block for displaying Party ID.
*/
UPROPERTY(meta = (BindWidget))
UTextBlock* Tb_PartyID;
public:
/**
* @brief Callback when creating party.
*/
UFUNCTION()
void OnClickedCreateParty();
/**
* @brief Callback when leaving party.
*/
UFUNCTION()
void OnClickedLeaveParty();
/**
* @brief Callback when inviting to party.
* @param UserId user ID to invited.
*/
UFUNCTION()
void OnClickedInviteParty(const FString& UserId);
private:
/**
* @brief Response for creating party.
*/
void OnCreatePartyResponse(const FAccelByteModelsCreatePartyResponse& Result);
/**
* @brief Response for failing create party.
*/
void OnCreatePartyFailed(int32 ErrorCode, const FString& ErrorMessage);
/**
* @brief Response for leaving party.
*/
void OnLeavePartyResponse(const FAccelByteModelsLeavePartyResponse& Result);
/**
* @brief Response for failing leaving party.
*/
void OnLeavePartyFailed(int32 ErrorCode, const FString& ErrorMessage);
/**
* @brief Response for inviting friend to party.
*/
void OnInvitePartyResponse(const FAccelByteModelsPartyInviteResponse& Result);
/**
* @brief Response for failing inviting friend to party.
*/
void OnInvitePartyFailed(int32 ErrorCode, const FString& ErrorMessage);
/**
* @brief Response for get notification for invitation party.
*/
void OnInvitePartyGetInviteNotice(const FAccelByteModelsPartyGetInvitedNotice& Result);
/**
* @brief Response for notification when someone kicked in the party.
*/
void OnInvitePartyKickedNotice(const FAccelByteModelsGotKickedFromPartyNotice& Result);
/**
* @brief Response for notification when someone leave party.
*/
void OnLeavePartyNotice(const FAccelByteModelsLeavePartyNotice& Result);
/**
* @brief Response for updating party data when someone do some action regarding to party.
*/
void OnPartyDataUpdateResponse(const FAccelByteModelsPartyDataNotif& Result);
public:
/**
* @brief Create an Empty Party List with UMG.
*/
void CreatePartyList();
/**
* @brief Function where all the notifications are being set.
*/
void SetNotificationDelegate();
/**
* @brief Refresh party entries.
*/
void SetRefreshPartyEntries();
/**
* @brief Update the leader icon.
* @param LeaderId The ID of the current party leader.
*/
void SetUpdateLeaderIcon(const FString& LeaderId) const;
/**
* @brief Set enabled / disabled state of the Create Party & Leave Party button.
*/
void SetCreatePartyButtonEnabled(bool bIsCreateParty) const;
private:
/**
* @brief Copy Array of player entry.
*/
TArray<TWeakObjectPtr<UAccelBytePartyPlayerEntry>> PartyPlayerEntryWidgetArray;
/**
* @brief Reference to Party Player Entry Class.
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelBytePartyPlayerEntry> PartyPlayerEntryClass;
/**
* @brief Reference to Party Invitation Pop Up Class.
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelBytePartyInvitationPopUp> PartyInvitationPopUpClass;
/**
* @brief Define maximum party member allowed.
*/
UPROPERTY(EditDefaultsOnly)
int MaximumPartyMember;
};
AccelByteParty.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 "AccelByteParty.h"
#include "AccelBytePartyPlayerEntry.h"
// AccelByte Services
#include "Api/AccelByteLobbyApi.h"
#include "Core/AccelByteRegistry.h"
// Widget Components
#include "Components/ScrollBox.h"
#include "Components/Button.h"
#include "Components/Image.h"
#include "Components/TextBlock.h"
// Menu HUD
#include "TutorialProject/TutorialMenuHUD.h"
void UAccelByteParty::NativeConstruct()
{
Super::NativeConstruct();
Btn_CreateParty->OnClicked.AddUniqueDynamic(this, &UAccelByteParty::OnClickedCreateParty);
Btn_LeaveParty->OnClicked.AddUniqueDynamic(this, &UAccelByteParty::OnClickedLeaveParty);
SetNotificationDelegate();
}
void UAccelByteParty::OnClickedCreateParty()
{
FRegistry::Lobby.SendCreatePartyRequest();
}
void UAccelByteParty::OnClickedLeaveParty()
{
FRegistry::Lobby.SendLeavePartyRequest();
}
void UAccelByteParty::OnClickedInviteParty(const FString& UserId)
{
FRegistry::Lobby.SendInviteToPartyRequest(UserId);
}
void UAccelByteParty::SetNotificationDelegate()
{
FRegistry::Lobby.SetCreatePartyResponseDelegate(Api::Lobby::FPartyCreateResponse::CreateUObject(this, &UAccelByteParty::OnCreatePartyResponse),
FErrorHandler::CreateUObject(this, &UAccelByteParty::OnCreatePartyFailed));
FRegistry::Lobby.SetLeavePartyResponseDelegate(Api::Lobby::FPartyLeaveResponse::CreateUObject(this, &UAccelByteParty::OnLeavePartyResponse),
FErrorHandler::CreateUObject(this, &UAccelByteParty::OnLeavePartyFailed));
FRegistry::Lobby.SetInvitePartyResponseDelegate(Api::Lobby::FPartyInviteResponse::CreateUObject(this, &UAccelByteParty::OnInvitePartyResponse),
FErrorHandler::CreateUObject(this, &UAccelByteParty::OnInvitePartyFailed));
FRegistry::Lobby.SetPartyGetInvitedNotifDelegate(Api::Lobby::FPartyGetInvitedNotif::CreateUObject(this, &UAccelByteParty::OnInvitePartyGetInviteNotice));
FRegistry::Lobby.SetPartyKickNotifDelegate(Api::Lobby::FPartyKickNotif::CreateUObject(this, &UAccelByteParty::OnInvitePartyKickedNotice));
FRegistry::Lobby.SetPartyMemberLeaveNotifDelegate(Api::Lobby::FPartyMemberLeaveNotif::CreateUObject(this, &UAccelByteParty::OnLeavePartyNotice));
FRegistry::Lobby.SetPartyDataUpdateResponseDelegate(Api::Lobby::FPartyDataUpdateNotif::CreateUObject(this, &UAccelByteParty::OnPartyDataUpdateResponse));
}
void UAccelByteParty::CreatePartyList()
{
// Clear any entries when going back and forth the menu.
Sb_Player->ClearChildren();
PartyPlayerEntryWidgetArray.Empty();
for (int i = 0; i < MaximumPartyMember; ++i)
{
PartyPlayerEntryWidgetArray.Add(MakeWeakObjectPtr<UAccelBytePartyPlayerEntry>(
CreateWidget<UAccelBytePartyPlayerEntry>(this, PartyPlayerEntryClass.Get())
));
PartyPlayerEntryWidgetArray[i]->EnableAllComponents(false);
Sb_Player->AddChild(PartyPlayerEntryWidgetArray[i].Get());
}
}
void UAccelByteParty::SetRefreshPartyEntries()
{
Tb_PartyID->SetText(FText::FromString("##############"));
SetCreatePartyButtonEnabled(true);
CreatePartyList();
}
void UAccelByteParty::SetUpdateLeaderIcon(const FString& LeaderId) const
{
const FString& LocalPlayerId = Cast<ATutorialMenuHUD>(GetOwningPlayer()->GetHUD())->PlayerInfo.UserId;
for (const TWeakObjectPtr<UAccelBytePartyPlayerEntry>& PlayerEntry : PartyPlayerEntryWidgetArray)
{
// Check if local player is leader.
if (LeaderId == LocalPlayerId)
{
if (LeaderId == PlayerEntry->GetUserData().UserId)
{
PlayerEntry->EnableAllComponents(false);
}
else if (PlayerEntry->GetUserData().UserId.IsEmpty())
{
PlayerEntry->EnableAllComponents(false);
}
else
{
PlayerEntry->EnableAllComponents(true);
}
}
else
{
PlayerEntry->EnableAllComponents(false);
}
// Set leader icon's color.
if (LeaderId == PlayerEntry->GetUserData().UserId)
{
PlayerEntry->SetImageIconLeader(true);
}
else
{
PlayerEntry->SetImageIconLeader(false);
}
}
}
void UAccelByteParty::SetCreatePartyButtonEnabled(bool bIsCreateParty) const
{
Btn_CreateParty->SetIsEnabled(bIsCreateParty);
Btn_LeaveParty->SetIsEnabled(!bIsCreateParty);
}
void UAccelByteParty::OnCreatePartyResponse(const FAccelByteModelsCreatePartyResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Create Party Success!"));
}
void UAccelByteParty::OnCreatePartyFailed(int32 ErrorCode, const FString& ErrorMessage)
{
const FString DebugMessage = FString::Printf(TEXT("Create Party Failed : %d , %s"), ErrorCode, *ErrorMessage);
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Cyan, DebugMessage);
}
void UAccelByteParty::OnLeavePartyResponse(const FAccelByteModelsLeavePartyResponse& Result)
{
SetRefreshPartyEntries();
UE_LOG(LogTemp, Log, TEXT("Leave Party Success!"));
}
void UAccelByteParty::OnLeavePartyFailed(int32 ErrorCode, const FString& ErrorMessage)
{
const FString DebugMessage = FString::Printf(TEXT("Leave Party Failed : %d , %s"), ErrorCode, *ErrorMessage);
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Cyan, DebugMessage);
UE_LOG(LogTemp, Warning, TEXT("Leave Party Failed : Code: %d, Reason: %s"), ErrorCode, *ErrorMessage);
}
void UAccelByteParty::OnInvitePartyResponse(const FAccelByteModelsPartyInviteResponse& Result)
{
UE_LOG(LogTemp, Log, TEXT("Invite Party Success!"));
}
void UAccelByteParty::OnInvitePartyFailed(int32 ErrorCode, const FString& ErrorMessage)
{
const FString DebugMessage = FString::Printf(TEXT("Invite Party Failed : %d , %s"), ErrorCode, *ErrorMessage);
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Cyan, DebugMessage);
UE_LOG(LogTemp, Warning, TEXT("Invite Party Failed : Code: %d, Reason: %s"), ErrorCode, *ErrorMessage);
}
void UAccelByteParty::OnInvitePartyGetInviteNotice(const FAccelByteModelsPartyGetInvitedNotice& Result)
{
UE_LOG(LogTemp, Log, TEXT("Accept Party Invitation!"));
/** Create a weak object pointer that refers to our popup widget **/
const TWeakObjectPtr<UAccelBytePartyInvitationPopUp> InvitationPopUpWidget = MakeWeakObjectPtr<UAccelBytePartyInvitationPopUp>(
CreateWidget<UAccelBytePartyInvitationPopUp>(this, PartyInvitationPopUpClass.Get()));
/** Initialize popup widget and add it to viewport **/
InvitationPopUpWidget.Get()->InitData(Result);
InvitationPopUpWidget->AddToViewport();
}
void UAccelByteParty::OnInvitePartyKickedNotice(const FAccelByteModelsGotKickedFromPartyNotice& Result)
{
SetRefreshPartyEntries();
}
void UAccelByteParty::OnLeavePartyNotice(const FAccelByteModelsLeavePartyNotice& Result)
{
SetRefreshPartyEntries();
}
void UAccelByteParty::OnPartyDataUpdateResponse(const FAccelByteModelsPartyDataNotif& Result)
{
if (!Result.PartyId.IsEmpty())
{
for (int i = 0; i < Result.Members.Num(); ++i)
{
PartyPlayerEntryWidgetArray[i]->InitData(Result.Members[i]);
}
Tb_PartyID->SetText(FText::FromString(Result.PartyId));
SetCreatePartyButtonEnabled(false);
SetUpdateLeaderIcon(Result.Leader);
}
}
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;
class UAccelByteParty;
/**
* 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;
/**
* @brief Party Menu widget class
*/
UPROPERTY(EditDefaultsOnly)
TSubclassOf<UAccelByteParty> PartyClass;
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; }
/**
* @brief Getter for Party Menu widget
*/
UAccelByteParty* GetPartyMenu() const {return PartyMenu; }
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;
/**
* @brief Party Menu widget pointer
*/
UPROPERTY()
UAccelByteParty* PartyMenu;
};
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"
#include "AccelByte/Party/AccelByteParty.h"
void ATutorialMenuHUD::BeginPlay()
{
Super::BeginPlay();
APlayerController* PlayerController = GetOwningPlayerController();
check(LoginMenuClass != nullptr);
check(MainMenuClass != nullptr);
check(LobbyMenuClass != nullptr);
check(FriendsMenuClass != nullptr);
check(FindFriendsMenuClass != nullptr);
check(PartyClass != 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());
PartyMenu = CreateWidget<UAccelByteParty>(PlayerController, PartyClass.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->AddPartyChild(PartyMenu);
LobbyMenu->ConnectToLobby();
LobbyMenu->SetVisibility(ESlateVisibility::Collapsed);
OpenMainMenu();
}
void ATutorialMenuHUD::OpenLobbyMenu()
{
LobbyMenu->SetVisibility(ESlateVisibility::Visible);
}
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()
{
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"
#include "../Party/AccelByteParty.h"
class ATutorialMenuHUD;
class UButton;
class UScrollBox;
/**
* Component for Join to 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;
/**
* @brief Scroll Box to spawn Party Widget.
*/
UPROPERTY(meta = (BindWidget))
UScrollBox* Sb_Party;
#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 Add new Party Menu to the party scroll box widget child.
* @param PartyMenu Party Menu that gonna add to party scroll box widget child.
*/
UFUNCTION()
void AddPartyChild(UAccelByteParty* PartyMenu) const;
/**
* @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::AddPartyChild(UAccelByteParty* PartyMenu) const
{
Sb_Party->AddChild(PartyMenu);
}
void UAccelByteLobby::SetLobbyNotificationDelegate()
{
FRegistry::Lobby.SetConnectSuccessDelegate(FSimpleDelegate::CreateWeakLambda(this, [this]()
{
UE_LOG(LogTemp, Log, TEXT("Successfully Connected to Lobby"));
TutorialMenuHUD->GetPartyMenu()->SetCreatePartyButtonEnabled(true);
TutorialMenuHUD->GetPartyMenu()->RefreshPartyEntries();
}));
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 The(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"));
TutorialMenuHUD->OnCloseLobbyMenu();
}));
FRegistry::Lobby.SetDisconnectNotifDelegate(Api::Lobby::FDisconnectNotif::CreateWeakLambda(this, [this](const FAccelByteModelsDisconnectNotif& Result)
{
UE_LOG(LogTemp, Log, TEXT("Disconnected from Lobby"));
TutorialMenuHUD->OnCloseLobbyMenu();
}));
}
#pragma endregion