🎮 Unreal Engine SDK Examples

Complete examples for integrating OddSockets into your Unreal Engine projects

🚀 Basic Setup Example

This example shows how to set up a basic OddSockets client in your Unreal Engine project.

Header File (MyGameActor.h)

#pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "OddSocketsClient.h" #include "OddSocketsChannel.h" #include "MyGameActor.generated.h" UCLASS() class MYGAME_API AMyGameActor : public AActor { GENERATED_BODY() public: AMyGameActor(); protected: virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; // OddSockets Components UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OddSockets") AOddSocketsClient* OddSocketsClient; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OddSockets") UOddSocketsChannel* GameChannel; // Event Handlers UFUNCTION() void OnConnected(); UFUNCTION() void OnDisconnected(const FString& Reason); UFUNCTION() void OnError(const FString& ErrorMessage); UFUNCTION() void OnChannelMessage(const FOddSocketsChannelMessageData& MessageData); // Public Methods UFUNCTION(BlueprintCallable, Category = "Game") void SendGameMessage(const FString& Message); };

Implementation File (MyGameActor.cpp)

#include "MyGameActor.h" #include "Engine/Engine.h" AMyGameActor::AMyGameActor() { PrimaryActorTick.bCanEverTick = false; } void AMyGameActor::BeginPlay() { Super::BeginPlay(); // Spawn OddSockets client OddSocketsClient = GetWorld()->SpawnActor<AOddSocketsClient>(); // Configure the client FOddSocketsConfig Config; Config.ApiKey = TEXT("your-api-key-here"); Config.UserId = FString::Printf(TEXT("player_%d"), FMath::RandRange(1000, 9999)); Config.bAutoConnect = true; Config.ReconnectAttempts = 5; Config.Timeout = 10; Config.HeartbeatInterval = 30; Config.LogLevel = EOddSocketsLogLevel::Info; // Initialize client OddSocketsClient->Initialize(Config); // Bind event handlers OddSocketsClient->OnConnected.AddDynamic(this, &AMyGameActor::OnConnected); OddSocketsClient->OnDisconnected.AddDynamic(this, &AMyGameActor::OnDisconnected); OddSocketsClient->OnError.AddDynamic(this, &AMyGameActor::OnError); // Connect to OddSockets OddSocketsClient->ConnectAsync(); } void AMyGameActor::EndPlay(const EEndPlayReason::Type EndPlayReason) { if (OddSocketsClient) { OddSocketsClient->Disconnect(); } Super::EndPlay(EndPlayReason); } void AMyGameActor::OnConnected() { UE_LOG(LogTemp, Log, TEXT("Connected to OddSockets!")); // Get a channel and subscribe GameChannel = OddSocketsClient->GetChannel(TEXT("game-lobby")); // Configure subscription options FOddSocketsSubscriptionOptions Options; Options.MaxHistory = 50; Options.bEnablePresence = true; Options.bRetainHistory = true; // Bind channel events GameChannel->OnMessage.AddDynamic(this, &AMyGameActor::OnChannelMessage); // Subscribe to the channel GameChannel->SubscribeAsync(Options); } void AMyGameActor::OnDisconnected(const FString& Reason) { UE_LOG(LogTemp, Warning, TEXT("Disconnected from OddSockets: %s"), *Reason); } void AMyGameActor::OnError(const FString& ErrorMessage) { UE_LOG(LogTemp, Error, TEXT("OddSockets error: %s"), *ErrorMessage); } void AMyGameActor::OnChannelMessage(const FOddSocketsChannelMessageData& MessageData) { UE_LOG(LogTemp, Log, TEXT("Received message from %s: %s"), *MessageData.Sender, *MessageData.Message); } void AMyGameActor::SendGameMessage(const FString& Message) { if (GameChannel && GameChannel->IsSubscribed()) { FOddSocketsPublishOptions Options; Options.Ttl = 3600; // 1 hour TTL GameChannel->PublishAsync(Message, Options); } }

💬 Chat System Example

A complete chat system implementation with presence tracking and message history.

Chat Manager Header (ChatManager.h)

#pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "OddSocketsClient.h" #include "OddSocketsChannel.h" #include "ChatManager.generated.h" USTRUCT(BlueprintType) struct FChatMessage { GENERATED_BODY() UPROPERTY(BlueprintReadOnly, Category = "Chat") FString Username; UPROPERTY(BlueprintReadOnly, Category = "Chat") FString Message; UPROPERTY(BlueprintReadOnly, Category = "Chat") FDateTime Timestamp; FChatMessage() { Username = TEXT(""); Message = TEXT(""); Timestamp = FDateTime::Now(); } }; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnChatMessageReceived, const FChatMessage&, ChatMessage); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnUserPresenceChanged, const FString&, Username, bool, bJoined); UCLASS(BlueprintType, Blueprintable) class MYGAME_API AChatManager : public AActor { GENERATED_BODY() public: AChatManager(); // Events UPROPERTY(BlueprintAssignable, Category = "Chat Events") FOnChatMessageReceived OnChatMessageReceived; UPROPERTY(BlueprintAssignable, Category = "Chat Events") FOnUserPresenceChanged OnUserPresenceChanged; // Public Methods UFUNCTION(BlueprintCallable, Category = "Chat") void JoinChatRoom(const FString& RoomName); UFUNCTION(BlueprintCallable, Category = "Chat") void LeaveChatRoom(); UFUNCTION(BlueprintCallable, Category = "Chat") void SendChatMessage(const FString& Message); UFUNCTION(BlueprintCallable, Category = "Chat") void SetUsername(const FString& NewUsername); UFUNCTION(BlueprintPure, Category = "Chat") TArray<FChatMessage> GetChatHistory() const { return ChatHistory; } UFUNCTION(BlueprintPure, Category = "Chat") TArray<FString> GetOnlineUsers() const { return OnlineUsers; } protected: virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; private: UPROPERTY() AOddSocketsClient* OddSocketsClient; UPROPERTY() UOddSocketsChannel* ChatChannel; UPROPERTY() FString Username; UPROPERTY() FString CurrentRoom; UPROPERTY() TArray<FChatMessage> ChatHistory; UPROPERTY() TArray<FString> OnlineUsers; // Event Handlers UFUNCTION() void OnConnected(); UFUNCTION() void OnChannelMessage(const FOddSocketsChannelMessageData& MessageData); UFUNCTION() void OnPresenceChange(const FOddSocketsChannelPresenceChangeData& PresenceData); // Helper Methods FChatMessage ParseChatMessage(const FString& JsonMessage); FString CreateChatMessageJson(const FString& Message); };

Chat Manager Implementation (ChatManager.cpp)

#include "ChatManager.h" #include "Engine/Engine.h" #include "Dom/JsonObject.h" #include "Serialization/JsonSerializer.h" #include "Serialization/JsonWriter.h" AChatManager::AChatManager() { PrimaryActorTick.bCanEverTick = false; Username = FString::Printf(TEXT("Player_%d"), FMath::RandRange(1000, 9999)); } void AChatManager::BeginPlay() { Super::BeginPlay(); // Initialize OddSockets client OddSocketsClient = GetWorld()->SpawnActor<AOddSocketsClient>(); FOddSocketsConfig Config; Config.ApiKey = TEXT("your-api-key-here"); Config.UserId = Username; Config.bAutoConnect = true; OddSocketsClient->Initialize(Config); OddSocketsClient->OnConnected.AddDynamic(this, &AChatManager::OnConnected); OddSocketsClient->ConnectAsync(); } void AChatManager::OnConnected() { UE_LOG(LogTemp, Log, TEXT("Chat system connected to OddSockets")); } void AChatManager::JoinChatRoom(const FString& RoomName) { if (!OddSocketsClient || !OddSocketsClient->IsConnected()) { UE_LOG(LogTemp, Warning, TEXT("Cannot join chat room: not connected")); return; } CurrentRoom = RoomName; ChatChannel = OddSocketsClient->GetChannel(RoomName); FOddSocketsSubscriptionOptions Options; Options.MaxHistory = 100; Options.bEnablePresence = true; Options.bRetainHistory = true; ChatChannel->OnMessage.AddDynamic(this, &AChatManager::OnChannelMessage); ChatChannel->OnPresenceChange.AddDynamic(this, &AChatManager::OnPresenceChange); ChatChannel->SubscribeAsync(Options); UE_LOG(LogTemp, Log, TEXT("Joined chat room: %s"), *RoomName); } void AChatManager::SendChatMessage(const FString& Message) { if (!ChatChannel || !ChatChannel->IsSubscribed()) { UE_LOG(LogTemp, Warning, TEXT("Cannot send message: not subscribed to channel")); return; } FString ChatJson = CreateChatMessageJson(Message); FOddSocketsPublishOptions Options; Options.Ttl = 3600; // 1 hour TTL ChatChannel->PublishAsync(ChatJson, Options); } void AChatManager::OnChannelMessage(const FOddSocketsChannelMessageData& MessageData) { FChatMessage ChatMessage = ParseChatMessage(MessageData.Message); if (!ChatMessage.Username.IsEmpty()) { ChatHistory.Add(ChatMessage); // Keep only last 100 messages if (ChatHistory.Num() > 100) { ChatHistory.RemoveAt(0); } OnChatMessageReceived.Broadcast(ChatMessage); } } void AChatManager::OnPresenceChange(const FOddSocketsChannelPresenceChangeData& PresenceData) { bool bJoined = PresenceData.Action == TEXT("join"); FString Username = PresenceData.User.UserId; if (bJoined) { OnlineUsers.AddUnique(Username); } else { OnlineUsers.Remove(Username); } OnUserPresenceChanged.Broadcast(Username, bJoined); UE_LOG(LogTemp, Log, TEXT("User %s %s the chat"), *Username, bJoined ? TEXT("joined") : TEXT("left")); } FString AChatManager::CreateChatMessageJson(const FString& Message) { TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject); JsonObject->SetStringField(TEXT("type"), TEXT("chat")); JsonObject->SetStringField(TEXT("username"), Username); JsonObject->SetStringField(TEXT("message"), Message); JsonObject->SetStringField(TEXT("timestamp"), FDateTime::UtcNow().ToIso8601()); FString OutputString; TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString); FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer); return OutputString; } FChatMessage AChatManager::ParseChatMessage(const FString& JsonMessage) { FChatMessage ChatMessage; TSharedPtr<FJsonObject> JsonObject; TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonMessage); if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid()) { FString Type; if (JsonObject->TryGetStringField(TEXT("type"), Type) && Type == TEXT("chat")) { JsonObject->TryGetStringField(TEXT("username"), ChatMessage.Username); JsonObject->TryGetStringField(TEXT("message"), ChatMessage.Message); FString TimestampStr; if (JsonObject->TryGetStringField(TEXT("timestamp"), TimestampStr)) { FDateTime::ParseIso8601(*TimestampStr, ChatMessage.Timestamp); } } } return ChatMessage; }
Blueprint Usage: This chat manager can be used directly in Blueprints. Bind to the OnChatMessageReceived and OnUserPresenceChanged events to update your UI when messages arrive or users join/leave.

🎮 Multiplayer Game State Sync

Synchronize player positions and game events across multiple clients.

// GameStateSyncer.h #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "OddSocketsClient.h" #include "OddSocketsChannel.h" #include "GameStateSyncer.generated.h" USTRUCT(BlueprintType) struct FPlayerState { GENERATED_BODY() UPROPERTY(BlueprintReadWrite, Category = "Player State") FString PlayerId; UPROPERTY(BlueprintReadWrite, Category = "Player State") FVector Position; UPROPERTY(BlueprintReadWrite, Category = "Player State") FRotator Rotation; UPROPERTY(BlueprintReadWrite, Category = "Player State") float Health; UPROPERTY(BlueprintReadWrite, Category = "Player State") int32 Score; FPlayerState() { PlayerId = TEXT(""); Position = FVector::ZeroVector; Rotation = FRotator::ZeroRotator; Health = 100.0f; Score = 0; } }; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPlayerStateUpdated, const FPlayerState&, PlayerState); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnGameEvent, const FString&, EventType, const FString&, EventData); UCLASS(BlueprintType, Blueprintable) class MYGAME_API AGameStateSyncer : public AActor { GENERATED_BODY() public: AGameStateSyncer(); // Events UPROPERTY(BlueprintAssignable, Category = "Game Events") FOnPlayerStateUpdated OnPlayerStateUpdated; UPROPERTY(BlueprintAssignable, Category = "Game Events") FOnGameEvent OnGameEvent; // Public Methods UFUNCTION(BlueprintCallable, Category = "Game Sync") void JoinGameSession(const FString& SessionId); UFUNCTION(BlueprintCallable, Category = "Game Sync") void SyncPlayerPosition(const FVector& Position, const FRotator& Rotation); UFUNCTION(BlueprintCallable, Category = "Game Sync") void SyncPlayerHealth(float Health); UFUNCTION(BlueprintCallable, Category = "Game Sync") void SyncPlayerScore(int32 Score); UFUNCTION(BlueprintCallable, Category = "Game Sync") void SendGameEvent(const FString& EventType, const FString& EventData); UFUNCTION(BlueprintPure, Category = "Game Sync") TArray<FPlayerState> GetAllPlayerStates() const; protected: virtual void BeginPlay() override; private: UPROPERTY() AOddSocketsClient* OddSocketsClient; UPROPERTY() UOddSocketsChannel* GameChannel; UPROPERTY() FString PlayerId; UPROPERTY() FString CurrentSession; UPROPERTY() TMap<FString, FPlayerState> PlayerStates; UPROPERTY() FTimerHandle SyncTimer; // Event Handlers UFUNCTION() void OnConnected(); UFUNCTION() void OnGameMessage(const FOddSocketsChannelMessageData& MessageData); // Helper Methods void ProcessPlayerStateUpdate(const FString& JsonMessage); void ProcessGameEvent(const FString& JsonMessage); FString CreatePlayerStateJson(const FString& UpdateType, const FString& Data); void PeriodicSync(); }; // GameStateSyncer.cpp #include "GameStateSyncer.h" #include "Engine/Engine.h" #include "TimerManager.h" AGameStateSyncer::AGameStateSyncer() { PrimaryActorTick.bCanEverTick = false; PlayerId = FString::Printf(TEXT("player_%d"), FMath::RandRange(10000, 99999)); } void AGameStateSyncer::BeginPlay() { Super::BeginPlay(); OddSocketsClient = GetWorld()->SpawnActor<AOddSocketsClient>(); FOddSocketsConfig Config; Config.ApiKey = TEXT("your-api-key-here"); Config.UserId = PlayerId; OddSocketsClient->Initialize(Config); OddSocketsClient->OnConnected.AddDynamic(this, &AGameStateSyncer::OnConnected); OddSocketsClient->ConnectAsync(); } void AGameStateSyncer::JoinGameSession(const FString& SessionId) { CurrentSession = SessionId; GameChannel = OddSocketsClient->GetChannel(FString::Printf(TEXT("game-session-%s"), *SessionId)); FOddSocketsSubscriptionOptions Options; Options.MaxHistory = 20; Options.bEnablePresence = true; GameChannel->OnMessage.AddDynamic(this, &AGameStateSyncer::OnGameMessage); GameChannel->SubscribeAsync(Options); // Start periodic sync timer GetWorld()->GetTimerManager().SetTimer(SyncTimer, this, &AGameStateSyncer::PeriodicSync, 0.1f, true); } void AGameStateSyncer::SyncPlayerPosition(const FVector& Position, const FRotator& Rotation) { if (!GameChannel || !GameChannel->IsSubscribed()) return; FString PositionData = FString::Printf( TEXT("{\"x\":%.2f,\"y\":%.2f,\"z\":%.2f,\"pitch\":%.2f,\"yaw\":%.2f,\"roll\":%.2f}"), Position.X, Position.Y, Position.Z, Rotation.Pitch, Rotation.Yaw, Rotation.Roll ); FString JsonMessage = CreatePlayerStateJson(TEXT("position"), PositionData); GameChannel->PublishAsync(JsonMessage, FOddSocketsPublishOptions()); } void AGameStateSyncer::SendGameEvent(const FString& EventType, const FString& EventData) { if (!GameChannel || !GameChannel->IsSubscribed()) return; FString EventJson = FString::Printf( TEXT("{\"type\":\"game_event\",\"event_type\":\"%s\",\"event_data\":\"%s\",\"player_id\":\"%s\"}"), *EventType, *EventData, *PlayerId ); GameChannel->PublishAsync(EventJson, FOddSocketsPublishOptions()); } void AGameStateSyncer::OnGameMessage(const FOddSocketsChannelMessageData& MessageData) { // Parse message type and route to appropriate handler if (MessageData.Message.Contains(TEXT("\"type\":\"player_state\""))) { ProcessPlayerStateUpdate(MessageData.Message); } else if (MessageData.Message.Contains(TEXT("\"type\":\"game_event\""))) { ProcessGameEvent(MessageData.Message); } }

👥 Presence Tracking Example

Track user presence and display online status in real-time.

// PresenceManager.h UCLASS(BlueprintType, Blueprintable) class MYGAME_API APresenceManager : public AActor { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "Presence") void UpdateUserStatus(const FString& Status); UFUNCTION(BlueprintCallable, Category = "Presence") void UpdateUserLocation(const FString& Location); UFUNCTION(BlueprintCallable, Category = "Presence") void SetUserAway(bool bIsAway); UFUNCTION(BlueprintPure, Category = "Presence") TArray<FString> GetOnlineUsers() const; UFUNCTION(BlueprintPure, Category = "Presence") int32 GetOnlineUserCount() const; private: UFUNCTION() void OnPresenceUpdate(const FOddSocketsChannelPresenceData& PresenceData); UFUNCTION() void OnPresenceChange(const FOddSocketsChannelPresenceChangeData& PresenceChangeData); void UpdateMyPresenceState(); }; // PresenceManager.cpp void APresenceManager::UpdateUserStatus(const FString& Status) { if (!PresenceChannel || !PresenceChannel->IsSubscribed()) return; TMap<FString, FString> State; State.Add(TEXT("status"), Status); State.Add(TEXT("last_update"), FDateTime::UtcNow().ToIso8601()); PresenceChannel->UpdateStateAsync(State); } void APresenceManager::OnPresenceChange(const FOddSocketsChannelPresenceChangeData& PresenceChangeData) { FString UserId = PresenceChangeData.User.UserId; bool bJoined = PresenceChangeData.Action == TEXT("join"); if (bJoined) { OnlineUsers.AddUnique(UserId); UE_LOG(LogTemp, Log, TEXT("User %s came online"), *UserId); } else { OnlineUsers.Remove(UserId); UE_LOG(LogTemp, Log, TEXT("User %s went offline"), *UserId); } // Broadcast presence change event OnUserPresenceChanged.Broadcast(UserId, bJoined); }

🎨 Blueprint Examples

Step-by-step Blueprint setup for common OddSockets operations.

Basic Connection Setup in Blueprints:

  1. Event BeginPlay → Spawn Actor from Class (OddSockets Client)
  2. Make OddSockets Config → Set API Key, User ID, etc.
  3. Initialize (OddSockets Client) → Connect Config input
  4. Connect Async (OddSockets Client)
  5. Bind On Connected event to your connection handler

Channel Subscription in Blueprints:

  1. In your On Connected event handler:
  2. Get Channel (OddSockets Client) → Set Channel Name
  3. Make Subscription Options → Configure history, presence, etc.
  4. Subscribe Async (Channel) → Connect Options input
  5. Bind On Message event to your message handler

Sending Messages in Blueprints:

  1. Is Subscribed (Channel) → Branch (True/False)
  2. If True: Publish Async (Channel)
  3. Connect your message string to the Message input
  4. Optionally create Publish Options for TTL, metadata

Handling Presence in Blueprints:

  1. Enable presence in Subscription Options
  2. Bind to On Presence Change event
  3. Use Get Presence Async to retrieve current users
  4. Use Update State Async to update your user state

Blueprint Event Handling Example:

// Blueprint Event Graph pseudo-code: Event BeginPlay ├── Spawn Actor from Class (OddSockets Client) ├── Make O