Skip to content

Commit d913998

Browse files
Add Unreal client SDK procedures (#3667)
# Description of Changes Closes: #3535 Updated the Unreal SDK to handle procedures and procedure callbacks as closely matched to Rust + C#. # API and ABI breaking changes N/A # Expected complexity level and risk 2 - This adds a new testing frame that should be removed once procedures are handled in /modules/sdk-test. # Testing Added a mirror of /sdks/unreal/tests/TestClient to use the new /modules/sdk-test-procedure which adds complexity we'll want to remove. - [x] Add Unreal client test of sdk-test-procedure
1 parent 71ff927 commit d913998

File tree

61 files changed

+6044
-530
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+6044
-530
lines changed

crates/codegen/src/unrealcpp.rs

Lines changed: 1201 additions & 396 deletions
Large diffs are not rendered by default.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,38 @@
11
#include "Connection/Callback.h"
2+
3+
uint32 UProcedureCallbacks::GetNextRequestId()
4+
{
5+
return NextRequestIdCounter.fetch_add(1, std::memory_order_relaxed);
6+
}
7+
8+
uint32 UProcedureCallbacks::RegisterCallback(const FOnProcedureCompleteDelegate& Callback)
9+
{
10+
uint32 RequestId = GetNextRequestId();
11+
PendingCallbacks.Add(RequestId, Callback);
12+
return RequestId;
13+
}
14+
15+
bool UProcedureCallbacks::ResolveCallback(uint32 RequestId, const FSpacetimeDBEvent& Event,
16+
const TArray<uint8>& ResultData, bool bSuccess)
17+
{
18+
if (FOnProcedureCompleteDelegate* Callback = PendingCallbacks.Find(RequestId))
19+
{
20+
// Execute the callback
21+
Callback->ExecuteIfBound(Event, ResultData, bSuccess);
22+
23+
// Remove the callback (one-time use, like Rust SDK)
24+
PendingCallbacks.Remove(RequestId);
25+
return true;
26+
}
27+
return false;
28+
}
29+
30+
bool UProcedureCallbacks::RemoveCallback(uint32 RequestId)
31+
{
32+
return PendingCallbacks.Remove(RequestId) > 0;
33+
}
34+
35+
void UProcedureCallbacks::ClearAllCallbacks()
36+
{
37+
PendingCallbacks.Empty();
38+
}

sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Private/Connection/DbConnectionBase.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
#include "Misc/ScopeLock.h"
1414
#include "Async/Async.h"
1515
#include "BSATN/UEBSATNHelpers.h"
16+
#include "Connection/ProcedureFlags.h"
1617

1718
UDbConnectionBase::UDbConnectionBase(const FObjectInitializer& ObjectInitializer)
1819
: Super(ObjectInitializer)
1920
{
2021
NextRequestId = 1;
2122
NextSubscriptionId = 1;
23+
ProcedureCallbacks = CreateDefaultSubobject<UProcedureCallbacks>(TEXT("ProcedureCallbacks"));
2224
}
2325

2426
void UDbConnectionBase::Disconnect()
@@ -336,6 +338,34 @@ void UDbConnectionBase::ProcessServerMessage(const FServerMessageType& Message)
336338
}
337339
break;
338340
}
341+
case EServerMessageTag::ProcedureResult:
342+
{
343+
const FProcedureResultType Payload = Message.GetAsProcedureResult();
344+
FProcedureEvent ProcEvent;
345+
ProcEvent.Status = Payload.Status;
346+
ProcEvent.Timestamp = Payload.Timestamp;
347+
ProcEvent.TotalHostExecutionDuration = Payload.TotalHostExecutionDuration;
348+
ProcEvent.Success = ProcEvent.Status.IsReturned();
349+
TArray<uint8> PayloadData;
350+
FString ErrorMessage = "";
351+
if (ProcEvent.Success)
352+
PayloadData = ProcEvent.Status.GetAsReturned();
353+
if (Payload.Status.IsOutOfEnergy())
354+
{
355+
ErrorMessage = TEXT("Out of energy");
356+
}
357+
else if (Payload.Status.IsInternalError())
358+
{
359+
ErrorMessage = Payload.Status.GetAsInternalError();
360+
}
361+
362+
ProcedureCallbacks->ResolveCallback(Payload.RequestId, FSpacetimeDBEvent::Procedure(ProcEvent), PayloadData, ProcEvent.Success);
363+
if (!ProcEvent.Success)
364+
{
365+
ProcedureEventFailed(ProcEvent, ErrorMessage);
366+
}
367+
break;
368+
}
339369
default:
340370
// Unknown tag - bail out
341371
UE_LOG(LogTemp, Warning, TEXT("Unknown server-message tag"));
@@ -601,7 +631,6 @@ void UDbConnectionBase::UnsubscribeInternal(USubscriptionHandleBase* Handle)
601631

602632
void UDbConnectionBase::InternalCallReducer(const FString& Reducer, TArray<uint8> Args, USetReducerFlagsBase* Flags)
603633
{
604-
605634
if (!WebSocket || !WebSocket->IsConnected())
606635
{
607636
UE_LOG(LogTemp, Error, TEXT("Cannot call reducer, not connected to server!"));
@@ -625,7 +654,24 @@ void UDbConnectionBase::InternalCallReducer(const FString& Reducer, TArray<uint8
625654
FClientMessageType Msg = FClientMessageType::CallReducer(MsgData);
626655
TArray<uint8> Data = UE::SpacetimeDB::Serialize(Msg);
627656
SendRawMessage(Data);
657+
}
658+
659+
void UDbConnectionBase::InternalCallProcedure(const FString& ProcedureName, TArray<uint8> Args, const FOnProcedureCompleteDelegate& Callback)
660+
{
661+
if (!WebSocket || !WebSocket->IsConnected())
662+
{
663+
UE_LOG(LogTemp, Error, TEXT("Cannot call proceduer, not connected to server!"));
664+
return;
665+
}
666+
FCallProcedureType MsgData;
667+
MsgData.Procedure = ProcedureName;
668+
MsgData.Args = Args;
669+
MsgData.RequestId = ProcedureCallbacks->RegisterCallback(Callback);
670+
MsgData.Flags = static_cast<uint8>(EProcedureFlags::Default);
628671

672+
FClientMessageType Msg = FClientMessageType::CallProcedure(MsgData);
673+
TArray<uint8> Data = UE::SpacetimeDB::Serialize(Msg);
674+
SendRawMessage(Data);
629675
}
630676

631677
void UDbConnectionBase::ApplyRegisteredTableUpdates(const FDatabaseUpdateType& Update, void* Context)

0 commit comments

Comments
 (0)