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.
Note
Reliable messages will not be stored in replays. If you wish the data to be present in replays, either save the data on an entity or use an event instead depending on context.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 );
}
}