Reliable Messages

Learn how to author, send, and receive reliable messages

Sometimes it can be useful to send and receive messages outside of the normal flow of simulation traffic. To do this, SnapNet provides a feature called Reliable Messages. Functionally, reliable messages are similar to Remote Procedure Calls when using Unreal Engine’s native replication. Common use cases include issuing user interface commands and exchanging chat messages.

Create a message type

To create a new message, create a new subclass of USnapNetReliableMessage. For example, here’s a reliable message type you might use to send chat messages.

#pragma once

#include "SnapNetPropertyPlayerIndex.h"
#include "SnapNetPropertyString.h"
#include "SnapNetReliableMessage.h"

#include "ExampleChatMessage.generated.h"

UCLASS()
class UExampleChatMessage : public USnapNetReliableMessage
{
    GENERATED_BODY()

public:
    virtual void OnReceivedFromClient( int32 PlayerIndex ) override;

    virtual void OnReceivedFromServer( int32 LocalPlayerIndex ) override;

    UPROPERTY()
    FSnapNetPropertyPlayerIndex FromPlayerIndex;

    UPROPERTY()
    FSnapNetPropertyString Message;
};
#include "ExampleChatMessage.h"

#include "SnapNetServer.h"
#include "SnapNetSettings.h"

void UExampleChatMessage::OnReceivedFromClient( int32 PlayerIndex )
{
    UE_LOG( LogTemp, Log, TEXT( "Received from client: Player %d said \"%s\"" ), PlayerIndex, *Message.GetValue() );

    // Create a new chat message and broadcast it to all connected players
    if ( USnapNetServer* Server = USnapNetServer::Get( this ) )
    {
        UExampleChatMessage* ChatMessage = NewObject<UExampleChatMessage>();
        ChatMessage->FromPlayerIndex.SetValue( PlayerIndex );
        ChatMessage->Message.SetValue( Message.GetValue() );

        const int32 MaxPlayers = GetDefault<USnapNetSettings>()->MaxPlayers;
        for ( int32 ConnectedPlayerIndex = 0 ; ConnectedPlayerIndex < MaxPlayers ; ++ConnectedPlayerIndex )
        {
            if ( Server->GetClientIndex( ConnectedPlayerIndex ) >= 0 )
            {
                Server->SendReliableMessage( ConnectedPlayerIndex, ChatMessage );
            }
        }
    }
}

void UExampleChatMessage::OnReceivedFromServer( int32 LocalPlayerIndex )
{
    UE_LOG( LogTemp, Log, TEXT( "Received from server: Player %d said \"%s\"" ), FromPlayerIndex.GetValue(), *Message.GetValue() );
}

Register the message type

Reliable message types must be registered with SnapNet prior to session start. This can be done via the SnapNet project settings or by calling RegisterReliableMessageClass() on the USnapNetSubsystem.

Sending a message

To send a reliable message, create it using NewObject and then call SendReliableMessage() on either the USnapNetClient or USnapNetServer.

void UMyGameInstance::SendChatMessage( int32 LocalPlayerIndex, const FString& message )
{
    if ( USnapNetClient* Client = USnapNetClient::Get( this ) )
    {
        UExampleChatMessage* ChatMessage = NewObject<UExampleChatMessage>();
        ChatMessage->Message.SetValue( message );
        Client->SendReliableMessage( LocalPlayerIndex, ChatMessage );
    }
}