Loading...
Loading...
SpacetimeDB Unreal Engine client SDK reference. Use when building Unreal Engine clients that connect to SpacetimeDB.
npx skill4agent add clockworklabs/spacetimedb unrealrust-servercsharp-serverPluginsSpacetimeDbSdkPlugins/.uproject"SpacetimeDbSdk"Build.csPublicDependencyModuleNames.AddRange(new string[] { "SpacetimeDbSdk" });spacetime generate --lang unrealcpp \
--uproject-dir <path_to_uproject_directory> \
--module-path <path_to_spacetimedb_module> \
--unreal-module-name <your_unreal_module_name>ModuleBindings/#include "ModuleBindings/SpacetimeDBClient.g.h"FrameTick#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ModuleBindings/SpacetimeDBClient.g.h"
#include "GameManager.generated.h"
class UDbConnection;
UCLASS()
class AGameManager : public AActor
{
GENERATED_BODY()
public:
AGameManager();
static AGameManager* Instance;
UPROPERTY(EditAnywhere, Category="SpacetimeDB")
FString ServerUri = TEXT("127.0.0.1:3000");
UPROPERTY(EditAnywhere, Category="SpacetimeDB")
FString DatabaseName = TEXT("my-module");
UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB")
UDbConnection* Conn = nullptr;
UPROPERTY(BlueprintReadOnly, Category="SpacetimeDB")
FSpacetimeDBIdentity LocalIdentity;
protected:
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
public:
virtual void Tick(float DeltaTime) override;
private:
UFUNCTION() void HandleConnect(UDbConnection* InConn, FSpacetimeDBIdentity Identity, const FString& Token);
UFUNCTION() void HandleConnectError(const FString& Error);
UFUNCTION() void HandleDisconnect(UDbConnection* InConn, const FString& Error);
UFUNCTION() void HandleSubscriptionApplied(FSubscriptionEventContext& Context);
};#include "GameManager.h"
#include "Connection/Credentials.h"
AGameManager* AGameManager::Instance = nullptr;
AGameManager::AGameManager()
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.bStartWithTickEnabled = true;
}
void AGameManager::BeginPlay()
{
Super::BeginPlay();
Instance = this;
FOnConnectDelegate ConnectDelegate;
BIND_DELEGATE_SAFE(ConnectDelegate, this, AGameManager, HandleConnect);
FOnDisconnectDelegate DisconnectDelegate;
BIND_DELEGATE_SAFE(DisconnectDelegate, this, AGameManager, HandleDisconnect);
FOnConnectErrorDelegate ConnectErrorDelegate;
BIND_DELEGATE_SAFE(ConnectErrorDelegate, this, AGameManager, HandleConnectError);
UCredentials::Init(TEXT(".spacetime_token"));
FString Token = UCredentials::LoadToken();
UDbConnectionBuilder* Builder = UDbConnection::Builder()
->WithUri(ServerUri)
->WithDatabaseName(DatabaseName)
->OnConnect(ConnectDelegate)
->OnDisconnect(DisconnectDelegate)
->OnConnectError(ConnectErrorDelegate);
if (!Token.IsEmpty())
{
Builder->WithToken(Token);
}
Conn = Builder->Build();
}
void AGameManager::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if (Conn) { Conn->Disconnect(); Conn = nullptr; }
if (Instance == this) { Instance = nullptr; }
Super::EndPlay(EndPlayReason);
}
void AGameManager::Tick(float DeltaTime)
{
if (Conn && Conn->IsActive())
{
Conn->FrameTick();
}
}
void AGameManager::HandleConnect(UDbConnection* InConn, FSpacetimeDBIdentity Identity, const FString& Token)
{
LocalIdentity = Identity;
UCredentials::SaveToken(Token);
FOnSubscriptionApplied AppliedDelegate;
BIND_DELEGATE_SAFE(AppliedDelegate, this, AGameManager, HandleSubscriptionApplied);
Conn->SubscriptionBuilder()
->OnApplied(AppliedDelegate)
->SubscribeToAllTables();
}
void AGameManager::HandleConnectError(const FString& Error)
{
UE_LOG(LogTemp, Error, TEXT("Connection error: %s"), *Error);
}
void AGameManager::HandleDisconnect(UDbConnection* InConn, const FString& Error)
{
UE_LOG(LogTemp, Warning, TEXT("Disconnected: %s"), *Error);
}
void AGameManager::HandleSubscriptionApplied(FSubscriptionEventContext& Context)
{
UE_LOG(LogTemp, Log, TEXT("Subscription applied - game state loaded"));
}Conn->FrameTick()Tick()Conn->SetAutoTicking(true)->UDbConnection* Conn = UDbConnection::Builder()
->WithUri(TEXT("127.0.0.1:3000"))
->WithDatabaseName(TEXT("my-module"))
->WithToken(SavedToken) // optional
->WithCompression(ESpacetimeDBCompression::Gzip) // optional
->OnConnect(ConnectDelegate)
->OnConnectError(ErrorDelegate)
->OnDisconnect(DisconnectDelegate)
->Build();UFUNCTION()
void OnConnected(UDbConnection* Connection, FSpacetimeDBIdentity Identity, const FString& Token);TokenIdentity// Subscribe to all public tables
Conn->SubscriptionBuilder()
->OnApplied(AppliedDelegate)
->SubscribeToAllTables();
// Subscribe to specific queries
TArray<FString> Queries = { TEXT("SELECT * FROM player"), TEXT("SELECT * FROM entity") };
Conn->SubscriptionBuilder()
->OnApplied(AppliedDelegate)
->OnError(ErrorDelegate)
->Subscribe(Queries);SubscribeSubscribeToAllTablesUSubscriptionHandle*USubscriptionHandle* Handle = Conn->SubscriptionBuilder()->...->Subscribe(Queries);
Handle->IsActive(); // true while subscription is live
Handle->Unsubscribe(); // cancel the subscription
Handle->UnsubscribeThen(OnEndDelegate); // cancel with callback
Handle->GetQuerySqls(); // get the SQL queriesSELECT * FROM view_name(literal_args)Conn->Db// Find by unique/primary key (returns by value; default-constructed if not found)
FUserType User = Conn->Db->User->Identity->Find(SomeIdentity);
// Filter by BTree index
TArray<FPlayerType> LevelFive = Conn->Db->Player->Level->Filter(5);
// Iterate all rows
TArray<FEntityType> AllEntities = Conn->Db->Entity->Iter();
// Count
int32 Total = Conn->Db->Player->Count();// OnInsert
Conn->Db->User->OnInsert.AddDynamic(this, &AMyActor::OnUserInsert);
// OnDelete
Conn->Db->User->OnDelete.AddDynamic(this, &AMyActor::OnUserDelete);
// OnUpdate (only fires for rows with a primary key)
Conn->Db->User->OnUpdate.AddDynamic(this, &AMyActor::OnUserUpdate);UFUNCTION()
void OnUserInsert(const FEventContext& Context, const FUserType& NewRow);
UFUNCTION()
void OnUserDelete(const FEventContext& Context, const FUserType& DeletedRow);
UFUNCTION()
void OnUserUpdate(const FEventContext& Context, const FUserType& OldRow, const FUserType& NewRow);HandleSubscriptionAppliedConn->ReducersConn->Reducers->SendMessage(TEXT("Hello!"));
Conn->Reducers->SetName(TEXT("Alice"));
Conn->Reducers->MovePlayer(1.0f, 0.0f);Conn->Reducers->OnSendMessage.AddDynamic(this, &AMyActor::OnSendMessageResult);UFUNCTION()
void OnSendMessageResult(const FReducerEventContext& Context, const FString& Text)
{
UE_LOG(LogTemp, Log, TEXT("SendMessage result for: %s"), *Text);
}BIND_DELEGATE_SAFEFOnConnectDelegate ConnectDelegate;
BIND_DELEGATE_SAFE(ConnectDelegate, this, AMyActor, HandleConnect);// FSpacetimeDBIdentity -- 256-bit unique user identifier, persists across connections
FSpacetimeDBIdentity Identity;
Identity.ToHex();
// FSpacetimeDBConnectionId -- 128-bit per-session connection identifier
FSpacetimeDBConnectionId ConnId = Conn->GetConnectionId();
// From any context
FSpacetimeDBIdentity Id;
bool Found = Context.TryGetIdentity(Id);
FSpacetimeDBConnectionId CId = Context.GetConnectionId();UCredentialsUCredentials::Init(TEXT(".spacetime_token"));
FString Token = UCredentials::LoadToken();
// ... after connect:
UCredentials::SaveToken(Token);DbReducers| Type | Used In |
|---|---|
| Table row callbacks (OnInsert, OnDelete, OnUpdate) |
| Reducer result callbacks |
| Subscription lifecycle callbacks (OnApplied, OnError) |
| Error callbacks |
FContextBaseContext.Db // URemoteTables* -- client cache
Context.Reducers // URemoteReducers* -- invoke reducers
Context.SubscriptionBuilder() // start a new subscriptionUFUNCTION(BlueprintCallable)UPROPERTY(BlueprintReadOnly/BlueprintAssignable)UDbConnection::Builder()BlueprintCallableOnInsertOnDeleteOnUpdateBlueprintAssignableConn->DbConn->ReducersBlueprintReadOnlyBlueprintTypeBlueprintReadWriteUDbConnectionFTickableGameObject// Option 1: Call FrameTick() manually in your Actor's Tick() (shown in GameManager above)
void Tick(float DeltaTime) { Conn->FrameTick(); }
// Option 2: Enable auto ticking. The SDK then processes messages every frame automatically
Conn->SetAutoTicking(true);Builder->WithCompression(ESpacetimeDBCompression::Gzip); // default
Builder->WithCompression(ESpacetimeDBCompression::None); // no compressionFFUserTypeFEntityTypeUUUserTableGENERATED_BODY()UPROPERTY()