unreal
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSpacetimeDB Unreal Engine Integration
SpacetimeDB Unreal Engine 集成
This skill covers Unreal Engine-specific patterns for connecting to SpacetimeDB. For server-side module development, see the or skills.
rust-servercsharp-server此 skill 介绍连接 SpacetimeDB 的 Unreal Engine 专属模式。对于服务端模块开发,请参阅 或 skills。
rust-servercsharp-serverInstallation
安装
Add the SpacetimeDB Unreal SDK as a plugin:
- Create a folder in your Unreal project root if it does not exist.
Plugins - Copy the folder into
SpacetimeDbSdk.Plugins/ - Right-click your file and select Generate Visual Studio project files.
.uproject - Add to your module's
"SpacetimeDbSdk":Build.cs
csharp
PublicDependencyModuleNames.AddRange(new string[] { "SpacetimeDbSdk" });将 SpacetimeDB Unreal SDK 作为 plugin 添加:
- 如果 Unreal 项目根目录中不存在 文件夹,请创建。
Plugins - 将 文件夹复制到
SpacetimeDbSdk。Plugins/ - 右键点击 文件并选择 生成 Visual Studio 项目文件。
.uproject - 将 添加到模块的
"SpacetimeDbSdk":Build.cs
csharp
PublicDependencyModuleNames.AddRange(new string[] { "SpacetimeDbSdk" });Generate Module Bindings
生成模块绑定
bash
spacetime generate --lang unrealcpp \
--uproject-dir <path_to_uproject_directory> \
--module-path <path_to_spacetimedb_module> \
--unreal-module-name <your_unreal_module_name>This generates C++ bindings in inside your project. Include the generated header:
ModuleBindings/cpp
#include "ModuleBindings/SpacetimeDBClient.g.h"Regenerate whenever you change module tables, reducers, or types.
bash
spacetime generate --lang unrealcpp \
--uproject-dir <path_to_uproject_directory> \
--module-path <path_to_spacetimedb_module> \
--unreal-module-name <your_unreal_module_name>这会在项目的 中生成 C++ 绑定。请包含生成的头文件:
ModuleBindings/cpp
#include "ModuleBindings/SpacetimeDBClient.g.h"每次更改模块 tables、reducers 或 types 后,都要重新生成。
GameManager Actor Pattern
GameManager Actor 模式
The recommended pattern is a singleton Actor that owns the connection. Enable ticking so is called every frame.
FrameTick推荐模式是使用一个拥有连接的单例 Actor。启用 ticking,使 每帧被调用。
FrameTickHeader (GameManager.h)
头文件(GameManager.h)
cpp
#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);
};cpp
#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);
};Source (GameManager.cpp)
源文件(GameManager.cpp)
cpp
#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"));
}cpp
#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"));
}FrameTick -- Critical
FrameTick -- 关键
You must either call every frame in your Actor's , or call once at startup. The SDK queues all network messages and only processes them on tick. Without one of these, no callbacks fire and the client appears frozen.
Conn->FrameTick()Tick()Conn->SetAutoTicking(true)你必须在 Actor 的 中每帧调用 ,或者在启动时调用一次 。 SDK 会将所有网络消息加入队列,并且仅在 tick 时处理它们。如果不采用其中任何一种方式,回调将不会触发,客户端看起来会陷入冻结状态。
Tick()Conn->FrameTick()Conn->SetAutoTicking(true)Connection Builder
连接 Builder
Build a connection with the builder pattern. All builder methods return pointers for chaining with .
->cpp
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();使用 builder 模式创建连接。所有 builder 方法都会返回指针,可通过 进行链式调用。
->cpp
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();OnConnect callback signature
OnConnect 回调签名
cpp
UFUNCTION()
void OnConnected(UDbConnection* Connection, FSpacetimeDBIdentity Identity, const FString& Token);Save the for future reconnection. The is the user's persistent identifier.
TokenIdentitycpp
UFUNCTION()
void OnConnected(UDbConnection* Connection, FSpacetimeDBIdentity Identity, const FString& Token);保存 以供后续重新连接。 是用户的持久标识符。
TokenIdentitySubscribing to Tables
订阅表
After connecting, subscribe to receive table data:
cpp
// 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);连接后,订阅以接收表数据:
cpp
// 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);Subscription Handle
订阅句柄
SubscribeSubscribeToAllTablesUSubscriptionHandle*cpp
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 queriesFor views with arguments (2.13+), use only raw SQL . Use explicit queries for every table on that connection, not subscribe-all. All argument values share one cache table; unsubscribe from obsolete arguments to avoid combining their rows. Validate/encode dynamic values as SQL literals rather than concatenating untrusted input.
SELECT * FROM view_name(literal_args)SubscribeSubscribeToAllTablesUSubscriptionHandle*cpp
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 queries对于带参数的 views(2.13+),只能使用原始 SQL 。在该连接上为每张表使用显式查询,不要使用 subscribe-all。所有参数值共享同一个缓存表;请取消订阅不再使用的参数,以避免将其行合并。对动态值进行验证并编码为 SQL 字面量,而不是直接拼接不受信任的输入。
SELECT * FROM view_name(literal_args)Reading the Client Cache
读取客户端缓存
Access tables through :
Conn->Dbcpp
// 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();通过 访问表:
Conn->Dbcpp
// 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();Row Callbacks
行回调
Register callbacks on table objects. Callbacks use Unreal dynamic multicast delegates.
cpp
// 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);在表对象上注册回调。回调使用 Unreal 动态多播 delegates。
cpp
// 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);Callback signatures (must be UFUNCTION)
回调签名(必须是 UFUNCTION)
cpp
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);Register callbacks before connecting or in .
HandleSubscriptionAppliedcpp
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);在连接前或 中注册回调。
HandleSubscriptionAppliedCalling Reducers
调用 Reducers
Invoke reducers through :
Conn->Reducerscpp
Conn->Reducers->SendMessage(TEXT("Hello!"));
Conn->Reducers->SetName(TEXT("Alice"));
Conn->Reducers->MovePlayer(1.0f, 0.0f);通过 调用 reducers:
Conn->Reducerscpp
Conn->Reducers->SendMessage(TEXT("Hello!"));
Conn->Reducers->SetName(TEXT("Alice"));
Conn->Reducers->MovePlayer(1.0f, 0.0f);Reducer Result Callbacks
Reducer 结果回调
Observe when a reducer you called completes:
cpp
Conn->Reducers->OnSendMessage.AddDynamic(this, &AMyActor::OnSendMessageResult);cpp
UFUNCTION()
void OnSendMessageResult(const FReducerEventContext& Context, const FString& Text)
{
UE_LOG(LogTemp, Log, TEXT("SendMessage result for: %s"), *Text);
}These delegates fire only for reducer calls made by this connection, not for other clients' calls.
观察你调用的 reducer 何时完成:
cpp
Conn->Reducers->OnSendMessage.AddDynamic(this, &AMyActor::OnSendMessageResult);cpp
UFUNCTION()
void OnSendMessageResult(const FReducerEventContext& Context, const FString& Text)
{
UE_LOG(LogTemp, Log, TEXT("SendMessage result for: %s"), *Text);
}这些 delegates 仅针对由此连接发起的 reducer 调用触发,而不会针对其他客户端的调用触发。
Delegate Binding with BIND_DELEGATE_SAFE
使用 BIND_DELEGATE_SAFE 绑定 Delegate
Use the macro to safely bind delegates to member functions:
BIND_DELEGATE_SAFEcpp
FOnConnectDelegate ConnectDelegate;
BIND_DELEGATE_SAFE(ConnectDelegate, this, AMyActor, HandleConnect);This is the recommended pattern for all SpacetimeDB delegate bindings in C++.
使用 宏将 delegates 安全绑定到成员函数:
BIND_DELEGATE_SAFEcpp
FOnConnectDelegate ConnectDelegate;
BIND_DELEGATE_SAFE(ConnectDelegate, this, AMyActor, HandleConnect);这是在 C++ 中所有 SpacetimeDB delegate 绑定的推荐模式。
Identity and ConnectionId
Identity 与 ConnectionId
cpp
// 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();cpp
// 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();Token Persistence
Token 持久化
Use the built-in helper to save and load tokens. Passing the saved server-issued token back on reconnect keeps the same identity. This token does not expire and a lost one can't be recovered, so self-issued identities are for development. For production, authenticate with an OIDC provider such as SpacetimeAuth, which handles token lifecycle.
UCredentialscpp
UCredentials::Init(TEXT(".spacetime_token"));
FString Token = UCredentials::LoadToken();
// ... after connect:
UCredentials::SaveToken(Token);使用内置的 helper 保存和加载 token。将服务器签发的已保存 token 在重新连接时传回,可保持相同的 identity。该 token 不会过期,丢失后也无法恢复,因此自行签发的 identity 仅用于开发。生产环境应使用 OIDC provider(例如 SpacetimeAuth)进行身份验证,由其管理 token 生命周期。
UCredentialscpp
UCredentials::Init(TEXT(".spacetime_token"));
FString Token = UCredentials::LoadToken();
// ... after connect:
UCredentials::SaveToken(Token);Context Types
Context 类型
All callbacks receive a context struct that provides access to and :
DbReducers| Type | Used In |
|---|---|
| Table row callbacks (OnInsert, OnDelete, OnUpdate) |
| Reducer result callbacks |
| Subscription lifecycle callbacks (OnApplied, OnError) |
| Error callbacks |
All inherit from which provides:
FContextBasecpp
Context.Db // URemoteTables* -- client cache
Context.Reducers // URemoteReducers* -- invoke reducers
Context.SubscriptionBuilder() // start a new subscription所有回调都会接收一个 context struct,该结构体提供对 和 的访问:
DbReducers| 类型 | 使用场景 |
|---|---|
| 表行回调(OnInsert、OnDelete、OnUpdate) |
| Reducer 结果回调 |
| 订阅生命周期回调(OnApplied、OnError) |
| 错误回调 |
它们都继承自 ,后者提供:
FContextBasecpp
Context.Db // URemoteTables* -- client cache
Context.Reducers // URemoteReducers* -- invoke reducers
Context.SubscriptionBuilder() // start a new subscriptionBlueprint Integration
Blueprint 集成
All core classes are Blueprint-accessible via and :
UFUNCTION(BlueprintCallable)UPROPERTY(BlueprintReadOnly/BlueprintAssignable)- and all builder methods are
UDbConnection::Builder().BlueprintCallable - Table callbacks (,
OnInsert,OnDelete) areOnUpdatedelegates.BlueprintAssignable - Reducer invoke methods and result delegates are Blueprint-accessible.
- and
Conn->DbareConn->Reducersproperties.BlueprintReadOnly - Generated row types are USTRUCTs with
BlueprintTypeproperties.BlueprintReadWrite
This means you can build the entire connection and callback flow in Blueprints without writing C++.
所有核心类都可通过 和 供 Blueprint 访问:
UFUNCTION(BlueprintCallable)UPROPERTY(BlueprintReadOnly/BlueprintAssignable)- 及所有 builder 方法均为
UDbConnection::Builder()。BlueprintCallable - 表 callbacks(、
OnInsert、OnDelete)是OnUpdatedelegates。BlueprintAssignable - Reducer 调用方法和结果 delegates 可供 Blueprint 访问。
- 和
Conn->Db是Conn->Reducersproperties。BlueprintReadOnly - 生成的行类型是带有 properties 的
BlueprintReadWriteUSTRUCT。BlueprintType
这意味着你可以在 Blueprints 中构建完整的连接和回调流程,而无需编写 C++。
Unreal-Specific Considerations
Unreal 专属注意事项
Auto Ticking Alternative
自动 Ticking 替代方案
UDbConnectionFTickableGameObjectcpp
// 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);Pick one. Without either, no callbacks fire.
UDbConnectionFTickableGameObjectcpp
// 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);选择其中一种。如果两者都不采用,回调将不会触发。
Compression
压缩
cpp
Builder->WithCompression(ESpacetimeDBCompression::Gzip); // default
Builder->WithCompression(ESpacetimeDBCompression::None); // no compressioncpp
Builder->WithCompression(ESpacetimeDBCompression::Gzip); // default
Builder->WithCompression(ESpacetimeDBCompression::None); // no compressionGenerated Types
生成的类型
Codegen produces USTRUCTs prefixed with (e.g., , ) and table classes prefixed with (e.g., ). Row types use and for full reflection support.
FFUserTypeFEntityTypeUUUserTableGENERATED_BODY()UPROPERTY()Codegen 会生成以 为前缀的 USTRUCT(例如 、),以及以 为前缀的表类(例如 )。行类型使用 和 来提供完整的反射支持。
FFUserTypeFEntityTypeUUUserTableGENERATED_BODY()UPROPERTY()