Skip to main content

Put it all together - Introduction to party - (Unreal Engine module)

Last updated on October 24, 2024

Connect the UI to display, leave, send invite, kick, and promote party member

  1. Open the PartyWidgetEntry_Starter class CPP file and add the code below to the SetPartyMember() function. This will display the party member display name and avatar.

    void UPartyWidgetEntry_Starter::SetPartyMember(const FUserOnlineAccountAccelByte& PartyMember, const bool bIsLeader)
    {
    W_PartyMember->SetNetId(PartyMember.GetUserId());

    // Display party member information.
    Ws_PartyMemberState->SetActiveWidget(W_PartyMemberPanel);

    // Set display name.
    if (PartyMember.GetDisplayName().IsEmpty())
    {
    const FUniqueNetIdAccelByteUserRef MemberABId = StaticCastSharedRef<const FUniqueNetIdAccelByteUser>(PartyMember.GetUserId());
    W_PartyMember->SetUsername(FText::FromString(UTutorialModuleOnlineUtility::GetUserDefaultDisplayName(MemberABId.Get())));
    }
    else
    {
    W_PartyMember->SetUsername(FText::FromString(PartyMember.GetDisplayName()));
    }

    // Set avatar
    FString AvatarURL;
    PartyMember.GetUserAttribute(ACCELBYTE_ACCOUNT_GAME_AVATAR_URL, AvatarURL);
    W_PartyMember->SetAvatar(AvatarURL);

    // Set color tint.
    const FLinearColor MemberColor = bIsLeader ? PartyLeaderColor : PartyMemberColor;
    SetPartyMemberColor(MemberColor);
    W_PartyMember->SetTextColor(MemberColor);
    W_PartyMember->SetAvatarTint(AvatarURL.IsEmpty() ? MemberColor : FLinearColor::White);

    // Set cached party member data as friend data.
    // Will be used to open player action menu widget.
    if (!CachedFriendData)
    {
    CachedFriendData = NewObject<UFriendData>();
    }
    CachedFriendData->UserId = PartyMember.GetUserId();
    CachedFriendData->DisplayName = PartyMember.GetDisplayName();
    CachedFriendData->AvatarURL = AvatarURL;

    W_PartyMember->ActivateWidget();
    }
  2. Next, open the PartyWidget_Starter class CPP file and add the code below to the DisplayParty() function. This will query the party member information and display them.

    void UPartyWidget_Starter::DisplayParty()
    {
    // Show loading.
    Btn_Leave->SetVisibility(ESlateVisibility::Collapsed);
    Ws_Party->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Loading);

    // Collect party member user IDs.
    const FUniqueNetIdPtr UserId = PartyOnlineSession->GetLocalPlayerUniqueNetId(GetOwningPlayer());
    TArray<FUniqueNetIdRef> PartyMemberUserIds = PartyOnlineSession->GetPartyMembers();

    // If not in any party, then only include player user ID to query its information.
    if (PartyMemberUserIds.IsEmpty())
    {
    PartyMemberUserIds.Add(UserId.ToSharedRef());
    }

    // Query and display party member information.
    if (UStartupSubsystem* StartupSubsystem = GetWorld()->GetGameInstance()->GetSubsystem<UStartupSubsystem>())
    {
    StartupSubsystem->QueryUserInfo(
    PartyOnlineSession->GetLocalUserNumFromPlayerController(GetOwningPlayer()),
    PartyMemberUserIds,
    FOnQueryUsersInfoCompleteDelegate::CreateWeakLambda(this, [this](
    const FOnlineError& Error,
    const TArray<TSharedPtr<FUserOnlineAccountAccelByte>> UsersInfo)
    {
    // If party members are changed during query, then re-query the party members' information.
    const bool bIsInParty = !PartyOnlineSession->GetPartyMembers().IsEmpty();
    if (bIsInParty)
    {
    if (UsersInfo.Num() != PartyOnlineSession->GetPartyMembers().Num())
    {
    DisplayParty();
    return;
    }
    for (int32 i = 0; i < UsersInfo.Num(); i++)
    {
    if (!UsersInfo[i]->GetUserId()->IsValid() ||
    !PartyOnlineSession->GetPartyMembers()[i]->IsValid() ||
    PartyOnlineSession->GetPartyMembers()[i].Get() != UsersInfo[i]->GetUserId().Get())
    {
    DisplayParty();
    return;
    }
    }
    }

    // Request failed.
    if (!Error.bSucceeded)
    {
    Ws_Party->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Error);
    return;
    }

    // Clean up last party member list.
    Ws_Party->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Not_Empty);
    Hb_Party->ClearChildren();
    Btn_Leave->SetVisibility(ESlateVisibility::Visible);

    // Display party members.
    for (int32 i = 0; i < MaxPartyMembers; i++)
    {
    if (i < UsersInfo.Num() && !UsersInfo[i])
    {
    continue;
    }

    const TWeakObjectPtr<UPartyWidgetEntry> PartyMemberEntry =
    MakeWeakObjectPtr<UPartyWidgetEntry>(
    CreateWidget<UPartyWidgetEntry>(this, PartyWidgetEntryClass.Get()));
    Hb_Party->AddChild(PartyMemberEntry.Get());

    // Display party member information.
    if (i < UsersInfo.Num())
    {
    /* Mark party member as leader if valid.
    * If not in any party, then assume the player as the leader.*/
    PartyMemberEntry->SetPartyMember(*UsersInfo[i],
    PartyOnlineSession->IsPartyLeader(UsersInfo[i]->GetUserId()) ||
    !bIsInParty);
    }
    // Display button to add more party members.
    else
    {
    PartyMemberEntry->ResetPartyMember();
    }
    }
    }));
    }
    }
  3. In the same file, add the code below to the OnLeaveButtonClicked() function. This will trigger to leave the party when the leave button is clicked.

    void UPartyWidget_Starter::OnLeaveButtonClicked()
    {
    // Leave current party.
    PartyOnlineSession->LeaveParty(PartyOnlineSession->GetLocalUserNumFromPlayerController(GetOwningPlayer()));
    DeactivateWidget();
    }
  4. In the same file, add the code below to the NativeOnActivated() function. This function will listen to the party event to update the displayed party member on the UI.

    void UPartyWidget_Starter::NativeOnActivated()
    {
    Super::NativeOnActivated();

    Btn_Leave->OnClicked().Clear();
    Btn_Leave->OnClicked().AddUObject(this, &ThisClass::OnLeaveButtonClicked);

    // Update the displayed party members on any changes.
    PartyOnlineSession->GetOnCreatePartyCompleteDelegates()->AddWeakLambda(this, [this](FName SessionName, bool bWasSuccessful)
    {
    DisplayParty();
    });
    PartyOnlineSession->GetOnLeavePartyCompleteDelegates()->AddWeakLambda(this, [this](FName SessionName, bool bWasSuccessful)
    {
    DisplayParty();
    });
    PartyOnlineSession->GetOnPartyMembersChangeDelegates()->AddWeakLambda(this, [this](FName SessionName, const FUniqueNetId& Participant, bool bJoined)
    {
    DisplayParty();
    });
    PartyOnlineSession->GetOnPartySessionUpdateReceivedDelegates()->AddWeakLambda(this, [this](FName SessionName)
    {
    DisplayParty();
    });

    DisplayParty();
    }
  5. In the same file, add the code below to the NativeOnDeactivated() function. This unbinds the party events after the party widget is deactivated.

    void UPartyWidget_Starter::NativeOnDeactivated()
    {
    Btn_Leave->OnClicked().Clear();

    // Clear online delegates.
    PartyOnlineSession->GetOnCreatePartyCompleteDelegates()->RemoveAll(this);
    PartyOnlineSession->GetOnLeavePartyCompleteDelegates()->RemoveAll(this);
    PartyOnlineSession->GetOnPartyMembersChangeDelegates()->RemoveAll(this);
    PartyOnlineSession->GetOnPartySessionUpdateReceivedDelegates()->RemoveAll(this);

    Super::NativeOnDeactivated();
    }
  6. The code to show party members on the UI is complete. Now, you must call several functions to perform party-related actions. Open the PartyOnlineSession_Starter class CPP file and add the code below to the respective predefined functions. What it does is call the respective party actions when the party action button is clicked. These action buttons are the generated buttons mentioned in the Add a party menu tutorial of this module.

    void UPartyOnlineSession_Starter::OnInviteToPartyButtonClicked(const int32 LocalUserNum, const FUniqueNetIdPtr& Invitee)
    {
    // Disable the button to avoid spamming.
    if (InviteToPartyButtonMetadata)
    {
    if (UAccelByteWarsButtonBase* Button =
    Cast<UAccelByteWarsButtonBase>(InviteToPartyButtonMetadata->GenerateWidgetRef))
    {
    Button->SetIsInteractionEnabled(false);
    }
    }

    SendPartyInvite(LocalUserNum, Invitee);
    }
    void UPartyOnlineSession_Starter::OnKickPlayerFromPartyButtonClicked(const int32 LocalUserNum, const FUniqueNetIdPtr& KickedPlayer)
    {
    // Disable the button to avoid spamming.
    if (KickPlayerFromPartyButtonMetadata)
    {
    if (UAccelByteWarsButtonBase* Button =
    Cast<UAccelByteWarsButtonBase>(KickPlayerFromPartyButtonMetadata->GenerateWidgetRef))
    {
    Button->SetIsInteractionEnabled(false);
    }
    }

    KickPlayerFromParty(LocalUserNum, KickedPlayer);
    }
    void UPartyOnlineSession_Starter::OnPromotePartyLeaderButtonClicked(const int32 LocalUserNum, const FUniqueNetIdPtr& NewLeader)
    {
    // Disable the button to avoid spamming.
    if (PromotePartyLeaderButtonMetadata)
    {
    if (UAccelByteWarsButtonBase* Button =
    Cast<UAccelByteWarsButtonBase>(PromotePartyLeaderButtonMetadata->GenerateWidgetRef))
    {
    Button->SetIsInteractionEnabled(false);
    }
    }

    PromotePartyLeader(LocalUserNum, NewLeader);
    }

Resources