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

Put it all together - Session chat - (Unreal Engine module)

Last updated on September 4, 2025

Connect the UI with session chat

In this tutorial, you will connect your implementation in SessionChatSubsystem_Starter to the session chat widget.

  1. Open the SessionChatWidget_Starter CPP file and start with connecting the UI to send session chat messages. Replace the SendSessionChatMessage() code with the following code:

    void USessionChatWidget_Starter::SendChatMessage(const FText& MessageText)
    {
    if (!SessionChatSubsystem)
    {
    UE_LOG_SESSIONCHAT(Warning, TEXT("Cannot send chat message. Session Chat subsystem is not valid."));
    return;
    }

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

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

    // Send room chat message.
    SessionChatSubsystem->SendChatMessage(
    LocalPlayer->GetPreferredUniqueNetId().GetUniqueNetId(),
    SessionChatSubsystem->GetChatRoomIdBasedOnType(CurrentChatRoomType),
    MessageText.ToString());
    }
  2. Next, replace the OnSendChatComplete() function with the code below to check whether the sent chat should be displayed depending on the current widget chat type:

    void USessionChatWidget_Starter::OnSendChatComplete(FString UserId, FString MsgBody, FString RoomId, bool bWasSuccessful)
    {
    // Abort and push a notification if failed.
    if (!bWasSuccessful)
    {
    if (PromptSubsystem)
    {
    PromptSubsystem->PushNotification(SEND_CHAT_FAILED_MESSAGE);
    }

    return;
    }

    if (!SessionChatSubsystem)
    {
    UE_LOG_SESSIONCHAT(Warning, TEXT("Cannot display a sent chat message. Session Chat subsystem is not valid."));
    return;
    }

    // Only show the chat if the type is valid.
    if (SessionChatSubsystem->GetChatRoomType(RoomId) != CurrentChatRoomType)
    {
    return;
    }

    // Display the chat if success.
    UChatData* ChatData = NewObject<UChatData>();
    ChatData->Message = MsgBody;
    ChatData->bIsSenderLocal = true;
    W_ActiveChat->AppendChatMessage(ChatData);
    }
  3. Replace the OnChatRoomMessageReceived() function with the code below to check the new chat type first before appending it to the displayed chats:

    void USessionChatWidget_Starter::OnChatRoomMessageReceived(const FUniqueNetId& UserId, const FChatRoomId& RoomId, const TSharedRef<FChatMessage>& Message)
    {
    if (!SessionChatSubsystem)
    {
    UE_LOG_SESSIONCHAT(Warning, TEXT("Cannot display a received chat message. Session Chat subsystem is not valid."));
    return;
    }

    // Only show the chat if the type is valid.
    if (SessionChatSubsystem->GetChatRoomType(RoomId) != CurrentChatRoomType)
    {
    return;
    }

    // Show the received chat message.
    AppendChatMessage(Message.Get());
    }
  4. Replace the GetLastChatMessages() function with the code below to get and display the chat message history based on the current selected chat type:

    void USessionChatWidget_Starter::GetLastChatMessages()
    {
    if (!SessionChatSubsystem)
    {
    UE_LOG_SESSIONCHAT(Warning, TEXT("Cannot get last chat messages. Session Chat subsystem is not valid."));
    return;
    }

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

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

    if (!ensure(W_ActiveChat))
    {
    UE_LOG_SESSIONCHAT(Warning, TEXT("Cannot get last chat messages. Chat widget component is not valid."));
    return;
    }

    // Get chat room id.
    FString ChatRoomId = SessionChatSubsystem->GetChatRoomIdBasedOnType(CurrentChatRoomType);

    // Abort if room id was not found.
    if (ChatRoomId.IsEmpty())
    {
    FText ChatRoomNotFoundMessage = INVALID_CHAT_ROOM_MESSAGE;
    switch (CurrentChatRoomType)
    {
    case EAccelByteChatRoomType::PARTY_V1:
    case EAccelByteChatRoomType::PARTY_V2:
    ChatRoomNotFoundMessage = INVALID_PARTY_CHAT_ROOM_MESSAGE;
    break;
    case EAccelByteChatRoomType::SESSION_V2:
    ChatRoomNotFoundMessage = INVALID_GAMESESSION_CHAT_ROOM_MESSAGE;
    break;
    }

    W_ActiveChat->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Error, ChatRoomNotFoundMessage);
    return;
    }

    // Get last chat messages.
    TArray<TSharedRef<FChatMessage>> OutMessages;
    if (SessionChatSubsystem->GetLastChatMessages(
    LocalPlayer->GetPreferredUniqueNetId().GetUniqueNetId(),
    ChatRoomId,
    W_ActiveChat->GetMaxChatHistory(),
    OutMessages))
    {
    // Abort if last messages is empty.
    if (OutMessages.IsEmpty())
    {
    W_ActiveChat->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_ActiveChat->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Error, FAILED_TO_LOAD_CHAT_MESSAGE);
    }
    }
  5. Next, replace the SwitchChatMessageType() function with the code below to immediately get chat message history when the widget chat type is changed:

    void USessionChatWidget_Starter::SwitchChatMessageType(const EAccelByteChatRoomType ChatRoomType)
    {
    // Switch chat message active panel based on type.
    switch(ChatRoomType)
    {
    case EAccelByteChatRoomType::SESSION_V2:
    Ws_ChatMessageType->SetActiveWidget(W_GameSessionChatOuter);
    W_ActiveChat = W_GameSessionChat;
    break;
    case EAccelByteChatRoomType::PARTY_V2:
    Ws_ChatMessageType->SetActiveWidget(W_PartyChatOuter);
    W_ActiveChat = W_PartyChat;
    break;
    }

    CurrentChatRoomType = ChatRoomType;

    // Try to display last chat messages if the current one is empty.
    if (W_ActiveChat)
    {
    W_ActiveChat->ClearChatMessages();
    W_ActiveChat->ClearInput();
    GetLastChatMessages();
    }
    }
  6. Replace the AppendChatMessage() function with the code below to append the chat message to be displayed with additional safeguards:

    void USessionChatWidget_Starter::AppendChatMessage(const FChatMessage& Message)
    {
    if (!SessionChatSubsystem)
    {
    UE_LOG_SESSIONCHAT(Warning, TEXT("Cannot append a chat message to display. Session Chat subsystem is not valid."));
    return;
    }

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

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

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

    // Display chat message.
    UChatData* ChatData = NewObject<UChatData>();
    ChatData->Message = Message.GetBody();
    ChatData->bIsSenderLocal = SessionChatSubsystem->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_ActiveChat->AppendChatMessage(ChatData);
    }
  7. 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 USessionChatWidget_Starter::NativeOnActivated()
    {
    Super::NativeOnActivated();

    // Reset chat widget
    W_GameSessionChat->ClearChatMessages();
    W_GameSessionChat->ClearInput();
    W_PartyChat->ClearChatMessages();
    W_PartyChat->ClearInput();

    // Bind event to switch between chat message type.
    Btn_SessionChat->OnClicked().AddUObject(this, &ThisClass::SwitchChatMessageType, EAccelByteChatRoomType::SESSION_V2);
    Btn_PartyChat->OnClicked().AddUObject(this, &ThisClass::SwitchChatMessageType, EAccelByteChatRoomType::PARTY_V2);

    // Setup widget
    W_GameSessionChat->OnSubmitDelegates.AddUObject(this, &ThisClass::SendChatMessage);
    W_PartyChat->OnSubmitDelegates.AddUObject(this, &ThisClass::SendChatMessage);
    Btn_Back->OnClicked().AddUObject(this, &ThisClass::DeactivateWidget);

    // Bind chat events.
    if (SessionChatSubsystem)
    {
    SessionChatSubsystem->GetOnSendChatCompleteDelegates()->AddUObject(this, &ThisClass::OnSendChatComplete);
    SessionChatSubsystem->GetOnChatRoomMessageReceivedDelegates()->AddUObject(this, &ThisClass::OnChatRoomMessageReceived);
    }

    SwitchChatMessageType(CurrentChatRoomType);
    }
  8. Finally, unbind those events when the widget is closed. To this, replace the pre-defined NativeOnDeactivated() function with the following code:

    void USessionChatWidget_Starter::NativeOnDeactivated()
    {
    CurrentChatRoomType = EAccelByteChatRoomType::SESSION_V2;

    // Unbind chat events.
    if (SessionChatSubsystem)
    {
    SessionChatSubsystem->GetOnSendChatCompleteDelegates()->RemoveAll(this);
    SessionChatSubsystem->GetOnChatRoomMessageReceivedDelegates()->RemoveAll(this);
    }

    // Cleanup widget
    Btn_SessionChat->OnClicked().Clear();
    Btn_PartyChat->OnClicked().Clear();
    W_GameSessionChat->OnSubmitDelegates.RemoveAll(this);
    W_PartyChat->OnSubmitDelegates.RemoveAll(this);
    Btn_Back->OnClicked().RemoveAll(this);

    Super::NativeOnDeactivated();
    }

Resources