メインコンテンツまでスキップ

Put it all together - Private Chat - (Unreal Engine module)

Last updated on September 4, 2025

Connect the UI with private chat

In this tutorial, you will connect your implementation in PrivateChatSubsystem_Starter to the private chat widget.

  1. Open the PrivateChatWidget_Starter CPP file and start with connecting the UI to send private chat messages. Replace the SendPrivateChatMessage() code with the following code:

    void UPrivateChatWidget_Starter::SendPrivateChatMessage(const FText& MessageText)
    {
    if (!PrivateChatSubsystem)
    {
    UE_LOG_PRIVATECHAT(Warning, TEXT("Cannot send private chat message. Private Chat subsystem is not valid."));
    return;
    }

    if (!ensure(GetOwningPlayer()))
    {
    UE_LOG_PRIVATECHAT(Warning, TEXT("Cannot send private chat message. PlayerController is not valid."));
    return;
    }

    const ULocalPlayer* LocalPlayer = GetOwningPlayer()->GetLocalPlayer();
    if (!ensure(LocalPlayer))
    {
    UE_LOG_PRIVATECHAT(Warning, TEXT("Cannot send private chat message. LocalPlayer is not valid."));
    return;
    }

    // Send private private chat message.
    PrivateChatSubsystem->SendPrivateChatMessage(
    LocalPlayer->GetPreferredUniqueNetId().GetUniqueNetId(),
    PrivateChatRecipientUserId,
    MessageText.ToString());
    }
  2. Replace the GetLastPrivateChatMessages() function with the code below to get and display the chat message history:

    void UPrivateChatWidget_Starter::GetLastPrivateChatMessages() const
    {
    if (!PrivateChatSubsystem)
    {
    UE_LOG_PRIVATECHAT(Warning, TEXT("Cannot get last private chat messages. Private Chat subsystem is not valid."));
    return;
    }

    if (!ensure(GetOwningPlayer()))
    {
    UE_LOG_PRIVATECHAT(Warning, TEXT("Cannot get last private chat messages. PlayerController is not valid."));
    return;
    }

    const ULocalPlayer* LocalPlayer = GetOwningPlayer()->GetLocalPlayer();
    if (!ensure(LocalPlayer))
    {
    UE_LOG_PRIVATECHAT(Warning, TEXT("Cannot get last private chat messages. LocalPlayer is not valid."));
    return;
    }

    // Get chat room id.
    const FString ChatRoomId = PrivateChatSubsystem->GetPrivateChatRoomId(
    LocalPlayer->GetPreferredUniqueNetId().GetUniqueNetId(),
    PrivateChatRecipientUserId);

    // Abort if room id was not found.
    if (ChatRoomId.IsEmpty())
    {
    W_Chat->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Empty, NO_CHAT_MESSAGE);
    return;
    }

    // Get last private chat messages.
    TArray<TSharedRef<FChatMessage>> OutMessages;
    if (PrivateChatSubsystem->GetLastPrivateChatMessages(
    LocalPlayer->GetPreferredUniqueNetId().GetUniqueNetId(),
    ChatRoomId,
    W_Chat->GetMaxChatHistory(),
    OutMessages))
    {
    // Abort if last messages is empty.
    if (OutMessages.IsEmpty())
    {
    W_Chat->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Empty, NO_CHAT_MESSAGE);
    return;
    }

    // Display last chat messages.
    Algo::Reverse(OutMessages);
    for (const TSharedRef<FChatMessage>& Message : OutMessages)
    {
    AppendChatMessage(Message.Get());
    }
    }
    // Show error message if failed.
    else
    {
    W_Chat->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Error, FAILED_TO_LOAD_CHAT_MESSAGE);
    }
    }
  3. Next, replace the AppendChatMessage() function with the code below to append the chat message to be displayed with additional safeguards:

    void UPrivateChatWidget_Starter::AppendChatMessage(const FChatMessage& Message) const
    {
    if (!PrivateChatSubsystem)
    {
    UE_LOG_PRIVATECHAT(Warning, TEXT("Cannot append a private chat message to display. Private Chat subsystem is not valid."));
    return;
    }

    if (!ensure(GetOwningPlayer()))
    {
    UE_LOG_PRIVATECHAT(Warning, TEXT("Cannot append a private chat message to display. PlayerController is not valid."));
    return;
    }

    const ULocalPlayer* LocalPlayer = GetOwningPlayer()->GetLocalPlayer();
    if (!ensure(LocalPlayer))
    {
    UE_LOG_PRIVATECHAT(Warning, TEXT("Cannot append a private chat message to display. LocalPlayer is not valid."));
    return;
    }

    const FUniqueNetIdAccelByteUserRef SenderABId = StaticCastSharedRef<const FUniqueNetIdAccelByteUser>(Message.GetUserId());
    if (!SenderABId.Get().IsValid())
    {
    UE_LOG_PRIVATECHAT(Warning, TEXT("Cannot append a private chat message to display. Sender User Id is invalid."));
    return;
    }

    // Construct chat message.
    UChatData* ChatData = NewObject<UChatData>();
    ChatData->Message = Message.GetBody();
    ChatData->bIsSenderLocal = PrivateChatSubsystem->IsMessageFromLocalUser(LocalPlayer->GetPreferredUniqueNetId().GetUniqueNetId(), Message);

    // If the sender doesn't have display name, then use the default display name.
    ChatData->Sender = Message.GetNickname();
    if (ChatData->Sender.IsEmpty() || SenderABId.Get().GetAccelByteId().Equals(ChatData->Sender))
    {
    ChatData->Sender = UTutorialModuleOnlineUtility::GetUserDefaultDisplayName(Message.GetUserId().Get());
    }

    // Display chat message.
    W_Chat->AppendChatMessage(ChatData);
    }
  4. Now, complete the code by binding the chat events with the widget. To do this, replace the pre-defined NativeOnActivated() function with the following code:

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

    // Reset chat widget
    W_Chat->ClearChatMessages();
    W_Chat->ClearInput();

    // Setup widget
    W_Chat->OnSubmitDelegates.AddUObject(this, &ThisClass::SendPrivateChatMessage);
    Btn_Back->OnClicked().AddUObject(this, &ThisClass::DeactivateWidget);

    if (PrivateChatSubsystem)
    {
    PrivateChatSubsystem->GetOnSendPrivateChatCompleteDelegates()->AddUObject(this, &ThisClass::OnSendPrivateChatComplete);
    PrivateChatSubsystem->GetOnPrivateChatMessageReceivedDelegates()->AddUObject(this, &ThisClass::OnPrivateChatMessageReceived);
    }

    // Display default state.
    GetLastPrivateChatMessages();
    }
  5. Finally, unbind those events when the widget is closed. To this, replace the pre-defined NativeOnDeactivated() function with the following code:

    void UPrivateChatWidget_Starter::NativeOnDeactivated()
    {
    PrivateChatRecipientUserId = nullptr;

    // Cleanup widget
    W_Chat->OnSubmitDelegates.RemoveAll(this);
    Btn_Back->OnClicked().RemoveAll(this);

    // Unbind chat events.
    if (PrivateChatSubsystem)
    {
    PrivateChatSubsystem->GetOnSendPrivateChatCompleteDelegates()->RemoveAll(this);
    PrivateChatSubsystem->GetOnPrivateChatMessageReceivedDelegates()->RemoveAll(this);
    }

    Super::NativeOnDeactivated();
    }

Resources